diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 737a5a3017b..46e7a2410e9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,7 +10,7 @@ jobs: run: | mkdir -p ./pr echo ${{ github.event.number }} > ./pr/NR - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v4 if: github.event_name == 'pull_request' with: name: pr @@ -20,7 +20,7 @@ jobs: # # We need to fetch more than one commit to be able to access HEAD^2 in case # of a pull request - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 10 # In case of a push event, the commit we care about is simply HEAD. @@ -46,7 +46,7 @@ jobs: echo "$(git log --format=%B -n 1 HEAD^2)" >> $GITHUB_ENV echo "EOF" >> $GITHUB_ENV echo "PREVIOUS_COMMIT=$(git log --format=%H -n 1 HEAD^2~1)" >> $GITHUB_ENV - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: '3.10' architecture: 'x64' @@ -110,10 +110,10 @@ jobs: PREVIOUS_COMMIT: ${{ needs.setup.outputs.previous_commit }} PR_NUMBER: ${{ github.event.pull_request.number }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 10 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: '3.10' architecture: 'x64' @@ -155,7 +155,7 @@ jobs: # run-ci.py runs the diffing to see if github actions needs to test this framework. Ideally/eventually, # we'd like to try and do the diffing before github_actions_clean & setup. # This will run the tests exactly as you would in your own vm: - docker network create tfb > /dev/null 2>&1 && docker run --network=tfb -e USER_ID=$(id -u) -v /var/run/docker.sock:/var/run/docker.sock --mount type=bind,source=`pwd`,target=/FrameworkBenchmarks techempower/tfb --mode verify --test-dir $RUN_TESTS --results-environment Github-Actions; + docker network create tfb > /dev/null 2>&1 && docker run --network=tfb -e USER_ID=$(id -u) -e CI=true -v /var/run/docker.sock:/var/run/docker.sock --mount type=bind,source=`pwd`,target=/FrameworkBenchmarks techempower/tfb --mode verify --test-dir $RUN_TESTS --results-environment Github-Actions; dependabot: needs: verify runs-on: ubuntu-latest diff --git a/.github/workflows/get-maintainers.yml b/.github/workflows/get-maintainers.yml index 7370310eb80..fb35e03b8c4 100644 --- a/.github/workflows/get-maintainers.yml +++ b/.github/workflows/get-maintainers.yml @@ -8,7 +8,7 @@ jobs: get_maintainers: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 10 - name: Get commit branch and commit message from PR @@ -19,7 +19,7 @@ jobs: echo "$(git log --format=%B -n 1 HEAD^2)" >> $GITHUB_ENV echo "EOF" >> $GITHUB_ENV echo "PREVIOUS_COMMIT=$(git log --format=%H -n 1 HEAD^2~1)" >> $GITHUB_ENV - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: '3.10' architecture: 'x64' @@ -31,7 +31,7 @@ jobs: run: | python ./toolset/github_actions/get_maintainers.py > ./maintainers/maintainers.md - name: Save Maintainers - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: maintainers path: maintainers/ diff --git a/.github/workflows/label-failing-pr.yml b/.github/workflows/label-failing-pr.yml index 84ba509086c..10910510ace 100644 --- a/.github/workflows/label-failing-pr.yml +++ b/.github/workflows/label-failing-pr.yml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: 'Download artifact' - uses: actions/github-script@v3.1.0 + uses: actions/github-script@v7 with: # scripts lightly modified from https://securitylab.github.com/research/github-actions-preventing-pwn-requests script: | @@ -32,7 +32,7 @@ jobs: fs.writeFileSync('${{github.workspace}}/pr.zip', Buffer.from(download.data)); - run: unzip pr.zip - name: Label PR - uses: actions/github-script@v3 + uses: actions/github-script@v7 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | diff --git a/.github/workflows/ping-maintainers.yml b/.github/workflows/ping-maintainers.yml index dd8dd607f68..5f97223b437 100644 --- a/.github/workflows/ping-maintainers.yml +++ b/.github/workflows/ping-maintainers.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: 'Download maintainers artifact' - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: script: | let artifacts = await github.rest.actions.listWorkflowRunArtifacts({ @@ -32,7 +32,7 @@ jobs: fs.writeFileSync('${{github.workspace}}/maintainers.zip', Buffer.from(download.data)); - run: unzip maintainers.zip - name: Ping maintainers - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | diff --git a/.gitignore b/.gitignore index bd7318e44d9..2f4e02babd6 100644 --- a/.gitignore +++ b/.gitignore @@ -69,3 +69,4 @@ benchmark.cfg # python .venv/ +frameworks/CSharp/akazawayun.pro/Dockerfile diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 00000000000..38838d563cc --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,133 @@ + +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, caste, color, religion, or sexual +identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the overall + community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or advances of + any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email address, + without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official email address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +tfb@techempower.com. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of +actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or permanent +ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the +community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.1, available at +[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. + +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder][Mozilla CoC]. + +For answers to common questions about this code of conduct, see the FAQ at +[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at +[https://www.contributor-covenant.org/translations][translations]. + +[homepage]: https://www.contributor-covenant.org +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html +[Mozilla CoC]: https://github.com/mozilla/diversity +[FAQ]: https://www.contributor-covenant.org/faq +[translations]: https://www.contributor-covenant.org/translations diff --git a/Dockerfile b/Dockerfile index b0a94b7b504..c02bb66c087 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,58 +1,56 @@ -FROM ubuntu:22.04 +FROM ubuntu:24.04 ARG DEBIAN_FRONTEND=noninteractive # WARNING: DON'T PUT A SPACE AFTER ANY BACKSLASH OR APT WILL BREAK # One -q produces output suitable for logging (mostly hides # progress indicators) -RUN apt-get -yqq update && \ - apt-get -yqq install \ +RUN apt-get install \ + --no-install-recommends \ -o Dpkg::Options::="--force-confdef" \ -o Dpkg::Options::="--force-confold" \ + -qqUy \ cloc \ curl \ gcc \ git-core \ gosu \ + iproute2 \ # Needed for mysqlclient libmysqlclient-dev \ libpq-dev \ pkg-config \ python3 \ + python3-colorama \ python3-dev \ + python3-dnspython \ + python3-packaging \ python3-pip \ + python3-psutil \ + python3-psycopg2 \ + python3-requests \ siege \ - software-properties-common - -RUN pip3 install \ - colorama==0.3.1 \ - docker==4.0.2 \ - mysqlclient \ - psutil \ - psycopg2-binary \ - pymongo==3.13.0 \ - # urllib3 incompatibility: - # https://github.com/docker/docker-py/issues/3113#issuecomment-1525500104 - requests==2.28.1 + software-properties-common && \ + # Ubuntu's equivalent packages are too old and/or broken. + pip3 install \ + --break-system-packages \ + docker==7.0.0 \ + mysqlclient==2.2.4 \ + pymongo==4.7.2 # Collect resource usage statistics -ARG DOOL_VERSION=v1.2.0 +ARG DOOL_VERSION=v1.3.1 WORKDIR /tmp RUN curl -LSs "https://github.com/scottchiefbaker/dool/archive/${DOOL_VERSION}.tar.gz" | \ tar --strip-components=1 -xz && \ ./install.py -# Check if the group ID is already created +# create group and user ARG GROUP_ID -RUN if ! getent group "$GROUP_ID"; then \ - addgroup --gid "$GROUP_ID" user; \ - fi - -# Check if the user ID is already created ARG USER_ID -RUN if ! getent passwd "$USER_ID"; then \ - adduser --disabled-password --gecos '' --gid "$GROUP_ID" --uid "$USER_ID" user; \ - fi + +RUN groupadd -g "$GROUP_ID" user || true && \ + useradd -m -u "$USER_ID" -g "$GROUP_ID" -s /bin/bash user || true ENV FWROOT=/FrameworkBenchmarks USER_ID="$USER_ID" ENV PYTHONPATH="$FWROOT" diff --git a/entrypoint.sh b/entrypoint.sh index 71ad543e960..eb22e6e75d7 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -4,4 +4,4 @@ set -eo pipefail -u chown -LR "$USER_ID" /var/run # Drop permissions of user to match those of the host system -gosu "$USER_ID" python3 "${FWROOT}/toolset/run-tests.py" "$@" +exec gosu "$USER_ID" python3 "${FWROOT}/toolset/run-tests.py" "$@" diff --git a/frameworks/C++/cinatra/README.md b/frameworks/C++/cinatra/README.md index df01ca2c237..cc965dfb351 100644 --- a/frameworks/C++/cinatra/README.md +++ b/frameworks/C++/cinatra/README.md @@ -1,10 +1,10 @@ # cinatra Benchmarking Test -cinatra is a high-performance, easy-to-use http framework developed in Modern C++ (C++17) with the goal of making it easy and quick to develop web applications using the C++ programming language, located at https://github.com/qicosmos/cinatra +cinatra is a high-performance, easy-to-use http framework developed in Modern C++ (C++20) with the goal of making it easy and quick to develop web applications using the C++ programming language, located at https://github.com/qicosmos/cinatra ## Testing Source Code -* [PLAINTEXT](cinatra_benchmark/main.cpp) +* [PLAINTEXT](example/benchmark.cpp) ## Test URLs diff --git a/frameworks/C++/cinatra/benchmark_config.json b/frameworks/C++/cinatra/benchmark_config.json index 9db843e9f98..ceba18e4486 100644 --- a/frameworks/C++/cinatra/benchmark_config.json +++ b/frameworks/C++/cinatra/benchmark_config.json @@ -1,23 +1,25 @@ { "framework": "cinatra", - "tests": [{ - "default": { - "plaintext_url": "/plaintext", - "port": 8090, - "approach": "Realistic", - "classification": "Fullstack", - "database": "None", - "framework": "cinatra", - "language": "C++", - "flavor": "None", - "orm": "None", - "platform": "None", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "cinatra", - "notes": "", - "versus": "cinatra" + "tests": [ + { + "default": { + "plaintext_url": "/plaintext", + "port": 8090, + "approach": "Realistic", + "classification": "Fullstack", + "database": "None", + "framework": "cinatra", + "language": "C++", + "flavor": "None", + "orm": "None", + "platform": "None", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "cinatra", + "notes": "", + "versus": "cinatra" + } } - }] -} + ] +} \ No newline at end of file diff --git a/frameworks/C++/cinatra/cinatra.dockerfile b/frameworks/C++/cinatra/cinatra.dockerfile index d3731c44673..fcda3f3b083 100644 --- a/frameworks/C++/cinatra/cinatra.dockerfile +++ b/frameworks/C++/cinatra/cinatra.dockerfile @@ -1,22 +1,11 @@ -FROM ubuntu:18.04 +FROM ubuntu:22.04 RUN apt-get update -yqq && \ apt-get install -yqq cmake git uuid-dev gcc g++ autoconf -ENV ASIO=/asio -ENV ASIO_INTERNAL=/asio/asio ENV CINATRA=/cinatra -ENV CINATRA_EXAMPLE=/cinatra/example -WORKDIR / -RUN git clone https://github.com/chriskohlhoff/asio.git -WORKDIR $ASIO -RUN git checkout 8087252a0c3c2f0baad96ddbd6554db17a846376 -WORKDIR $ASIO_INTERNAL -RUN ./autogen.sh && ./configure -RUN make && make install WORKDIR / RUN git clone https://github.com/qicosmos/cinatra.git WORKDIR $CINATRA -RUN git checkout 5acb35cd72c3f72512c0a55e7dea9e25d7779039 -WORKDIR $CINATRA_EXAMPLE -RUN mkdir build && cd build && cmake .. && make +RUN git checkout c9bec308e27174c8b7f0f01c92652509f7b47253 +RUN mkdir build && cd build && cmake .. && make -j EXPOSE 8090 -CMD ./build/cinatra_example +CMD ./build/example/benchmark \ No newline at end of file diff --git a/frameworks/C++/cinatra/cinatra_benchmark/CMakeLists.txt b/frameworks/C++/cinatra/cinatra_benchmark/CMakeLists.txt index 615d6fa46d1..8bd58c0c53e 100644 --- a/frameworks/C++/cinatra/cinatra_benchmark/CMakeLists.txt +++ b/frameworks/C++/cinatra/cinatra_benchmark/CMakeLists.txt @@ -5,61 +5,10 @@ include_directories($ENV{CINATRA_HOME}) if (MSVC) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /std:c++latest") else () - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -pthread -msse4.2 -std=c++17") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -pthread -std=c++20") endif () -SET(ENABLE_GZIP OFF) -SET(ENABLE_SSL OFF) -SET(ENABLE_CLIENT_SSL OFF) -SET(ENABLE_ASIO_STANDALONE ON) +add_executable(cinatra_example main.cpp) +target_compile_definitions(cinatra_example PRIVATE ASYNC_SIMPLE_HAS_NOT_AIO) -if (ENABLE_SSL) - add_definitions(-DCINATRA_ENABLE_SSL) - message(STATUS "Use SSL") -endif() - -if(ENABLE_GZIP) - add_definitions(-DCINATRA_ENABLE_GZIP) -endif() - -if(ENABLE_CLIENT_SSL) - add_definitions(-DCINATRA_ENABLE_CLIENT_SSL) -endif() - -if(ENABLE_ASIO_STANDALONE) - add_definitions(-DASIO_STANDALONE) -else() - find_package(Boost 1.60 REQUIRED COMPONENTS system) -endif() - -if (ENABLE_SSL) -find_package(OpenSSL REQUIRED) -endif() -if (ENABLE_CLIENT_SSL) - find_package(OpenSSL REQUIRED) -endif() - -if (ENABLE_GZIP) - find_package(ZLIB REQUIRED) -endif() - -set(CINATRA_EXAMPLE - main.cpp - ) - -add_executable(${project_name} ${CINATRA_EXAMPLE}) -include_directories(${Boost_INCLUDE_DIRS} ${OPENSSL_INCLUDE_DIR}) - -target_link_libraries(${project_name} ${Boost_LIBRARIES} uuid -lstdc++fs) -if (ENABLE_SSL) - target_link_libraries(${project_name} ${OPENSSL_LIBRARIES} pthread -ldl) -endif() - -if (ENABLE_CLIENT_SSL) - target_link_libraries(${project_name} ${OPENSSL_LIBRARIES} pthread -ldl) -endif() - -if (ENABLE_GZIP) - target_link_libraries(${project_name} ${ZLIB_LIBRARIES}) -endif() install(TARGETS ${project_name} DESTINATION include) diff --git a/frameworks/C++/cinatra/cinatra_benchmark/main.cpp b/frameworks/C++/cinatra/cinatra_benchmark/main.cpp index 6d4e3fa30e9..a7ee33a846f 100644 --- a/frameworks/C++/cinatra/cinatra_benchmark/main.cpp +++ b/frameworks/C++/cinatra/cinatra_benchmark/main.cpp @@ -1,21 +1,15 @@ -#include #include +#include using namespace cinatra; +using namespace std::chrono_literals; int main() { - http_server server(std::thread::hardware_concurrency()); - bool r = server.listen("0.0.0.0", "8090"); - if (!r) { - std::cout << "listen failed\n"; - return -1; - } - - server.enable_timeout(false); - server.set_http_handler("/plaintext", [](request& req, response& res) { - res.set_status_and_content("Hello, World!"); - }); - - server.run(); - return 0; + coro_http_server server(std::thread::hardware_concurrency(), 8090); + server.set_http_handler( + "/plaintext", [](coro_http_request &req, coro_http_response &resp) { + resp.need_date_head(false); + resp.set_status_and_content(status_type::ok, "Hello, world!"); + }); + server.sync_start(); } diff --git a/frameworks/C++/cuehttp/README.md b/frameworks/C++/cuehttp/README.md deleted file mode 100644 index 600152a6635..00000000000 --- a/frameworks/C++/cuehttp/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# cuehttp Benchmarking Test - -https://github.com/xcyl/cuehttp - -## Testing Source Code - -* [PLAINTEXT](plaintext/main.cpp) - -## Test URLs - -### PLAINTEXT - -http://localhost:8080/plaintext diff --git a/frameworks/C++/cuehttp/benchmark_config.json b/frameworks/C++/cuehttp/benchmark_config.json deleted file mode 100644 index 85b98fb5188..00000000000 --- a/frameworks/C++/cuehttp/benchmark_config.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "framework": "cuehttp", - "tests": [ - { - "default": { - "plaintext_url": "/plaintext", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "None", - "framework": "cuehttp", - "language": "C++", - "flavor": "None", - "orm": "None", - "platform": "None", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "cuehttp", - "notes": "", - "versus": "cuehttp" - } - } - ] -} \ No newline at end of file diff --git a/frameworks/C++/cuehttp/config.toml b/frameworks/C++/cuehttp/config.toml deleted file mode 100644 index c9eb86399f0..00000000000 --- a/frameworks/C++/cuehttp/config.toml +++ /dev/null @@ -1,14 +0,0 @@ -[framework] -name = "cuehttp" - -[main] -urls.plaintext = "/plaintext" -approach = "Realistic" -classification = "Fullstack" -database = "None" -database_os = "Linux" -os = "Linux" -orm = "None" -platform = "None" -webserver = "None" -versus = "cuehttp" diff --git a/frameworks/C++/cuehttp/cuehttp.dockerfile b/frameworks/C++/cuehttp/cuehttp.dockerfile deleted file mode 100644 index 5ea59fbf51b..00000000000 --- a/frameworks/C++/cuehttp/cuehttp.dockerfile +++ /dev/null @@ -1,18 +0,0 @@ -FROM ubuntu:18.04 - -RUN apt-get update -yqq -RUN apt-get install -yqq g++-7 cmake git libboost-all-dev - -ENV CUEHTTP=/cuehttp - -WORKDIR / -RUN git clone https://github.com/xcyl/cuehttp.git - -WORKDIR /cuehttp - -RUN git checkout a7f5a4c935e22d110b70c5928c8ea2ce4dcbeeb5 - -WORKDIR /cuehttp/examples/plaintext -RUN mkdir build && cd build && cmake .. && make -j8 -EXPOSE 8080 -CMD ./build/plaintext diff --git a/frameworks/C++/cuehttp/plaintext/CMakeLists.txt b/frameworks/C++/cuehttp/plaintext/CMakeLists.txt deleted file mode 100644 index dc7352aabad..00000000000 --- a/frameworks/C++/cuehttp/plaintext/CMakeLists.txt +++ /dev/null @@ -1,21 +0,0 @@ -cmake_minimum_required(VERSION 2.6) - -project(plaintext) - -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -msse4.2 -Wall -std=c++17") - -set(SRC main.cpp) -include_directories($ENV{CUEHTTP}/include) - -find_package(Boost COMPONENTS system REQUIRED) -include_directories(${Boost_INCLUDE_DIRS}) - -add_executable(${PROJECT_NAME} ${SRC}) - -target_link_libraries(${PROJECT_NAME} ${Boost_LIBRARIES}) - -if (WIN32) - target_link_libraries(${PROJECT_NAME} ws2_32 wsock32) -else () - target_link_libraries(${PROJECT_NAME} pthread) -endif () diff --git a/frameworks/C++/cuehttp/plaintext/main.cpp b/frameworks/C++/cuehttp/plaintext/main.cpp deleted file mode 100644 index 2b103e2a909..00000000000 --- a/frameworks/C++/cuehttp/plaintext/main.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include - -using namespace cue::http; - -int main(int argc, char** argv) { - router route; - route.post("/plaintext", [](context& ctx) { - ctx.type("text/plain"); - ctx.status(200); - ctx.body("Hello, World!"); - }); - cuehttp app; - app.use(route); - app.listen(8080).run(); - - return 0; -} diff --git a/frameworks/C++/drogon/drogon-core.dockerfile b/frameworks/C++/drogon/drogon-core.dockerfile index 7d02dc6637f..0149f1fb228 100644 --- a/frameworks/C++/drogon/drogon-core.dockerfile +++ b/frameworks/C++/drogon/drogon-core.dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:20.04 +FROM ubuntu:22.04 COPY ./ ./ @@ -11,7 +11,7 @@ RUN apt-get update -yqq && \ zlib1g-dev && \ add-apt-repository ppa:ubuntu-toolchain-r/test -y && \ apt-get update -yqq && \ - apt-get install -yqq gcc-10 g++-10 + apt-get install -yqq gcc g++ RUN locale-gen en_US.UTF-8 @@ -19,10 +19,10 @@ ENV LANG en_US.UTF-8 ENV LANGUAGE en_US:en ENV LC_ALL en_US.UTF-8 -ENV CC=gcc-10 -ENV CXX=g++-10 -ENV AR=gcc-ar-10 -ENV RANLIB=gcc-ranlib-10 +ENV CC=gcc +ENV CXX=g++ +ENV AR=gcc-ar +ENV RANLIB=gcc-ranlib ENV IROOT=/install ENV DROGON_ROOT=$IROOT/drogon @@ -41,7 +41,7 @@ RUN git clone https://github.com/an-tao/drogon WORKDIR $DROGON_ROOT -RUN git checkout ebf87d69d7bb45dfa478ba364ef9374d9be25092 +RUN git checkout 96919df488e0ebaa0ed304bbd76bba33508df3cc RUN git submodule update --init RUN mkdir build diff --git a/frameworks/C++/drogon/drogon.dockerfile b/frameworks/C++/drogon/drogon.dockerfile index c94d2f43525..104219222f0 100644 --- a/frameworks/C++/drogon/drogon.dockerfile +++ b/frameworks/C++/drogon/drogon.dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:20.04 +FROM ubuntu:22.04 COPY ./ ./ @@ -11,7 +11,7 @@ RUN apt-get update -yqq && \ zlib1g-dev && \ add-apt-repository ppa:ubuntu-toolchain-r/test -y && \ apt-get update -yqq && \ - apt-get install -yqq gcc-10 g++-10 + apt-get install -yqq gcc g++ RUN locale-gen en_US.UTF-8 @@ -19,10 +19,10 @@ ENV LANG en_US.UTF-8 ENV LANGUAGE en_US:en ENV LC_ALL en_US.UTF-8 -ENV CC=gcc-10 -ENV CXX=g++-10 -ENV AR=gcc-ar-10 -ENV RANLIB=gcc-ranlib-10 +ENV CC=gcc +ENV CXX=g++ +ENV AR=gcc-ar +ENV RANLIB=gcc-ranlib ENV IROOT=/install ENV DROGON_ROOT=$IROOT/drogon @@ -41,7 +41,7 @@ RUN git clone https://github.com/an-tao/drogon WORKDIR $DROGON_ROOT -RUN git checkout ebf87d69d7bb45dfa478ba364ef9374d9be25092 +RUN git checkout 96919df488e0ebaa0ed304bbd76bba33508df3cc RUN git submodule update --init RUN mkdir build diff --git a/frameworks/C++/drogon/drogon_benchmark/controllers/FortuneCtrlRaw.cc b/frameworks/C++/drogon/drogon_benchmark/controllers/FortuneCtrlRaw.cc index 143c7a4ec63..0e21a547ff6 100644 --- a/frameworks/C++/drogon/drogon_benchmark/controllers/FortuneCtrlRaw.cc +++ b/frameworks/C++/drogon/drogon_benchmark/controllers/FortuneCtrlRaw.cc @@ -22,8 +22,8 @@ void FortuneCtrlRaw::asyncHandleHttpRequest( rows.reserve(r.size() + 1); for (auto const &row : r) { - rows.emplace_back(row[0ul].as(), // id - row[1ul].as()); // message + rows.emplace_back(row[0ul].as(), // id + row[1ul].as()); // message } rows.emplace_back("0", "Additional fortune added at request time."); std::sort(rows.begin(), diff --git a/frameworks/C++/drogon/drogon_benchmark/controllers/FortuneCtrlRaw.h b/frameworks/C++/drogon/drogon_benchmark/controllers/FortuneCtrlRaw.h index ec0217bcd88..82f3c0ebcd1 100644 --- a/frameworks/C++/drogon/drogon_benchmark/controllers/FortuneCtrlRaw.h +++ b/frameworks/C++/drogon/drogon_benchmark/controllers/FortuneCtrlRaw.h @@ -1,17 +1,18 @@ #pragma once #include #include +#include using namespace drogon; struct Fortune { - Fortune(string_view &&id, string_view &&message) + Fortune(std::string_view &&id, std::string_view &&message) : id_(std::move(id)), message_(std::move(message)) { } Fortune() = default; - string_view id_; - string_view message_; + std::string_view id_; + std::string_view message_; }; class FortuneCtrlRaw : public drogon::HttpSimpleController { diff --git a/frameworks/C++/drogon/drogon_benchmark/controllers/UpdatesCtrlRaw.cc b/frameworks/C++/drogon/drogon_benchmark/controllers/UpdatesCtrlRaw.cc index 71c19bcf2f7..065362eee85 100644 --- a/frameworks/C++/drogon/drogon_benchmark/controllers/UpdatesCtrlRaw.cc +++ b/frameworks/C++/drogon/drogon_benchmark/controllers/UpdatesCtrlRaw.cc @@ -43,7 +43,7 @@ void UpdatesCtrlRaw::update( const DbClientPtr &client) { auto const &sql = getSQL(results->size()); - auto sqlBinder = *client << string_view(sql.data(), sql.length()); + auto sqlBinder = *client << std::string_view(sql.data(), sql.length()); Json::Value json; json.resize(0); for (auto const &w : *results) diff --git a/frameworks/C++/ffead-cpp/benchmark_config.json b/frameworks/C++/ffead-cpp/benchmark_config.json index 6ab98997f9d..0a61221fc46 100644 --- a/frameworks/C++/ffead-cpp/benchmark_config.json +++ b/frameworks/C++/ffead-cpp/benchmark_config.json @@ -198,7 +198,7 @@ "display_name": "ffead-cpp [pg-raw-async-prof-pool-m]", "notes": "async memory profiled", "versus": "", - "tags": [] + "tags": ["broken"] }, "postgresql-raw-async-clibpqb-profiled": { "db_url": "/t4/d", @@ -301,7 +301,7 @@ "display_name": "ffead-cpp [pg-raw-async-qw-prof-pool-m]", "notes": "async memory profiled", "versus": "", - "tags": [] + "tags": ["broken"] } }] } diff --git a/frameworks/C++/just-boost/just-boost.dockerfile b/frameworks/C++/just-boost/just-boost.dockerfile index 0eb409e1ab9..32aba994393 100644 --- a/frameworks/C++/just-boost/just-boost.dockerfile +++ b/frameworks/C++/just-boost/just-boost.dockerfile @@ -1,14 +1,14 @@ # docker build --progress=plain --build-arg CXXFLAGS="-Wall" -t just-boost -f just-boost.dockerfile . # docker run --rm --name just-boost -p 8000:8000 -d just-boost # docker container stop just-boost -FROM alpine:3.18 +FROM alpine:3.19 ARG APP=just-boost ARG CXXFLAGS=-O3 ENV LANG=C.UTF-8 LC_ALL=C.UTF-8 ENV BCPP_PG_CONN_STR="postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world" -ENV BCPP_N_THREADS=32 +#ENV BCPP_N_THREADS=0 # default 0 : number of cores WORKDIR /usr/src/${APP} diff --git a/frameworks/C++/just-boost/main.cpp b/frameworks/C++/just-boost/main.cpp index fc296da6837..caa15084aea 100644 --- a/frameworks/C++/just-boost/main.cpp +++ b/frameworks/C++/just-boost/main.cpp @@ -117,8 +117,6 @@ handle_target( http::request>&& req, PGconn* conn = nullptr) { - static std::string msg = "Hello, World!"; - //std::cout << "handle_target: " << req.target() << std::endl; http::response res{http::status::ok, req.version()}; res.set(http::field::server, BOOST_BEAST_VERSION_STRING); @@ -130,13 +128,13 @@ handle_target( { // {"message":"Hello, World!"} json::object obj; - obj["message"] = msg; + obj["message"] = "Hello, World!"; res.body() = json::serialize(obj); } else if (req.target() == "/plaintext") { res.set(http::field::content_type, "text/plain"); - res.body() = msg; + res.body() = "Hello, World!"; } else if (req.target() == "/db" || req.target().starts_with("/queries/")) { @@ -328,9 +326,10 @@ do_listen(tcp::endpoint endpoint) { std::rethrow_exception(e); } - catch (std::exception &e) { - std::cerr << "Error in session: " << e.what() << "\n"; - } + catch (std::exception&){} +// catch (std::exception &e) { +// std::cerr << "Error in session: " << e.what() << "\n"; +// } }); } @@ -339,7 +338,13 @@ int main(int argc, char* argv[]) { auto const address = net::ip::make_address(becpp::env("BCPP_ADDRESS", "0.0.0.0")); auto const port = static_cast(std::atoi(becpp::env("BCPP_PORT", "8000"))); - auto const threads = std::max(1, std::atoi(becpp::env("BCPP_N_THREADS", "3"))); + auto env_threads = std::atoi(becpp::env("BCPP_N_THREADS", "0")); + if (env_threads == 0) + { + env_threads = std::thread::hardware_concurrency(); + std::cout << "Using number of cores: " << env_threads << '\n'; + } + auto const threads = std::max(1, env_threads); std::cout << "__GNUG__=" << __GNUG__ << '\n'; std::cout << "__cplusplus=" << __cplusplus << '\n'; diff --git a/frameworks/C++/libsniper/libs/core b/frameworks/C++/libsniper/libs/core new file mode 160000 index 00000000000..a792ecfebb0 --- /dev/null +++ b/frameworks/C++/libsniper/libs/core @@ -0,0 +1 @@ +Subproject commit a792ecfebb02f98bbdd8db232fba69f3f92907b3 diff --git a/frameworks/C++/paozhu/README.md b/frameworks/C++/paozhu/README.md new file mode 100755 index 00000000000..089e3030ca3 --- /dev/null +++ b/frameworks/C++/paozhu/README.md @@ -0,0 +1,40 @@ +# paozhu Benchmarking Test + +This is the [Paozhu](https://github.com/hggq/paozhu) + +This Benchmarking Test code from https://github.com/hggq/paozhu/releases/tag/v1.5.8 + +### Test Type Implementation Source Code + +* [Benchmark code](controller/src/techempower.cpp) +* [ORM config](conf/orm.conf) +* [Server config](conf/server.conf) + +## Test URLs +### JSON + +http://localhost:8888/json + +### PLAINTEXT + +http://localhost:8888/plaintext + + +### Single Database Query + +http://localhost:8888/db + +### Fortune + +http://localhost:8888/fortunes + +### Multiple Database Queries + +http://localhost:8888/queries?queries=10 + +### Database Updates + +http://localhost:8888/updates?queries=10 + +### Cache +http://localhost:8888/cached-queries?count=20 \ No newline at end of file diff --git a/frameworks/C++/paozhu/benchmark_config.json b/frameworks/C++/paozhu/benchmark_config.json new file mode 100755 index 00000000000..e50ee5ece64 --- /dev/null +++ b/frameworks/C++/paozhu/benchmark_config.json @@ -0,0 +1,31 @@ +{ + "framework": "paozhu", + "tests": [ + { + "default": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "db_url": "/db", + "fortune_url": "/fortunes", + "query_url": "/queries?queries=", + "update_url": "/updates?queries=", + "cached_query_url": "/cached-queries?count=", + "port": 8888, + "approach": "Realistic", + "classification": "Fullstack", + "database": "MySQL", + "framework": "paozhu", + "language": "C++", + "flavor": "None", + "orm": "Micro", + "platform": "None", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "paozhu", + "notes": "", + "versus": "None" + } + } + ] +} \ No newline at end of file diff --git a/frameworks/C++/paozhu/config.toml b/frameworks/C++/paozhu/config.toml new file mode 100644 index 00000000000..dab3170664a --- /dev/null +++ b/frameworks/C++/paozhu/config.toml @@ -0,0 +1,22 @@ +[framework] +name = "paozhu" +authors = ["Huang ziquan "] +github = "https://github.com/hggq/paozhu" + +[main] +urls.plaintext = "/plaintext" +urls.json = "/json" +urls.db = "/db" +urls.query = "/queries?queries=" +urls.update = "/updates?queries=" +urls.fortune = "/fortunes" +urls.cached_query = "/cached-queries?count=" +approach = "Realistic" +classification = "Fullstack" +database = "MySQL" +database_os = "Linux" +os = "Linux" +orm = "Micro" +platform = "None" +webserver = "None" +versus = "None" diff --git a/frameworks/C++/paozhu/paozhu.dockerfile b/frameworks/C++/paozhu/paozhu.dockerfile new file mode 100644 index 00000000000..a5995e66b67 --- /dev/null +++ b/frameworks/C++/paozhu/paozhu.dockerfile @@ -0,0 +1,118 @@ +FROM ubuntu:24.04 +RUN apt-get update -yqq && apt-get install -yqq apt-utils software-properties-common wget unzip cmake git +RUN apt-get install -yqq gcc g++ openssl libssl-dev zlib1g-dev build-essential locales + +RUN apt-get -y install brotli libbrotli-dev +RUN apt-get -y install libreadline-dev +# RUN apt-get -y install mysql-client +# RUN apt-get -y install libmysqlclient-dev + +RUN locale-gen en_US.UTF-8 +ENV LANG en_US.UTF-8 +ENV LANGUAGE en_US:en +ENV LC_ALL en_US.UTF-8 + +COPY ./ ./ +WORKDIR / + +# RUN wget https://github.com/hggq/paozhu/releases/download/v1.5.8/benchmark.zip +RUN git clone https://github.com/hggq/paozhu +# RUN unzip benchmark.zip +RUN rm -Rf ./paozhu/controller +RUN rm -Rf ./paozhu/libs +# RUN rm -Rf ./paozhu/view +RUN rm -Rf ./paozhu/viewsrc +RUN rm -Rf ./paozhu/orm +RUN rm -Rf ./paozhu/models +#RUN rm -Rf ./paozhu/common +RUN rm -Rf ./paozhu/common/autocontrolmethod.hpp +RUN rm -Rf ./paozhu/common/autorestfulpaths.hpp +RUN rm -Rf ./paozhu/common/json_reflect_headers.h +RUN rm -Rf ./paozhu/common/reghttpmethod_pre.hpp +RUN rm -Rf ./paozhu/common/reghttpmethod.hpp +RUN rm -Rf ./paozhu/common/websockets_method_reg.hpp +RUN rm -Rf ./paozhu/common/httphook.cpp +# COPY ./paozhu_benchmark/controller ./paozhu/ +# COPY ./paozhu_benchmark/libs ./paozhu/ +# COPY ./paozhu_benchmark/view ./paozhu/ +# COPY ./paozhu_benchmark/viewsrc ./paozhu/ + +# COPY ./paozhu_benchmark/orm ./paozhu/ +# COPY ./paozhu_benchmark/models ./paozhu/ +# COPY ./paozhu_benchmark/common ./paozhu/ + +# RUN ls -l ./paozhu +# RUN pwd +#RUN mkdir ./paozhu/common +RUN mkdir ./paozhu/libs +RUN mkdir ./paozhu/libs/types +COPY ./paozhu_benchmark/libs/types/techempower_json.h ./paozhu/libs/types/ +COPY ./paozhu_benchmark/libs/types/techempower_json_jsonreflect.cpp ./paozhu/libs/types/ + +RUN mkdir ./paozhu/controller +RUN mkdir ./paozhu/controller/include +RUN mkdir ./paozhu/controller/src + +COPY ./paozhu_benchmark/controller/include/techempower.h ./paozhu/controller/include/ +COPY ./paozhu_benchmark/controller/src/techempower.cpp ./paozhu/controller/src/ + + +COPY ./paozhu_benchmark/common/autocontrolmethod.hpp ./paozhu/common/ +COPY ./paozhu_benchmark/common/reghttpmethod_pre.hpp ./paozhu/common/ +COPY ./paozhu_benchmark/common/reghttpmethod.hpp ./paozhu/common/ +COPY ./paozhu_benchmark/common/json_reflect_headers.h ./paozhu/common/ + +#COPY ./paozhu_benchmark/common/cost_define.h ./paozhu/common/ +COPY ./paozhu_benchmark/common/autorestfulpaths.hpp ./paozhu/common/ +COPY ./paozhu_benchmark/common/websockets_method_reg.hpp ./paozhu/common/ +COPY ./paozhu_benchmark/common/httphook.cpp ./paozhu/common/ + +COPY ./paozhu_benchmark/conf/server.conf ./paozhu/conf/server.conf +COPY ./paozhu_benchmark/conf/orm.conf ./paozhu/conf/orm.conf + +# must use testbenchmark.cpp to test benchmark +COPY ./paozhu_benchmark/CMakeLists.txt ./paozhu/CMakeLists.txt + +# RUN mkdir ./paozhu/view +# RUN mkdir ./paozhu/view/techempower + +# COPY ./paozhu_benchmark/view/techempower/fortunes.html ./paozhu/view/techempower/ + +RUN mkdir ./paozhu/viewsrc +RUN mkdir ./paozhu/viewsrc/include +RUN mkdir ./paozhu/viewsrc/view +RUN mkdir ./paozhu/viewsrc/view/techempower + +COPY ./paozhu_benchmark/viewsrc/view/techempower/fortunes.cpp ./paozhu/viewsrc/view/techempower/ +COPY ./paozhu_benchmark/viewsrc/include/viewsrc.h ./paozhu/viewsrc/include/ +COPY ./paozhu_benchmark/viewsrc/include/regviewmethod.hpp ./paozhu/viewsrc/include/ + + + +RUN mkdir ./paozhu/orm +RUN mkdir ./paozhu/orm/include + + +COPY ./paozhu_benchmark/orm/orm.h ./paozhu/orm/ +COPY ./paozhu_benchmark/orm/include/fortune_base.h ./paozhu/orm/include/ +COPY ./paozhu_benchmark/orm/include/world_base.h ./paozhu/orm/include/ +COPY ./paozhu_benchmark/orm/include/fortune_mysql.h ./paozhu/orm/include/ +COPY ./paozhu_benchmark/orm/include/world_mysql.h ./paozhu/orm/include/ + +RUN mkdir ./paozhu/models +RUN mkdir ./paozhu/models/include + +COPY ./paozhu_benchmark/models/include/Fortune.h ./paozhu/models/include/ +COPY ./paozhu_benchmark/models/include/World.h ./paozhu/models/include/ +COPY ./paozhu_benchmark/models/World.cpp ./paozhu/models/ +COPY ./paozhu_benchmark/models/Fortune.cpp ./paozhu/models/ + +WORKDIR /paozhu +RUN unzip asio.zip + +RUN cmake . -B build -DCMAKE_BUILD_TYPE=Release +RUN cmake --build build + +EXPOSE 8888 + +CMD ./bin/paozhu \ No newline at end of file diff --git a/frameworks/C++/paozhu/paozhu_benchmark/CMakeLists.txt b/frameworks/C++/paozhu/paozhu_benchmark/CMakeLists.txt new file mode 100755 index 00000000000..e63ec9c1a13 --- /dev/null +++ b/frameworks/C++/paozhu/paozhu_benchmark/CMakeLists.txt @@ -0,0 +1,619 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 3.20) + +cmake_policy(SET CMP0048 NEW) + +set(ENABLE_VCPKG OFF CACHE BOOL "choose ON to enable") +set(ENABLE_BOOST OFF CACHE BOOL "choose ON to enable") +set(ENABLE_GD OFF CACHE BOOL "choose ON to enable") +set(ENABLE_WIN_VCPKG OFF CACHE BOOL "choose ON to enable") + +if(ENABLE_VCPKG) + set(vcpkg_root $ENV{VCPKG_ROOT}) + if(NOT DEFINED CMAKE_TOOLCHAIN_FILE AND vcpkg_root) + set(CMAKE_TOOLCHAIN_FILE "${vcpkg_root}/scripts/buildsystems/vcpkg.cmake") + endif() +endif() + +macro(auto_enable_vcpkg_feature opt feature) + if(${opt}) + list(FIND VCPKG_MANIFEST_FEATURES ${feature} index) + if(index EQUAL -1) + message(STATUS "Auto append features: ${feature}") + list(APPEND VCPKG_MANIFEST_FEATURES ${feature}) + endif() + endif() +endmacro() + +if(ENABLE_VCPKG) + auto_enable_vcpkg_feature(ENABLE_GD "gd") + auto_enable_vcpkg_feature(ENABLE_BOOST "boost") +endif() + +PROJECT(Paozhu_web_framework) +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +set(mode "CMAKE_BUILD_TYPE") + +set(BOOST_OPEN " ") +set(GD_OPEN " ") + +if(ENABLE_BOOST STREQUAL "ON") + message("ENABLE_BOOST") + set(BOOST_OPEN " -DENABLE_BOOST ") +endif() + +if(ENABLE_GD STREQUAL "ON") + message("ENABLE_GD") + set(GD_OPEN " -DENABLE_GD ") +endif() + +set(sys_so_path "/usr/lib64") + +if (IS_DIRECTORY "/usr/lib/x86_64-linux-gnu") + set(sys_so_path "/usr/lib/x86_64-linux-gnu") +endif() + +if (CMAKE_SYSTEM_NAME MATCHES "Windows") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_WIN32_WINNT=0x0601") +endif() + +if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /utf-8 /EHsc") +endif () + +if(${mode} AND (CMAKE_BUILD_TYPE STREQUAL "Debug")) + + if(CMAKE_SYSTEM_NAME MATCHES "Windows") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DASIO_STANDALONE -DBENCHMARK -DDEBUG ${BOOST_OPEN} ${GD_OPEN}") + if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /fsanitize=address") + elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pthread -g") + endif () + else() + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wall -Wextra") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pthread -g -fsanitize=address -DASIO_STANDALONE -DBENCHMARK -DDEBUG ${BOOST_OPEN} ${GD_OPEN} -I/usr/local/include -I/usr/include " ) + endif () + message("Debug mode:${CMAKE_CXX_FLAGS_DEBUG}") + +elseif(${mode} AND (CMAKE_BUILD_TYPE STREQUAL "Release")) + + if (CMAKE_SYSTEM_NAME MATCHES "Windows") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DASIO_STANDALONE ${BOOST_OPEN} ${GD_OPEN} -DBENCHMARK -O3") + if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pthread") + endif () + else () + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Wall -Wextra -O3") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread -DASIO_STANDALONE ${BOOST_OPEN} ${GD_OPEN} -DBENCHMARK -I/usr/local/include -I/usr/include " ) + file(MAKE_DIRECTORY /usr/local/etc/paozhu) + file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/conf/ DESTINATION /usr/local/etc/paozhu/) + endif () + message("Release mode:${CMAKE_CXX_FLAGS_RELEASE}") + +else() + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wall -Wextra") + message("Debug mode:${CMAKE_CXX_FLAGS_DEBUG}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pthread -g -fsanitize=address -DASIO_STANDALONE -DBENCHMARK -DDEBUG ${BOOST_OPEN} ${GD_OPEN} -I/usr/local/include -I/usr/include " ) + + if(NOT CMAKE_SYSTEM_NAME MATCHES "Windows") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address") + endif () +endif() + + + +file(MAKE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/temp) +file(MAKE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/log) +set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/bin) +set(USE_STANDALONE_ASIO ON) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +message(STATUS "SOURCE dir ${CMAKE_CURRENT_SOURCE_DIR}") + + +set(CMAKE_BUILD_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/build) +set(CMAKE_CACHEFILE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/build) +set(CMAKE_CURRENT_BINARY_DIR ${CMAKE_CURRENT_SOURCE_DIR}/build) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/common) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/controller) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/vendor/httpcli) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/viewsrc/include) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/websockets/include) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/orm) + +if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/bin/paozhu_pre) + file(REMOVE_RECURSE ${CMAKE_CURRENT_SOURCE_DIR}/bin/paozhu_pre) +endif() +set(PAOZHU_PRE paozhu_pre) +add_executable(${PAOZHU_PRE} ${CMAKE_CURRENT_SOURCE_DIR}/vendor/httpcli/autopickmethod.cpp ${CMAKE_CURRENT_SOURCE_DIR}/vendor/httpserver/src/md5.cpp) + + + +file(GLOB_RECURSE orm_list ${CMAKE_CURRENT_SOURCE_DIR}/orm/*.cpp) +file(GLOB_RECURSE source_list ${CMAKE_CURRENT_SOURCE_DIR}/models/*.cpp) +file(GLOB_RECURSE FRAMEWORK_CPP_PATH ${CMAKE_CURRENT_SOURCE_DIR}/vendor/httpserver/*.cpp) +file(GLOB_RECURSE common_list ${CMAKE_CURRENT_SOURCE_DIR}/common/*.cpp) +file(GLOB_RECURSE controller_list ${CMAKE_CURRENT_SOURCE_DIR}/controller/src/*.cpp) +file(GLOB_RECURSE viewsrc_list ${CMAKE_CURRENT_SOURCE_DIR}/viewsrc/view/*.cpp) +file(GLOB_RECURSE reflect_list ${CMAKE_CURRENT_SOURCE_DIR}/libs/*.cpp) +file(GLOB_RECURSE src_list ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp) + +foreach(cppfile IN LISTS controller_list) + string(REGEX REPLACE "${CMAKE_CURRENT_SOURCE_DIR}/controller/src/" "" cppfilename ${cppfile}) + string(FIND ${cppfilename} "/" strpos) + if(${strpos} GREATER_EQUAL "0" ) + string(REGEX MATCHALL "([A-Za-z0-9._-]+)/" npaths ${cppfilename} ) + set(fullpaths "") + string(APPEND fullpaths "${CMAKE_CURRENT_SOURCE_DIR}/controller/include/") + foreach(onepathname ${npaths}) + string(REPLACE "/" "" toucpath ${onepathname}) + string(APPEND fullpaths ${toucpath}) + if (IS_DIRECTORY "${fullpaths}") + else() + message("mkdir ${fullpaths}") + file(MAKE_DIRECTORY "${fullpaths}") + endif() + string(APPEND fullpaths "/") + endforeach() + endif() + string(REGEX REPLACE ".cpp" "" cppbasename ${cppfilename}) +# message(${cppbasename}) + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/controller/include/${cppbasename}.h") + else() + file(TOUCH "${CMAKE_CURRENT_SOURCE_DIR}/controller/include/${cppbasename}.h") + endif() +endforeach() + +function(include_sub_directories_recursively root_dir) + if (IS_DIRECTORY ${root_dir}) # 当前路径是一个目录吗,是的话就加入到包含目录 + # if (${root_dir} MATCHES "include") + message("include dir: " ${root_dir}) + include_directories(${root_dir}) + # endif() + endif() + + file(GLOB ALL_SUB RELATIVE ${root_dir} ${root_dir}/*) # 获得当前目录下的所有文件,让如ALL_SUB列表中 + + foreach(sub ${ALL_SUB}) + if (IS_DIRECTORY ${root_dir}/${sub}) + include_sub_directories_recursively(${root_dir}/${sub}) # 对子目录递归调用,包含 + endif() + endforeach() +endfunction() + +include_sub_directories_recursively(${CMAKE_CURRENT_SOURCE_DIR}/vendor/httpserver) +include_sub_directories_recursively(${CMAKE_CURRENT_SOURCE_DIR}/orm) +include_sub_directories_recursively(${CMAKE_CURRENT_SOURCE_DIR}/models) +include_sub_directories_recursively(${CMAKE_CURRENT_SOURCE_DIR}/controller/include) +include_sub_directories_recursively(${CMAKE_CURRENT_SOURCE_DIR}/libs) +include_sub_directories_recursively(${CMAKE_CURRENT_SOURCE_DIR}/include) +include_sub_directories_recursively(${CMAKE_CURRENT_SOURCE_DIR}/common) + +add_executable(paozhu_cli ${CMAKE_CURRENT_SOURCE_DIR}/vendor/httpcli/http_cli.cpp ${CMAKE_CURRENT_SOURCE_DIR}/vendor/httpserver/src/mysql_conn.cpp ${CMAKE_CURRENT_SOURCE_DIR}/vendor/httpserver/src/mysql_conn_pool.cpp ${CMAKE_CURRENT_SOURCE_DIR}/vendor/httpserver/src/clientdatacache.cpp) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/bin) + + +if(${mode} AND (CMAKE_BUILD_TYPE STREQUAL "Release")) + add_executable(paozhu ${CMAKE_CURRENT_SOURCE_DIR}/startup/main_docker.cpp ${common_list} ${viewsrc_list} ${FRAMEWORK_CPP_PATH} ${orm_list} ${reflect_list} ${src_list} ${source_list} ${controller_list}) +else() + add_executable(paozhu ${CMAKE_CURRENT_SOURCE_DIR}/startup/main_dev.cpp ${common_list} ${viewsrc_list} ${FRAMEWORK_CPP_PATH} ${orm_list} ${reflect_list} ${src_list} ${source_list} ${controller_list}) +endif() + +if (ENABLE_WIN_VCPKG STREQUAL "ON") +else() +add_custom_command( + TARGET paozhu_pre POST_BUILD + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/ + COMMAND echo "-- controls method --" + COMMAND ${PAOZHU_PRE} ${CMAKE_CURRENT_SOURCE_DIR}/ + ) +endif() + +if (ENABLE_VCPKG) + add_compile_definitions(ENABLE_VCPKG) + find_package(asio CONFIG REQUIRED) + target_link_libraries(paozhu asio::asio) + + if (ENABLE_BOOST) + add_compile_definitions(ENABLE_BOOST) + set(Boost_NO_WARN_NEW_VERSIONS ON) + find_package(Boost REQUIRED COMPONENTS filesystem coroutine) + target_link_libraries(paozhu Boost::boost Boost::filesystem Boost::coroutine) + endif () + + find_package(OpenSSL REQUIRED) + target_link_libraries(paozhu OpenSSL::Crypto OpenSSL::SSL) + + find_package(ZLIB REQUIRED) + target_link_libraries(paozhu ZLIB::ZLIB) + + # find_package(libmysql REQUIRED) + # find_package(unofficial-libmariadb CONFIG REQUIRED) + # find_path(MYSQL_ROOT_DIR mysql) + # target_link_libraries(paozhu ${MYSQL_LIBRARIES}) + # target_link_libraries(paozhu_cli ${MYSQL_LIBRARIES}) + # target_link_libraries(paozhu unofficial::libmariadb) + # target_link_libraries(paozhu_cli unofficial::libmariadb) + # target_include_directories(paozhu PUBLIC ${MYSQL_ROOT_DIR}/mysql) + # target_include_directories(paozhu_cli PUBLIC ${MYSQL_ROOT_DIR}/mysql) + + target_link_libraries(paozhu_cli asio::asio) + target_link_libraries(paozhu_cli OpenSSL::Crypto OpenSSL::SSL) + + if (ENABLE_GD STREQUAL "ON") + find_package(PkgConfig) + pkg_check_modules(LIBGD REQUIRED IMPORTED_TARGET gdlib) + target_link_libraries(paozhu PkgConfig::LIBGD) + + find_path(QRENCODE_INCLUDE_DIR NAMES qrencode.h) + find_library(QRENCODE_LIBRARY_RELEASE qrencode) + # find_library(QRENCODE_LIBRARY_DEBUG qrencoded) + # set(QRENCODE_LIBRARIES optimized ${QRENCODE_LIBRARY_RELEASE} debug ${QRENCODE_LIBRARY_DEBUG}) + target_include_directories(paozhu PRIVATE ${QRENCODE_INCLUDE_DIR}) + target_link_libraries(paozhu ${QRENCODE_LIBRARY_RELEASE}) + # MESSAGE(STATUS ${QRENCODE_LIBRARY_RELEASE}) + + # warning: Fixed an issue where ports/libqrencode would not automatically + # copy dll files to the bin directory + if (CMAKE_SYSTEM_NAME MATCHES "Windows") + set(PATH_TO_QRENCODE_DLL "") + if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + set(PATH_TO_QRENCODE_DLL "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/bin/qrencode.dll") + elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + set(PATH_TO_QRENCODE_DLL "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/lib/libqrencode.dll") + endif () + message(STATUS "Selected libqrencode.dll: ${PATH_TO_QRENCODE_DLL}") + + add_custom_command( + TARGET paozhu POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + ${PATH_TO_QRENCODE_DLL} ${CMAKE_CURRENT_SOURCE_DIR}/bin/ + ) + endif () + + find_package(PNG REQUIRED) + target_link_libraries(paozhu PNG::PNG) + + find_package(Freetype REQUIRED) + target_link_libraries(paozhu Freetype::Freetype) + endif () + + find_package(unofficial-brotli CONFIG REQUIRED) + target_link_libraries(paozhu unofficial::brotli::brotlidec unofficial::brotli::brotlienc) +else () + +if(USE_STANDALONE_ASIO) +if(CMAKE_SYSTEM_NAME MATCHES "Darwin") +set(ASIO_PATH "/usr/local/opt/asio/include" "/usr/local/include" "/opt/homebrew/opt/asio" ${CMAKE_CURRENT_SOURCE_DIR}/asio) +else() +set(ASIO_PATH ${CMAKE_CURRENT_SOURCE_DIR}/asio "/usr/include") +endif() + + target_compile_definitions(paozhu INTERFACE ASIO_STANDALONE) + find_path(ASIO_PATH asio.hpp) + message(state " Standalone Asio found: " ${ASIO_PATH}) + if(NOT ASIO_PATH) + message(FATAL_ERROR "Standalone Asio not found") + else() + target_include_directories(paozhu INTERFACE ${ASIO_PATH}) + endif() + + include_directories(${ASIO_PATH}) + +endif() + + +if(ENABLE_BOOST STREQUAL "ON") +message("---ENABLE_BOOST-----") +find_package(Boost REQUIRED + COMPONENTS system filesystem) +if(Boost_FOUND) + add_compile_definitions(ENABLE_BOOST) + include_directories("${Boost_INCLUDE_DIRS}/boost") + + MESSAGE( STATUS "Boost_INCLUDE_DIRS = ${Boost_INCLUDE_DIRS}") + MESSAGE( STATUS "Boost_LIBRARIES = ${Boost_LIBRARY_DIRS}") + MESSAGE( STATUS "Boost_LIB_VERSION = ${Boost_LIB_VERSION}") + link_directories(${Boost_LIBRARY_DIRS}) + target_link_libraries (paozhu ${Boost_LIBRARIES}) +endif() + +endif() + + +find_package(OpenSSL REQUIRED) + +if(OPENSSL_FOUND) + + message(STATUS "OPENSSL_VERSION = ${OPENSSL_VERSION}") + message(STATUS "OPENSSL_SSL_LIBRARY = ${OPENSSL_SSL_LIBRARY}") + message(STATUS "OPENSSL_CRYPTO_LIBRARY = ${OPENSSL_CRYPTO_LIBRARY}") + message(STATUS "OPENSSL_INCLUDE_DIR = ${OPENSSL_INCLUDE_DIR}") + INCLUDE_DIRECTORIES("${OPENSSL_INCLUDE_DIR}") + target_link_libraries (paozhu ${OPENSSL_SSL_LIBRARY}) + target_link_libraries (paozhu ${OPENSSL_CRYPTO_LIBRARY}) + + target_link_libraries (paozhu_cli ${OPENSSL_SSL_LIBRARY}) + target_link_libraries (paozhu_cli ${OPENSSL_CRYPTO_LIBRARY}) +endif() + + +find_package(ZLIB REQUIRED) +if(ZLIB_FOUND) + message(STATUS "Zlib Found! ${ZLIB_LIBRARIES}") + include_directories(${ZLIB_INCLUDE_DIR}) + set(zlib_library ${ZLIB_LIBRARIES}) + target_link_libraries(paozhu z) +endif() + + +#if(CMAKE_SYSTEM_NAME MATCHES "Darwin") +# if (IS_DIRECTORY "/usr/local/mysql/include") +# MESSAGE( STATUS "/usr/local/mysql") +# set(MYSQL_INCLUDE_DIR "/usr/local/mysql/include") +# include_sub_directories_recursively(/usr/local/mysql/include) +# endif() +# +# if (IS_DIRECTORY "/usr/local/opt/mysql-client") +# MESSAGE( STATUS "/usr/local/opt/mysql-client") +# set(MYSQL_INCLUDE_DIR "/usr/local/opt/mysql-client/include") +# include_sub_directories_recursively(/usr/local/opt/mysql-client/include) +# endif() +# +# if (IS_DIRECTORY "/opt/homebrew/opt/mysql") +# MESSAGE( STATUS "/opt/homebrew/opt/mysql") +# set(MYSQL_INCLUDE_DIR "/opt/homebrew/opt/mysql/include") +# include_sub_directories_recursively(/opt/homebrew/opt/mysql/include) +# endif() +# +# +# if (IS_DIRECTORY "/opt/homebrew/opt/mysql-client") +# MESSAGE( STATUS "/opt/homebrew/opt/mysql-client") +# set(MYSQL_INCLUDE_DIR "/opt/homebrew/opt/mysql-client/include") +# include_sub_directories_recursively(/opt/homebrew/opt/mysql-client/include) +# endif() +# MESSAGE( STATUS "MYSQL_ROOT_DIR = ${MYSQL_ROOT_DIR} ") +#else() +# find_path(MYSQL_ROOT_DIR mysql) +#endif() +# +# +# FIND_PATH(MYSQL_INCLUDE_DIR NAMES mysql.h +# PATHS /usr/local/include/mysql /usr/include/mysql /opt/homebrew/opt/mysql/include /usr/local/opt/mysql-client/include /opt/homebrew/opt/mysql-client/include +# ) +# +# MESSAGE( STATUS "MYSQL_ROOT_DIR = ${MYSQL_ROOT_DIR} ") +# find_package_handle_standard_args(mysql REQUIRED_VARS MYSQL_ROOT_DIR) +# +# +# if(NOT MYSQL_INCLUDE_DIR) +# message(STATUS "Could not find \"mysql.h\" from searching ") +# endif() +# +# SET(MYSQL_NAMES mysqlclient) +# FIND_LIBRARY(MYSQL_LIBRARY +# NAMES ${MYSQL_NAMES} +# PATHS /usr/lib /usr/local/lib /usr/local/mysql/lib /usr/local/opt/mysql/lib /opt/homebrew/opt/mysql/lib /opt/homebrew/opt/mysql-client/lib +# PATH_SUFFIXES mysql +# ) +# +# IF (MYSQL_INCLUDE_DIR AND MYSQL_LIBRARY) +# SET(MYSQL_FOUND TRUE) +# SET( MYSQL_LIBRARIES ${MYSQL_LIBRARY} ) +# ELSE (MYSQL_INCLUDE_DIR AND MYSQL_LIBRARY) +# SET(MYSQL_FOUND FALSE) +# SET( MYSQL_LIBRARIES ) +# ENDIF (MYSQL_INCLUDE_DIR AND MYSQL_LIBRARY) +# +# IF (MYSQL_FOUND) +# IF (NOT MYSQL_FIND_QUIETLY) +# MESSAGE(STATUS "Found MySQL: ${MYSQL_LIBRARY}") +# ENDIF (NOT MYSQL_FIND_QUIETLY) +# ELSE (MYSQL_FOUND) +# IF (MYSQL_FIND_REQUIRED) +# MESSAGE(STATUS "Looked for MySQL libraries named ${MYSQL_NAMES}.") +# MESSAGE(FATAL_ERROR "Could NOT find MySQL library") +# ENDIF (MYSQL_FIND_REQUIRED) +# ENDIF (MYSQL_FOUND) +# +# target_include_directories(paozhu PUBLIC ${MYSQL_INCLUDE_DIR}) +# target_link_libraries(paozhu ${MYSQL_LIBRARY}) +# +# target_include_directories(paozhu_cli PUBLIC ${MYSQL_INCLUDE_DIR}) +# target_link_libraries(paozhu_cli ${MYSQL_LIBRARY}) + + + +if(ENABLE_GD STREQUAL "ON") +message("---ENABLE_GD-----") + +if(CMAKE_SYSTEM_NAME MATCHES "Darwin") + + if (IS_DIRECTORY "/usr/local/opt/gd/lib") + MESSAGE( STATUS "/usr/local/opt/gd/lib") + set(GD_ROOT_DIR "/usr/local/opt/gd/lib") + include_sub_directories_recursively(/usr/local/opt/gd/include) + endif() + if (IS_DIRECTORY "/opt/homebrew/opt/gd/lib") + MESSAGE( STATUS "/opt/homebrew/opt/gd/lib") + set(GD_ROOT_DIR "/opt/homebrew/opt/gd/lib") + include_sub_directories_recursively(/opt/homebrew/opt/gd/include) + endif() +else() + set(GD_ROOT_DIR "${sys_so_path}") +endif() + +set(find_gdname gd) + +find_library(GD_LIB_DIR + NAMES ${find_gdname} + PATHS "${GD_ROOT_DIR}" + NO_DEFAULT_PATH +) + +if(NOT GD_LIB_DIR) +message(FATAL_ERROR +"GD Graphics Library NOT FOUND! please install . " +) +endif() + +message(STATUS "GD Graphics Library at: ${GD_LIB_DIR}") + +if(CMAKE_SYSTEM_NAME MATCHES "Darwin") + + if (IS_DIRECTORY "/usr/local/opt/qrencode/lib") + MESSAGE( STATUS "/usr/local/opt/qrencode/lib") + set(QR_ROOT_DIR "/usr/local/opt/qrencode/lib") + include_sub_directories_recursively(/usr/local/opt/qrencode/include) + endif() + if (IS_DIRECTORY "/opt/homebrew/opt/qrencode/lib") + MESSAGE( STATUS "/opt/homebrew/opt/qrencode/lib") + set(QR_ROOT_DIR "/opt/homebrew/opt/qrencode/lib") + include_sub_directories_recursively(/opt/homebrew/opt/qrencode/include) + endif() + +else() +set(QR_ROOT_DIR "${sys_so_path}") +endif() + +set(find_qrname qrencode) + +find_library(QR_LIB_DIR + NAMES ${find_qrname} + PATHS "${QR_ROOT_DIR}" + NO_DEFAULT_PATH +) + +if(NOT QR_LIB_DIR) +message(FATAL_ERROR +"qrencode Library NOT FOUND! please install . " +) +endif() + +message(STATUS "qrencode at: ${QR_LIB_DIR}") + +INCLUDE_DIRECTORIES("${GD_ROOT_DIR}/include") +INCLUDE_DIRECTORIES("${QR_ROOT_DIR}/include") +link_directories("${QR_ROOT_DIR}/lib") +link_directories("${GD_ROOT_DIR}/lib") +target_link_libraries(paozhu ${GD_LIB_DIR}) +target_link_libraries(paozhu ${QR_LIB_DIR}) + +if(CMAKE_SYSTEM_NAME MATCHES "Darwin") + + if (IS_DIRECTORY "/usr/local/opt/libpng/lib") + MESSAGE( STATUS "/usr/local/opt/libpng/lib") + set(PNG_ROOT_DIR "/usr/local/opt/libpng/lib") + include_sub_directories_recursively(/usr/local/opt/libpng/include) + endif() + if (IS_DIRECTORY "/opt/homebrew/opt/libpng/lib") + MESSAGE( STATUS "/opt/homebrew/opt/libpng/lib") + set(PNG_ROOT_DIR "/opt/homebrew/opt/libpng/lib") + include_sub_directories_recursively(/opt/homebrew/opt/libpng/include) + endif() + +else() +set(PNG_ROOT_DIR "${sys_so_path}") +endif() + +find_library(PNG_LIB_DIR + NAMES png + PATHS "${PNG_ROOT_DIR}" + NO_DEFAULT_PATH +) +target_link_libraries(paozhu ${PNG_LIB_DIR}) + +if(CMAKE_SYSTEM_NAME MATCHES "Darwin") + + if (IS_DIRECTORY "/usr/local/opt/freetype/lib") + MESSAGE( STATUS "/usr/local/opt/freetype/lib") + set(FREETYPE_ROOT_DIR "/usr/local/opt/freetype/lib") + include_sub_directories_recursively(/usr/local/opt/freetype/include) + endif() + if (IS_DIRECTORY "/opt/homebrew/opt/freetype/lib") + MESSAGE( STATUS "/opt/homebrew/opt/freetype/lib") + set(FREETYPE_ROOT_DIR "/opt/homebrew/opt/freetype/lib") + include_sub_directories_recursively(/opt/homebrew/opt/freetype/include) + endif() + +else() + set(FREETYPE_ROOT_DIR "${sys_so_path}") +endif() + +find_library(FREETYPE_LIB_DIR + NAMES freetype + PATHS "${FREETYPE_ROOT_DIR}" + NO_DEFAULT_PATH +) +target_link_libraries(paozhu ${FREETYPE_LIB_DIR}) +#end ENABLE_GD +endif() + +if(CMAKE_SYSTEM_NAME MATCHES "Darwin") + if (IS_DIRECTORY "/usr/local/opt/brotli/lib") + set(BROTLI_ROOT_DIR "/usr/local/opt/brotli/lib") + INCLUDE_DIRECTORIES("/usr/local/opt/brotli/include") + endif() +# set(BROTLI_ROOT_DIR "/usr/local/opt/brotli/lib") + if (IS_DIRECTORY "/opt/homebrew/opt/brotli/lib") + set(BROTLI_ROOT_DIR "/opt/homebrew/opt/brotli/lib") + INCLUDE_DIRECTORIES("/opt/homebrew/opt/brotli/include") + endif() +else() + set(BROTLI_ROOT_DIR "${sys_so_path}") +endif() + + + +#find_package(Brotli COMPONENTS encoder decoder common REQUIRED) + +message(STATUS "Brotli at: ${BROTLI_ROOT_DIR}") + +set(find_brname brotlienc) +set(find_brdename brotlidec) +find_library(BR_LIB_DIR + NAMES ${find_brname} + PATHS "${BROTLI_ROOT_DIR}" + NO_DEFAULT_PATH +) +find_library(BRDEC_LIB_DIR + NAMES ${find_brdename} + PATHS "${BROTLI_ROOT_DIR}" + NO_DEFAULT_PATH +) +INCLUDE_DIRECTORIES("${BROTLI_ROOT_DIR}/include") +link_directories("${BROTLI_ROOT_DIR}/lib") + +if(NOT BR_LIB_DIR) +message(FATAL_ERROR +"Brotli Library NOT FOUND! please install . " +) +endif() + +message(STATUS "Brotli at: ${BR_LIB_DIR}") +target_link_libraries(paozhu ${BR_LIB_DIR}) + + +if(NOT BRDEC_LIB_DIR) +message(FATAL_ERROR +"Brotli Library NOT FOUND! please install . " +) +endif() + +message(STATUS "Brotli at: ${BRDEC_LIB_DIR}") +target_link_libraries(paozhu ${BRDEC_LIB_DIR}) + + +message("Compile framework mode") + +target_link_libraries(paozhu m dl) + +endif () + +if (CMAKE_SYSTEM_NAME MATCHES "Windows") + target_link_libraries(paozhu ws2_32) + target_link_libraries(paozhu_cli ws2_32) +endif () diff --git a/frameworks/C++/paozhu/paozhu_benchmark/common/autocontrolmethod.hpp b/frameworks/C++/paozhu/paozhu_benchmark/common/autocontrolmethod.hpp new file mode 100755 index 00000000000..b793d7f8d5e --- /dev/null +++ b/frameworks/C++/paozhu/paozhu_benchmark/common/autocontrolmethod.hpp @@ -0,0 +1,76 @@ + +#ifndef __HTTP_AUTO_REG_CONTROL_HTTPMETHOD_HPP +#define __HTTP_AUTO_REG_CONTROL_HTTPMETHOD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +#pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "httppeer.h" + +#include "techempower.h" + +namespace http +{ + + void _initauto_control_httpmethodregto(std::map &methodcallback) + { + struct regmethold_t temp; + + + + } + + void _initauto_co_control_httpmethodregto(std::map &methodcallback) + { + struct regmethold_co_t temp; + temp.pre = nullptr; + temp.regfun = techempowerplaintext; + methodcallback.emplace("plaintext",temp); + temp.pre = nullptr; + temp.regfun = techempowerjson; + methodcallback.emplace("json",temp); + temp.pre = nullptr; + temp.regfun = techempowerdb; + methodcallback.emplace("db",temp); + temp.pre = nullptr; + temp.regfun = techempowerqueries; + methodcallback.emplace("queries",temp); + temp.pre = nullptr; + temp.regfun = techempowerfortunes; + methodcallback.emplace("fortunes",temp); + temp.pre = nullptr; + temp.regfun = techempowerupdates; + methodcallback.emplace("updates",temp); + temp.pre = nullptr; + temp.regfun = techempowercached_queries; + methodcallback.emplace("cached-queries",temp); + temp.pre = nullptr; + temp.regfun = techempowercached_db; + methodcallback.emplace("cached-db",temp); + + + } + + void _initauto_domain_httpmethodregto(std::map> &domain_methodcallback) + { + struct regmethold_t temp; + std::map methodcallback; + std::map>::iterator domain_iterator; + + + } + + void _initauto_co_domain_httpmethodregto(std::map> &domain_methodcallback) + { + struct regmethold_co_t temp; + std::map methodcallback; + std::map>::iterator domain_iterator; + + + } + +} +#endif + + \ No newline at end of file diff --git a/frameworks/C++/paozhu/paozhu_benchmark/common/autorestfulpaths.hpp b/frameworks/C++/paozhu/paozhu_benchmark/common/autorestfulpaths.hpp new file mode 100755 index 00000000000..dabbdbda827 --- /dev/null +++ b/frameworks/C++/paozhu/paozhu_benchmark/common/autorestfulpaths.hpp @@ -0,0 +1,40 @@ + +#ifndef __HTTP_AUTO_REG_CONTROL_HTTPRESTFUL_HPP +#define __HTTP_AUTO_REG_CONTROL_HTTPRESTFUL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +#pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "httppeer.h" + + + +namespace http +{ + void _initauto_control_httprestful_paths(std::map> &restfulmethod) + { + + + if(restfulmethod.size()) + {} + + + } + + void _initauto_domain_httprestful_paths(std::map>> &restfulmethod) + { + std::map> temp_path; + std::map>>::iterator domain_iterator; + + domain_iterator=restfulmethod.begin(); + temp_path.clear(); + + + } + +} + +#endif + + \ No newline at end of file diff --git a/frameworks/C++/paozhu/paozhu_benchmark/common/cost_define.h b/frameworks/C++/paozhu/paozhu_benchmark/common/cost_define.h new file mode 100755 index 00000000000..36a3a013330 --- /dev/null +++ b/frameworks/C++/paozhu/paozhu_benchmark/common/cost_define.h @@ -0,0 +1,20 @@ +#pragma once +#ifndef _CONST_DEFINE_FUNC_H +#define _CONST_DEFINE_FUNC_H + +#define CONST_MONEY_PART 1000000 +#define CONST_HTTP_HEADER_BODY_SIZE 16384 +#define CONST_PHP_BODY_POST_SIZE 16777216 + +#define CONST_HTTP_BODY_POST_SIZE 33554432 +#define CONST_HTTP_JSON_POST_SIZE 2097152 + +#define CONST_HTTP2_SlEEP_MIN_TIME 1100000 + +#define CONST_ORM_CLEAR_TIME 7200 +#define CONST_ORM_CLEAR_NUMBER 1024 +#define CONST_ORM_QUERY_CONNECT_TIMEOUT 30 +#define CONST_ORM_QUERY_LOG_TIME 30 + +#define COOKIE_SESSION_NAME "PHPSESSID" +#endif \ No newline at end of file diff --git a/frameworks/C++/paozhu/paozhu_benchmark/common/httphook.cpp b/frameworks/C++/paozhu/paozhu_benchmark/common/httphook.cpp new file mode 100755 index 00000000000..327ecab4b71 --- /dev/null +++ b/frameworks/C++/paozhu/paozhu_benchmark/common/httphook.cpp @@ -0,0 +1,50 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "httppeer.h" +#include "client_session.h" +namespace http +{ +std::map _block_ip_tables; +std::map _block_host_tables; +std::map _passport_ip_tables; +std::map _passport_host_tables; +bool check_blockip(std::shared_ptr peer_session) +{ + if (peer_session->isssl) + { + return false; + } + return false; +} +bool check_pressl_blockip(std::shared_ptr peer_session) +{ + if (peer_session->isssl) + { + return false; + } + return false; +} +bool hook_host_http1(std::shared_ptr peer) +{ + if (peer->host.size() > 0) + { + return false; + } + return false; +} +bool hook_host_http2(std::shared_ptr peer) +{ + if (peer->host.size() > 0) + { + return false; + } + return false; +} +}// namespace http diff --git a/frameworks/C++/paozhu/paozhu_benchmark/common/json_reflect_headers.h b/frameworks/C++/paozhu/paozhu_benchmark/common/json_reflect_headers.h new file mode 100755 index 00000000000..176500bf383 --- /dev/null +++ b/frameworks/C++/paozhu/paozhu_benchmark/common/json_reflect_headers.h @@ -0,0 +1,32 @@ +#pragma once +#include +#include +#include +#include + +#include "types/techempower_json.h" +#include "unicode.h" + +template +std::string json_encode([[maybe_unused]] const JSON_REF_OBJ_TEMP &json_reflectobj) { return ""; } + +template +std::string json_encode([[maybe_unused]] const std::vector &json_reflectobj) { return ""; } + +template +unsigned int json_decode([[maybe_unused]] JSON_REF_OBJ_TEMP &json_reflectobj, [[maybe_unused]] const std::string &_json_data, [[maybe_unused]] unsigned int _offset) { return 0; } + +template +unsigned int json_decode([[maybe_unused]] std::vector &json_reflectobj, [[maybe_unused]] const std::string &_json_data, [[maybe_unused]] unsigned int _offset) { return 0; } + +namespace http +{ + +std::string json_encode(const techempower_outjson_t &json_reflectobj); + +std::string json_encode(const std::vector &json_reflectobj); + +unsigned int json_decode(techempower_outjson_t &json_reflectobj, const std::string &_json_data, unsigned int _offset = 0); + +unsigned int json_decode(std::vector &json_reflectobj, const std::string &_json_data, unsigned int _offset = 0); +}// namespace http diff --git a/frameworks/C++/paozhu/paozhu_benchmark/common/reghttpmethod.hpp b/frameworks/C++/paozhu/paozhu_benchmark/common/reghttpmethod.hpp new file mode 100755 index 00000000000..3333ed08bf0 --- /dev/null +++ b/frameworks/C++/paozhu/paozhu_benchmark/common/reghttpmethod.hpp @@ -0,0 +1,16 @@ +#ifndef __HTTP_REGHTTPMETHOD_HPP +#define __HTTP_REGHTTPMETHOD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +#pragma once +#endif// defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "httppeer.h" +namespace http +{ +void _inithttpmethodregto(std::map &methodcallback) +{ +} + +}// namespace http +#endif \ No newline at end of file diff --git a/frameworks/C++/paozhu/paozhu_benchmark/common/reghttpmethod_pre.hpp b/frameworks/C++/paozhu/paozhu_benchmark/common/reghttpmethod_pre.hpp new file mode 100755 index 00000000000..bf2d5407381 --- /dev/null +++ b/frameworks/C++/paozhu/paozhu_benchmark/common/reghttpmethod_pre.hpp @@ -0,0 +1,20 @@ +#ifndef __HTTP_REGHTTPMETHOD_PRE_HPP +#define __HTTP_REGHTTPMETHOD_PRE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +#pragma once +#endif// defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "httppeer.h" +namespace http +{ +void _inithttpmethodregto_pre(std::map &methodcallback) +{ + struct regmethold_t temp; + //temp.pre = adminlogin; + //temp.regfun = adminmar; + //methodcallback.emplace("adminmar", temp); +} + +}// namespace http +#endif \ No newline at end of file diff --git a/frameworks/C++/paozhu/paozhu_benchmark/common/websockets_method_reg.hpp b/frameworks/C++/paozhu/paozhu_benchmark/common/websockets_method_reg.hpp new file mode 100755 index 00000000000..b8e9c718ea9 --- /dev/null +++ b/frameworks/C++/paozhu/paozhu_benchmark/common/websockets_method_reg.hpp @@ -0,0 +1,19 @@ +#pragma once +#include +#include "httppeer.h" +#include "websockets.h" +#include "mywebsockets.hpp" +#include "websockets_callback.h" +namespace http +{ +void _initwebsocketmethodregto(WEBSOCKET_REG &methodcallback) +{ + + methodcallback.emplace("wstest", [](std::weak_ptr p) -> std::shared_ptr + { return http::mywebsockets::create(p); }); + // methodcallback.emplace("looptest",[](std::weak_ptr p)->std::shared_ptr{ + // return http::loopwebsockets::create(p); + // }); +} + +}// namespace http \ No newline at end of file diff --git a/frameworks/C++/paozhu/paozhu_benchmark/conf/orm.conf b/frameworks/C++/paozhu/paozhu_benchmark/conf/orm.conf new file mode 100644 index 00000000000..b8eae8460ab --- /dev/null +++ b/frameworks/C++/paozhu/paozhu_benchmark/conf/orm.conf @@ -0,0 +1,22 @@ +[default] +type=main +host=tfb-database +port=3306 +dbname=hello_world +user=benchmarkdbuser +password=benchmarkdbpass +pretable= +maxpool=120 +minpool=30 +dbtype=mysql + +type=second +host=tfb-database +port=3306 +dbname=hello_world +user=benchmarkdbuser +password=benchmarkdbpass +pretable= +maxpool=120 +minpool=30 +dbtype=mysql diff --git a/frameworks/C++/paozhu/paozhu_benchmark/conf/server.conf b/frameworks/C++/paozhu/paozhu_benchmark/conf/server.conf new file mode 100755 index 00000000000..265e2193570 --- /dev/null +++ b/frameworks/C++/paozhu/paozhu_benchmark/conf/server.conf @@ -0,0 +1,48 @@ +[default] +threadmax=1024 +threadmin=5 +httpport=8888 +httpsport=4430 +cothreadnum=16 ;Coroutines run on thread num + +http2_enable=0 +debug_enable=1 +deamon_enable=0 +mainhost=localhost +certificate_chain_file=localhost.pem +private_key_file=localhost.key +tmp_dh_file=dh4096.pem +reboot_password=e10adc3949ba59abbe56e057f20f883e ;md5(md5("123456")+"rand_char"+md5("123456")) +reboot_cron =w1h5 ;MDSW+Hhours reboot process M month D day S season (1 4 7 10) W week +clean_cron =m5t600 ;5-minute interval clean 600 seconds ago inactive connection +links_restart_process =n9998877ts1te5 ;More than 15000 connections, restart the process from 1:00 am to 5:00 am +session_type=1 ;session save type 0.file 1.memory 2.redis 3.memcache 4.reserve +static_file_compress_cache=1 ;1 enable, Cache static file compress(gzip,br) content to cache directory +modelspath=/paozhu/models +serverpath=/paozhu +viewpath=/paozhu/view +viewsopath=/paozhu/module/view + +controlpath=/paozhu/controller +controlsopath=/paozhu/module/controller + +temppath=/paozhu/temp +logpath=/paozhu/log +wwwpath=/paozhu/www/default +pluginspath=/paozhu/plugins +libspath=/paozhu/libs +directorylist=0 +index=index.html +;usehtmlcache=1 +;usehtmlcachetime=3600 +rewrite_404=0 ;1 file 2 action url path +rewrite_404_action=index.html +method_pre= +method_after= +show_visitinfo=0 +upload_max_size=16777216 + +siteid=0 +groupid=0 +alias_domain= +init_func= \ No newline at end of file diff --git a/frameworks/C++/paozhu/paozhu_benchmark/controller/include/techempower.h b/frameworks/C++/paozhu/paozhu_benchmark/controller/include/techempower.h new file mode 100644 index 00000000000..ce43babe19f --- /dev/null +++ b/frameworks/C++/paozhu/paozhu_benchmark/controller/include/techempower.h @@ -0,0 +1,17 @@ + +#pragma once +#include +#include +#include "httppeer.h" + +namespace http +{ + asio::awaitable techempowerplaintext(std::shared_ptr peer); + asio::awaitable techempowerjson(std::shared_ptr peer); + asio::awaitable techempowerdb(std::shared_ptr peer); + asio::awaitable techempowerqueries(std::shared_ptr peer); + asio::awaitable techempowerfortunes(std::shared_ptr peer); + asio::awaitable techempowerupdates(std::shared_ptr peer); + asio::awaitable techempowercached_queries(std::shared_ptr peer); + asio::awaitable techempowercached_db(std::shared_ptr peer); +} diff --git a/frameworks/C++/paozhu/paozhu_benchmark/controller/src/techempower.cpp b/frameworks/C++/paozhu/paozhu_benchmark/controller/src/techempower.cpp new file mode 100755 index 00000000000..045a53ba2d4 --- /dev/null +++ b/frameworks/C++/paozhu/paozhu_benchmark/controller/src/techempower.cpp @@ -0,0 +1,255 @@ +#include "orm.h" +#include +#include +#include +#include +#include +#include "httppeer.h" +#include "techempower.h" +#include "request.h" +#include "techempower_json.h" +#include "datetime.h" +#include "func.h" +#include "pzcache.h" +#include "json_reflect_headers.h" +namespace http +{ +//@urlpath(null,plaintext) +asio::awaitable techempowerplaintext(std::shared_ptr peer) +{ + peer->type("text/plain; charset=UTF-8"); + peer->set_header("Date", get_gmttime()); + peer->output = "Hello, World!"; + co_return ""; +} + +//@urlpath(null,json) +asio::awaitable techempowerjson(std::shared_ptr peer) +{ + peer->type("application/json; charset=UTF-8"); + peer->set_header("Date", get_gmttime()); + struct techempower_outjson_t a; + a.message = "Hello, World!"; + peer->output = json_encode(a); + co_return ""; +} + +//@urlpath(null,db) +asio::awaitable techempowerdb(std::shared_ptr peer) +{ + peer->type("application/json; charset=UTF-8"); + peer->set_header("Date", get_gmttime()); + auto myworld = orm::World(); + unsigned int rd_num = rand_range(1, 10000); + myworld.where("id", rd_num); + myworld.limit(1); + co_await myworld.async_fetch_one(); + + peer->output = myworld.data_tojson(); + co_return ""; +} + +//@urlpath(null,queries) +asio::awaitable techempowerqueries(std::shared_ptr peer) +{ + peer->type("application/json; charset=UTF-8"); + peer->set_header("Date", get_gmttime()); + + unsigned int get_num = peer->get["queries"].to_int(); + if (get_num == 0) + { + get_num = 1; + } + else if (get_num > 500) + { + get_num = 500; + } + auto myworld = orm::World(); + myworld.record.reserve(get_num); + myworld.lock_conn(); + for (unsigned int i = 0; i < get_num; i++) + { + myworld.wheresql.clear(); + unsigned int rd_num = rand_range(1, 10000); + myworld.where("id", rd_num); + co_await myworld.async_fetch_append(); + } + myworld.unlock_conn(); + peer->output = myworld.to_json(); + co_return ""; +} + +//@urlpath(null,fortunes) +asio::awaitable techempowerfortunes(std::shared_ptr peer) +{ + peer->type("text/html; charset=UTF-8"); + peer->set_header("Date", get_gmttime()); + + auto myfortune = orm::Fortune(); + co_await myfortune.async_fetch(); + myfortune.data.id = 0; + myfortune.data.message = "Additional fortune added at request time."; + myfortune.record.push_back(myfortune.data); + + std::sort(myfortune.record.begin(), myfortune.record.end(), [](const auto &lhs, const auto &rhs) + { return lhs.message < rhs.message; }); + peer->val["list"].set_array(); + obj_val item; + for (unsigned int i = 0; i < myfortune.record.size(); i++) + { + item["id"] = myfortune.record[i].id; + item["message"] = html_encode(myfortune.record[i].message); + peer->val["list"].push(item); + } + peer->view("techempower/fortunes"); + // peer->output = "Fortunes"; + // for (unsigned int i = 0; i < myfortune.record.size(); i++) + // { + // peer->output += ""; + // } + // peer->output += "
idmessage
" + std::to_string(myfortune.record[i].id) + "" + html_encode(myfortune.record[i].message) + "
"; + co_return ""; +} + +//@urlpath(null,updates) +asio::awaitable techempowerupdates(std::shared_ptr peer) +{ + peer->type("application/json; charset=UTF-8"); + peer->set_header("Date", get_gmttime()); + unsigned int get_num = peer->get["queries"].to_int(); + + if (get_num == 0) + { + get_num = 1; + } + else if (get_num > 500) + { + get_num = 500; + } + auto myworld = orm::World(); + myworld.record.clear(); + myworld.record.reserve(get_num); + myworld.lock_conn(); + for (unsigned int i = 0; i < get_num; i++) + { + myworld.wheresql.clear(); + myworld.where("id", rand_range(1, 10000)); + co_await myworld.async_fetch_append(); + if (myworld.effect() > 0) + { + unsigned int j = myworld.record.size() - 1; + myworld.data.randomnumber = rand_range(1, 10000); + myworld.record[j].randomnumber = myworld.data.randomnumber; + co_await myworld.async_update("randomnumber"); + } + } + myworld.unlock_conn(); + peer->output = myworld.to_json(); + co_return ""; +} + +//@urlpath(null,cached-queries) +asio::awaitable techempowercached_queries(std::shared_ptr peer) +{ + peer->type("application/json; charset=UTF-8"); + peer->set_header("Date", get_gmttime()); + + unsigned int get_num = peer->get["count"].to_int(); + if (get_num == 0) + { + get_num = 1; + } + else if (get_num > 500) + { + get_num = 500; + } + auto myworld = orm::World(); + std::string mycacheid = "alldatacache"; + + pzcache> &temp_cache = pzcache>::conn(); + + std::vector allcachedata_array; + allcachedata_array.reserve(10000); + //create rand data to cache + if (temp_cache.check(mycacheid) > -1) + { + allcachedata_array = temp_cache.get(mycacheid); + } + else + { + allcachedata_array.resize(10000); + for (unsigned int i = 0; i < 10000; i++) + { + allcachedata_array[i].id = i + 1; + allcachedata_array[i].randomnumber = rand_range(1, 10000); + } + temp_cache.save(mycacheid, allcachedata_array, 360); + } + //get rand data from cache + mycacheid = "my" + std::to_string(get_num); + myworld.record.reserve(get_num); + if (temp_cache.check(mycacheid) > -1) + { + myworld.record = temp_cache.get(mycacheid); + } + else + { + if (allcachedata_array.size() == 10000) + { + for (unsigned int i = 0; i < get_num; i++) + { + unsigned int temp_rid = rand_range(0, 9999); + myworld.record.push_back(allcachedata_array[temp_rid]); + } + } + temp_cache.save(mycacheid, myworld.record, 360); + } + + peer->output = myworld.to_json(); + co_return ""; +} + +//@urlpath(null,cached-db) +asio::awaitable techempowercached_db(std::shared_ptr peer) +{ + peer->type("application/json; charset=UTF-8"); + peer->set_header("Date", get_gmttime()); + //this test from database to cache + unsigned int get_num = peer->get["count"].to_int(); + if (get_num == 0) + { + get_num = 1; + } + else if (get_num > 500) + { + get_num = 500; + } + auto myworld = orm::World(); + std::string mycacheid = "my" + std::to_string(get_num); + + pzcache> &temp_cache = pzcache>::conn(); + + myworld.record.reserve(get_num); + if (temp_cache.check(mycacheid) > -1) + { + myworld.record = temp_cache.get(mycacheid); + } + else + { + std::vector cacheid; + for (unsigned int i = 0; i < get_num; i++) + { + cacheid.push_back(rand_range(1, 10000)); + } + + std::string sqlstr = array_to_sql(cacheid); + myworld.whereIn("id", sqlstr); + co_await myworld.async_fetch(); + temp_cache.save(mycacheid, myworld.record, 360); + } + + peer->output = myworld.to_json(); + co_return ""; +} + +}// namespace http diff --git a/frameworks/C++/paozhu/paozhu_benchmark/libs/types/techempower_json.h b/frameworks/C++/paozhu/paozhu_benchmark/libs/types/techempower_json.h new file mode 100755 index 00000000000..364c06bb2cf --- /dev/null +++ b/frameworks/C++/paozhu/paozhu_benchmark/libs/types/techempower_json.h @@ -0,0 +1,15 @@ +#ifndef LIBS_TYPES_TECHEMPOWER_TYPE_H +#define LIBS_TYPES_TECHEMPOWER_TYPE_H +#include +#include + +namespace http +{ +//@reflect json to_json from_json +struct techempower_outjson_t +{ + std::string message; +}; + +}// namespace http +#endif diff --git a/frameworks/C++/paozhu/paozhu_benchmark/libs/types/techempower_json_jsonreflect.cpp b/frameworks/C++/paozhu/paozhu_benchmark/libs/types/techempower_json_jsonreflect.cpp new file mode 100755 index 00000000000..8ff68cdbae2 --- /dev/null +++ b/frameworks/C++/paozhu/paozhu_benchmark/libs/types/techempower_json_jsonreflect.cpp @@ -0,0 +1,291 @@ +#include +#include +#include +#include +#include "types/techempower_json.h" +#include "json_reflect_headers.h" +#include "unicode.h" +#include "func.h" +//This file is automatically created, do not edit it + +namespace http +{ + + +std::string json_encode(const techempower_outjson_t &json_reflectobj) + { + + std::stringstream _stream; + _stream << "{"; + _stream << "\"message\":\"" << http::utf8_to_jsonstring(json_reflectobj.message)<< "\""; + + _stream << "}"; + + return _stream.str(); + + } + + +std::string json_encode(const std::vector &json_reflectobj) + { + std::stringstream _stream; + _stream << "["; + + for(unsigned int i=0;i0) + { + _stream <<","; + } + _stream < + //递归代码 + + _offset++; + for ( ; _offset < _json_data.size(); _offset++) + { + if (_json_data[_offset] == '}') + { + //offset++; + break; + } + if (_json_data[_offset] == '"') + { + _offset++; + for ( ; _offset < _json_data.size(); _offset++) + { + if (_json_data[_offset] == '"'&&_json_data[_offset-1]!=0x5C) + { + break; + } + } + } + } + + + if(_offset < _json_data.size() && (_json_data[_offset]==']'||_json_data[_offset]=='}')) + { + _offset-=1; + } + //直接下一个,不用处理键值 + continue; + } + else if(_json_data[_offset]=='[') + { //表示有数组 + ////////////////////////////////////////////////////////////////////// + //begin level1 [] + //vector vector> vector> + //如果是非内置类型 直接使用json_decode<> + + //递归代码 + + + _offset++; + for ( ; _offset < _json_data.size(); _offset++) + { + if (_json_data[_offset] == ']') + { + //offset++; + break; + } + if (_json_data[_offset] == '"') + { + _offset++; + for ( ; _offset < _json_data.size(); _offset++) + { + if (_json_data[_offset] == '"'&&_json_data[_offset-1]!=0x5C) + { + break; + } + } + } + } + + //直接下一个,不用处理键值 + if(_offset < _json_data.size() && (_json_data[_offset]==']'||_json_data[_offset]=='}')) + { + _offset-=1; + } + continue; + //end level1[] + //////////////////////////////////////////////////////////////////// + } + else if(_json_data[_offset]==0x22) + { + //如果键值也是字符串 + temp_offset=_offset; + _json_value_name=http::jsonstring_to_utf8(&_json_data[_offset],_json_data.size()-_offset,temp_offset); + _offset=temp_offset; + if(_json_data[_offset]==0x22) + { + if((_offset+1)<_json_data.size()) + { + if(_json_data[_offset+1]!=']'&&_json_data[_offset+1]!='}') + { + _offset+=1; + } + } + } + } + else + { + //表示是数字 bool NULL + for(;_offset<_json_data.size();_offset++) + { + //结束条件 + if(_json_data[_offset]==','||_json_data[_offset]==']'||_json_data[_offset]=='}'||_json_data[_offset]==0x20||_json_data[_offset]==0x0A||_json_data[_offset]==0x0D||_json_data[_offset]=='\t') + { + break; + } + _json_value_name.push_back(_json_data[_offset]); + } + //让前面循环退出或返回 + if(_offset < _json_data.size() && _json_data[_offset]=='}') + { + _offset-=1; + } + } + //////////////////////////////////////////////////////// + // level1 + //处理对象赋值 + if (http::str_casecmp(_json_key_name, "message")) + { + + json_reflectobj.message=_json_value_name; + } + + //////////////////////////////////////////////////////// + //继续循环下一个键值 + continue; + } + } + } + return _offset; + } + +unsigned int json_decode(std::vector &json_reflectobj,const std::string &_json_data,unsigned int _offset) + { + bool _isarray=false; + for(;_offset<_json_data.size();_offset++) + { + if(_json_data[_offset]=='{') + { + break; + } + if(_json_data[_offset]=='[') + { + _isarray=true; + break; + } + } + + if(_isarray) + { + if(_json_data[_offset]=='[') + { + _offset+=1; + } + for(;_offset<_json_data.size();_offset++) + { + _offset=http::json_string_trim(_json_data,_offset); + //直接返回,这样可以防插入空的对象 + if(_json_data[_offset]==0x5D) + { + return _offset; + }else if(_json_data[_offset]=='{') + { + techempower_outjson_t temp; + _offset=json_decode(temp,_json_data,_offset); + json_reflectobj.push_back(temp); + } + + } + + } + else + { + techempower_outjson_t temp; + _offset=json_decode(temp,_json_data,_offset); + json_reflectobj.push_back(temp); + + } + + return _offset; + } + +} diff --git a/frameworks/C++/paozhu/paozhu_benchmark/models/Fortune.cpp b/frameworks/C++/paozhu/paozhu_benchmark/models/Fortune.cpp new file mode 100644 index 00000000000..96ede3889a4 --- /dev/null +++ b/frameworks/C++/paozhu/paozhu_benchmark/models/Fortune.cpp @@ -0,0 +1,16 @@ + +#include "fortune_mysql.h" +#include "fortune_base.h" +#include "Fortune.h" + +/* 如果此文件存在不会自动覆盖,没有则会自动生成。 +*If this file exists, it will not be overwritten automatically. If not, it will be generated automatically. */ + + + namespace orm{ + + Fortune::Fortune(std::string dbtag):fortune_mysql(dbtag){ mod=this; } + Fortune::Fortune():fortune_mysql(){ mod=this; } + + + } diff --git a/frameworks/C++/paozhu/paozhu_benchmark/models/World.cpp b/frameworks/C++/paozhu/paozhu_benchmark/models/World.cpp new file mode 100644 index 00000000000..eb721c0fda6 --- /dev/null +++ b/frameworks/C++/paozhu/paozhu_benchmark/models/World.cpp @@ -0,0 +1,16 @@ + +#include "world_mysql.h" +#include "world_base.h" +#include "World.h" + +/* 如果此文件存在不会自动覆盖,没有则会自动生成。 +*If this file exists, it will not be overwritten automatically. If not, it will be generated automatically. */ + + + namespace orm{ + + World::World(std::string dbtag):world_mysql(dbtag){ mod=this; } + World::World():world_mysql(){ mod=this; } + + + } diff --git a/frameworks/C++/paozhu/paozhu_benchmark/models/include/Fortune.h b/frameworks/C++/paozhu/paozhu_benchmark/models/include/Fortune.h new file mode 100644 index 00000000000..321ee707da7 --- /dev/null +++ b/frameworks/C++/paozhu/paozhu_benchmark/models/include/Fortune.h @@ -0,0 +1,16 @@ +#ifndef ORM_DEFAULT_FORTUNE_H +#define ORM_DEFAULT_FORTUNE_H +#include "fortune_mysql.h" +#include "fortune_base.h" + +/* 如果此文件存在不会自动覆盖,没有则会自动生成。 +*If this file exists, it will not be overwritten automatically. If not, it will be generated automatically. */ + + namespace orm { + class Fortune : public fortune_mysql{ + public: + Fortune(std::string dbtag); + Fortune(); + }; +} +#endif diff --git a/frameworks/C++/paozhu/paozhu_benchmark/models/include/World.h b/frameworks/C++/paozhu/paozhu_benchmark/models/include/World.h new file mode 100644 index 00000000000..56a5db1620f --- /dev/null +++ b/frameworks/C++/paozhu/paozhu_benchmark/models/include/World.h @@ -0,0 +1,16 @@ +#ifndef ORM_DEFAULT_WORLD_H +#define ORM_DEFAULT_WORLD_H +#include "world_mysql.h" +#include "world_base.h" + +/* 如果此文件存在不会自动覆盖,没有则会自动生成。 +*If this file exists, it will not be overwritten automatically. If not, it will be generated automatically. */ + + namespace orm { + class World : public world_mysql{ + public: + World(std::string dbtag); + World(); + }; +} +#endif diff --git a/frameworks/C++/paozhu/paozhu_benchmark/orm/include/fortune_base.h b/frameworks/C++/paozhu/paozhu_benchmark/orm/include/fortune_base.h new file mode 100644 index 00000000000..ce6dfa47786 --- /dev/null +++ b/frameworks/C++/paozhu/paozhu_benchmark/orm/include/fortune_base.h @@ -0,0 +1,2626 @@ +#ifndef ORM_DEFAULT_FORTUNEBASEMATA_H +#define ORM_DEFAULT_FORTUNEBASEMATA_H +/* +*This file is auto create from paozhu_cli +*本文件为自动生成 Sat, 26 Apr 2025 15:58:21 GMT +***/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "unicode.h" + +namespace orm { + + +struct fortune_base +{ + struct meta{ + unsigned int id = 0; ///**/ + std::string message = ""; ///**/ + } data; + std::vector record; +std::string _rmstag="default";//this value must be default or tag value, tag in mysqlconnect config file . +unsigned int _offset=0; +std::vector::iterator begin(){ return record.begin(); } +std::vector::iterator end(){ return record.end(); } +std::vector::const_iterator begin() const{ return record.begin(); } +std::vector::const_iterator end() const{ return record.end(); } +static constexpr std::array col_names={"id","message"}; +static constexpr std::array col_types={3,253}; +static constexpr std::array col_length={0,0}; +static constexpr std::array col_decimals={0,0}; +std::string tablename="fortune"; +static constexpr std::string_view modelname="Fortune"; + + unsigned char findcolpos(const std::string &coln){ + if(coln.size()==0) + { + return 255; + } + unsigned char bi=coln[0]; + + + if(bi<91&&bi>64){ + bi+=32; + } + switch(coln[0]){ + + + case 'i': + return 0; +break; +case 'm': + return 1; +break; + + } + return 255; + } + + int size(){ return record.size(); } + + std::string getPKname(){ + return "id"; +} + + void record_reset() + { + record.clear(); + } + void data_reset(){ + fortune_base::meta metatemp; + data = metatemp; + } + + std::string soft_remove_sql([[maybe_unused]] const std::string &fieldsql){ + std::string temp; + + return temp; + } + + + inline std::string stringaddslash(const std::string &content){ + std::string temp; + for(unsigned int i=0;i0){ + tempsql<<"`,`"; + }else{ + tempsql<<"`"; + } + tempsql<0){ + tempsql<<"`"; + } + tempsql<<") VALUES ("; + + if(data.id==0){ +tempsql<<"null"; + }else{ + tempsql<0){ + tempsql<<"`,`"; + }else{ + tempsql<<"`"; + } + tempsql<0){ + tempsql<<"`"; + } + tempsql<<") VALUES ("; + + if(insert_data.id==0){ +tempsql<<"null"; + }else{ + tempsql< &insert_data){ + unsigned int j=0; + std::ostringstream tempsql; + tempsql<<"INSERT INTO "; + tempsql<0){ + tempsql<<"`,`"; + }else{ + tempsql<<"`"; + } + tempsql<0){ + tempsql<<"`"; + } + tempsql<<") VALUES "; + + for(unsigned int i=0;i0) + { + tempsql<<","; + } + tempsql<<"("; + + + if(insert_data[i].id==0){ + tempsql<<"null"; + }else{ + tempsql< keypos; + for(;jj0){ + unsigned char bpos_i=findcolpos(keyname); + #ifdef DEBUG + if (bpos_i == 255) + { + std::cout << "\033[1m\033[31m-----------\n" + << keyname << " not in " << tablename << " table Field.\n-----------\033[0m" + << std::endl; + } +#endif + keypos.emplace_back(bpos_i); + keyname.clear(); + } + for(jj=0;jj0){ tempsql<<","; } +if(data.id==0){ + tempsql<<"`id`=0"; + }else{ + tempsql<<"`id`="<0){ tempsql<<","; } +tempsql<<"`message`='"< 0) + { + tempsql << "`,`"; + } + else + { + tempsql << "`"; + } + tempsql << col_names[j]; + } + if (j > 0) + { + tempsql << "`"; + } + tempsql << ") VALUES "; + + for (unsigned int i = 0; i < record.size(); i++) + { + if (i > 0) + { + tempsql << ",\n"; + } + tempsql << "("; + if(record[i].id==0){ + tempsql<<"null"; + }else{ + tempsql< 0) + { + tempsql << "`,`"; + } + else + { + tempsql << "`"; + } + tempsql << col_names[j]; + } + if (j > 0) + { + tempsql << "`"; + } + tempsql << ") VALUES "; + + for (unsigned int i = 0; i < record.size(); i++) + { + if (i > 0) + { + tempsql << ",\n"; + } + tempsql << "("; + if(record[i].id==0){ + tempsql<<"null"; + }else{ + tempsql<0){ + for(;jj0) + { + tempsql<<","; + } + tempsql<0){ + if(findcolpos(keyname)<255) + { + if(j>0) + { + tempsql<<","; + } + tempsql< data_toarray(std::string fileld=""){ + std::vector temparray; + std::string keyname; + unsigned char jj=0; + std::vector keypos; + if(fileld.size()>1){ + for(;jj0){ + keypos.emplace_back(findcolpos(keyname)); + keyname.clear(); + } + }else{ + for(jj=0;jj data_tomap(std::string fileld=""){ + std::map tempsql; + std::string keyname; + unsigned char jj=0; + std::vector keypos; + if(fileld.size()>1){ + for(;jj0){ + keypos.emplace_back(findcolpos(keyname)); + keyname.clear(); + } + }else{ + for(jj=0;jj keypos; + if(fileld.size()>0){ + for(;jj0){ + keypos.emplace_back(findcolpos(keyname)); + keyname.clear(); + } + }else{ + for(jj=0;jj0){ tempsql<<","; } +if(data.id==0){ + tempsql<<"\"id\":0"; + }else{ + tempsql<<"\"id\":"<0){ tempsql<<","; } +tempsql<<"\"message\":\""< list_content; + for(;json_offset0) + { + data=metatemp; + } + if(json_offset>=json_content.size()) + { + break; + } + for(;json_offset=json_content.size()) + { + break; + } + json_value_name.clear(); + if(json_content[json_offset]==0x22) + { + + temp_offset=json_offset; + json_value_name=http::jsonstring_to_utf8(&json_content[json_offset],json_content.size()-json_offset,temp_offset); + json_offset=temp_offset; + if(json_content[json_offset]==0x22) + { + json_offset+=1; + } + } + else + { + if(json_content[json_offset]!='{'&&json_content[json_offset]!=']') + { + for(;json_offset1) + { + data=record[0]; + } + } + else + { + if(json_content[json_offset]=='{') + { + json_offset+=1; + std::string json_key_name,json_value_name; + + + for(;json_offset=json_content.size()) + { + break; + } + json_value_name.clear(); + if(json_content[json_offset]==0x22) + { + + temp_offset=json_offset; + json_value_name=http::jsonstring_to_utf8(&json_content[json_offset],json_content.size()-json_offset,temp_offset); + json_offset=temp_offset; + if(json_content[json_offset]==0x22) + { + json_offset+=1; + } + } + else + { + if(json_content[json_offset]!='{'&&json_content[json_offset]!=']') + { + for(;json_offset keypos; + if(fileld.size()>0){ + for(;jj0){ + keypos.emplace_back(findcolpos(keyname)); + keyname.clear(); + } + }else{ + for(jj=0;jj0){ + tempsql<<",{"; + }else{ + tempsql<<"{"; + } + + for(jj=0;jj0){ tempsql<<","; } +if(record[n].id==0){ + tempsql<<"\"id\":0"; + }else{ + tempsql<<"\"id\":"<0){ tempsql<<","; } +tempsql<<"\"message\":\""< func,std::string fileld=""){ + std::ostringstream tempsql; + std::string keyname; + unsigned char jj=0; + std::vector keypos; + if(fileld.size()>0){ + for(;jj0){ + keypos.emplace_back(findcolpos(keyname)); + keyname.clear(); + } + }else{ + for(jj=0;jj0){ + tempsql<<",{"; + }else{ + tempsql<<"{"; + } + tempsql<0){ tempsql<<","; } +if(record[n].id==0){ + tempsql<<"\"id\":0"; + }else{ + tempsql<<"\"id\":"<0){ tempsql<<","; } +tempsql<<"\"message\":\""< getRecord(){ + return record; +} + + + template::value,bool>::type = true> + T& ref_meta([[maybe_unused]] std::string key_name) + { + if(key_name=="message") + { + return data.message; + } + return nullptr; + } + + + template,bool>::type = true> + T& ref_meta([[maybe_unused]] std::string key_name) + { + if(key_name=="id") + { + return data.id; + } + return nullptr; + } + + + template,bool>::type = true > + T& ref_meta([[maybe_unused]] std::string key_name) + { + return nullptr; + } + + template,bool>::type = true > + std::vector getCol([[maybe_unused]] std::string keyname) + { + std::vector a; + + + unsigned char kpos; + kpos=findcolpos(keyname); + for(auto &iter:record) + { + switch(kpos) + { + case 0: + a.emplace_back(iter.id); + break; + + } + } + + return a; + } + + template,bool>::type = true > + std::vector getCol([[maybe_unused]] std::string keyname) + { + std::vector a; + + + return a; + } + + template,bool>::type = true > + T getVal([[maybe_unused]] std::string keyname) + { + + unsigned char kpos; + kpos=findcolpos(keyname); + switch(kpos) + { + + case 0: + return data.id; + break; + } + return 0; + } + + template,bool>::type = true > + T getVal([[maybe_unused]] fortune_base::meta & iter,[[maybe_unused]] std::string keyname) + { + + + unsigned char kpos; + kpos=findcolpos(keyname); + switch(kpos) + { + case 0: + return iter.id; + break; + + } + + return 0; + } + + template,bool>::type = true > + T getVal(std::string keyname) + { + unsigned char kpos; + kpos=findcolpos(keyname); + + switch(kpos) + { + + + } + + + return 0.0; + } + + template,bool>::type = true > + T getVal([[maybe_unused]] fortune_base::meta & iter,std::string keyname) + { + unsigned char kpos; + kpos=findcolpos(keyname); + switch(kpos) + { + + } + + + + return 0.0; + } + + template::value,bool>::type = true > + std::string getVal(std::string keyname) + { + unsigned char kpos; + kpos=findcolpos(keyname); + + switch(kpos) + { + + case 1: + return data.message; + break; + + } + return ""; + } + + template::value,bool>::type = true > + std::string getVal([[maybe_unused]] fortune_base::meta & iter,std::string keyname) + { + + unsigned char kpos; + kpos=findcolpos(keyname); + + switch(kpos) + { + + case 1: + return iter.message; + break; + + } + + + + return ""; + } + + template::value,bool>::type = true > + std::vector getCol([[maybe_unused]] std::string keyname) + { + std::vector a; + + + unsigned char kpos; + kpos=findcolpos(keyname); + for(auto &iter:record) + { + switch(kpos) + { + + case 1: + a.emplace_back(iter.message); + break; + } + } + + return a; + } + + std::string getstrCol(std::string keyname,[[maybe_unused]] bool isyinhao=false) + { + std::ostringstream a; + + unsigned char kpos; + kpos=findcolpos(keyname); + int j=0; + if(isyinhao&&record.size()>0) + { + a<<'"'; + } + for(auto &iter:record) + { + if(j>0) + { + if(isyinhao) + { + a<<"\",\""; + }else{ + a<<','; + } + } + switch(kpos) + { + + case 0: + a<0){ + a<<'"'; + } + + return a.str(); + } + + template::value,bool>::type = true,typename std::enable_if::value,bool>::type = true> + std::map getCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname) + { + std::map a; + + unsigned char kpos,vpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + std::string ktemp,vtemp; + for(auto &iter:record) + { + switch(kpos) + { + + case 1: + ktemp=iter.message; + break; + } + switch(vpos){ + case 1: + vtemp=iter.message; + break; + + } + if(ktemp.size()>0) + { + a.emplace(ktemp,vtemp); + } + } + + + return a; + } + + + template::value,bool>::type = true, typename std::enable_if::value,bool>::type = true> + std::map getCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname) + { + std::map a; + + unsigned char kpos,vpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + std::string ktemp; + U vtemp; + for(auto &iter:record) + { + switch(kpos) + { + + case 1: + ktemp=iter.message; + break; + } + switch(vpos){ + + } + if(ktemp.size()>0) + { + a.emplace(ktemp,vtemp); + } + } + + return a; + } + + template,bool>::type = true, typename std::enable_if::value,bool>::type = true> + std::map getCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname) + { + std::map a; + + unsigned char kpos,vpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + T ktemp; + U vtemp; + for(auto &iter:record) + { + switch(kpos) + { + + case 0: + ktemp=iter.id; + break; + } + switch(vpos){ + + } + if(ktemp.size()>0) + { + a.emplace(ktemp,vtemp); + } + } + + return a; + } + template,bool>::type = true, typename std::enable_if::value,bool>::type = true> + std::map getCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname) + { + std::map a; + + unsigned char kpos,vpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + T ktemp; + std::string vtemp; + for(auto &iter:record) + { + switch(kpos) + { + + case 0: + ktemp=iter.id; + break; + } + switch(vpos){ + case 1: + vtemp=iter.message; + break; + + } + if(ktemp.size()>0) + { + a.emplace(ktemp,vtemp); + } + } + + return a; + } + + template::value,bool>::type = true,typename std::enable_if,bool>::type = true> + std::map getCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname) + { + std::map a; + + unsigned char kpos,vpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + std::string ktemp; + U vtemp; + for(auto &iter:record) + { + switch(kpos) + { + + case 1: + ktemp=iter.message; + break; + } + switch(vpos){ + case 0: + vtemp=iter.id; + break; + + } + if(ktemp.size()>0) + { + a.emplace(ktemp,vtemp); + } + } + + return a; + } + + template,bool>::type = true,typename std::enable_if,bool>::type = true> + std::map getCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname) + { + std::map a; + + unsigned char kpos,vpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + T ktemp; + U vtemp; + for(auto &iter:record) + { + switch(kpos) + { + + case 0: + ktemp=iter.id; + break; + } + switch(vpos){ + case 0: + vtemp=iter.id; + break; + + } + if(ktemp.size()>0) + { + a.emplace(ktemp,vtemp); + } + } + + return a; + } + + template,bool>::type = true > + std::map getmapRows([[maybe_unused]] std::string keyname) + { + std::map a; + + unsigned char kpos; + kpos=findcolpos(keyname); + for(auto &iter:record) + { + switch(kpos) + { + + case 0: + a.emplace(iter.id,iter); + break; + + } + } + + return a; + } + + template::value,bool>::type = true > + std::map getmapRows([[maybe_unused]] std::string keyname) + { + std::map a; + + + unsigned char kpos; + kpos=findcolpos(keyname); + for(auto &iter:record) + { + switch(kpos) + { + + case 1: + a.emplace(iter.message,iter); + break; + + } + //a.emplace(ktemp,iter); + } + + + return a; + } + + template::value,bool>::type = true, typename std::enable_if::value,bool>::type = true> + std::vector> getvecCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname) + { + std::vector> a; + + unsigned char kpos,vpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + std::string ktemp; + U vtemp; + for(auto &iter:record) + { + switch(kpos) + { + + case 1: + ktemp=iter.message; + break; + } + switch(vpos){ + + } + + a.emplace_back(ktemp,vtemp); + } + + + + return a; + } + + template,bool>::type = true, typename std::enable_if::value,bool>::type = true> + std::vector> getvecCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname) + { + std::vector> a; + + unsigned char kpos,vpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + T ktemp; + U vtemp; + for(auto &iter:record) + { + switch(kpos) + { + + case 0: + ktemp=iter.id; + break; + } + switch(vpos){ + + } + + a.emplace_back(ktemp,vtemp); + } + + + + return a; + } + + template,bool>::type = true, typename std::enable_if::value,bool>::type = true> + std::vector> getvecCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname) + { + std::vector> a; + + + unsigned char kpos,vpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + T ktemp; + U vtemp; + for(auto &iter:record) + { + switch(kpos) + { + + case 0: + ktemp=iter.id; + break; + } + switch(vpos){ + case 1: + vtemp=iter.message; + break; + + } + + a.emplace_back(ktemp,vtemp); + } + + return a; + } + + template::value,bool>::type = true,typename std::enable_if,bool>::type = true> + std::vector> getvecCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname) + { + std::vector> a; + + unsigned char kpos,vpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + T ktemp; + U vtemp; + for(auto &iter:record) + { + + switch(kpos) + { + + case 1: + ktemp=iter.message; + break; + } + switch(vpos){ + case 0: + vtemp=iter.id; + break; + + } + a.emplace_back(ktemp,vtemp); + } + + return a; + } + + template,bool>::type = true,typename std::enable_if,bool>::type = true> + std::vector> getvecCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname) + { + std::vector> a; + + unsigned char kpos,vpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + T ktemp; + U vtemp; + for(auto &iter:record) + { + switch(kpos) + { + + case 0: + ktemp=iter.id; + break; + } + switch(vpos){ + case 0: + vtemp=iter.id; + break; + + } + a.emplace_back(ktemp,vtemp); + } + + return a; + } + + template::value,bool>::type = true,typename std::enable_if::value,bool>::type = true> + std::vector> getvecCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname) + { + std::vector> a; + + unsigned char kpos,vpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + T ktemp; + U vtemp; + for(auto &iter:record) + { + switch(kpos) + { + + case 1: + ktemp=iter.message; + break; + } + switch(vpos){ +case 1: + vtemp=iter.message; + break; + + } + + a.emplace_back(ktemp,vtemp); + } + + return a; + } + + template,bool>::type = true > + std::vector> getvecRows([[maybe_unused]] std::string keyname) + { + std::vector> a; + + unsigned char kpos; + kpos=findcolpos(keyname); + for(auto &iter:record) + { + switch(kpos) + { + + case 0: + a.emplace_back(iter.id,iter); + break; + + } + } + + return a; + } + template::value,bool>::type = true > + std::vector> getvecRows([[maybe_unused]] std::string keyname) + { + std::vector> a; + + unsigned char kpos; + kpos=findcolpos(keyname); + for(auto &iter:record) + { + switch(kpos) + { + + case 1: + a.emplace_back(iter.message,iter); + break; + + } + } + + + return a; + } + template,bool>::type = true,typename std::enable_if,bool>::type = true, typename std::enable_if::value,bool>::type = true> + std::map>> getgroupCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname,[[maybe_unused]] std::string dataname) + { + std::map>> a; + + unsigned char kpos,vpos,dpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + dpos=findcolpos(dataname); + T ktemp; + U vtemp; + for(auto &iter:record) + { + switch(kpos) + { + + case 0: + ktemp=iter.id; + break; + } + + switch(vpos){ + case 0: + vtemp=iter.id; + break; + } + + switch(dpos){ + + } + } + + + return a; + } + + template,bool>::type = true,typename std::enable_if,bool>::type = true, typename std::enable_if,bool>::type = true> + std::map>> getgroupCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname,[[maybe_unused]] std::string dataname) + { + std::map>> a; + + unsigned char kpos,vpos,dpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + dpos=findcolpos(dataname); + T ktemp; + U vtemp; + //D vtemp; + + for(auto &iter:record) + { + switch(kpos) + { + + case 0: + ktemp=iter.id; + break; + } + + switch(vpos){ + case 0: + vtemp=iter.id; + break; + } + + switch(dpos){ + case 0: + a[ktemp][vtemp].emplace_back(iter.id); + break; + + } + } + + return a; + } + + template,bool>::type = true,typename std::enable_if,bool>::type = true, typename std::enable_if::value,bool>::type = true> + std::map>> getgroupCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname,[[maybe_unused]] std::string dataname) + { + std::map>> a; + + unsigned char kpos,vpos,dpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + dpos=findcolpos(dataname); + T ktemp; + U vtemp; + // D dtemp; + + for(auto &iter:record) + { + switch(kpos) + { + + case 0: + ktemp=iter.id; + break; + } + + switch(vpos){ + case 0: + vtemp=iter.id; + break; + } + + switch(dpos){ + case 1: + a[ktemp][vtemp].emplace_back(iter.message); + break; + + } + } + + return a; + } + + template,bool>::type = true, typename std::enable_if::value,bool>::type = true, typename std::enable_if::value,bool>::type = true> + std::map>> getgroupCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname,[[maybe_unused]] std::string dataname) + { + std::map>> a; + + unsigned char kpos,vpos,dpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + dpos=findcolpos(dataname); + T ktemp; + U vtemp; + // D dtemp; + + for(auto &iter:record) + { + + switch(kpos) + { + + case 0: + ktemp=iter.id; + break; + } + + switch(vpos){ + case 1: + vtemp=iter.message; + break; + } + + switch(dpos){ + + } + } + + return a; + } + + template,bool>::type = true, typename std::enable_if::value,bool>::type = true, typename std::enable_if,bool>::type = true> + std::map>> getgroupCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname,[[maybe_unused]] std::string dataname) + { + std::map>> a; + + + unsigned char kpos,vpos,dpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + dpos=findcolpos(dataname); + T ktemp; + U vtemp; + // D dtemp; + + for(auto &iter:record) + { + switch(kpos) + { + + case 0: + ktemp=iter.id; + break; + } + + switch(vpos){ + case 1: + vtemp=iter.message; + break; + } + + switch(dpos){ + case 0: + a[ktemp][vtemp].emplace_back(iter.id); + break; + + } + } + + return a; + } + template,bool>::type = true, typename std::enable_if::value,bool>::type = true, typename std::enable_if::value,bool>::type = true> + std::map>> getgroupCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname,[[maybe_unused]] std::string dataname) + { + std::map>> a; + + unsigned char kpos,vpos,dpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + dpos=findcolpos(dataname); + T ktemp; + U vtemp; + // D dtemp; + + for(auto &iter:record) + { + switch(kpos) + { + + case 0: + ktemp=iter.id; + break; + } + + switch(vpos){ + case 1: + vtemp=iter.message; + break; + } + + switch(dpos){ + case 1: + a[ktemp][vtemp].emplace_back(iter.message); + break; + + } + } + + return a; + } + + template::value,bool>::type = true,typename std::enable_if,bool>::type = true, typename std::enable_if::value,bool>::type = true> + std::map>> getgroupCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname,[[maybe_unused]] std::string dataname) + { + std::map>> a; + + unsigned char kpos,vpos,dpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + dpos=findcolpos(dataname); + T ktemp; + U vtemp; + //D vtemp; + for(auto &iter:record) + { + switch(kpos) + { + + case 1: + ktemp=iter.message; + break; + } + + switch(vpos){ + case 0: + vtemp=iter.id; + break; + } + + switch(dpos){ + + } + } + + + return a; + } + + template::value,bool>::type = true,typename std::enable_if,bool>::type = true, typename std::enable_if,bool>::type = true> + std::map>> getgroupCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname,[[maybe_unused]] std::string dataname) + { + std::map>> a; + + unsigned char kpos,vpos,dpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + dpos=findcolpos(dataname); + T ktemp; + U vtemp; + //D vtemp; + + for(auto &iter:record) + { + + switch(kpos) + { + + case 1: + ktemp=iter.message; + break; + } + + switch(vpos){ + case 0: + vtemp=iter.id; + break; + } + + switch(dpos){ + case 0: + a[ktemp][vtemp].emplace_back(iter.id); + break; + + } + } + + return a; + } + + template::value,bool>::type = true,typename std::enable_if,bool>::type = true, typename std::enable_if::value,bool>::type = true> + std::map>> getgroupCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname,[[maybe_unused]] std::string dataname) + { + std::map>> a; + + + unsigned char kpos,vpos,dpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + dpos=findcolpos(dataname); + T ktemp; + U vtemp; + // D dtemp; + + for(auto &iter:record) + { + + switch(kpos) + { + + case 1: + ktemp=iter.message; + break; + } + + switch(vpos){ + case 0: + vtemp=iter.id; + break; + } + + switch(dpos){ + case 1: + a[ktemp][vtemp].emplace_back(iter.message); + break; + + } + } + + return a; + } + + template::value,bool>::type = true, typename std::enable_if::value,bool>::type = true, typename std::enable_if::value,bool>::type = true> + std::map>> getgroupCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname,[[maybe_unused]] std::string dataname) + { + std::map>> a; + + unsigned char kpos,vpos,dpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + dpos=findcolpos(dataname); + T ktemp; + U vtemp; + // D dtemp; + + for(auto &iter:record) + { + switch(kpos) + { + + case 1: + ktemp=iter.message; + break; + } + + switch(vpos){ + case 1: + vtemp=iter.message; + break; + } + + switch(dpos){ + + } + } + + + return a; + } + template::value,bool>::type = true, typename std::enable_if::value,bool>::type = true, typename std::enable_if,bool>::type = true> + std::map>> getgroupCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname,[[maybe_unused]] std::string dataname) + { + std::map>> a; + + unsigned char kpos,vpos,dpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + dpos=findcolpos(dataname); + T ktemp; + U vtemp; + // D dtemp; + + for(auto &iter:record) + { + + switch(kpos) + { + + case 1: + ktemp=iter.message; + break; + } + + switch(vpos){ + case 1: + vtemp=iter.message; + break; + } + + switch(dpos){ + case 0: + a[ktemp][vtemp].emplace_back(iter.id); + break; + + } + } + + return a; + } + + template::value,bool>::type = true, typename std::enable_if::value,bool>::type = true, typename std::enable_if::value,bool>::type = true> + std::map>> getgroupCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname,[[maybe_unused]] std::string dataname) + { + std::map>> a; + + unsigned char kpos,vpos,dpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + dpos=findcolpos(dataname); + T ktemp; + U vtemp; + // D dtemp; + + for(auto &iter:record) + { + switch(kpos) + { + + case 1: + ktemp=iter.message; + break; + } + + switch(vpos){ + case 1: + vtemp=iter.message; + break; + } + + switch(dpos){ + case 1: + a[ktemp][vtemp].emplace_back(iter.message); + break; + + } + } + + return a; + } + + template::value,bool>::type = true, typename std::enable_if::value,bool>::type = true> + std::map> getgroupCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname) + { + std::map> a; + + + unsigned char kpos,vpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + T ktemp; + //U vtemp; + + for(auto &iter:record) + { + switch(kpos) + { + + case 1: + ktemp=iter.message; + break; + } + + switch(vpos){ + case 1: + a[ktemp].emplace_back(iter.message); + break; + + } + } + + return a; + } + + template::value,bool>::type = true,typename std::enable_if::value,bool>::type = true> + std::map> getgroupCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname) + { + std::map> a; + + unsigned char kpos,vpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + T ktemp; + //U vtemp; + + for(auto &iter:record) + { + switch(kpos) + { + + case 1: + ktemp=iter.message; + break; + } + + switch(vpos){ + + } + } + + + return a; + } + + template::value,bool>::type = true,typename std::enable_if,bool>::type = true> + std::map> getgroupCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname) + { + std::map> a; + + unsigned char kpos,vpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + T ktemp; + //U vtemp; + + for(auto &iter:record) + { + + switch(kpos) + { + + case 1: + ktemp=iter.message; + break; + } + + switch(vpos){ + case 0: + a[ktemp].emplace_back(iter.id); + break; + + } + } + + return a; + } + + template,bool>::type = true, typename std::enable_if::value,bool>::type = true> + std::map> getgroupCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname) + { + std::map> a; + + unsigned char kpos,vpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + T ktemp; + //U vtemp; + + for(auto &iter:record) + { + + switch(kpos) + { + + case 0: + ktemp=iter.id; + break; + } + + switch(vpos){ + case 1: + a[ktemp].emplace_back(iter.message); + break; + + } + } + + + return a; + } + + template,bool>::type = true,typename std::enable_if::value,bool>::type = true> + std::map> getgroupCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname) + { + std::map> a; + + unsigned char kpos,vpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + T ktemp; + //U vtemp; + + for(auto &iter:record) + { + + switch(kpos) + { + + case 0: + ktemp=iter.id; + break; + } + + switch(vpos){ + + } + } + + return a; + } + + template,bool>::type = true,typename std::enable_if,bool>::type = true> + std::map> getgroupCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname) + { + std::map> a; + + unsigned char kpos,vpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + T ktemp; + //U vtemp; + + for(auto &iter:record) + { + + switch(kpos) + { + + case 0: + ktemp=iter.id; + break; + } + + switch(vpos){ + case 0: + a[ktemp].emplace_back(iter.id); + break; + + } + } + + return a; + } + + template,bool>::type = true> + std::map> getgroupRows([[maybe_unused]] std::string keyname) + { + std::map> a; + + unsigned char kpos; + kpos=findcolpos(keyname); + + for(auto &iter:record) + { + switch(kpos) + { + + case 0: + a[iter.id].emplace_back(iter); + break; + + } + } + + return a; + } + + template::value,bool>::type = true> + std::map> getgroupRows([[maybe_unused]] std::string keyname) + { + std::map> a; + + unsigned char kpos; + kpos=findcolpos(keyname); + + for(auto &iter:record) + { + + switch(kpos) + { + + case 1: + a[iter.message].emplace_back(iter); + break; + + } + } + + return a; + } + + template::value,bool>::type = true, typename std::enable_if::value,bool>::type = true> + std::map>> getgroupRows([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname) + { + std::map>> a; + + unsigned char kpos,vpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + T ktemp; + + for(auto &iter:record) + { + + switch(kpos) + { + + case 1: + ktemp=iter.message; + break; + } + + switch(vpos){ + case 1: + a[ktemp][iter.message].emplace_back(iter); + break; + + } + } + + return a; + } + + template::value,bool>::type = true,typename std::enable_if,bool>::type = true> + std::map>> getgroupRows([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname) + { + std::map>> a; + + unsigned char kpos,vpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + T ktemp; + + for(auto &iter:record) + { + + switch(kpos) + { + + case 1: + ktemp=iter.message; + break; + } + + switch(vpos){ + case 0: + a[ktemp][iter.id].emplace_back(iter); + break; + + } + } + + + return a; + } + + template,bool>::type = true,typename std::enable_if,bool>::type = true> + std::map>> getgroupRows([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname) + { + std::map>> a; + + unsigned char kpos,vpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + T ktemp; + + for(auto &iter:record) + { + + switch(kpos) + { + + case 0: + ktemp=iter.id; + break; + } + + switch(vpos){ + case 0: + a[ktemp][iter.id].emplace_back(iter); + break; + + } + } + + return a; + } + + template,bool>::type = true,typename std::enable_if::value,bool>::type = true> + std::map>> getgroupRows([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname) + { + std::map>> a; + + + unsigned char kpos,vpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + T ktemp; + + for(auto &iter:record) + { + + switch(kpos) + { + + case 0: + ktemp=iter.id; + break; + } + + switch(vpos){ + case 1: + a[ktemp][iter.message].emplace_back(iter); + break; + + } + } + + return a; + } + + }; + + +} +#endif + \ No newline at end of file diff --git a/frameworks/C++/paozhu/paozhu_benchmark/orm/include/fortune_mysql.h b/frameworks/C++/paozhu/paozhu_benchmark/orm/include/fortune_mysql.h new file mode 100644 index 00000000000..5bca5120b86 --- /dev/null +++ b/frameworks/C++/paozhu/paozhu_benchmark/orm/include/fortune_mysql.h @@ -0,0 +1,11476 @@ +#ifndef _ORM_DEFAULT_FORTUNE_OPERATE_H +#define _ORM_DEFAULT_FORTUNE_OPERATE_H +/* + * @author 黄自权 huangziquan + * @date 2022-05-04 + * @update 2025-03-12 + * @dest ORM MySQL中间连接层 + */ +#include +#include +#include +#include +#include +#include +#include +#include "request.h" +#include "unicode.h" +#include "datetime.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mysql_conn.h" +#include "mysql_conn_pool.h" +#include "orm_cache.hpp" +#include "mysql_connect_mar.h" +/*baseincludefile*/ +namespace orm +{ +// mysql Operational SQL middleware +/*tagnamespace*/ +//{ /*tagnamespace_replace*/ + template + class fortune_mysql : public B_BASE + { + public: + fortune_mysql(const std::string &tag) : dbtag(tag) + { + std::map> &conn_pool_obj = get_orm_conn_pool_obj(); + auto iter = conn_pool_obj.find(dbtag); + if (iter != conn_pool_obj.end()) + { + conn_obj = iter->second; + } + else + { + conn_obj = nullptr; + iserror = true; + error_msg = "conn_pool not found " + dbtag; + } + } + fortune_mysql() : dbtag(B_BASE::_rmstag) + { + std::map> &conn_pool_obj = get_orm_conn_pool_obj(); + auto iter = conn_pool_obj.find(dbtag); + if (iter != conn_pool_obj.end()) + { + conn_obj = iter->second; + } + else + { + conn_obj = nullptr; + iserror = true; + error_msg = "conn_pool not found " + dbtag; + } + } + M_MODEL &switchDB(const std::string &temptag) + { + std::map> &conn_pool_obj = get_orm_conn_pool_obj(); + auto iter = conn_pool_obj.find(temptag); + if (iter != conn_pool_obj.end()) + { + conn_obj = iter->second; + } + else + { + conn_obj = nullptr; + iserror = true; + error_msg = "conn_pool not found " + temptag; + } + } + M_MODEL &set_table(const std::string &table_name) + { + if (original_tablename.empty()) + { + original_tablename = B_BASE::tablename; + } + if (table_name.size() > 0) + { + B_BASE::tablename = table_name; + } + return *mod; + } + M_MODEL &reset_table() + { + if (original_tablename.empty()) + { + return *mod; + } + B_BASE::tablename = original_tablename; + return *mod; + } + unsigned int count() + { + std::string countsql; + countsql = "SELECT count(*) as total_countnum FROM "; + countsql.append(B_BASE::tablename); + countsql.append(" WHERE "); + if (wheresql.empty()) + { + countsql.append(" 1 "); + } + else + { + countsql.append(wheresql); + } + if (!groupsql.empty()) + { + countsql.append(groupsql); + } + if (!limitsql.empty()) + { + countsql.append(limitsql); + } + + if (iserror) + { + return 0; + } + + try + { + effect_num = 0; + if (conn_empty()) + { + return 0; + } + //auto conn = conn_obj->get_select_conn(); + if (islock_conn) + { + if (!select_conn) + { + select_conn = conn_obj->get_select_conn(); + } + } + else + { + select_conn = conn_obj->get_select_conn(); + } + + if (select_conn->isdebug) + { + select_conn->begin_time(); + } + std::size_t n = select_conn->write_sql(countsql); + if (n == 0) + { + error_msg = select_conn->error_msg; + select_conn.reset(); + return 0; + } + + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + bool is_sql_item = false; + //std::vector field_array; + unsigned char action_setup = 0; + unsigned int column_num = 0; + unsigned int offset = 0; + + unsigned int querysql_len = 0; + + for (; is_sql_item == false;) + { + n = select_conn->read_loop(); + offset = 0; + if (n == 0) + { + error_msg = select_conn->error_msg; + select_conn.reset(); + return 0; + } + for (; offset < n;) + { + select_conn->read_field_pack(select_conn->_cache_data, n, offset, temp_pack_data); + if (temp_pack_data.error > 0) + { + iserror = true; + error_msg = temp_pack_data.data; + select_conn.reset(); + return 0; + } + if (temp_pack_data.length == temp_pack_data.current_length && temp_pack_data.current_length > 0) + { + if (select_conn->pack_eof_check(temp_pack_data)) + { + is_sql_item = true; + break; + } + + if (action_setup == 0) + { + if (temp_pack_data.length == 2 && (unsigned char)temp_pack_data.data[0] < 251 && (unsigned char)temp_pack_data.data[0] > 0) + { + action_setup = 1; + column_num = (unsigned char)temp_pack_data.data[0]; + } + } + else if (action_setup == 1) + { + field_info_t temp_filed_col; + select_conn->read_col_info(temp_pack_data.data, temp_filed_col); + + column_num--; + if (column_num == 0) + { + action_setup = 2; + } + } + else if (action_setup == 2) + { + unsigned int tempnum = 0; + + unsigned int name_length = select_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], tempnum); + + querysql_len = 0; + for (unsigned int ik = 0; ik < name_length; ik++) + { + if (temp_pack_data.data[tempnum] >= '0' && temp_pack_data.data[tempnum] <= '9') + { + querysql_len = querysql_len * 10 + (temp_pack_data.data[tempnum] - '0'); + } + tempnum++; + } + effect_num++; + } + } + else + { + if (offset >= n) + { + break; + } + is_sql_item = true; + break; + } + } + } + + if (select_conn->isdebug) + { + select_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = select_conn->count_time(); + conn_mar.push_log(countsql, std::to_string(du_time)); + } + + if (!islock_conn) + { + conn_obj->back_select_conn(std::move(select_conn)); + } + + return querysql_len; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + return 0; + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + return 0; + } + + return 0; + } + std::tuple + page(unsigned int page, unsigned int per_page = 10, unsigned int list_num = 5) + { + unsigned int total_page = count(); + if (per_page == 0) + { + per_page = 10; + } + if (list_num < 1) + { + list_num = 1; + } + total_page = std::ceil((float)total_page / per_page); + + if (total_page < 1) + { + total_page = 1; + } + if (page > total_page) + { + page = total_page; + } + if (page < 1) + { + page = 1; + } + unsigned int mid_num = std::floor(list_num / 2); + unsigned int last_num = list_num - 1; + + int temp_num = page - mid_num; + + unsigned int minpage = temp_num < 1 ? 1 : temp_num; + unsigned int maxpage = minpage + last_num; + + if (maxpage > total_page) + { + maxpage = total_page; + temp_num = (maxpage - last_num); + if (temp_num < 1) + { + minpage = 1; + } + else + { + minpage = temp_num; + } + } + limit((page - 1) * per_page, per_page); + return std::make_tuple(minpage, maxpage, page, total_page); + } + asio::awaitable async_count() + { + std::string countsql; + countsql = "SELECT count(*) as total_countnum FROM "; + countsql.append(B_BASE::tablename); + countsql.append(" WHERE "); + if (wheresql.empty()) + { + countsql.append(" 1 "); + } + else + { + countsql.append(wheresql); + } + if (!groupsql.empty()) + { + countsql.append(groupsql); + } + if (!limitsql.empty()) + { + countsql.append(limitsql); + } + + if (iserror) + { + co_return 0; + } + + try + { + effect_num = 0; + if (conn_empty()) + { + co_return 0; + } + //auto conn = co_await conn_obj->async_get_select_conn(); + if (islock_conn) + { + if (!select_conn) + { + select_conn = co_await conn_obj->async_get_select_conn(); + } + } + else + { + select_conn = co_await conn_obj->async_get_select_conn(); + } + + if (select_conn->isdebug) + { + select_conn->begin_time(); + } + std::size_t n = co_await select_conn->async_write_sql(countsql); + if (n == 0) + { + error_msg = select_conn->error_msg; + select_conn.reset(); + co_return 0; + } + //std::size_t n = co_await asio::async_write(*conn->socket, asio::buffer(conn->send_data), asio::use_awaitable); + + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + bool is_sql_item = false; + //std::vector field_array; + unsigned char action_setup = 0; + unsigned int column_num = 0; + unsigned int offset = 0; + + unsigned int querysql_len = 0; + + for (; is_sql_item == false;) + { + n = co_await select_conn->async_read_loop(); + offset = 0; + if (n == 0) + { + select_conn.reset(); + co_return 0; + } + for (; offset < n;) + { + select_conn->read_field_pack(select_conn->_cache_data, n, offset, temp_pack_data); + if (temp_pack_data.error > 0) + { + iserror = true; + error_msg = temp_pack_data.data; + select_conn.reset(); + co_return 0; + } + if (temp_pack_data.length == temp_pack_data.current_length && temp_pack_data.current_length > 0) + { + if (select_conn->pack_eof_check(temp_pack_data)) + { + is_sql_item = true; + break; + } + + if (action_setup == 0) + { + if (temp_pack_data.length == 2 && (unsigned char)temp_pack_data.data[0] < 251 && (unsigned char)temp_pack_data.data[0] > 0) + { + action_setup = 1; + column_num = (unsigned char)temp_pack_data.data[0]; + } + } + else if (action_setup == 1) + { + field_info_t temp_filed_col; + select_conn->read_col_info(temp_pack_data.data, temp_filed_col); + + column_num--; + if (column_num == 0) + { + action_setup = 2; + } + } + else if (action_setup == 2) + { + unsigned int tempnum = 0; + + unsigned int name_length = select_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], tempnum); + + querysql_len = 0; + for (unsigned int ik = 0; ik < name_length; ik++) + { + if (temp_pack_data.data[tempnum] >= '0' && temp_pack_data.data[tempnum] <= '9') + { + querysql_len = querysql_len * 10 + (temp_pack_data.data[tempnum] - '0'); + } + tempnum++; + } + effect_num++; + } + } + else + { + if (offset >= n) + { + break; + } + is_sql_item = true; + break; + } + } + } + + if (select_conn->isdebug) + { + select_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = select_conn->count_time(); + conn_mar.push_log(countsql, std::to_string(du_time)); + } + if (!islock_conn) + { + conn_obj->back_select_conn(std::move(select_conn)); + } + co_return querysql_len; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + co_return 0; + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + co_return 0; + } + co_return 0; + } + + asio::awaitable> + async_page(unsigned int page, unsigned int per_page = 10, unsigned int list_num = 5) + { + unsigned int total_page = async_count(); + if (per_page == 0) + { + per_page = 10; + } + if (list_num < 1) + { + list_num = 1; + } + total_page = std::ceil((float)total_page / per_page); + + if (total_page < 1) + { + total_page = 1; + } + if (page > total_page) + { + page = total_page; + } + if (page < 1) + { + page = 1; + } + unsigned int mid_num = std::floor(list_num / 2); + unsigned int last_num = list_num - 1; + + int temp_num = page - mid_num; + + unsigned int minpage = temp_num < 1 ? 1 : temp_num; + unsigned int maxpage = minpage + last_num; + + if (maxpage > total_page) + { + maxpage = total_page; + temp_num = (maxpage - last_num); + if (temp_num < 1) + { + minpage = 1; + } + else + { + minpage = temp_num; + } + } + limit((page - 1) * per_page, per_page); + co_return std::make_tuple(minpage, maxpage, page, total_page); + } + + unsigned int update_col(std::string colname, int num, char symbol = '+') + { + effect_num = 0; + std::string countsql; + countsql = "UPDATE "; + countsql.append(B_BASE::tablename); + countsql.append(" SET "); + countsql.append(colname); + if (num > 0) + { + countsql.append(" = "); + countsql.append(colname); + countsql.push_back(' '); + countsql.push_back(symbol); + countsql.append(std::to_string(num)); + } + else + { + countsql.append(" = "); + countsql.append(colname); + countsql.push_back(' '); + countsql.push_back(symbol); + countsql.push_back('('); + countsql.push_back('-'); + countsql.append(std::to_string(std::abs(num))); + countsql.push_back(')'); + } + countsql.append(" where "); + if (wheresql.empty()) + { + if (B_BASE::getPK() > 0) + { + std::ostringstream tempsql; + tempsql << " "; + tempsql << B_BASE::getPKname(); + tempsql << " = '"; + tempsql << B_BASE::getPK(); + tempsql << "' "; + countsql.append(tempsql.str()); + } + else + { + return 0; + } + } + else + { + countsql.append(wheresql); + } + if (!groupsql.empty()) + { + countsql.append(groupsql); + } + if (!limitsql.empty()) + { + countsql.append(limitsql); + } + if (iscommit) + { + iscommit = false; + return 0; + } + + if (iserror) + { + return 0; + } + + try + { + if (conn_empty()) + { + return 0; + } + //auto conn = conn_obj->get_edit_conn(); + + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = conn_obj->get_edit_conn(); + } + } + else + { + edit_conn = conn_obj->get_edit_conn(); + } + + if (edit_conn->isdebug) + { + edit_conn->begin_time(); + } + std::size_t n = edit_conn->write_sql(countsql); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return 0; + } + + unsigned int offset = 0; + n = edit_conn->read_loop(); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return 0; + } + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + edit_conn->read_field_pack(edit_conn->_cache_data, n, offset, temp_pack_data); + if (edit_conn->isdebug) + { + edit_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = edit_conn->count_time(); + conn_mar.push_log(countsql, std::to_string(du_time)); + } + + if ((unsigned char)temp_pack_data.data[0] == 0xFF) + { + error_msg = temp_pack_data.data.substr(3); + } + else if ((unsigned char)temp_pack_data.data[0] == 0x00) + { + + unsigned int d_offset = 1; + effect_num = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + } + if (!islock_conn) + { + conn_obj->back_edit_conn(std::move(edit_conn)); + } + return effect_num; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + return 0; + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + return 0; + } + + asio::awaitable async_update_col(std::string colname, int num, char symbol = '+') + { + effect_num = 0; + std::string countsql; + countsql = "UPDATE "; + countsql.append(B_BASE::tablename); + countsql.append(" SET "); + countsql.append(colname); + if (num > 0) + { + countsql.append(" = "); + countsql.append(colname); + countsql.push_back(' '); + countsql.push_back(symbol); + countsql.append(std::to_string(num)); + } + else + { + countsql.append(" = "); + countsql.append(colname); + countsql.push_back(' '); + countsql.push_back(symbol); + countsql.push_back('('); + countsql.push_back('-'); + countsql.append(std::to_string(std::abs(num))); + countsql.push_back(')'); + } + countsql.append(" where "); + if (wheresql.empty()) + { + if (B_BASE::getPK() > 0) + { + std::ostringstream tempsql; + tempsql << " "; + tempsql << B_BASE::getPKname(); + tempsql << " = '"; + tempsql << B_BASE::getPK(); + tempsql << "' "; + countsql.append(tempsql.str()); + } + else + { + co_return 0; + } + } + else + { + countsql.append(wheresql); + } + if (!groupsql.empty()) + { + countsql.append(groupsql); + } + if (!limitsql.empty()) + { + countsql.append(limitsql); + } + if (iscommit) + { + iscommit = false; + co_return 0; + } + + if (iserror) + { + co_return 0; + } + + try + { + + if (conn_empty()) + { + co_return 0; + } + + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = co_await conn_obj->async_get_edit_conn(); + } + } + else + { + edit_conn = co_await conn_obj->async_get_edit_conn(); + } + + if (edit_conn->isdebug) + { + edit_conn->begin_time(); + } + std::size_t n = co_await edit_conn->async_write_sql(countsql); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + co_return 0; + } + + unsigned int offset = 0; + n = co_await edit_conn->async_read_loop(); + if (n == 0) + { + edit_conn.reset(); + co_return 0; + } + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + edit_conn->read_field_pack(edit_conn->_cache_data, n, offset, temp_pack_data); + if (edit_conn->isdebug) + { + edit_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = edit_conn->count_time(); + conn_mar.push_log(countsql, std::to_string(du_time)); + } + + if ((unsigned char)temp_pack_data.data[0] == 0xFF) + { + error_msg = temp_pack_data.data.substr(3); + } + else if ((unsigned char)temp_pack_data.data[0] == 0x00) + { + + unsigned int d_offset = 1; + effect_num = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + } + if (!islock_conn) + { + conn_obj->back_edit_conn(std::move(edit_conn)); + } + co_return effect_num; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + co_return 0; + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + co_return 0; + } + + int replace_col(std::string colname, const std::string &old_string, const std::string &new_string) + { + effect_num = 0; + std::string countsql; + countsql = "UPDATE "; + countsql.append(B_BASE::tablename); + countsql.append(" SET "); + countsql.append(colname); + + countsql.append(" = REPLACE("); + countsql.append(colname); + countsql.append(",'"); + countsql.append(old_string); + countsql.append("','"); + countsql.append(new_string); + countsql.append("') "); + + countsql.append(" where "); + if (wheresql.empty()) + { + if (B_BASE::getPK() > 0) + { + std::ostringstream tempsql; + tempsql << " "; + tempsql << B_BASE::getPKname(); + tempsql << " = '"; + tempsql << B_BASE::getPK(); + tempsql << "' "; + countsql.append(tempsql.str()); + } + else + { + return 0; + } + } + else + { + countsql.append(wheresql); + } + if (!groupsql.empty()) + { + countsql.append(groupsql); + } + if (!limitsql.empty()) + { + countsql.append(limitsql); + } + if (iscommit) + { + iscommit = false; + return 0; + } + + if (iserror) + { + return 0; + } + + try + { + if (conn_empty()) + { + return 0; + } + //auto conn = conn_obj->get_edit_conn(); + + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = conn_obj->get_edit_conn(); + } + } + else + { + edit_conn = conn_obj->get_edit_conn(); + } + + if (edit_conn->isdebug) + { + edit_conn->begin_time(); + } + + std::size_t n = edit_conn->write_sql(countsql); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return 0; + } + + unsigned int offset = 0; + n = edit_conn->read_loop(); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return 0; + } + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + edit_conn->read_field_pack(edit_conn->_cache_data, n, offset, temp_pack_data); + if (edit_conn->isdebug) + { + edit_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = edit_conn->count_time(); + conn_mar.push_log(countsql, std::to_string(du_time)); + } + + if ((unsigned char)temp_pack_data.data[0] == 0xFF) + { + error_msg = temp_pack_data.data.substr(3); + } + else if ((unsigned char)temp_pack_data.data[0] == 0x00) + { + + unsigned int d_offset = 1; + effect_num = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + } + if (!islock_conn) + { + conn_obj->back_edit_conn(std::move(edit_conn)); + } + return effect_num; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + return 0; + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + return 0; + } + + void assign_field_value(unsigned char index_pos, unsigned char *result_temp_data, unsigned int value_size, typename B_BASE::meta &data_temp) + { + switch(index_pos) + { + case 0: + data_temp.id=0; + + for(unsigned int i=0; i< value_size; i++) + { + if(result_temp_data[i]>='0'&&result_temp_data[i]<='9') + { + + data_temp.id= data_temp.id * 10 + (result_temp_data[i]-'0'); + } + if(i>32) + { + break; + } + } + break; + case 1: + data_temp.message.clear(); + data_temp.message.resize(value_size); + + std::memcpy(data_temp.message.data(), result_temp_data, value_size); + break; + + } + } + + +M_MODEL& eqId(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id = "); + + try + { + wheresql.append(std::to_string(std::stoll(val))); + } + catch (std::invalid_argument const& ex) + { + wheresql.push_back('0'); + } + catch (std::out_of_range const& ex) + { + wheresql.push_back('0'); + } + return *mod; + } + + +M_MODEL& nqId(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id != "); + + try + { + wheresql.append(std::to_string(std::stoll(val))); + } + catch (std::invalid_argument const& ex) + { + wheresql.push_back('0'); + } + catch (std::out_of_range const& ex) + { + wheresql.push_back('0'); + } + return *mod; + } + + +M_MODEL& inId(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id IN("); + + wheresql.append(val); + wheresql.push_back(')'); + return *mod; + } + + +template + requires std::is_integral_v +M_MODEL& inId(const std::vector& val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id IN("); + + for(unsigned int i=0;i 0) + { + wheresql.push_back(','); + } + wheresql.append(std::to_string(val[i])); + } + wheresql.push_back(')'); + + return *mod; + } + + +M_MODEL& inId(const std::vector& val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id IN("); + + for(unsigned int i=0;i 0) + { + wheresql.push_back(','); + } + + try + { + wheresql.append(std::to_string(std::stoll(val[i]))); + } + catch (std::invalid_argument const& ex) + { + wheresql.push_back('0'); + } + catch (std::out_of_range const& ex) + { + wheresql.push_back('0'); + } + } + wheresql.push_back(')'); + + return *mod; + } + + +M_MODEL& ninId(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id NOT IN("); + + wheresql.append(val); + wheresql.push_back(')'); + return *mod; + } + + +template + requires std::is_integral_v +M_MODEL& ninId(const std::vector& val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id NOT IN("); + + for(unsigned int i=0;i 0) + { + wheresql.push_back(','); + } + wheresql.append(std::to_string(val[i])); + } + wheresql.push_back(')'); + + return *mod; + } + + +M_MODEL& ninId(const std::vector& val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id NOT IN("); + + for(unsigned int i=0;i 0) + { + wheresql.push_back(','); + } + + try + { + wheresql.append(std::to_string(std::stoll(val[i]))); + } + catch (std::invalid_argument const& ex) + { + wheresql.push_back('0'); + } + catch (std::out_of_range const& ex) + { + wheresql.push_back('0'); + } + } + wheresql.push_back(')'); + + return *mod; + } + + +M_MODEL& btId(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id > "); + + try + { + wheresql.append(std::to_string(std::stoll(val))); + } + catch (std::invalid_argument const& ex) + { + wheresql.push_back('0'); + } + catch (std::out_of_range const& ex) + { + wheresql.push_back('0'); + } + return *mod; + } + + +M_MODEL& beId(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id >= "); + + try + { + wheresql.append(std::to_string(std::stoll(val))); + } + catch (std::invalid_argument const& ex) + { + wheresql.push_back('0'); + } + catch (std::out_of_range const& ex) + { + wheresql.push_back('0'); + } + return *mod; + } + + +M_MODEL& ltId(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id < "); + + try + { + wheresql.append(std::to_string(std::stoll(val))); + } + catch (std::invalid_argument const& ex) + { + wheresql.push_back('0'); + } + catch (std::out_of_range const& ex) + { + wheresql.push_back('0'); + } + return *mod; + } + + +M_MODEL& leId(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id <= "); + + try + { + wheresql.append(std::to_string(std::stoll(val))); + } + catch (std::invalid_argument const& ex) + { + wheresql.push_back('0'); + } + catch (std::out_of_range const& ex) + { + wheresql.push_back('0'); + } + return *mod; + } + + +M_MODEL& or_eqId(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id = "); + + try + { + wheresql.append(std::to_string(std::stoll(val))); + } + catch (std::invalid_argument const& ex) + { + wheresql.push_back('0'); + } + catch (std::out_of_range const& ex) + { + wheresql.push_back('0'); + } + return *mod; + } + + +M_MODEL& or_nqId(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id != "); + + try + { + wheresql.append(std::to_string(std::stoll(val))); + } + catch (std::invalid_argument const& ex) + { + wheresql.push_back('0'); + } + catch (std::out_of_range const& ex) + { + wheresql.push_back('0'); + } + return *mod; + } + + +M_MODEL& or_inId(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id IN("); + + wheresql.append(val); + wheresql.push_back(')'); + return *mod; + } + + +template + requires std::is_integral_v +M_MODEL& or_inId(const std::vector& val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id IN("); + + for(unsigned int i=0;i 0) + { + wheresql.push_back(','); + } + wheresql.append(std::to_string(val[i])); + } + wheresql.push_back(')'); + + return *mod; + } + + +M_MODEL& or_inId(const std::vector& val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id IN("); + + for(unsigned int i=0;i 0) + { + wheresql.push_back(','); + } + + try + { + wheresql.append(std::to_string(std::stoll(val[i]))); + } + catch (std::invalid_argument const& ex) + { + wheresql.push_back('0'); + } + catch (std::out_of_range const& ex) + { + wheresql.push_back('0'); + } + } + wheresql.push_back(')'); + + return *mod; + } + + +M_MODEL& or_ninId(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id NOT IN("); + + wheresql.append(val); + wheresql.push_back(')'); + return *mod; + } + + +template + requires std::is_integral_v +M_MODEL& or_ninId(const std::vector& val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id NOT IN("); + + for(unsigned int i=0;i 0) + { + wheresql.push_back(','); + } + wheresql.append(std::to_string(val[i])); + } + wheresql.push_back(')'); + + return *mod; + } + + +M_MODEL& or_ninId(const std::vector& val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id NOT IN("); + + for(unsigned int i=0;i 0) + { + wheresql.push_back(','); + } + + try + { + wheresql.append(std::to_string(std::stoll(val[i]))); + } + catch (std::invalid_argument const& ex) + { + wheresql.push_back('0'); + } + catch (std::out_of_range const& ex) + { + wheresql.push_back('0'); + } + } + wheresql.push_back(')'); + + return *mod; + } + + +M_MODEL& or_btId(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id > "); + + try + { + wheresql.append(std::to_string(std::stoll(val))); + } + catch (std::invalid_argument const& ex) + { + wheresql.push_back('0'); + } + catch (std::out_of_range const& ex) + { + wheresql.push_back('0'); + } + return *mod; + } + + +M_MODEL& or_beId(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id >= "); + + try + { + wheresql.append(std::to_string(std::stoll(val))); + } + catch (std::invalid_argument const& ex) + { + wheresql.push_back('0'); + } + catch (std::out_of_range const& ex) + { + wheresql.push_back('0'); + } + return *mod; + } + + +M_MODEL& or_ltId(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id < "); + + try + { + wheresql.append(std::to_string(std::stoll(val))); + } + catch (std::invalid_argument const& ex) + { + wheresql.push_back('0'); + } + catch (std::out_of_range const& ex) + { + wheresql.push_back('0'); + } + return *mod; + } + + +M_MODEL& or_leId(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id <= "); + + try + { + wheresql.append(std::to_string(std::stoll(val))); + } + catch (std::invalid_argument const& ex) + { + wheresql.push_back('0'); + } + catch (std::out_of_range const& ex) + { + wheresql.push_back('0'); + } + return *mod; + } + + +template + requires std::is_integral_v +M_MODEL& eqId(T val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id = "); + + wheresql.append(std::to_string(val)); + return *mod; + } + + +template + requires std::is_integral_v +M_MODEL& nqId(T val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id != "); + + wheresql.append(std::to_string(val)); + return *mod; + } + + +template + requires std::is_integral_v +M_MODEL& btId(T val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id > "); + + wheresql.append(std::to_string(val)); + return *mod; + } + + +template + requires std::is_integral_v +M_MODEL& beId(T val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id >= "); + + wheresql.append(std::to_string(val)); + return *mod; + } + + +template + requires std::is_integral_v +M_MODEL& ltId(T val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id < "); + + wheresql.append(std::to_string(val)); + return *mod; + } + + +template + requires std::is_integral_v +M_MODEL& leId(T val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id <= "); + + wheresql.append(std::to_string(val)); + return *mod; + } + + +template + requires std::is_integral_v +M_MODEL& or_eqId(T val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id = "); + + wheresql.append(std::to_string(val)); + return *mod; + } + + +template + requires std::is_integral_v +M_MODEL& or_nqId(T val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id != "); + + wheresql.append(std::to_string(val)); + return *mod; + } + + +template + requires std::is_integral_v +M_MODEL& or_btId(T val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id > "); + + wheresql.append(std::to_string(val)); + return *mod; + } + + +template + requires std::is_integral_v +M_MODEL& or_beId(T val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id >= "); + + wheresql.append(std::to_string(val)); + return *mod; + } + + +template + requires std::is_integral_v +M_MODEL& or_ltId(T val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id < "); + + wheresql.append(std::to_string(val)); + return *mod; + } + + +template + requires std::is_integral_v +M_MODEL& or_leId(T val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id <= "); + + wheresql.append(std::to_string(val)); + return *mod; + } + + +M_MODEL& nullMessage() + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" message = NULL "); + + return *mod; + } + + +M_MODEL& nnullMessage() + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" message != NULL "); + + return *mod; + } + + +M_MODEL& eqMessage(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" message = '"); + wheresql.append(B_BASE::stringaddslash(val)); + wheresql.push_back('\''); + + return *mod; + } + + +M_MODEL& nqMessage(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" message != '"); + wheresql.append(B_BASE::stringaddslash(val)); + wheresql.push_back('\''); + + return *mod; + } + + +M_MODEL& inMessage(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" message IN("); + wheresql.append(val); + wheresql.push_back(')'); + + return *mod; + } + + +M_MODEL& inMessage(const std::vector &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" message IN("); + + for(unsigned int i=0;i0) + { + wheresql.push_back(','); + } + wheresql.push_back('\''); + wheresql.append(B_BASE::stringaddslash(val[i])); + wheresql.push_back('\''); + } + + + + return *mod; + } + + +template + requires std::is_integral_v +M_MODEL& inMessage(const std::vector &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" message IN("); + + for(unsigned int i=0;i0) + { + wheresql.push_back(','); + } + wheresql.push_back('\''); + wheresql.append(std::to_string(val[i])); + wheresql.push_back('\''); + } + + + + return *mod; + } + + +M_MODEL& ninMessage(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" message NOT IN("); + wheresql.append(val); + wheresql.push_back(')'); + + return *mod; + } + + +M_MODEL& ninMessage(const std::vector &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" message NOT IN("); + + for(unsigned int i=0;i0) + { + wheresql.push_back(','); + } + wheresql.push_back('\''); + wheresql.append(B_BASE::stringaddslash(val[i])); + wheresql.push_back('\''); + } + + + + return *mod; + } + + +template + requires std::is_integral_v +M_MODEL& ninMessage(const std::vector &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" message NOT IN("); + + for(unsigned int i=0;i0) + { + wheresql.push_back(','); + } + wheresql.push_back('\''); + wheresql.append(std::to_string(val[i])); + wheresql.push_back('\''); + } + + + + return *mod; + } + + +M_MODEL& likeMessage(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" message LIKE '%"); + wheresql.append(B_BASE::stringaddslash(val)); + wheresql.append("%'"); + + return *mod; + } + + +M_MODEL& l_likeMessage(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" message LIKE '%"); + wheresql.append(B_BASE::stringaddslash(val)); + wheresql.append("'"); + + return *mod; + } + + +M_MODEL& r_likeMessage(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" message LIKE '"); + wheresql.append(B_BASE::stringaddslash(val)); + wheresql.append("%'"); + + return *mod; + } + + +M_MODEL& btMessage(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" message > '"); + wheresql.append(B_BASE::stringaddslash(val)); + wheresql.push_back('\''); + + return *mod; + } + + +M_MODEL& beMessage(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" message >= '"); + wheresql.append(B_BASE::stringaddslash(val)); + wheresql.push_back('\''); + + return *mod; + } + + +M_MODEL& ltMessage(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" message < '"); + wheresql.append(B_BASE::stringaddslash(val)); + wheresql.push_back('\''); + + return *mod; + } + + +M_MODEL& leMessage(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" message <= '"); + wheresql.append(B_BASE::stringaddslash(val)); + wheresql.push_back('\''); + + return *mod; + } + + +M_MODEL& or_nullMessage() + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" message = NULL "); + + return *mod; + } + + +M_MODEL& or_nnullMessage() + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" message != NULL "); + + return *mod; + } + + +M_MODEL& or_eqMessage(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" message = '"); + wheresql.append(B_BASE::stringaddslash(val)); + wheresql.push_back('\''); + + return *mod; + } + + +M_MODEL& or_nqMessage(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" message != '"); + wheresql.append(B_BASE::stringaddslash(val)); + wheresql.push_back('\''); + + return *mod; + } + + +M_MODEL& or_inMessage(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" message IN("); + wheresql.append(val); + wheresql.push_back(')'); + + return *mod; + } + + +M_MODEL& or_inMessage(const std::vector &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" message IN("); + + for(unsigned int i=0;i0) + { + wheresql.push_back(','); + } + wheresql.push_back('\''); + wheresql.append(B_BASE::stringaddslash(val[i])); + wheresql.push_back('\''); + } + + + + return *mod; + } + + +template + requires std::is_integral_v +M_MODEL& or_inMessage(const std::vector &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" message IN("); + + for(unsigned int i=0;i0) + { + wheresql.push_back(','); + } + wheresql.push_back('\''); + wheresql.append(std::to_string(val[i])); + wheresql.push_back('\''); + } + + + + return *mod; + } + + +M_MODEL& or_ninMessage(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" message NOT IN("); + wheresql.append(val); + wheresql.push_back(')'); + + return *mod; + } + + +M_MODEL& or_ninMessage(const std::vector &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" message NOT IN("); + + for(unsigned int i=0;i0) + { + wheresql.push_back(','); + } + wheresql.push_back('\''); + wheresql.append(B_BASE::stringaddslash(val[i])); + wheresql.push_back('\''); + } + + + + return *mod; + } + + +template + requires std::is_integral_v +M_MODEL& or_ninMessage(const std::vector &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" message NOT IN("); + + for(unsigned int i=0;i0) + { + wheresql.push_back(','); + } + wheresql.push_back('\''); + wheresql.append(std::to_string(val[i])); + wheresql.push_back('\''); + } + + + + return *mod; + } + + +M_MODEL& or_likeMessage(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" message LIKE '%"); + wheresql.append(B_BASE::stringaddslash(val)); + wheresql.append("%'"); + + return *mod; + } + + +M_MODEL& orl_likeMessage(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" message LIKE '%"); + wheresql.append(B_BASE::stringaddslash(val)); + wheresql.append("'"); + + return *mod; + } + + +M_MODEL& orr_likeMessage(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" message LIKE '"); + wheresql.append(B_BASE::stringaddslash(val)); + wheresql.append("%'"); + + return *mod; + } + + +M_MODEL& or_btMessage(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" message > '"); + wheresql.append(B_BASE::stringaddslash(val)); + wheresql.push_back('\''); + + return *mod; + } + + +M_MODEL& or_beMessage(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" message >= '"); + wheresql.append(B_BASE::stringaddslash(val)); + wheresql.push_back('\''); + + return *mod; + } + + +M_MODEL& or_ltMessage(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" message < '"); + wheresql.append(B_BASE::stringaddslash(val)); + wheresql.push_back('\''); + + return *mod; + } + + +M_MODEL& or_leMessage(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" message <= '"); + wheresql.append(B_BASE::stringaddslash(val)); + wheresql.push_back('\''); + + return *mod; + } + + +template + requires std::is_floating_point_v||std::is_integral_v +M_MODEL& eqMessage(T val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" message = '"); + wheresql.append(std::to_string(val)); + wheresql.push_back('\''); + + return *mod; + } + + +template + requires std::is_floating_point_v||std::is_integral_v +M_MODEL& nqMessage(T val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" message != '"); + wheresql.append(std::to_string(val)); + wheresql.push_back('\''); + + return *mod; + } + + +template + requires std::is_floating_point_v||std::is_integral_v +M_MODEL& btMessage(T val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" message > '"); + wheresql.append(std::to_string(val)); + wheresql.push_back('\''); + + return *mod; + } + + +template + requires std::is_floating_point_v||std::is_integral_v +M_MODEL& beMessage(T val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" message >= '"); + wheresql.append(std::to_string(val)); + wheresql.push_back('\''); + + return *mod; + } + + +template + requires std::is_floating_point_v||std::is_integral_v +M_MODEL& ltMessage(T val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" message < '"); + wheresql.append(std::to_string(val)); + wheresql.push_back('\''); + + return *mod; + } + + +template + requires std::is_floating_point_v||std::is_integral_v +M_MODEL& leMessage(T val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" message <= '"); + wheresql.append(std::to_string(val)); + wheresql.push_back('\''); + + return *mod; + } + + +template + requires std::is_floating_point_v||std::is_integral_v +M_MODEL& or_eqMessage(T val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" message = '"); + wheresql.append(std::to_string(val)); + wheresql.push_back('\''); + + return *mod; + } + + +template + requires std::is_floating_point_v||std::is_integral_v +M_MODEL& or_nqMessage(T val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" message != '"); + wheresql.append(std::to_string(val)); + wheresql.push_back('\''); + + return *mod; + } + + +template + requires std::is_floating_point_v||std::is_integral_v +M_MODEL& or_btMessage(T val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" message > '"); + wheresql.append(std::to_string(val)); + wheresql.push_back('\''); + + return *mod; + } + + +template + requires std::is_floating_point_v||std::is_integral_v +M_MODEL& or_beMessage(T val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" message >= '"); + wheresql.append(std::to_string(val)); + wheresql.push_back('\''); + + return *mod; + } + + +template + requires std::is_floating_point_v||std::is_integral_v +M_MODEL& or_ltMessage(T val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" message < '"); + wheresql.append(std::to_string(val)); + wheresql.push_back('\''); + + return *mod; + } + + +template + requires std::is_floating_point_v||std::is_integral_v +M_MODEL& or_leMessage(T val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" message <= '"); + wheresql.append(std::to_string(val)); + wheresql.push_back('\''); + + return *mod; + } + + + M_MODEL &select(const std::string &fieldname) + { + if (selectsql.size() > 0) + { + selectsql.push_back(','); + } + selectsql.append(fieldname); + return *mod; + } + + M_MODEL &where(const std::string &wq) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + + wheresql.append(wq); + return *mod; + } + template + requires std::is_integral_v<_SQL_Value> || std::is_floating_point_v<_SQL_Value> + M_MODEL &where(const std::string &wq, _SQL_Value val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.push_back('='); + wheresql.append(std::to_string(val)); + return *mod; + } + + M_MODEL &where(const std::string &wq, char bi, http::obj_val &obj) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.push_back(bi); + if (obj.is_string()) + { + wheresql.push_back('\''); + wheresql.append(obj.as_string()); + wheresql.push_back('\''); + } + else + { + + wheresql.append(obj.to_string()); + } + return *mod; + } + M_MODEL &where(const std::string &wq, http::obj_val &obj) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.push_back('='); + + if (obj.is_string()) + { + wheresql.push_back('\''); + wheresql.append(obj.as_string()); + wheresql.push_back('\''); + } + else + { + + wheresql.append(obj.to_string()); + } + return *mod; + } + template + requires std::is_integral_v<_SQL_Value> || std::is_floating_point_v<_SQL_Value> + M_MODEL &where(const std::string &wq, char bi, _SQL_Value val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.push_back(bi); + wheresql.append(std::to_string(val)); + return *mod; + } + + M_MODEL &where(const std::string &wq, char bi, const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.push_back(bi); + wheresql.push_back('\''); + + wheresql.append(val); + wheresql.push_back('\''); + return *mod; + } + M_MODEL &where(const std::string &wq, const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.push_back('='); + + wheresql.push_back('\''); + wheresql.append(val); + wheresql.push_back('\''); + return *mod; + } + + M_MODEL &whereBT(const std::string &wq, const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.push_back('>'); + + wheresql.push_back('\''); + wheresql.append(val); + wheresql.push_back('\''); + return *mod; + } + + M_MODEL &whereBE(const std::string &wq, const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.append(">="); + + wheresql.push_back('\''); + wheresql.append(val); + wheresql.push_back('\''); + return *mod; + } + + M_MODEL &whereLT(const std::string &wq, const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.append(" < "); + + wheresql.push_back('\''); + wheresql.append(val); + wheresql.push_back('\''); + return *mod; + } + + M_MODEL &whereLE(const std::string &wq, const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.append(" <= "); + + wheresql.push_back('\''); + wheresql.append(val); + wheresql.push_back('\''); + return *mod; + } + + M_MODEL &between(const std::string &wq, const std::string &a, const std::string &b) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" ("); + wheresql.append(wq); + wheresql.append(" BETWEEN '"); + std::stringstream _stream; + _stream << a; + _stream << "' AND '"; + _stream << b; + _stream << "' ) "; + wheresql.append(_stream.str()); + return *mod; + } + template + requires std::is_integral_v<_SQL_Value> || std::is_floating_point_v<_SQL_Value> + M_MODEL &between(const std::string &wq, _SQL_Value a, _SQL_Value b) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" ("); + wheresql.append(wq); + wheresql.append(" BETWEEN "); + std::stringstream _stream; + _stream << a; + _stream << " AND "; + _stream << b; + _stream << " ) "; + wheresql.append(_stream.str()); + return *mod; + } + template + requires std::is_integral_v<_SQL_Value> || std::is_floating_point_v<_SQL_Value> + M_MODEL &orBetween(const std::string &wq, _SQL_Value a, _SQL_Value b) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" ("); + wheresql.append(wq); + wheresql.append(" BETWEEN "); + std::stringstream _stream; + _stream << a; + _stream << " AND "; + _stream << b; + _stream << " ) "; + wheresql.append(_stream.str()); + return *mod; + } + M_MODEL &whereLike(const std::string &wq, const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.append(" like '"); + if (val.size() > 0 && (val[0] == '%' || val.back() == '%')) + { + wheresql.append(val); + wheresql.append("' "); + } + else + { + wheresql.push_back('%'); + wheresql.append(val); + wheresql.append("%' "); + } + return *mod; + } + M_MODEL &whereLikeLeft(const std::string &wq, const std::string &val) + { + + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.append(" like '"); + wheresql.push_back('%'); + wheresql.append(val); + wheresql.append("' "); + return *mod; + } + M_MODEL &whereLikeRight(const std::string &wq, const std::string &val) + { + + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.append(" like '"); + wheresql.append(val); + wheresql.append("%' "); + return *mod; + } + M_MODEL &whereOrLike(const std::string &wq, const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.append(" like '"); + if (val[0] == '%' || val.back() == '%') + { + wheresql.append(val); + wheresql.append("' "); + } + else + { + wheresql.push_back('%'); + wheresql.append(val); + wheresql.append("%' "); + } + return *mod; + } + M_MODEL &whereAnd(const std::string &wq) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + return *mod; + } + template + requires std::is_integral_v<_SQL_Value> || std::is_floating_point_v<_SQL_Value> + M_MODEL &whereAnd(const std::string &wq, _SQL_Value val) + { + + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.push_back('='); + wheresql.append(std::to_string(val)); + return *mod; + } + + template + requires std::is_integral_v<_SQL_Value> || std::is_floating_point_v<_SQL_Value> + M_MODEL &whereBT(const std::string &wq, _SQL_Value val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.append(" > "); + wheresql.append(std::to_string(val)); + return *mod; + } + + template + requires std::is_integral_v<_SQL_Value> || std::is_floating_point_v<_SQL_Value> + M_MODEL &whereBE(const std::string &wq, _SQL_Value val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.append(" >= "); + wheresql.append(std::to_string(val)); + return *mod; + } + + template + requires std::is_integral_v<_SQL_Value> || std::is_floating_point_v<_SQL_Value> + M_MODEL &whereLT(const std::string &wq, _SQL_Value val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.append(" < "); + wheresql.append(std::to_string(val)); + return *mod; + } + + template + requires std::is_integral_v<_SQL_Value> || std::is_floating_point_v<_SQL_Value> + M_MODEL &whereLE(const std::string &wq, _SQL_Value val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.append(" <= "); + wheresql.append(std::to_string(val)); + return *mod; + } + //where and + M_MODEL &whereEQ(const std::string &wq, const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.push_back('='); + wheresql.push_back('\''); + wheresql.append(val); + wheresql.push_back('\''); + + return *mod; + } + + M_MODEL &whereAnd(const std::string &wq, const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.push_back('='); + wheresql.push_back('\''); + wheresql.append(val); + wheresql.push_back('\''); + + return *mod; + } + //where string or + + M_MODEL &whereOrBT(const std::string &wq, const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.push_back('>'); + + wheresql.push_back('\''); + wheresql.append(val); + wheresql.push_back('\''); + return *mod; + } + + M_MODEL &whereOrBE(const std::string &wq, const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.append(">="); + + wheresql.push_back('\''); + wheresql.append(val); + wheresql.push_back('\''); + return *mod; + } + + M_MODEL &whereOrLT(const std::string &wq, const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.append(" < "); + + wheresql.push_back('\''); + wheresql.append(val); + wheresql.push_back('\''); + return *mod; + } + + M_MODEL &whereOrLE(const std::string &wq, const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.append(" <= "); + + wheresql.push_back('\''); + wheresql.append(val); + wheresql.push_back('\''); + return *mod; + } + + //where or + template + requires std::is_integral_v<_SQL_Value> || std::is_floating_point_v<_SQL_Value> + M_MODEL &whereOrBT(const std::string &wq, _SQL_Value val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.append(" > "); + wheresql.append(std::to_string(val)); + return *mod; + } + + template + requires std::is_integral_v<_SQL_Value> || std::is_floating_point_v<_SQL_Value> + M_MODEL &whereOrBE(const std::string &wq, _SQL_Value val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.append(" >= "); + wheresql.append(std::to_string(val)); + return *mod; + } + + template + requires std::is_integral_v<_SQL_Value> || std::is_floating_point_v<_SQL_Value> + M_MODEL &whereOrLT(const std::string &wq, _SQL_Value val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.append(" < "); + wheresql.append(std::to_string(val)); + return *mod; + } + + template + requires std::is_integral_v<_SQL_Value> || std::is_floating_point_v<_SQL_Value> + M_MODEL &whereOrLE(const std::string &wq, _SQL_Value val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.append(" <= "); + wheresql.append(std::to_string(val)); + return *mod; + } + + M_MODEL &whereOr(const std::string &wq) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + return *mod; + } + template + requires std::is_integral_v<_SQL_Value> || std::is_floating_point_v<_SQL_Value> + M_MODEL &whereOr(const std::string &wq, _SQL_Value val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.push_back('='); + wheresql.append(std::to_string(val)); + return *mod; + } + M_MODEL &whereOr(const std::string &wq, const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.push_back('='); + wheresql.push_back('\''); + wheresql.append(val); + wheresql.push_back('\''); + return *mod; + } + M_MODEL &whereIn(const std::string &k) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(k); + return *mod; + } + M_MODEL &whereIn(const std::string &k, const std::string &a) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + + wheresql.append(k); + wheresql.append(" IN("); + wheresql.append(a); + wheresql.append(") "); + return *mod; + } + + M_MODEL &whereIn(const std::string &k, const std::vector &a) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(k); + wheresql.append(" in("); + int i = 0; + for (auto &key : a) + { + if (i > 0) + { + wheresql.append(",\'"); + } + else + { + wheresql.append("\'"); + } + wheresql.append(key); + wheresql.append("\'"); + i++; + } + wheresql.append(") "); + return *mod; + } + M_MODEL &whereNotIn(const std::string &k, const std::vector &a) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + + wheresql.append(k); + wheresql.append(" NOT IN("); + int i = 0; + for (auto &key : a) + { + if (i > 0) + { + wheresql.append(",\'"); + } + else + { + wheresql.append("\'"); + } + wheresql.append(key); + wheresql.append("\'"); + i++; + } + wheresql.append(") "); + return *mod; + } + template + requires std::is_integral_v<_SQL_Value> || std::is_floating_point_v<_SQL_Value> + M_MODEL &whereIn(const std::string &k, const std::list<_SQL_Value> &a) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + + wheresql.append(k); + wheresql.append(" in("); + int i = 0; + std::stringstream _stream; + for (auto &key : a) + { + if (i > 0) + { + wheresql.append(","); + } + _stream << key; + wheresql.append(_stream.str()); + i++; + _stream.str(""); + } + wheresql.append(") "); + return *mod; + } + + template + requires std::is_integral_v<_SQL_Value> || std::is_floating_point_v<_SQL_Value> + M_MODEL &whereIn(const std::string &k, const std::vector<_SQL_Value> &a) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + + wheresql.append(k); + wheresql.append(" IN("); + int i = 0; + std::stringstream _stream; + for (auto &key : a) + { + if (i > 0) + { + wheresql.append(","); + } + _stream << key; + wheresql.append(_stream.str()); + i++; + _stream.str(""); + } + wheresql.append(") "); + return *mod; + } + template + requires std::is_integral_v<_SQL_Value> || std::is_floating_point_v<_SQL_Value> + M_MODEL &whereNotIn(const std::string &k, const std::vector<_SQL_Value> &a) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + + wheresql.append(k); + wheresql.append(" NOT IN("); + int i = 0; + std::stringstream _stream; + for (auto &key : a) + { + if (i > 0) + { + wheresql.append(","); + } + _stream << key; + wheresql.append(_stream.str()); + i++; + _stream.str(""); + } + wheresql.append(") "); + return *mod; + } + + M_MODEL &order(const std::string &wq) + { + ordersql.append(" ORDER by "); + ordersql.append(wq); + return *mod; + } + M_MODEL &asc(const std::string &wq) + { + + ordersql.append(" ORDER by "); + ordersql.append(wq); + ordersql.append(" ASC "); + return *mod; + } + + M_MODEL &desc(const std::string &wq) + { + + ordersql.append(" ORDER by "); + ordersql.append(wq); + ordersql.append(" DESC "); + return *mod; + } + + M_MODEL &having(const std::string &wq) + { + + groupsql.append(" HAVING by "); + groupsql.append(wq); + return *mod; + } + + M_MODEL &group(const std::string &wq) + { + + groupsql.append(" GROUP BY "); + groupsql.append(wq); + return *mod; + } + + M_MODEL &orsub() + { + + if (iskuohao == true) + { + iskuohao = false; + ishascontent = false; + wheresql.append(" )"); + } + else + { + wheresql.append(" OR ("); + iskuohao = true; + ishascontent = false; + } + return *mod; + } + M_MODEL &andsub() + { + + if (iskuohao == true) + { + iskuohao = false; + wheresql.append(" )"); + ishascontent = false; + } + else + { + wheresql.append(" AND ("); + iskuohao = true; + ishascontent = false; + } + + return *mod; + } + + M_MODEL &endsub() + { + if (iskuohao == true) + { + iskuohao = false; + ishascontent = false; + wheresql.append(" )"); + } + return *mod; + } + + M_MODEL &or_b() + { + + if (iskuohao == true) + { + iskuohao = false; + ishascontent = false; + wheresql.append(" )"); + } + else + { + wheresql.append(" OR ("); + iskuohao = true; + ishascontent = false; + } + return *mod; + } + M_MODEL &and_b() + { + + if (iskuohao == true) + { + iskuohao = false; + wheresql.append(" )"); + ishascontent = false; + } + else + { + wheresql.append(" AND ("); + iskuohao = true; + ishascontent = false; + } + + return *mod; + } + + M_MODEL &or_e() + { + if (iskuohao == true) + { + iskuohao = false; + ishascontent = false; + wheresql.append(" )"); + } + return *mod; + } + + M_MODEL &and_e() + { + if (iskuohao == true) + { + iskuohao = false; + ishascontent = false; + wheresql.append(" )"); + } + return *mod; + } + + M_MODEL &limit(unsigned int num) + { + limitsql.clear(); + limitsql.append(" limit "); + limitsql.append(std::to_string(num)); + return *mod; + } + M_MODEL &limit(unsigned int num, unsigned int endnum) + { + limitsql.clear(); + limitsql.append(" limit "); + limitsql.append(std::to_string(num)); + limitsql.push_back(','); + limitsql.append(std::to_string(endnum)); + return *mod; + } + + std::vector> fetch_obj() + { + effect_num = 0; + if (selectsql.empty()) + { + sqlstring = "SELECT * FROM "; + } + else + { + sqlstring = "SELECT "; + sqlstring.append(selectsql); + sqlstring.append(" FROM "); + } + + sqlstring.append(B_BASE::tablename); + sqlstring.append(" WHERE "); + + if (wheresql.empty()) + { + sqlstring.append(" 1 "); + } + else + { + sqlstring.append(wheresql); + } + if (!groupsql.empty()) + { + sqlstring.append(groupsql); + } + if (!ordersql.empty()) + { + sqlstring.append(ordersql); + } + if (!limitsql.empty()) + { + sqlstring.append(limitsql); + } + + std::vector> temprecord; + + if (iserror) + { + return temprecord; + } + + try + { + effect_num = 0; + if (conn_empty()) + { + return temprecord; + } + //auto conn = conn_obj->get_select_conn(); + if (islock_conn) + { + if (!select_conn) + { + select_conn = conn_obj->get_select_conn(); + } + } + else + { + select_conn = conn_obj->get_select_conn(); + } + + if (select_conn->isdebug) + { + select_conn->begin_time(); + } + + std::size_t n = select_conn->write_sql(sqlstring); + if (n == 0) + { + error_msg = select_conn->error_msg; + select_conn.reset(); + return temprecord; + } + + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + bool is_sql_item = false; + std::vector field_array; + unsigned char action_setup = 0; + unsigned int column_num = 0; + unsigned int offset = 0; + + std::vector field_pos; + + for (; is_sql_item == false;) + { + n = select_conn->read_loop(); + offset = 0; + if (n == 0) + { + error_msg = select_conn->error_msg; + select_conn.reset(); + return temprecord; + } + for (; offset < n;) + { + select_conn->read_field_pack(select_conn->_cache_data, n, offset, temp_pack_data); + if (temp_pack_data.error > 0) + { + iserror = true; + error_msg = temp_pack_data.data; + select_conn.reset(); + return temprecord; + } + if (temp_pack_data.length == temp_pack_data.current_length && temp_pack_data.current_length > 0) + { + if (select_conn->pack_eof_check(temp_pack_data)) + { + is_sql_item = true; + break; + } + + if (action_setup == 0) + { + if (temp_pack_data.length == 2 && (unsigned char)temp_pack_data.data[0] < 251 && (unsigned char)temp_pack_data.data[0] > 0) + { + action_setup = 1; + column_num = (unsigned char)temp_pack_data.data[0]; + } + } + else if (action_setup == 1) + { + field_info_t temp_filed_col; + select_conn->read_col_info(temp_pack_data.data, temp_filed_col); + + field_array.emplace_back(std::move(temp_filed_col)); + column_num--; + if (column_num == 0) + { + action_setup = 2; + for (unsigned int ii = 0; ii < field_array.size(); ii++) + { + field_pos.push_back(B_BASE::findcolpos(field_array[ii].org_name)); + } + } + } + else if (action_setup == 2) + { + unsigned int column_num = field_array.size(); + unsigned int tempnum = 0; + + std::map data_temp; + for (unsigned int ij = 0; ij < column_num; ij++) + { + unsigned long long name_length = 0; + name_length = select_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], tempnum); + + std::string temp_str; + temp_str.resize(name_length); + std::memcpy(temp_str.data(), (unsigned char *)&temp_pack_data.data[tempnum], name_length); + if (field_array[ij].name.size() > 0) + { + data_temp.insert({field_array[ij].name, std::move(temp_str)}); + } + else if (field_array[ij].org_name.size() > 0) + { + data_temp.insert({field_array[ij].org_name, std::move(temp_str)}); + } + + tempnum = tempnum + name_length; + } + temprecord.emplace_back(std::move(data_temp)); + effect_num++; + } + } + else + { + if (offset >= n) + { + break; + } + is_sql_item = true; + break; + } + } + } + if (select_conn->isdebug) + { + select_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = select_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + + if (!islock_conn) + { + conn_obj->back_select_conn(std::move(select_conn)); + } + + if (iscache) + { + if (exptime > 0) + { + save_cache(exptime); + exptime = 0; + iscache = false; + } + } + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + return temprecord; + } + std::tuple, std::map, std::vector>> + fetch_row() + { + effect_num = 0; + if (selectsql.empty()) + { + sqlstring = "SELECT * FROM "; + } + else + { + sqlstring = "SELECT "; + sqlstring.append(selectsql); + sqlstring.append(" FROM "); + } + + sqlstring.append(B_BASE::tablename); + sqlstring.append(" WHERE "); + + if (wheresql.empty()) + { + sqlstring.append(" 1 "); + } + else + { + sqlstring.append(wheresql); + } + if (!groupsql.empty()) + { + sqlstring.append(groupsql); + } + if (!ordersql.empty()) + { + sqlstring.append(ordersql); + } + if (!limitsql.empty()) + { + sqlstring.append(limitsql); + } + + std::vector> temprecord; + std::vector table_fieldname; + std::map table_fieldmap; + + if (iscache) + { + std::size_t sqlhashid = std::hash{}(sqlstring); + + model_meta_cache>> &temp_cache = + model_meta_cache>>::getinstance(); + temprecord = temp_cache.get(sqlhashid); + if (temprecord.size() > 0) + { + iscache = false; + model_meta_cache> &table_cache = model_meta_cache>::getinstance(); + table_fieldname = table_cache.get(sqlhashid); + + model_meta_cache> &tablemap_cache = + model_meta_cache>::getinstance(); + table_fieldmap = tablemap_cache.get(sqlhashid); + + return std::make_tuple(table_fieldname, table_fieldmap, temprecord); + } + } + + if (iserror) + { + return std::make_tuple(table_fieldname, table_fieldmap, temprecord); + } + + try + { + if (conn_empty()) + { + return std::make_tuple(table_fieldname, table_fieldmap, temprecord); + } + //auto conn = conn_obj->get_select_conn(); + if (islock_conn) + { + if (!select_conn) + { + select_conn = conn_obj->get_select_conn(); + } + } + else + { + select_conn = conn_obj->get_select_conn(); + } + + if (select_conn->isdebug) + { + select_conn->begin_time(); + } + + std::size_t n = select_conn->write_sql(sqlstring); + if (n == 0) + { + error_msg = select_conn->error_msg; + select_conn.reset(); + return std::make_tuple(table_fieldname, table_fieldmap, temprecord); + } + + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + bool is_sql_item = false; + std::vector field_array; + // std::vector> field_value; + + unsigned char action_setup = 0; + unsigned int column_num = 0; + + unsigned int offset = 0; + + std::vector field_pos; + + for (; is_sql_item == false;) + { + n = select_conn->read_loop(); + offset = 0; + if (n == 0) + { + error_msg = select_conn->error_msg; + select_conn.reset(); + return std::make_tuple(table_fieldname, table_fieldmap, temprecord); + } + for (; offset < n;) + { + select_conn->read_field_pack(select_conn->_cache_data, n, offset, temp_pack_data); + if (temp_pack_data.error > 0) + { + iserror = true; + error_msg = temp_pack_data.data; + select_conn.reset(); + return std::make_tuple(table_fieldname, table_fieldmap, temprecord); + } + if (temp_pack_data.length == temp_pack_data.current_length && temp_pack_data.current_length > 0) + { + if (select_conn->pack_eof_check(temp_pack_data)) + { + is_sql_item = true; + break; + } + + if (action_setup == 0) + { + if (temp_pack_data.length == 2 && (unsigned char)temp_pack_data.data[0] < 251 && (unsigned char)temp_pack_data.data[0] > 0) + { + action_setup = 1; + column_num = (unsigned char)temp_pack_data.data[0]; + } + } + else if (action_setup == 1) + { + field_info_t temp_filed_col; + select_conn->read_col_info(temp_pack_data.data, temp_filed_col); + + field_array.emplace_back(std::move(temp_filed_col)); + column_num--; + if (column_num == 0) + { + action_setup = 2; + for (unsigned int ii = 0; ii < field_array.size(); ii++) + { + field_pos.push_back(B_BASE::findcolpos(field_array[ii].org_name)); + table_fieldmap.emplace(field_array[ii].org_name, table_fieldname.size()); + table_fieldname.push_back(field_array[ii].org_name); + } + } + } + else if (action_setup == 2) + { + unsigned int column_num = field_array.size(); + unsigned int tempnum = 0; + + std::vector temp_v_record; + for (unsigned int ij = 0; ij < column_num; ij++) + { + unsigned long long name_length = 0; + name_length = select_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], tempnum); + std::string tempstr; + tempstr.resize(name_length); + std::memcpy(tempstr.data(), (unsigned char *)&temp_pack_data.data[tempnum], name_length); + temp_v_record.push_back(std::move(tempstr)); + tempnum = tempnum + name_length; + } + temprecord.push_back(temp_v_record); + effect_num++; + } + } + else + { + if (offset >= n) + { + break; + } + is_sql_item = true; + break; + } + } + } + if (select_conn->isdebug) + { + select_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = select_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + + if (!islock_conn) + { + conn_obj->back_select_conn(std::move(select_conn)); + } + + if (iscache) + { + if (exptime > 0) + { + if (temprecord.size() > 0) + { + std::size_t sqlhashid = std::hash{}(sqlstring); + + model_meta_cache>> &temp_cache = + model_meta_cache>>::getinstance(); + temp_cache.save(sqlhashid, temprecord, exptime); + + exptime += 1; + model_meta_cache> &table_cache = model_meta_cache>::getinstance(); + table_cache.save(sqlhashid, table_fieldname, exptime); + + model_meta_cache> &tablemap_cache = + model_meta_cache>::getinstance(); + tablemap_cache.save(sqlhashid, table_fieldmap, exptime); + exptime = 0; + iscache = false; + } + } + } + + return std::make_tuple(std::move(table_fieldname), std::move(table_fieldmap), std::move(temprecord)); + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + return std::make_tuple(table_fieldname, table_fieldmap, temprecord); + } + M_MODEL &fetch() + { + effect_num = 0; + if (selectsql.empty()) + { + sqlstring = "SELECT * FROM "; + } + else + { + sqlstring = "SELECT "; + sqlstring.append(selectsql); + sqlstring.append(" FROM "); + } + + sqlstring.append(B_BASE::tablename); + sqlstring.append(" WHERE "); + + if (wheresql.empty()) + { + sqlstring.append(" 1 "); + } + else + { + sqlstring.append(wheresql); + } + if (!groupsql.empty()) + { + sqlstring.append(groupsql); + } + if (!ordersql.empty()) + { + sqlstring.append(ordersql); + } + if (!limitsql.empty()) + { + sqlstring.append(limitsql); + } + + if (iscache) + { + std::size_t sqlhashid = std::hash{}(sqlstring); + if (get_record_cache(sqlhashid)) + { + iscache = false; + return *mod; + } + } + + B_BASE::record_reset(); + if (iserror) + { + return *mod; + } + + try + { + if (conn_empty()) + { + return *mod; + } + //auto conn = conn_obj->get_select_conn(); + if (islock_conn) + { + if (!select_conn) + { + select_conn = conn_obj->get_select_conn(); + } + } + else + { + select_conn = conn_obj->get_select_conn(); + } + if (select_conn->isdebug) + { + select_conn->begin_time(); + } + + std::size_t n = select_conn->write_sql(sqlstring); + if (n == 0) + { + error_msg = select_conn->error_msg; + select_conn.reset(); + return *mod; + } + + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + bool is_sql_item = false; + std::vector field_array; + + unsigned char action_setup = 0; + unsigned int column_num = 0; + + unsigned int offset = 0; + + std::vector field_pos; + + for (; is_sql_item == false;) + { + n = select_conn->read_loop(); + offset = 0; + if (n == 0) + { + iserror = true; + error_msg = select_conn->error_msg; + select_conn.reset(); + return *mod; + } + for (; offset < n;) + { + select_conn->read_field_pack(select_conn->_cache_data, n, offset, temp_pack_data); + if (temp_pack_data.error > 0) + { + iserror = true; + error_msg = temp_pack_data.data; + select_conn.reset(); + return *mod; + } + if (temp_pack_data.length == temp_pack_data.current_length && temp_pack_data.current_length > 0) + { + if (select_conn->pack_eof_check(temp_pack_data)) + { + is_sql_item = true; + break; + } + + if (action_setup == 0) + { + if (temp_pack_data.length == 2 && (unsigned char)temp_pack_data.data[0] < 251 && (unsigned char)temp_pack_data.data[0] > 0) + { + action_setup = 1; + column_num = (unsigned char)temp_pack_data.data[0]; + } + } + else if (action_setup == 1) + { + field_info_t temp_filed_col; + select_conn->read_col_info(temp_pack_data.data, temp_filed_col); + + field_array.emplace_back(std::move(temp_filed_col)); + column_num--; + if (column_num == 0) + { + action_setup = 2; + for (unsigned int ii = 0; ii < field_array.size(); ii++) + { + field_pos.push_back(B_BASE::findcolpos(field_array[ii].org_name)); + } + } + } + else if (action_setup == 2) + { + unsigned int column_num = field_array.size(); + unsigned int tempnum = 0; + + typename B_BASE::meta data_temp; + for (unsigned int ij = 0; ij < column_num; ij++) + { + unsigned long long name_length = 0; + name_length = select_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], tempnum); + + assign_field_value(field_pos[ij], (unsigned char *)&temp_pack_data.data[tempnum], name_length, data_temp); + tempnum = tempnum + name_length; + } + B_BASE::record.emplace_back(std::move(data_temp)); + effect_num++; + } + } + else + { + if (offset >= n) + { + break; + } + is_sql_item = true; + break; + } + } + } + if (select_conn->isdebug) + { + select_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = select_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + + if (!islock_conn) + { + conn_obj->back_select_conn(std::move(select_conn)); + } + + if (iscache) + { + if (exptime > 0) + { + save_cache(exptime); + exptime = 0; + iscache = false; + } + } + return *mod; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + return *mod; + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + return *mod; + } + + asio::awaitable async_fetch() + { + effect_num = 0; + if (selectsql.empty()) + { + sqlstring = "SELECT * FROM "; + } + else + { + sqlstring = "SELECT "; + sqlstring.append(selectsql); + sqlstring.append(" FROM "); + } + + sqlstring.append(B_BASE::tablename); + sqlstring.append(" WHERE "); + + if (wheresql.empty()) + { + sqlstring.append(" 1 "); + } + else + { + sqlstring.append(wheresql); + } + if (!groupsql.empty()) + { + sqlstring.append(groupsql); + } + if (!ordersql.empty()) + { + sqlstring.append(ordersql); + } + if (!limitsql.empty()) + { + sqlstring.append(limitsql); + } + + if (iscache) + { + std::size_t sqlhashid = std::hash{}(sqlstring); + if (get_record_cache(sqlhashid)) + { + iscache = false; + co_return 0; + } + } + + B_BASE::record_reset(); + if (iserror) + { + co_return 0; + } + + try + { + if (conn_empty()) + { + co_return 0; + } + //auto conn = co_await conn_obj->async_get_select_conn(); + if (islock_conn) + { + if (!select_conn) + { + select_conn = co_await conn_obj->async_get_select_conn(); + } + } + else + { + select_conn = co_await conn_obj->async_get_select_conn(); + } + if (select_conn->isdebug) + { + select_conn->begin_time(); + } + + std::size_t n = co_await select_conn->async_write_sql(sqlstring); + + if (n == 0) + { + error_msg = select_conn->error_msg; + select_conn.reset(); + co_return 0; + } + + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + bool is_sql_item = false; + std::vector field_array; + + unsigned char action_setup = 0; + unsigned int column_num = 0; + + unsigned int offset = 0; + + std::vector field_pos; + + for (; is_sql_item == false;) + { + n = co_await select_conn->async_read_loop(); + offset = 0; + if (n == 0) + { + select_conn.reset(); + co_return 0; + } + for (; offset < n;) + { + select_conn->read_field_pack(select_conn->_cache_data, n, offset, temp_pack_data); + if (temp_pack_data.error > 0) + { + iserror = true; + error_msg = temp_pack_data.data; + select_conn.reset(); + co_return 0; + } + if (temp_pack_data.length == temp_pack_data.current_length && temp_pack_data.current_length > 0) + { + if (select_conn->pack_eof_check(temp_pack_data)) + { + is_sql_item = true; + break; + } + + if (action_setup == 0) + { + if (temp_pack_data.length == 2 && (unsigned char)temp_pack_data.data[0] < 251 && (unsigned char)temp_pack_data.data[0] > 0) + { + action_setup = 1; + column_num = (unsigned char)temp_pack_data.data[0]; + } + } + else if (action_setup == 1) + { + field_info_t temp_filed_col; + select_conn->read_col_info(temp_pack_data.data, temp_filed_col); + + field_array.emplace_back(std::move(temp_filed_col)); + column_num--; + if (column_num == 0) + { + action_setup = 2; + for (unsigned int ii = 0; ii < field_array.size(); ii++) + { + field_pos.push_back(B_BASE::findcolpos(field_array[ii].org_name)); + } + } + } + else if (action_setup == 2) + { + unsigned int column_num = field_array.size(); + unsigned int tempnum = 0; + + typename B_BASE::meta data_temp; + for (unsigned int ij = 0; ij < column_num; ij++) + { + unsigned long long name_length = 0; + name_length = select_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], tempnum); + + assign_field_value(field_pos[ij], (unsigned char *)&temp_pack_data.data[tempnum], name_length, data_temp); + tempnum = tempnum + name_length; + } + B_BASE::record.emplace_back(std::move(data_temp)); + effect_num++; + } + } + else + { + if (offset >= n) + { + break; + } + is_sql_item = true; + break; + } + } + } + if (select_conn->isdebug) + { + select_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = select_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + if (!islock_conn) + { + conn_obj->back_select_conn(std::move(select_conn)); + } + if (iscache) + { + if (exptime > 0) + { + save_cache(exptime); + exptime = 0; + iscache = false; + } + } + co_return effect_num; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + co_return 0; + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + co_return 0; + } + M_MODEL &fetch_append() + { + effect_num = 0; + if (selectsql.empty()) + { + sqlstring = "SELECT * FROM "; + } + else + { + sqlstring = "SELECT "; + sqlstring.append(selectsql); + sqlstring.append(" FROM "); + } + + sqlstring.append(B_BASE::tablename); + sqlstring.append(" WHERE "); + + if (wheresql.empty()) + { + sqlstring.append(" 1 "); + } + else + { + sqlstring.append(wheresql); + } + if (!groupsql.empty()) + { + sqlstring.append(groupsql); + } + if (!ordersql.empty()) + { + sqlstring.append(ordersql); + } + if (!limitsql.empty()) + { + sqlstring.append(limitsql); + } + + if (iscache) + { + std::size_t sqlhashid = std::hash{}(sqlstring); + if (get_record_cache(sqlhashid)) + { + iscache = false; + return *mod; + } + } + + if (iserror) + { + return *mod; + } + + try + { + + if (conn_empty()) + { + return 0; + } + //auto conn = conn_obj->get_select_conn(); + if (islock_conn) + { + if (!select_conn) + { + select_conn = conn_obj->get_select_conn(); + } + } + else + { + select_conn = conn_obj->get_select_conn(); + } + + if (select_conn->isdebug) + { + select_conn->begin_time(); + } + std::size_t n = select_conn->write_sql(sqlstring); + if (n == 0) + { + error_msg = select_conn->error_msg; + select_conn.reset(); + return 0; + } + + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + bool is_sql_item = false; + std::vector field_array; + + unsigned char action_setup = 0; + unsigned int column_num = 0; + + unsigned int offset = 0; + + std::vector field_pos; + + for (; is_sql_item == false;) + { + n = select_conn->read_loop(); + offset = 0; + if (n == 0) + { + error_msg = select_conn->error_msg; + select_conn.reset(); + return 0; + } + for (; offset < n;) + { + select_conn->read_field_pack(select_conn->_cache_data, n, offset, temp_pack_data); + if (temp_pack_data.error > 0) + { + iserror = true; + error_msg = temp_pack_data.data; + select_conn.reset(); + return 0; + } + if (temp_pack_data.length == temp_pack_data.current_length && temp_pack_data.current_length > 0) + { + if (select_conn->pack_eof_check(temp_pack_data)) + { + is_sql_item = true; + break; + } + + if (action_setup == 0) + { + if (temp_pack_data.length == 2 && (unsigned char)temp_pack_data.data[0] < 251 && (unsigned char)temp_pack_data.data[0] > 0) + { + action_setup = 1; + column_num = (unsigned char)temp_pack_data.data[0]; + } + } + else if (action_setup == 1) + { + field_info_t temp_filed_col; + select_conn->read_col_info(temp_pack_data.data, temp_filed_col); + + field_array.emplace_back(std::move(temp_filed_col)); + column_num--; + if (column_num == 0) + { + action_setup = 2; + for (unsigned int ii = 0; ii < field_array.size(); ii++) + { + field_pos.push_back(B_BASE::findcolpos(field_array[ii].org_name)); + } + } + } + else if (action_setup == 2) + { + unsigned int column_num = field_array.size(); + unsigned int tempnum = 0; + + typename B_BASE::meta data_temp; + for (unsigned int ij = 0; ij < column_num; ij++) + { + unsigned long long name_length = 0; + name_length = select_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], tempnum); + + assign_field_value(field_pos[ij], (unsigned char *)&temp_pack_data.data[tempnum], name_length, data_temp); + tempnum = tempnum + name_length; + } + B_BASE::record.emplace_back(std::move(data_temp)); + effect_num++; + } + } + else + { + if (offset >= n) + { + break; + } + is_sql_item = true; + break; + } + } + } + if (select_conn->isdebug) + { + select_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = select_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + + if (!islock_conn) + { + conn_obj->back_select_conn(std::move(select_conn)); + } + + if (iscache) + { + if (exptime > 0) + { + save_cache(exptime); + exptime = 0; + iscache = false; + } + } + return *mod; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + return *mod; + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + return *mod; + } + + asio::awaitable async_fetch_append() + { + effect_num = 0; + if (selectsql.empty()) + { + sqlstring = "SELECT * FROM "; + } + else + { + sqlstring = "SELECT "; + sqlstring.append(selectsql); + sqlstring.append(" FROM "); + } + + sqlstring.append(B_BASE::tablename); + sqlstring.append(" WHERE "); + + if (wheresql.empty()) + { + sqlstring.append(" 1 "); + } + else + { + sqlstring.append(wheresql); + } + if (!groupsql.empty()) + { + sqlstring.append(groupsql); + } + if (!ordersql.empty()) + { + sqlstring.append(ordersql); + } + if (!limitsql.empty()) + { + sqlstring.append(limitsql); + } + + if (iscache) + { + std::size_t sqlhashid = std::hash{}(sqlstring); + if (get_record_cache(sqlhashid)) + { + iscache = false; + co_return 1; + } + } + + if (iserror) + { + co_return 0; + } + + try + { + effect_num = 0; + + if (conn_empty()) + { + co_return 0; + } + //auto conn = co_await conn_obj->async_get_select_conn(); + if (islock_conn) + { + if (!select_conn) + { + select_conn = co_await conn_obj->async_get_select_conn(); + } + } + else + { + select_conn = co_await conn_obj->async_get_select_conn(); + } + + if (select_conn->isdebug) + { + select_conn->begin_time(); + } + std::size_t n = co_await select_conn->async_write_sql(sqlstring); + if (n == 0) + { + error_msg = select_conn->error_msg; + select_conn.reset(); + co_return 0; + } + + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + bool is_sql_item = false; + std::vector field_array; + // std::vector> field_value; + + unsigned char action_setup = 0; + unsigned int column_num = 0; + + unsigned int offset = 0; + + std::vector field_pos; + // std::map other_col; + + for (; is_sql_item == false;) + { + n = co_await select_conn->async_read_loop(); + offset = 0; + if (n == 0) + { + select_conn.reset(); + co_return 0; + } + for (; offset < n;) + { + select_conn->read_field_pack(select_conn->_cache_data, n, offset, temp_pack_data); + if (temp_pack_data.error > 0) + { + iserror = true; + error_msg = temp_pack_data.data; + select_conn.reset(); + co_return 0; + } + if (temp_pack_data.length == temp_pack_data.current_length && temp_pack_data.current_length > 0) + { + if (select_conn->pack_eof_check(temp_pack_data)) + { + is_sql_item = true; + break; + } + + if (action_setup == 0) + { + if (temp_pack_data.length == 2 && (unsigned char)temp_pack_data.data[0] < 251 && (unsigned char)temp_pack_data.data[0] > 0) + { + action_setup = 1; + column_num = (unsigned char)temp_pack_data.data[0]; + } + } + else if (action_setup == 1) + { + field_info_t temp_filed_col; + select_conn->read_col_info(temp_pack_data.data, temp_filed_col); + + field_array.emplace_back(std::move(temp_filed_col)); + column_num--; + if (column_num == 0) + { + action_setup = 2; + for (unsigned int ii = 0; ii < field_array.size(); ii++) + { + field_pos.push_back(B_BASE::findcolpos(field_array[ii].org_name)); + } + } + } + else if (action_setup == 2) + { + unsigned int column_num = field_array.size(); + unsigned int tempnum = 0; + + typename B_BASE::meta data_temp; + for (unsigned int ij = 0; ij < column_num; ij++) + { + unsigned long long name_length = 0; + name_length = select_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], tempnum); + + assign_field_value(field_pos[ij], (unsigned char *)&temp_pack_data.data[tempnum], name_length, data_temp); + tempnum = tempnum + name_length; + } + effect_num++; + B_BASE::record.emplace_back(std::move(data_temp)); + } + } + else + { + if (offset >= n) + { + break; + } + is_sql_item = true; + break; + } + } + } + if (select_conn->isdebug) + { + select_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = select_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + if (!islock_conn) + { + conn_obj->back_select_conn(std::move(select_conn)); + } + if (iscache) + { + if (exptime > 0) + { + save_cache(exptime); + exptime = 0; + iscache = false; + } + } + co_return effect_num; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + co_return 0; + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + co_return 0; + } + unsigned int fetch_one(bool isappend = false) + { + effect_num = 0; + if (selectsql.empty()) + { + sqlstring = "SELECT * FROM "; + } + else + { + sqlstring = "SELECT "; + sqlstring.append(selectsql); + sqlstring.append(" FROM "); + } + + sqlstring.append(B_BASE::tablename); + sqlstring.append(" WHERE "); + + if (wheresql.empty()) + { + sqlstring.append(" 1 "); + } + else + { + sqlstring.append(wheresql); + } + if (!groupsql.empty()) + { + sqlstring.append(groupsql); + } + if (!ordersql.empty()) + { + sqlstring.append(ordersql); + } + + sqlstring.append(" limit 1"); + + if (iscache) + { + std::size_t sqlhashid = std::hash{}(sqlstring); + if (get_data_cache(sqlhashid)) + { + iscache = false; + return 0; + } + } + + B_BASE::data_reset(); + if (iserror) + { + return 0; + } + + try + { + effect_num = 0; + if (conn_empty()) + { + return 0; + } + //auto conn = conn_obj->get_select_conn(); + if (islock_conn) + { + if (!select_conn) + { + select_conn = conn_obj->get_select_conn(); + } + } + else + { + select_conn = conn_obj->get_select_conn(); + } + + if (select_conn->isdebug) + { + select_conn->begin_time(); + } + + std::size_t n = select_conn->write_sql(sqlstring); + if (n == 0) + { + error_msg = select_conn->error_msg; + select_conn.reset(); + return 0; + } + + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + bool is_sql_item = false; + std::vector field_array; + unsigned char action_setup = 0; + unsigned int column_num = 0; + unsigned int offset = 0; + + std::vector field_pos; + + for (; is_sql_item == false;) + { + n = select_conn->read_loop(); + offset = 0; + if (n == 0) + { + error_msg = select_conn->error_msg; + select_conn.reset(); + return 0; + } + for (; offset < n;) + { + select_conn->read_field_pack(select_conn->_cache_data, n, offset, temp_pack_data); + if (temp_pack_data.error > 0) + { + iserror = true; + error_msg = temp_pack_data.data; + select_conn.reset(); + return 0; + } + if (temp_pack_data.length == temp_pack_data.current_length && temp_pack_data.current_length > 0) + { + if (select_conn->pack_eof_check(temp_pack_data)) + { + is_sql_item = true; + break; + } + + if (action_setup == 0) + { + if (temp_pack_data.length == 2 && (unsigned char)temp_pack_data.data[0] < 251 && (unsigned char)temp_pack_data.data[0] > 0) + { + action_setup = 1; + column_num = (unsigned char)temp_pack_data.data[0]; + } + } + else if (action_setup == 1) + { + field_info_t temp_filed_col; + select_conn->read_col_info(temp_pack_data.data, temp_filed_col); + + field_array.emplace_back(std::move(temp_filed_col)); + column_num--; + if (column_num == 0) + { + action_setup = 2; + for (unsigned int ii = 0; ii < field_array.size(); ii++) + { + field_pos.push_back(B_BASE::findcolpos(field_array[ii].org_name)); + } + } + } + else if (action_setup == 2) + { + unsigned int column_num = field_array.size(); + unsigned int tempnum = 0; + + if (isappend) + { + typename B_BASE::meta data_temp; + for (unsigned int ij = 0; ij < column_num; ij++) + { + unsigned long long name_length = 0; + name_length = select_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], tempnum); + + assign_field_value(field_pos[ij], (unsigned char *)&temp_pack_data.data[tempnum], name_length, data_temp); + tempnum = tempnum + name_length; + } + B_BASE::record.emplace_back(std::move(data_temp)); + effect_num++; + } + else + { + for (unsigned int ij = 0; ij < column_num; ij++) + { + unsigned long long name_length = 0; + name_length = select_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], tempnum); + + assign_field_value(field_pos[ij], (unsigned char *)&temp_pack_data.data[tempnum], name_length, B_BASE::data); + tempnum = tempnum + name_length; + } + effect_num++; + } + } + } + else + { + if (offset >= n) + { + break; + } + is_sql_item = true; + break; + } + } + } + if (select_conn->isdebug) + { + select_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = select_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + + if (!islock_conn) + { + conn_obj->back_select_conn(std::move(select_conn)); + } + + if (iscache) + { + if (exptime > 0) + { + save_data_cache(exptime); + exptime = 0; + iscache = false; + } + } + return effect_num; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + return 0; + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + return 0; + } + + asio::awaitable async_fetch_one(bool isappend = false) + { + effect_num = 0; + if (selectsql.empty()) + { + sqlstring = "SELECT * FROM "; + } + else + { + sqlstring = "SELECT "; + sqlstring.append(selectsql); + sqlstring.append(" FROM "); + } + + sqlstring.append(B_BASE::tablename); + sqlstring.append(" WHERE "); + + if (wheresql.empty()) + { + sqlstring.append(" 1 "); + } + else + { + sqlstring.append(wheresql); + } + if (!groupsql.empty()) + { + sqlstring.append(groupsql); + } + if (!ordersql.empty()) + { + sqlstring.append(ordersql); + } + + sqlstring.append(" limit 1"); + + if (iscache) + { + std::size_t sqlhashid = std::hash{}(sqlstring); + if (get_data_cache(sqlhashid)) + { + iscache = false; + co_return 0; + } + } + + B_BASE::data_reset(); + if (iserror) + { + co_return 0; + } + + try + { + effect_num = 0; + + if (conn_empty()) + { + co_return 0; + } + //auto conn = co_await conn_obj->async_get_select_conn(); + if (islock_conn) + { + if (!select_conn) + { + select_conn = co_await conn_obj->async_get_select_conn(); + } + } + else + { + select_conn = co_await conn_obj->async_get_select_conn(); + } + if (select_conn->isdebug) + { + select_conn->begin_time(); + } + + std::size_t n = co_await select_conn->async_write_sql(sqlstring); + + if (n == 0) + { + error_msg = select_conn->error_msg; + select_conn.reset(); + co_return 0; + } + + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + bool is_sql_item = false; + std::vector field_array; + + unsigned char action_setup = 0; + unsigned int column_num = 0; + + unsigned int offset = 0; + + std::vector field_pos; + + for (; is_sql_item == false;) + { + n = co_await select_conn->async_read_loop(); + offset = 0; + if (n == 0) + { + select_conn.reset(); + co_return 0; + } + for (; offset < n;) + { + select_conn->read_field_pack(select_conn->_cache_data, n, offset, temp_pack_data); + if (temp_pack_data.error > 0) + { + iserror = true; + error_msg = temp_pack_data.data; + select_conn.reset(); + co_return 0; + } + if (temp_pack_data.length == temp_pack_data.current_length && temp_pack_data.current_length > 0) + { + if (select_conn->pack_eof_check(temp_pack_data)) + { + is_sql_item = true; + break; + } + + if (action_setup == 0) + { + if (temp_pack_data.length == 2 && (unsigned char)temp_pack_data.data[0] < 251 && (unsigned char)temp_pack_data.data[0] > 0) + { + action_setup = 1; + column_num = (unsigned char)temp_pack_data.data[0]; + } + } + else if (action_setup == 1) + { + field_info_t temp_filed_col; + select_conn->read_col_info(temp_pack_data.data, temp_filed_col); + + field_array.emplace_back(std::move(temp_filed_col)); + column_num--; + if (column_num == 0) + { + action_setup = 2; + for (unsigned int ii = 0; ii < field_array.size(); ii++) + { + field_pos.push_back(B_BASE::findcolpos(field_array[ii].org_name)); + } + } + } + else if (action_setup == 2) + { + unsigned int column_num = field_array.size(); + unsigned int tempnum = 0; + + if (isappend) + { + typename B_BASE::meta data_temp; + for (unsigned int ij = 0; ij < column_num; ij++) + { + unsigned long long name_length = 0; + name_length = select_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], tempnum); + + assign_field_value(field_pos[ij], (unsigned char *)&temp_pack_data.data[tempnum], name_length, data_temp); + tempnum = tempnum + name_length; + } + B_BASE::record.emplace_back(std::move(data_temp)); + effect_num++; + } + else + { + for (unsigned int ij = 0; ij < column_num; ij++) + { + unsigned long long name_length = 0; + name_length = select_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], tempnum); + + assign_field_value(field_pos[ij], (unsigned char *)&temp_pack_data.data[tempnum], name_length, B_BASE::data); + tempnum = tempnum + name_length; + } + effect_num++; + } + } + } + else + { + if (offset >= n) + { + break; + } + is_sql_item = true; + break; + } + } + } + if (select_conn->isdebug) + { + select_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = select_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + if (!islock_conn) + { + conn_obj->back_select_conn(std::move(select_conn)); + } + if (iscache) + { + if (exptime > 0) + { + save_data_cache(exptime); + exptime = 0; + iscache = false; + } + } + co_return effect_num; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + co_return 0; + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + co_return 0; + } + + M_MODEL &use_cache(int cache_time = 0) + { + iscache = true; + exptime = cache_time; + return *mod; + } + bool isuse_cache(bool iscachedate = false) + { + if (iscachedate) + { + return exptime == 0 && iscache == false; + } + return iscache; + } + void set_cache_state(bool isrestatus = false) { iscache = isrestatus; } + void remove_exptime_cache() + { + model_meta_cache &temp_cache = model_meta_cache::getinstance(); + temp_cache.remove_exptime(); + } + void clear_cache() + { + model_meta_cache &temp_cache = model_meta_cache::getinstance(); + temp_cache.clear(); + } + bool remove_cache() + { + model_meta_cache &temp_cache = model_meta_cache::getinstance(); + std::size_t sqlhashid = std::hash{}(sqlstring); + return temp_cache.remove(sqlhashid); + } + bool remove_cache(std::size_t cache_key_name) + { + model_meta_cache &temp_cache = model_meta_cache::getinstance(); + return temp_cache.remove(cache_key_name); + } + int check_cache(std::size_t cache_key_name) + { + model_meta_cache &temp_cache = model_meta_cache::getinstance(); + return temp_cache.check(cache_key_name); + } + + bool get_data_cache(std::size_t cache_key_name) + { + try + { + model_meta_cache &temp_cache = model_meta_cache::getinstance(); + B_BASE::data = temp_cache.get(cache_key_name); + return true; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + } + catch (const std::string &e) + { + error_msg = e; + } + catch (const char *e) + { + error_msg = e; + } + catch (...) + { + } + B_BASE::data_reset(); + return false; + } + int update_cache(int exp_time = 0) + { + model_meta_cache> &temp_cache = model_meta_cache>::getinstance(); + std::size_t sqlhashid = std::hash{}(sqlstring); + return temp_cache.update(sqlhashid, exp_time); + } + int update_cache(std::size_t cache_key_name, int exp_time) + { + model_meta_cache> &temp_cache = model_meta_cache>::getinstance(); + return temp_cache.update(cache_key_name, exp_time); + } + bool save_cache(int exp_time = 0) + { + model_meta_cache> &temp_cache = model_meta_cache>::getinstance(); + std::size_t sqlhashid = std::hash{}(sqlstring); + temp_cache.save(sqlhashid, B_BASE::record, exp_time); + return true; + } + + bool save_data_cache(int exp_time = 0) + { + model_meta_cache &temp_cache = model_meta_cache::getinstance(); + std::size_t sqlhashid = std::hash{}(sqlstring); + temp_cache.save(sqlhashid, B_BASE::data, exp_time); + return true; + } + + bool save_data_cache(const std::string &cache_key_name, const typename B_BASE::meta &cache_data, int exp_time = 0) + { + model_meta_cache &temp_cache = model_meta_cache::getinstance(); + std::size_t sqlhashid = std::hash{}(cache_key_name); + temp_cache.save(sqlhashid, cache_data, exp_time); + return true; + } + + bool save_cache(std::size_t cache_key_name, const std::vector &cache_data, int exp_time = 0) + { + model_meta_cache> &temp_cache = model_meta_cache>::getinstance(); + temp_cache.save(cache_key_name, cache_data, exp_time); + return true; + } + bool save_cache(const std::string cache_key_name, const std::vector &cache_data, int exp_time = 0) + { + model_meta_cache> &temp_cache = model_meta_cache>::getinstance(); + std::size_t sqlhashid = std::hash{}(cache_key_name); + temp_cache.save(sqlhashid, cache_data, exp_time); + return true; + } + bool save_vector_cache(const std::string cache_key_name, const std::vector &cache_data, int exp_time = 0) + { + model_meta_cache> &temp_cache = model_meta_cache>::getinstance(); + std::size_t sqlhashid = std::hash{}(cache_key_name); + temp_cache.save(sqlhashid, cache_data, exp_time); + return true; + } + bool save_cache(const std::string cache_key_name, const typename B_BASE::meta &cache_data, int exp_time = 0) + { + model_meta_cache &temp_cache = model_meta_cache::getinstance(); + std::size_t sqlhashid = std::hash{}(cache_key_name); + temp_cache.save(sqlhashid, cache_data, exp_time); + return true; + } + typename B_BASE::meta &get_cache(const std::string &cache_key_name) + { + try + { + model_meta_cache &temp_cache = model_meta_cache::getinstance(); + std::size_t sqlhashid = std::hash{}(cache_key_name); + return temp_cache.get(sqlhashid); + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + } + catch (const std::string &e) + { + error_msg = e; + } + catch (const char *e) + { + error_msg = e; + } + catch (...) + { + } + throw "Not in cache"; + } + + std::vector &get_vector_cache(const std::string &cache_key_name) + { + try + { + model_meta_cache> &temp_cache = model_meta_cache>::getinstance(); + std::size_t sqlhashid = std::hash{}(cache_key_name); + return temp_cache.get(sqlhashid); + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + } + catch (const std::string &e) + { + error_msg = e; + } + catch (const char *e) + { + error_msg = e; + } + catch (...) + { + } + throw "Not in cache"; + } + + bool get_record_cache(std::size_t cache_key_name) + { + try + { + model_meta_cache> &temp_cache = model_meta_cache>::getinstance(); + B_BASE::record = temp_cache.get(cache_key_name); + return true; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + } + catch (const std::string &e) + { + error_msg = e; + } + catch (const char *e) + { + error_msg = e; + } + catch (...) + { + } + B_BASE::record.clear(); + return false; + } + http::obj_val fetch_json() + { + effect_num = 0; + if (selectsql.empty()) + { + sqlstring = "SELECT * FROM "; + } + else + { + sqlstring = "SELECT "; + sqlstring.append(selectsql); + sqlstring.append(" FROM "); + } + + sqlstring.append(B_BASE::tablename); + sqlstring.append(" WHERE "); + + if (wheresql.empty()) + { + sqlstring.append(" 1 "); + } + else + { + sqlstring.append(wheresql); + } + if (!groupsql.empty()) + { + sqlstring.append(groupsql); + } + if (!ordersql.empty()) + { + sqlstring.append(ordersql); + } + if (!limitsql.empty()) + { + sqlstring.append(limitsql); + } + + http::obj_val valuetemp; + valuetemp.set_array(); + + if (iserror) + { + return valuetemp; + } + + try + { + if (conn_empty()) + { + return 0; + } + //auto conn = conn_obj->get_select_conn(); + if (islock_conn) + { + if (!select_conn) + { + select_conn = conn_obj->get_select_conn(); + } + } + else + { + select_conn = conn_obj->get_select_conn(); + } + + if (select_conn->isdebug) + { + select_conn->begin_time(); + } + + std::size_t n = select_conn->write_sql(sqlstring); + if (n == 0) + { + error_msg = select_conn->error_msg; + select_conn.reset(); + return 0; + } + + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + bool is_sql_item = false; + std::vector field_array; + + unsigned char action_setup = 0; + unsigned int column_num = 0; + + unsigned int offset = 0; + + for (; is_sql_item == false;) + { + n = select_conn->read_loop(); + offset = 0; + if (n == 0) + { + error_msg = select_conn->error_msg; + select_conn.reset(); + return 0; + } + for (; offset < n;) + { + select_conn->read_field_pack(select_conn->_cache_data, n, offset, temp_pack_data); + if (temp_pack_data.error > 0) + { + iserror = true; + error_msg = temp_pack_data.data; + select_conn.reset(); + return 0; + } + if (temp_pack_data.length == temp_pack_data.current_length && temp_pack_data.current_length > 0) + { + if (select_conn->pack_eof_check(temp_pack_data)) + { + is_sql_item = true; + break; + } + + if (action_setup == 0) + { + if (temp_pack_data.length == 2 && (unsigned char)temp_pack_data.data[0] < 251 && (unsigned char)temp_pack_data.data[0] > 0) + { + action_setup = 1; + column_num = (unsigned char)temp_pack_data.data[0]; + } + } + else if (action_setup == 1) + { + field_info_t temp_filed_col; + select_conn->read_col_info(temp_pack_data.data, temp_filed_col); + + field_array.emplace_back(std::move(temp_filed_col)); + column_num--; + if (column_num == 0) + { + action_setup = 2; + } + } + else if (action_setup == 2) + { + unsigned int column_num = field_array.size(); + unsigned int tempnum = 0; + + http::obj_val json_temp_v; + for (unsigned int ij = 0; ij < column_num; ij++) + { + unsigned long long name_length = 0; + name_length = select_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], tempnum); + + std::string temp_str; + temp_str.resize(name_length); + std::memcpy(temp_str.data(), (unsigned char *)&temp_pack_data.data[tempnum], name_length); + if (field_array[ij].name.size() > 0) + { + //or alias name + json_temp_v[field_array[ij].name] = std::move(temp_str); + } + else if (field_array[ij].org_name.size() > 0) + { + json_temp_v[field_array[ij].org_name] = std::move(temp_str); + } + tempnum = tempnum + name_length; + } + valuetemp.push(json_temp_v); + effect_num++; + } + } + else + { + if (offset >= n) + { + break; + } + is_sql_item = true; + break; + } + } + } + if (select_conn->isdebug) + { + select_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = select_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + if (!islock_conn) + { + conn_obj->back_select_conn(std::move(select_conn)); + } + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + return valuetemp; + } + + asio::awaitable async_fetch_json() + { + effect_num = 0; + if (selectsql.empty()) + { + sqlstring = "SELECT * FROM "; + } + else + { + sqlstring = "SELECT "; + sqlstring.append(selectsql); + sqlstring.append(" FROM "); + } + + sqlstring.append(B_BASE::tablename); + sqlstring.append(" WHERE "); + + if (wheresql.empty()) + { + sqlstring.append(" 1 "); + } + else + { + sqlstring.append(wheresql); + } + if (!groupsql.empty()) + { + sqlstring.append(groupsql); + } + if (!ordersql.empty()) + { + sqlstring.append(ordersql); + } + if (!limitsql.empty()) + { + sqlstring.append(limitsql); + } + + http::obj_val valuetemp; + valuetemp.set_array(); + + if (iserror) + { + co_return valuetemp; + } + + try + { + if (conn_empty()) + { + co_return valuetemp; + } + //auto conn = co_await conn_obj->async_get_select_conn(); + if (islock_conn) + { + if (!select_conn) + { + select_conn = co_await conn_obj->async_get_select_conn(); + } + } + else + { + select_conn = co_await conn_obj->async_get_select_conn(); + } + + if (select_conn->isdebug) + { + select_conn->begin_time(); + } + std::size_t n = co_await select_conn->async_write_sql(sqlstring); + if (n == 0) + { + error_msg = select_conn->error_msg; + select_conn.reset(); + co_return valuetemp; + } + + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + bool is_sql_item = false; + std::vector field_array; + + unsigned char action_setup = 0; + unsigned int column_num = 0; + + unsigned int offset = 0; + + for (; is_sql_item == false;) + { + n = co_await select_conn->async_read_loop(); + offset = 0; + if (n == 0) + { + select_conn.reset(); + co_return valuetemp; + } + for (; offset < n;) + { + select_conn->read_field_pack(select_conn->_cache_data, n, offset, temp_pack_data); + if (temp_pack_data.error > 0) + { + iserror = true; + error_msg = temp_pack_data.data; + select_conn.reset(); + co_return 0; + } + if (temp_pack_data.length == temp_pack_data.current_length && temp_pack_data.current_length > 0) + { + if (select_conn->pack_eof_check(temp_pack_data)) + { + is_sql_item = true; + break; + } + + if (action_setup == 0) + { + if (temp_pack_data.length == 2 && (unsigned char)temp_pack_data.data[0] < 251 && (unsigned char)temp_pack_data.data[0] > 0) + { + action_setup = 1; + column_num = (unsigned char)temp_pack_data.data[0]; + } + } + else if (action_setup == 1) + { + field_info_t temp_filed_col; + select_conn->read_col_info(temp_pack_data.data, temp_filed_col); + + field_array.emplace_back(std::move(temp_filed_col)); + column_num--; + if (column_num == 0) + { + action_setup = 2; + } + } + else if (action_setup == 2) + { + unsigned int column_num = field_array.size(); + unsigned int tempnum = 0; + + http::obj_val json_temp_v; + for (unsigned int ij = 0; ij < column_num; ij++) + { + unsigned long long name_length = 0; + name_length = select_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], tempnum); + + std::string temp_str; + temp_str.resize(name_length); + std::memcpy(temp_str.data(), (unsigned char *)&temp_pack_data.data[tempnum], name_length); + if (field_array[ij].name.size() > 0) + { + //or alias name + json_temp_v[field_array[ij].name] = std::move(temp_str); + } + else if (field_array[ij].org_name.size() > 0) + { + json_temp_v[field_array[ij].org_name] = std::move(temp_str); + } + tempnum = tempnum + name_length; + } + valuetemp.push(json_temp_v); + effect_num++; + } + } + else + { + if (offset >= n) + { + break; + } + is_sql_item = true; + break; + } + } + } + if (select_conn->isdebug) + { + select_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = select_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + if (!islock_conn) + { + conn_obj->back_select_conn(std::move(select_conn)); + } + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + co_return valuetemp; + } + + long long get_one(long long id) + { + effect_num = 0; + if (selectsql.empty()) + { + sqlstring = "SELECT * FROM "; + } + else + { + sqlstring = "SELECT "; + sqlstring.append(selectsql); + sqlstring.append(" FROM "); + } + + sqlstring.append(B_BASE::tablename); + sqlstring.append(" WHERE "); + + sqlstring.append(B_BASE::getPKname()); + sqlstring.append("="); + sqlstring.append(std::to_string(id)); + sqlstring.append(" limit 1"); + if (iscache) + { + std::size_t sqlhashid = std::hash{}(sqlstring); + if (get_data_cache(sqlhashid)) + { + iscache = false; + return 0; + } + } + + B_BASE::data_reset(); + + if (iserror) + { + return 0; + } + + try + { + if (conn_empty()) + { + return 0; + } + //auto conn = conn_obj->get_select_conn(); + if (islock_conn) + { + if (!select_conn) + { + select_conn = conn_obj->get_select_conn(); + } + } + else + { + select_conn = conn_obj->get_select_conn(); + } + + if (select_conn->isdebug) + { + select_conn->begin_time(); + } + + std::size_t n = select_conn->write_sql(sqlstring); + if (n == 0) + { + error_msg = select_conn->error_msg; + select_conn.reset(); + return 0; + } + + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + bool is_sql_item = false; + std::vector field_array; + + unsigned char action_setup = 0; + unsigned int column_num = 0; + + unsigned int offset = 0; + + std::vector field_pos; + + for (; is_sql_item == false;) + { + n = select_conn->read_loop(); + offset = 0; + if (n == 0) + { + error_msg = select_conn->error_msg; + select_conn.reset(); + return 0; + } + for (; offset < n;) + { + select_conn->read_field_pack(select_conn->_cache_data, n, offset, temp_pack_data); + if (temp_pack_data.error > 0) + { + iserror = true; + error_msg = temp_pack_data.data; + select_conn.reset(); + return 0; + } + if (temp_pack_data.length == temp_pack_data.current_length && temp_pack_data.current_length > 0) + { + if (select_conn->pack_eof_check(temp_pack_data)) + { + is_sql_item = true; + break; + } + + if (action_setup == 0) + { + if (temp_pack_data.length == 2 && (unsigned char)temp_pack_data.data[0] < 251 && (unsigned char)temp_pack_data.data[0] > 0) + { + action_setup = 1; + column_num = (unsigned char)temp_pack_data.data[0]; + } + } + else if (action_setup == 1) + { + field_info_t temp_filed_col; + select_conn->read_col_info(temp_pack_data.data, temp_filed_col); + + field_array.emplace_back(std::move(temp_filed_col)); + column_num--; + if (column_num == 0) + { + action_setup = 2; + for (unsigned int ii = 0; ii < field_array.size(); ii++) + { + field_pos.push_back(B_BASE::findcolpos(field_array[ii].org_name)); + } + } + } + else if (action_setup == 2) + { + unsigned int column_num = field_array.size(); + unsigned int tempnum = 0; + + for (unsigned int ij = 0; ij < column_num; ij++) + { + unsigned long long name_length = 0; + name_length = select_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], tempnum); + + assign_field_value(field_pos[ij], (unsigned char *)&temp_pack_data.data[tempnum], name_length, B_BASE::data); + tempnum = tempnum + name_length; + } + + effect_num++; + } + } + else + { + if (offset >= n) + { + break; + } + is_sql_item = true; + break; + } + } + } + if (select_conn->isdebug) + { + select_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = select_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + if (!islock_conn) + { + conn_obj->back_select_conn(std::move(select_conn)); + } + if (iscache) + { + if (exptime > 0) + { + save_data_cache(exptime); + exptime = 0; + iscache = false; + } + } + return 0; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + return 0; + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + return 0; + } + + asio::awaitable async_get_one(long long id) + { + effect_num = 0; + if (selectsql.empty()) + { + sqlstring = "SELECT * FROM "; + } + else + { + sqlstring = "SELECT "; + sqlstring.append(selectsql); + sqlstring.append(" FROM "); + } + + sqlstring.append(B_BASE::tablename); + sqlstring.append(" WHERE "); + + sqlstring.append(B_BASE::getPKname()); + sqlstring.append("="); + sqlstring.append(std::to_string(id)); + sqlstring.append(" limit 1"); + if (iscache) + { + std::size_t sqlhashid = std::hash{}(sqlstring); + if (get_data_cache(sqlhashid)) + { + iscache = false; + co_return 0; + } + } + + B_BASE::data_reset(); + + if (iserror) + { + co_return 0; + } + + try + { + if (conn_empty()) + { + co_return 0; + } + //auto conn = co_await conn_obj->async_get_select_conn(); + if (islock_conn) + { + if (!select_conn) + { + select_conn = co_await conn_obj->async_get_select_conn(); + } + } + else + { + select_conn = co_await conn_obj->async_get_select_conn(); + } + + if (select_conn->isdebug) + { + select_conn->begin_time(); + } + std::size_t n = co_await select_conn->async_write_sql(sqlstring); + if (n == 0) + { + error_msg = select_conn->error_msg; + select_conn.reset(); + co_return 0; + } + + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + bool is_sql_item = false; + std::vector field_array; + + unsigned char action_setup = 0; + unsigned int column_num = 0; + + unsigned int offset = 0; + + std::vector field_pos; + + for (; is_sql_item == false;) + { + n = co_await select_conn->async_read_loop(); + offset = 0; + if (n == 0) + { + select_conn.reset(); + co_return 0; + } + for (; offset < n;) + { + select_conn->read_field_pack(select_conn->_cache_data, n, offset, temp_pack_data); + if (temp_pack_data.error > 0) + { + iserror = true; + error_msg = temp_pack_data.data; + select_conn.reset(); + co_return 0; + } + if (temp_pack_data.length == temp_pack_data.current_length && temp_pack_data.current_length > 0) + { + if (select_conn->pack_eof_check(temp_pack_data)) + { + is_sql_item = true; + break; + } + + if (action_setup == 0) + { + if (temp_pack_data.length == 2 && (unsigned char)temp_pack_data.data[0] < 251 && (unsigned char)temp_pack_data.data[0] > 0) + { + action_setup = 1; + column_num = (unsigned char)temp_pack_data.data[0]; + } + } + else if (action_setup == 1) + { + field_info_t temp_filed_col; + select_conn->read_col_info(temp_pack_data.data, temp_filed_col); + + field_array.emplace_back(std::move(temp_filed_col)); + column_num--; + if (column_num == 0) + { + action_setup = 2; + for (unsigned int ii = 0; ii < field_array.size(); ii++) + { + field_pos.push_back(B_BASE::findcolpos(field_array[ii].org_name)); + } + } + } + else if (action_setup == 2) + { + unsigned int column_num = field_array.size(); + unsigned int tempnum = 0; + + for (unsigned int ij = 0; ij < column_num; ij++) + { + unsigned long long name_length = 0; + name_length = select_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], tempnum); + + assign_field_value(field_pos[ij], (unsigned char *)&temp_pack_data.data[tempnum], name_length, B_BASE::data); + tempnum = tempnum + name_length; + } + + effect_num++; + } + } + else + { + if (offset >= n) + { + break; + } + is_sql_item = true; + break; + } + } + } + if (select_conn->isdebug) + { + select_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = select_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + if (!islock_conn) + { + conn_obj->back_select_conn(std::move(select_conn)); + } + if (iscache) + { + if (exptime > 0) + { + save_data_cache(exptime); + exptime = 0; + iscache = false; + } + } + co_return effect_num; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + co_return 0; + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + co_return 0; + } + + int update() + { + effect_num = 0; + if (wheresql.empty()) + { + if (B_BASE::getPK() > 0) + { + std::ostringstream tempsql; + tempsql << " "; + tempsql << B_BASE::getPKname(); + tempsql << " = '"; + tempsql << B_BASE::getPK(); + tempsql << "' "; + wheresql = tempsql.str(); + } + else + { + return 0; + } + } + sqlstring = B_BASE::_makeupdatesql(""); + sqlstring.append(" where "); + if (wheresql.empty()) + { + return 0; + } + else + { + sqlstring.append(wheresql); + } + if (!groupsql.empty()) + { + sqlstring.append(groupsql); + } + if (!ordersql.empty()) + { + sqlstring.append(ordersql); + } + if (!limitsql.empty()) + { + sqlstring.append(limitsql); + } + + if (iscommit) + { + iscommit = false; + return 0; + } + + if (iserror) + { + return 0; + } + + try + { + if (conn_empty()) + { + return 0; + } + //auto conn = conn_obj->get_edit_conn(); + + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = conn_obj->get_edit_conn(); + } + } + else + { + edit_conn = conn_obj->get_edit_conn(); + } + + if (edit_conn->isdebug) + { + edit_conn->begin_time(); + } + + std::size_t n = edit_conn->write_sql(sqlstring); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return 0; + } + + unsigned int offset = 0; + n = edit_conn->read_loop(); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return 0; + } + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + edit_conn->read_field_pack(edit_conn->_cache_data, n, offset, temp_pack_data); + + if (edit_conn->isdebug) + { + edit_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = edit_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + + if ((unsigned char)temp_pack_data.data[0] == 0xFF) + { + error_msg = temp_pack_data.data.substr(3); + } + else if ((unsigned char)temp_pack_data.data[0] == 0x00) + { + + unsigned int d_offset = 1; + effect_num = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + } + if (!islock_conn) + { + conn_obj->back_edit_conn(std::move(edit_conn)); + } + return effect_num; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + return 0; + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + return 0; + } + int update(const std::string &fieldname) + { + effect_num = 0; + if (wheresql.empty()) + { + if (B_BASE::getPK() > 0) + { + std::ostringstream tempsql; + tempsql << " "; + tempsql << B_BASE::getPKname(); + tempsql << " = '"; + tempsql << B_BASE::getPK(); + tempsql << "' "; + wheresql = tempsql.str(); + } + else + { + error_msg = "warning empty where sql!"; + return 0; + } + } + + sqlstring = B_BASE::_makeupdatesql(fieldname); + sqlstring.append(" where "); + if (wheresql.empty()) + { + return 0; + } + else + { + sqlstring.append(wheresql); + } + if (!groupsql.empty()) + { + sqlstring.append(groupsql); + } + if (!ordersql.empty()) + { + sqlstring.append(ordersql); + } + if (!limitsql.empty()) + { + sqlstring.append(limitsql); + } + + if (iscommit) + { + iscommit = false; + return 0; + } + + if (iserror) + { + return 0; + } + + try + { + if (conn_empty()) + { + return 0; + } + //auto conn = conn_obj->get_edit_conn(); + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = conn_obj->get_edit_conn(); + } + } + else + { + edit_conn = conn_obj->get_edit_conn(); + } + if (edit_conn->isdebug) + { + edit_conn->begin_time(); + } + + std::size_t n = edit_conn->write_sql(sqlstring); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return 0; + } + + unsigned int offset = 0; + n = edit_conn->read_loop(); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return 0; + } + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + edit_conn->read_field_pack(edit_conn->_cache_data, n, offset, temp_pack_data); + + if (edit_conn->isdebug) + { + edit_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = edit_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + + if ((unsigned char)temp_pack_data.data[0] == 0xFF) + { + error_msg = temp_pack_data.data.substr(3); + } + else if ((unsigned char)temp_pack_data.data[0] == 0x00) + { + + unsigned int d_offset = 1; + effect_num = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + } + if (!islock_conn) + { + conn_obj->back_edit_conn(std::move(edit_conn)); + } + return effect_num; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + return 0; + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + return 0; + } + + asio::awaitable async_update(const std::string &fieldname) + { + effect_num = 0; + if (wheresql.empty()) + { + if (B_BASE::getPK() > 0) + { + std::ostringstream tempsql; + tempsql << " "; + tempsql << B_BASE::getPKname(); + tempsql << " = '"; + tempsql << B_BASE::getPK(); + tempsql << "' "; + wheresql = tempsql.str(); + } + else + { + error_msg = "warning empty where sql!"; + co_return 0; + } + } + + sqlstring = B_BASE::_makeupdatesql(fieldname); + sqlstring.append(" where "); + if (wheresql.empty()) + { + co_return 0; + } + else + { + sqlstring.append(wheresql); + } + if (!groupsql.empty()) + { + sqlstring.append(groupsql); + } + if (!ordersql.empty()) + { + sqlstring.append(ordersql); + } + if (!limitsql.empty()) + { + sqlstring.append(limitsql); + } + + if (iscommit) + { + iscommit = false; + co_return 0; + } + + if (iserror) + { + co_return 0; + } + try + { + + if (conn_empty()) + { + co_return 0; + } + + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = co_await conn_obj->async_get_edit_conn(); + } + } + else + { + edit_conn = co_await conn_obj->async_get_edit_conn(); + } + + if (edit_conn->isdebug) + { + edit_conn->begin_time(); + } + std::size_t n = co_await edit_conn->async_write_sql(sqlstring); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + co_return 0; + } + + unsigned int offset = 0; + n = co_await edit_conn->async_read_loop(); + if (n == 0) + { + edit_conn.reset(); + co_return 0; + } + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + edit_conn->read_field_pack(edit_conn->_cache_data, n, offset, temp_pack_data); + if (edit_conn->isdebug) + { + edit_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = edit_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + + if ((unsigned char)temp_pack_data.data[0] == 0xFF) + { + error_msg = temp_pack_data.data.substr(3); + iserror = true; + } + else if ((unsigned char)temp_pack_data.data[0] == 0x00) + { + + unsigned int d_offset = 1; + effect_num = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + } + if (!islock_conn) + { + conn_obj->back_edit_conn(std::move(edit_conn)); + } + co_return effect_num; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + co_return 0; + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + co_return 0; + } + asio::awaitable async_update() + { + effect_num = 0; + if (wheresql.empty()) + { + if (B_BASE::getPK() > 0) + { + std::ostringstream tempsql; + tempsql << " "; + tempsql << B_BASE::getPKname(); + tempsql << " = '"; + tempsql << B_BASE::getPK(); + tempsql << "' "; + wheresql = tempsql.str(); + } + else + { + error_msg = "warning empty where sql!"; + co_return 0; + } + } + + sqlstring = B_BASE::_makeupdatesql(""); + sqlstring.append(" where "); + if (wheresql.empty()) + { + co_return 0; + } + else + { + sqlstring.append(wheresql); + } + if (!groupsql.empty()) + { + sqlstring.append(groupsql); + } + if (!ordersql.empty()) + { + sqlstring.append(ordersql); + } + if (!limitsql.empty()) + { + sqlstring.append(limitsql); + } + + if (iscommit) + { + iscommit = false; + co_return 0; + } + + if (iserror) + { + co_return 0; + } + try + { + + if (conn_empty()) + { + co_return 0; + } + + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = co_await conn_obj->async_get_edit_conn(); + } + } + else + { + edit_conn = co_await conn_obj->async_get_edit_conn(); + } + + if (edit_conn->isdebug) + { + edit_conn->begin_time(); + } + std::size_t n = co_await edit_conn->async_write_sql(sqlstring); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + co_return 0; + } + + unsigned int offset = 0; + n = co_await edit_conn->async_read_loop(); + if (n == 0) + { + edit_conn.reset(); + co_return 0; + } + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + edit_conn->read_field_pack(edit_conn->_cache_data, n, offset, temp_pack_data); + if (edit_conn->isdebug) + { + edit_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = edit_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + + if ((unsigned char)temp_pack_data.data[0] == 0xFF) + { + error_msg = temp_pack_data.data.substr(3); + iserror = true; + } + else if ((unsigned char)temp_pack_data.data[0] == 0x00) + { + + unsigned int d_offset = 1; + effect_num = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + } + if (!islock_conn) + { + conn_obj->back_edit_conn(std::move(edit_conn)); + } + co_return effect_num; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + co_return 0; + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + co_return 0; + } + + int update_batch(const std::string &fieldname) + { + effect_num = 0; + if (B_BASE::record.size() == 0) + { + return 0; + } + if (fieldname.size() > 0) + { + sqlstring = B_BASE::_make_insert_into_sql(fieldname); + } + else + { + sqlstring = B_BASE::_make_replace_into_sql(); + } + + if (iserror) + { + return 0; + } + + try + { + if (conn_empty()) + { + return 0; + } + //auto conn = conn_obj->get_edit_conn(); + + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = conn_obj->get_edit_conn(); + } + } + else + { + edit_conn = conn_obj->get_edit_conn(); + } + + if (edit_conn->isdebug) + { + edit_conn->begin_time(); + } + std::size_t n = edit_conn->write_sql(sqlstring); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return 0; + } + + unsigned int offset = 0; + n = edit_conn->read_loop(); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return 0; + } + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + edit_conn->read_field_pack(edit_conn->_cache_data, n, offset, temp_pack_data); + if (edit_conn->isdebug) + { + edit_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = edit_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + + if ((unsigned char)temp_pack_data.data[0] == 0xFF) + { + error_msg = temp_pack_data.data.substr(3); + } + else if ((unsigned char)temp_pack_data.data[0] == 0x00) + { + + unsigned int d_offset = 1; + effect_num = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + } + if (!islock_conn) + { + conn_obj->back_edit_conn(std::move(edit_conn)); + } + return effect_num; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + return 0; + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + return 0; + } + int remove() + { + effect_num = 0; + if (wheresql.empty()) + { + if (B_BASE::getPK() > 0) + { + std::ostringstream tempsql; + tempsql << " "; + tempsql << B_BASE::getPKname(); + tempsql << " = '"; + tempsql << B_BASE::getPK(); + tempsql << "' "; + wheresql = tempsql.str(); + } + else + { + return 0; + } + } + + sqlstring = "DELETE FROM "; + sqlstring.append(B_BASE::tablename); + sqlstring.append(" WHERE "); + + if (wheresql.empty()) + { + return 0; + } + else + { + sqlstring.append(wheresql); + } + if (!groupsql.empty()) + { + sqlstring.append(groupsql); + } + if (!ordersql.empty()) + { + sqlstring.append(ordersql); + } + if (!limitsql.empty()) + { + sqlstring.append(limitsql); + } + + if (iscommit) + { + iscommit = false; + return 0; + } + + if (iserror) + { + return 0; + } + + try + { + if (conn_empty()) + { + return 0; + } + //auto conn = conn_obj->get_edit_conn(); + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = conn_obj->get_edit_conn(); + } + } + else + { + edit_conn = conn_obj->get_edit_conn(); + } + + if (edit_conn->isdebug) + { + edit_conn->begin_time(); + } + std::size_t n = edit_conn->write_sql(sqlstring); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return 0; + } + + unsigned int offset = 0; + n = edit_conn->read_loop(); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return 0; + } + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + edit_conn->read_field_pack(edit_conn->_cache_data, n, offset, temp_pack_data); + if (edit_conn->isdebug) + { + edit_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = edit_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + + if ((unsigned char)temp_pack_data.data[0] == 0xFF) + { + error_msg = temp_pack_data.data.substr(3); + } + else if ((unsigned char)temp_pack_data.data[0] == 0x00) + { + + unsigned int d_offset = 1; + effect_num = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + } + if (!islock_conn) + { + conn_obj->back_edit_conn(std::move(edit_conn)); + } + return effect_num; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + return 0; + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + return 0; + } + + asio::awaitable async_remove() + { + effect_num = 0; + if (wheresql.empty()) + { + if (B_BASE::getPK() > 0) + { + std::ostringstream tempsql; + tempsql << " "; + tempsql << B_BASE::getPKname(); + tempsql << " = '"; + tempsql << B_BASE::getPK(); + tempsql << "' "; + wheresql = tempsql.str(); + } + else + { + co_return 0; + } + } + + sqlstring = "DELETE FROM "; + sqlstring.append(B_BASE::tablename); + sqlstring.append(" WHERE "); + + if (wheresql.empty()) + { + co_return 0; + } + else + { + sqlstring.append(wheresql); + } + if (!groupsql.empty()) + { + sqlstring.append(groupsql); + } + if (!ordersql.empty()) + { + sqlstring.append(ordersql); + } + if (!limitsql.empty()) + { + sqlstring.append(limitsql); + } + + if (iscommit) + { + iscommit = false; + co_return 0; + } + + if (iserror) + { + co_return 0; + } + + try + { + if (conn_empty()) + { + co_return 0; + } + + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = co_await conn_obj->async_get_edit_conn(); + } + } + else + { + edit_conn = co_await conn_obj->async_get_edit_conn(); + } + + if (edit_conn->isdebug) + { + edit_conn->begin_time(); + } + std::size_t n = co_await edit_conn->async_write_sql(sqlstring); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + co_return 0; + } + + unsigned int offset = 0; + n = co_await edit_conn->async_read_loop(); + if (n == 0) + { + edit_conn.reset(); + co_return 0; + } + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + edit_conn->read_field_pack(edit_conn->_cache_data, n, offset, temp_pack_data); + if (edit_conn->isdebug) + { + edit_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = edit_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + + if ((unsigned char)temp_pack_data.data[0] == 0xFF) + { + error_msg = temp_pack_data.data.substr(3); + } + else if ((unsigned char)temp_pack_data.data[0] == 0x00) + { + + unsigned int d_offset = 1; + effect_num = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + } + if (!islock_conn) + { + conn_obj->back_edit_conn(std::move(edit_conn)); + } + co_return effect_num; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + co_return 0; + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + co_return 0; + } + + int remove(long long id) + { + effect_num = 0; + sqlstring = "DELETE FROM "; + sqlstring.append(B_BASE::tablename); + sqlstring.append(" WHERE "); + + sqlstring.append(B_BASE::getPKname()); + sqlstring.append("="); + sqlstring.append(std::to_string(id)); + + if (iscommit) + { + iscommit = false; + return 0; + } + + if (iserror) + { + return 0; + } + + try + { + if (conn_empty()) + { + return 0; + } + //auto conn = conn_obj->get_edit_conn(); + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = conn_obj->get_edit_conn(); + } + } + else + { + edit_conn = conn_obj->get_edit_conn(); + } + + if (edit_conn->isdebug) + { + edit_conn->begin_time(); + } + std::size_t n = edit_conn->write_sql(sqlstring); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return 0; + } + + unsigned int offset = 0; + n = edit_conn->read_loop(); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return 0; + } + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + edit_conn->read_field_pack(edit_conn->_cache_data, n, offset, temp_pack_data); + if (edit_conn->isdebug) + { + edit_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = edit_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + + if ((unsigned char)temp_pack_data.data[0] == 0xFF) + { + error_msg = temp_pack_data.data.substr(3); + } + else if ((unsigned char)temp_pack_data.data[0] == 0x00) + { + + unsigned int d_offset = 1; + effect_num = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + } + if (!islock_conn) + { + conn_obj->back_edit_conn(std::move(edit_conn)); + } + return effect_num; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + return 0; + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + return 0; + } + + asio::awaitable async_remove(long long id) + { + effect_num = 0; + sqlstring = "DELETE FROM "; + sqlstring.append(B_BASE::tablename); + sqlstring.append(" WHERE "); + + sqlstring.append(B_BASE::getPKname()); + sqlstring.append("="); + sqlstring.append(std::to_string(id)); + + if (iscommit) + { + iscommit = false; + co_return 0; + } + + if (iserror) + { + co_return 0; + } + + try + { + if (conn_empty()) + { + co_return 0; + } + + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = co_await conn_obj->async_get_edit_conn(); + } + } + else + { + edit_conn = co_await conn_obj->async_get_edit_conn(); + } + + if (edit_conn->isdebug) + { + edit_conn->begin_time(); + } + std::size_t n = co_await edit_conn->async_write_sql(sqlstring); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + co_return 0; + } + + unsigned int offset = 0; + n = co_await edit_conn->async_read_loop(); + if (n == 0) + { + edit_conn.reset(); + co_return 0; + } + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + edit_conn->read_field_pack(edit_conn->_cache_data, n, offset, temp_pack_data); + if (edit_conn->isdebug) + { + edit_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = edit_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + + if ((unsigned char)temp_pack_data.data[0] == 0xFF) + { + error_msg = temp_pack_data.data.substr(3); + } + else if ((unsigned char)temp_pack_data.data[0] == 0x00) + { + + unsigned int d_offset = 1; + effect_num = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + } + if (!islock_conn) + { + conn_obj->back_edit_conn(std::move(edit_conn)); + } + co_return effect_num; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + co_return 0; + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + co_return 0; + } + + int soft_remove(const std::string &fieldsql) + { + effect_num = 0; + if (wheresql.empty()) + { + if (B_BASE::getPK() > 0) + { + std::ostringstream tempsql; + tempsql << " "; + tempsql << B_BASE::getPKname(); + tempsql << " = '"; + tempsql << B_BASE::getPK(); + tempsql << "' "; + wheresql = tempsql.str(); + } + else + { + return 0; + } + } + + sqlstring = B_BASE::soft_remove_sql(fieldsql); + if (sqlstring.empty()) + { + error_msg = "soft delete field empty."; + return 0; + } + sqlstring.append(" where "); + if (wheresql.empty()) + { + return 0; + } + else + { + sqlstring.append(wheresql); + } + if (!groupsql.empty()) + { + sqlstring.append(groupsql); + } + if (!ordersql.empty()) + { + sqlstring.append(ordersql); + } + if (!limitsql.empty()) + { + sqlstring.append(limitsql); + } + + if (iscommit) + { + iscommit = false; + return 0; + } + + if (iserror) + { + return 0; + } + + try + { + if (conn_empty()) + { + return 0; + } + //auto conn = conn_obj->get_edit_conn(); + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = conn_obj->get_edit_conn(); + } + } + else + { + edit_conn = conn_obj->get_edit_conn(); + } + + if (edit_conn->isdebug) + { + edit_conn->begin_time(); + } + std::size_t n = edit_conn->write_sql(sqlstring); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return 0; + } + + unsigned int offset = 0; + n = edit_conn->read_loop(); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return 0; + } + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + edit_conn->read_field_pack(edit_conn->_cache_data, n, offset, temp_pack_data); + if (edit_conn->isdebug) + { + edit_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = edit_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + + if ((unsigned char)temp_pack_data.data[0] == 0xFF) + { + error_msg = temp_pack_data.data.substr(3); + } + else if ((unsigned char)temp_pack_data.data[0] == 0x00) + { + + unsigned int d_offset = 1; + effect_num = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + } + if (!islock_conn) + { + conn_obj->back_edit_conn(std::move(edit_conn)); + } + return effect_num; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + return 0; + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + return 0; + } + int soft_remove() + { + effect_num = 0; + if (wheresql.empty()) + { + if (B_BASE::getPK() > 0) + { + std::ostringstream tempsql; + effect_num = 1; + tempsql << " "; + tempsql << B_BASE::getPKname(); + tempsql << " = '"; + tempsql << B_BASE::getPK(); + tempsql << "' "; + wheresql = tempsql.str(); + } + else + { + return 0; + } + } + if (effect_num == 1) + { + sqlstring = B_BASE::soft_remove_sql(" "); + } + else + { + sqlstring = B_BASE::soft_remove_sql(""); + } + effect_num = 0; + if (sqlstring.empty()) + { + error_msg = "soft delete field empty."; + return 0; + } + sqlstring.append(" where "); + if (wheresql.empty()) + { + return 0; + } + else + { + sqlstring.append(wheresql); + } + if (!groupsql.empty()) + { + sqlstring.append(groupsql); + } + if (!ordersql.empty()) + { + sqlstring.append(ordersql); + } + if (!limitsql.empty()) + { + sqlstring.append(limitsql); + } + + if (iscommit) + { + iscommit = false; + return 0; + } + + if (iserror) + { + return 0; + } + + try + { + if (conn_empty()) + { + return 0; + } + //auto conn = conn_obj->get_edit_conn(); + + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = conn_obj->get_edit_conn(); + } + } + else + { + edit_conn = conn_obj->get_edit_conn(); + } + + if (edit_conn->isdebug) + { + edit_conn->begin_time(); + } + std::size_t n = edit_conn->write_sql(sqlstring); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return 0; + } + + unsigned int offset = 0; + n = edit_conn->read_loop(); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return 0; + } + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + edit_conn->read_field_pack(edit_conn->_cache_data, n, offset, temp_pack_data); + if (edit_conn->isdebug) + { + edit_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = edit_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + + if ((unsigned char)temp_pack_data.data[0] == 0xFF) + { + error_msg = temp_pack_data.data.substr(3); + } + else if ((unsigned char)temp_pack_data.data[0] == 0x00) + { + + unsigned int d_offset = 1; + effect_num = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + } + if (!islock_conn) + { + conn_obj->back_edit_conn(std::move(edit_conn)); + } + return effect_num; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + return 0; + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + return 0; + } + std::tuple insert(typename B_BASE::meta &insert_data) + { + effect_num = 0; + sqlstring = B_BASE::_makerecordinsertsql(insert_data); + if (iscommit) + { + iscommit = false; + return std::make_tuple(0, 0); + } + + if (iserror) + { + return std::make_tuple(0, 0); + } + + try + { + if (conn_empty()) + { + return std::make_tuple(0, 0); + } + //auto conn = conn_obj->get_edit_conn(); + + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = conn_obj->get_edit_conn(); + } + } + else + { + edit_conn = conn_obj->get_edit_conn(); + } + + if (edit_conn->isdebug) + { + edit_conn->begin_time(); + } + std::size_t n = edit_conn->write_sql(sqlstring); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return std::make_tuple(0, 0); + } + + unsigned int offset = 0; + n = edit_conn->read_loop(); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return std::make_tuple(0, 0); + } + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + edit_conn->read_field_pack(edit_conn->_cache_data, n, offset, temp_pack_data); + if (edit_conn->isdebug) + { + edit_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = edit_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + + long long insert_last_id = 0; + if ((unsigned char)temp_pack_data.data[0] == 0xFF) + { + error_msg = temp_pack_data.data.substr(3); + } + else if ((unsigned char)temp_pack_data.data[0] == 0x00) + { + + unsigned int d_offset = 1; + effect_num = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + insert_last_id = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + B_BASE::setPK(insert_last_id); + } + if (!islock_conn) + { + conn_obj->back_edit_conn(std::move(edit_conn)); + } + //return insert_last_id; + return std::make_tuple(effect_num, insert_last_id); + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + return std::make_tuple(0, 0); + } + + asio::awaitable> async_insert(typename B_BASE::meta &insert_data) + { + effect_num = 0; + sqlstring = B_BASE::_makerecordinsertsql(insert_data); + if (iscommit) + { + iscommit = false; + co_return std::make_tuple(0, 0); + } + + if (iserror) + { + co_return std::make_tuple(0, 0); + } + + try + { + if (conn_empty()) + { + co_return std::make_tuple(0, 0); + } + + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = co_await conn_obj->async_get_edit_conn(); + } + } + else + { + edit_conn = co_await conn_obj->async_get_edit_conn(); + } + + if (edit_conn->isdebug) + { + edit_conn->begin_time(); + } + std::size_t n = co_await edit_conn->async_write_sql(sqlstring); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + co_return std::make_tuple(0, 0); + } + + unsigned int offset = 0; + n = co_await edit_conn->async_read_loop(); + if (n == 0) + { + edit_conn.reset(); + co_return std::make_tuple(0, 0); + } + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + edit_conn->read_field_pack(edit_conn->_cache_data, n, offset, temp_pack_data); + if (edit_conn->isdebug) + { + edit_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = edit_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + + long long insert_last_id = 0; + if ((unsigned char)temp_pack_data.data[0] == 0xFF) + { + error_msg = temp_pack_data.data.substr(3); + } + else if ((unsigned char)temp_pack_data.data[0] == 0x00) + { + + unsigned int d_offset = 1; + effect_num = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + insert_last_id = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + B_BASE::setPK(insert_last_id); + } + if (!islock_conn) + { + conn_obj->back_edit_conn(std::move(edit_conn)); + } + //co_return insert_last_id; + co_return std::make_tuple(effect_num, insert_last_id); + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + co_return std::make_tuple(0, 0); + } + + std::tuple insert(std::vector &insert_data) + { + effect_num = 0; + sqlstring = B_BASE::_makerecordinsertsql(insert_data); + if (iscommit) + { + iscommit = false; + return std::make_tuple(0, 0); + } + + if (iserror) + { + return std::make_tuple(0, 0); + } + + try + { + if (conn_empty()) + { + return std::make_tuple(0, 0); + } + //auto conn = conn_obj->get_edit_conn(); + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = conn_obj->get_edit_conn(); + } + } + else + { + edit_conn = conn_obj->get_edit_conn(); + } + + if (edit_conn->isdebug) + { + edit_conn->begin_time(); + } + std::size_t n = edit_conn->write_sql(sqlstring); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return std::make_tuple(0, 0); + } + + unsigned int offset = 0; + n = edit_conn->read_loop(); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return std::make_tuple(0, 0); + } + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + edit_conn->read_field_pack(edit_conn->_cache_data, n, offset, temp_pack_data); + if (edit_conn->isdebug) + { + edit_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = edit_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + + long long insert_last_id = 0; + if ((unsigned char)temp_pack_data.data[0] == 0xFF) + { + error_msg = temp_pack_data.data.substr(3); + } + else if ((unsigned char)temp_pack_data.data[0] == 0x00) + { + + unsigned int d_offset = 1; + effect_num = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + insert_last_id = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + B_BASE::setPK(insert_last_id); + } + if (!islock_conn) + { + conn_obj->back_edit_conn(std::move(edit_conn)); + } + //return insert_last_id; + return std::make_tuple(effect_num, insert_last_id); + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + return std::make_tuple(0, 0); + } + + asio::awaitable> async_insert(std::vector &insert_data) + { + effect_num = 0; + sqlstring = B_BASE::_makerecordinsertsql(insert_data); + if (iscommit) + { + iscommit = false; + co_return std::make_tuple(0, 0); + } + + if (iserror) + { + co_return std::make_tuple(0, 0); + } + + try + { + if (conn_empty()) + { + co_return std::make_tuple(0, 0); + } + + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = co_await conn_obj->async_get_edit_conn(); + } + } + else + { + edit_conn = co_await conn_obj->async_get_edit_conn(); + } + + if (edit_conn->isdebug) + { + edit_conn->begin_time(); + } + std::size_t n = co_await edit_conn->async_write_sql(sqlstring); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + co_return std::make_tuple(0, 0); + } + + unsigned int offset = 0; + n = co_await edit_conn->async_read_loop(); + if (n == 0) + { + edit_conn.reset(); + co_return std::make_tuple(0, 0); + } + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + edit_conn->read_field_pack(edit_conn->_cache_data, n, offset, temp_pack_data); + if (edit_conn->isdebug) + { + edit_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = edit_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + + long long insert_last_id = 0; + if ((unsigned char)temp_pack_data.data[0] == 0xFF) + { + error_msg = temp_pack_data.data.substr(3); + } + else if ((unsigned char)temp_pack_data.data[0] == 0x00) + { + unsigned int d_offset = 1; + effect_num = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + insert_last_id = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + B_BASE::setPK(insert_last_id); + } + if (!islock_conn) + { + conn_obj->back_edit_conn(std::move(edit_conn)); + } + //co_return insert_last_id; + co_return std::make_tuple(effect_num, insert_last_id); + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + co_return std::make_tuple(0, 0); + } + + std::tuple insert() + { + effect_num = 0; + sqlstring = B_BASE::_makeinsertsql(); + if (iscommit) + { + iscommit = false; + return std::make_tuple(0, 0); + } + + if (iserror) + { + return std::make_tuple(0, 0); + } + + try + { + if (conn_empty()) + { + return std::make_tuple(0, 0); + } + //auto conn = conn_obj->get_edit_conn(); + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = conn_obj->get_edit_conn(); + } + } + else + { + edit_conn = conn_obj->get_edit_conn(); + } + + if (edit_conn->isdebug) + { + edit_conn->begin_time(); + } + std::size_t n = edit_conn->write_sql(sqlstring); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return std::make_tuple(0, 0); + } + + unsigned int offset = 0; + n = edit_conn->read_loop(); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return std::make_tuple(0, 0); + } + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + edit_conn->read_field_pack(edit_conn->_cache_data, n, offset, temp_pack_data); + if (edit_conn->isdebug) + { + edit_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = edit_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + + long long insert_last_id = 0; + if ((unsigned char)temp_pack_data.data[0] == 0xFF) + { + error_msg = temp_pack_data.data.substr(3); + } + else if ((unsigned char)temp_pack_data.data[0] == 0x00) + { + unsigned int d_offset = 1; + effect_num = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + insert_last_id = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + B_BASE::setPK(insert_last_id); + } + if (!islock_conn) + { + conn_obj->back_edit_conn(std::move(edit_conn)); + } + //return insert_last_id; + return std::make_tuple(effect_num, insert_last_id); + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + return std::make_tuple(0, 0); + } + + asio::awaitable> async_insert() + { + effect_num = 0; + sqlstring = B_BASE::_makeinsertsql(); + if (iscommit) + { + iscommit = false; + co_return std::make_tuple(0, 0); + } + + if (iserror) + { + co_return std::make_tuple(0, 0); + } + + try + { + if (conn_empty()) + { + co_return std::make_tuple(0, 0); + } + + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = co_await conn_obj->async_get_edit_conn(); + } + } + else + { + edit_conn = co_await conn_obj->async_get_edit_conn(); + } + + if (edit_conn->isdebug) + { + edit_conn->begin_time(); + } + std::size_t n = co_await edit_conn->async_write_sql(sqlstring); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + co_return std::make_tuple(0, 0); + } + + unsigned int offset = 0; + n = co_await edit_conn->async_read_loop(); + if (n == 0) + { + edit_conn.reset(); + co_return std::make_tuple(0, 0); + } + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + edit_conn->read_field_pack(edit_conn->_cache_data, n, offset, temp_pack_data); + if (edit_conn->isdebug) + { + edit_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = edit_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + + long long insert_last_id = 0; + if ((unsigned char)temp_pack_data.data[0] == 0xFF) + { + error_msg = temp_pack_data.data.substr(3); + } + else if ((unsigned char)temp_pack_data.data[0] == 0x00) + { + + unsigned int d_offset = 1; + effect_num = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + insert_last_id = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + B_BASE::setPK(insert_last_id); + } + if (!islock_conn) + { + conn_obj->back_edit_conn(std::move(edit_conn)); + } + //co_return insert_last_id; + co_return std::make_tuple(effect_num, insert_last_id); + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + co_return std::make_tuple(0, 0); + } + + std::tuple save(bool isrealnew = false) + { + effect_num = 0; + if (B_BASE::getPK() > 0 && isrealnew == false) + { + if (wheresql.empty()) + { + std::ostringstream tempsql; + tempsql << " "; + tempsql << B_BASE::getPKname(); + tempsql << " = '"; + tempsql << B_BASE::getPK(); + tempsql << "' "; + wheresql = tempsql.str(); + } + sqlstring = B_BASE::_makeupdatesql(""); + sqlstring.append(" where "); + if (wheresql.empty()) + { + return std::make_tuple(0, 0); + } + else + { + sqlstring.append(wheresql); + } + if (!groupsql.empty()) + { + sqlstring.append(groupsql); + } + if (!ordersql.empty()) + { + sqlstring.append(ordersql); + } + if (!limitsql.empty()) + { + sqlstring.append(limitsql); + } + if (iscommit) + { + iscommit = false; + return std::make_tuple(0, 0); + } + + if (iserror) + { + return std::make_tuple(0, 0); + } + if (conn_empty()) + { + return std::make_tuple(0, 0); + } + //auto conn = conn_obj->get_edit_conn(); + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = conn_obj->get_edit_conn(); + } + } + else + { + edit_conn = conn_obj->get_edit_conn(); + } + + if (edit_conn->isdebug) + { + edit_conn->begin_time(); + } + std::size_t n = edit_conn->write_sql(sqlstring); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return std::make_tuple(0, 0); + } + + unsigned int offset = 0; + n = edit_conn->read_loop(); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return std::make_tuple(0, 0); + } + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + edit_conn->read_field_pack(edit_conn->_cache_data, n, offset, temp_pack_data); + if (edit_conn->isdebug) + { + edit_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = edit_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + + if ((unsigned char)temp_pack_data.data[0] == 0xFF) + { + error_msg = temp_pack_data.data.substr(3); + } + else if ((unsigned char)temp_pack_data.data[0] == 0x00) + { + + unsigned int d_offset = 1; + effect_num = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + } + if (!islock_conn) + { + conn_obj->back_edit_conn(std::move(edit_conn)); + } + //return effect_num; + return std::make_tuple(effect_num, 0); + } + else + { + sqlstring = B_BASE::_makeinsertsql(); + if (conn_empty()) + { + return std::make_tuple(0, 0); + } + //auto conn = conn_obj->get_edit_conn(); + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = conn_obj->get_edit_conn(); + } + } + else + { + edit_conn = conn_obj->get_edit_conn(); + } + + if (edit_conn->isdebug) + { + edit_conn->begin_time(); + } + std::size_t n = edit_conn->write_sql(sqlstring); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return std::make_tuple(0, 0); + } + + unsigned int offset = 0; + n = edit_conn->read_loop(); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return std::make_tuple(0, 0); + } + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + edit_conn->read_field_pack(edit_conn->_cache_data, n, offset, temp_pack_data); + if (edit_conn->isdebug) + { + edit_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = edit_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + + long long insert_last_id = 0; + if ((unsigned char)temp_pack_data.data[0] == 0xFF) + { + error_msg = temp_pack_data.data.substr(3); + } + else if ((unsigned char)temp_pack_data.data[0] == 0x00) + { + + unsigned int d_offset = 1; + effect_num = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + insert_last_id = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + B_BASE::setPK(insert_last_id); + } + if (!islock_conn) + { + conn_obj->back_edit_conn(std::move(edit_conn)); + } + //return insert_last_id; + return std::make_tuple(effect_num, insert_last_id); + } + return std::make_tuple(0, 0); + } + + asio::awaitable> async_save(bool isrealnew = false) + { + effect_num = 0; + if (B_BASE::getPK() > 0 && isrealnew == false) + { + if (wheresql.empty()) + { + std::ostringstream tempsql; + tempsql << " "; + tempsql << B_BASE::getPKname(); + tempsql << " = '"; + tempsql << B_BASE::getPK(); + tempsql << "' "; + wheresql = tempsql.str(); + } + sqlstring = B_BASE::_makeupdatesql(""); + sqlstring.append(" where "); + if (wheresql.empty()) + { + co_return std::make_tuple(0, 0); + } + else + { + sqlstring.append(wheresql); + } + if (!groupsql.empty()) + { + sqlstring.append(groupsql); + } + if (!ordersql.empty()) + { + sqlstring.append(ordersql); + } + if (!limitsql.empty()) + { + sqlstring.append(limitsql); + } + if (iscommit) + { + iscommit = false; + co_return std::make_tuple(0, 0); + } + + if (iserror) + { + co_return std::make_tuple(0, 0); + } + + try + { + if (conn_empty()) + { + co_return std::make_tuple(0, 0); + } + + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = co_await conn_obj->async_get_edit_conn(); + } + } + else + { + edit_conn = co_await conn_obj->async_get_edit_conn(); + } + + if (edit_conn->isdebug) + { + edit_conn->begin_time(); + } + std::size_t n = co_await edit_conn->async_write_sql(sqlstring); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + co_return std::make_tuple(0, 0); + } + + unsigned int offset = 0; + n = co_await edit_conn->async_read_loop(); + if (n == 0) + { + edit_conn.reset(); + co_return std::make_tuple(0, 0); + } + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + edit_conn->read_field_pack(edit_conn->_cache_data, n, offset, temp_pack_data); + if (edit_conn->isdebug) + { + edit_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = edit_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + + if ((unsigned char)temp_pack_data.data[0] == 0xFF) + { + error_msg = temp_pack_data.data.substr(3); + iserror = true; + } + else if ((unsigned char)temp_pack_data.data[0] == 0x00) + { + + unsigned int d_offset = 1; + effect_num = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + } + if (!islock_conn) + { + conn_obj->back_edit_conn(std::move(edit_conn)); + } + co_return std::make_tuple(effect_num, 0); + //co_return effect_num; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + co_return std::make_tuple(0, 0); + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + co_return std::make_tuple(0, 0); + } + co_return std::make_tuple(0, 0); + } + else + { + sqlstring = B_BASE::_makeinsertsql(); + try + { + if (conn_empty()) + { + co_return std::make_tuple(0, 0); + } + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = co_await conn_obj->async_get_edit_conn(); + } + } + else + { + edit_conn = co_await conn_obj->async_get_edit_conn(); + } + + if (edit_conn->isdebug) + { + edit_conn->begin_time(); + } + std::size_t n = co_await edit_conn->async_write_sql(sqlstring); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + co_return std::make_tuple(0, 0); + } + + unsigned int offset = 0; + n = co_await edit_conn->async_read_loop(); + if (n == 0) + { + edit_conn.reset(); + co_return std::make_tuple(0, 0); + } + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + edit_conn->read_field_pack(edit_conn->_cache_data, n, offset, temp_pack_data); + if (edit_conn->isdebug) + { + edit_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = edit_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + + long long insert_last_id = 0; + if ((unsigned char)temp_pack_data.data[0] == 0xFF) + { + error_msg = temp_pack_data.data.substr(3); + } + else if ((unsigned char)temp_pack_data.data[0] == 0x00) + { + + unsigned int d_offset = 1; + effect_num = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + insert_last_id = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + B_BASE::setPK(insert_last_id); + } + if (!islock_conn) + { + conn_obj->back_edit_conn(std::move(edit_conn)); + } + co_return std::make_tuple(effect_num, insert_last_id); + //co_return insert_last_id; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + co_return std::make_tuple(0, 0); + } + co_return std::make_tuple(0, 0); + } + + std::tuple, std::map, std::vector>> + query(const std::string &rawsql) + { + effect_num = 0; + std::vector> temprecord; + std::vector table_fieldname; + std::map table_fieldmap; + + if (rawsql.size() > 10) + { + unsigned int i = 0; + for (; i < rawsql.size(); i++) + { + if (rawsql[i] != 0x20) + { + break; + } + } + if (i < 5) + { + //must be select + if (rawsql[i] != 's' && rawsql[i] != 'S') + { + error_msg = "Query sql string must be select."; + iserror = true; + } + } + else + { + iserror = true; + } + } + else + { + iserror = true; + } + + if (iserror) + { + return std::make_tuple(table_fieldname, table_fieldmap, temprecord); + } + + try + { + if (conn_empty()) + { + return std::make_tuple(table_fieldname, table_fieldmap, temprecord); + } + //auto conn = conn_obj->get_select_conn(); + if (islock_conn) + { + if (!select_conn) + { + select_conn = conn_obj->get_select_conn(); + } + } + else + { + select_conn = conn_obj->get_select_conn(); + } + + if (select_conn->isdebug) + { + select_conn->begin_time(); + } + std::size_t n = select_conn->write_sql(rawsql); + if (n == 0) + { + error_msg = select_conn->error_msg; + select_conn.reset(); + return std::make_tuple(table_fieldname, table_fieldmap, temprecord); + } + + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + bool is_sql_item = false; + std::vector field_array; + + unsigned char action_setup = 0; + unsigned int column_num = 0; + + unsigned int offset = 0; + + std::vector field_pos; + + for (; is_sql_item == false;) + { + n = select_conn->read_loop(); + offset = 0; + if (n == 0) + { + error_msg = select_conn->error_msg; + select_conn.reset(); + return std::make_tuple(table_fieldname, table_fieldmap, temprecord); + } + for (; offset < n;) + { + select_conn->read_field_pack(select_conn->_cache_data, n, offset, temp_pack_data); + if (temp_pack_data.error > 0) + { + iserror = true; + error_msg = temp_pack_data.data; + select_conn.reset(); + return std::make_tuple(table_fieldname, table_fieldmap, temprecord); + } + if (temp_pack_data.length == temp_pack_data.current_length && temp_pack_data.current_length > 0) + { + if (select_conn->pack_eof_check(temp_pack_data)) + { + is_sql_item = true; + break; + } + + if (action_setup == 0) + { + if (temp_pack_data.length == 2 && (unsigned char)temp_pack_data.data[0] < 251 && (unsigned char)temp_pack_data.data[0] > 0) + { + action_setup = 1; + column_num = (unsigned char)temp_pack_data.data[0]; + } + } + else if (action_setup == 1) + { + field_info_t temp_filed_col; + select_conn->read_col_info(temp_pack_data.data, temp_filed_col); + + field_array.emplace_back(std::move(temp_filed_col)); + column_num--; + if (column_num == 0) + { + action_setup = 2; + for (unsigned int ii = 0; ii < field_array.size(); ii++) + { + field_pos.push_back(B_BASE::findcolpos(field_array[ii].org_name)); + table_fieldmap.emplace(field_array[ii].org_name, table_fieldname.size()); + table_fieldname.push_back(field_array[ii].org_name); + } + } + } + else if (action_setup == 2) + { + unsigned int column_num = field_array.size(); + unsigned int tempnum = 0; + + std::vector temp_v_record; + for (unsigned int ij = 0; ij < column_num; ij++) + { + unsigned long long name_length = 0; + name_length = select_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], tempnum); + std::string tempstr; + tempstr.resize(name_length); + std::memcpy(tempstr.data(), (unsigned char *)&temp_pack_data.data[tempnum], name_length); + temp_v_record.push_back(std::move(tempstr)); + tempnum = tempnum + name_length; + } + temprecord.push_back(temp_v_record); + effect_num++; + } + } + else + { + if (offset >= n) + { + break; + } + is_sql_item = true; + break; + } + } + } + if (select_conn->isdebug) + { + select_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = select_conn->count_time(); + conn_mar.push_log(rawsql, std::to_string(du_time)); + } + if (!islock_conn) + { + conn_obj->back_select_conn(std::move(select_conn)); + } + return std::make_tuple(std::move(table_fieldname), std::move(table_fieldmap), std::move(temprecord)); + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + return std::make_tuple(table_fieldname, table_fieldmap, temprecord); + } + + asio::awaitable, std::map, std::vector>>> + async_query(const std::string &rawsql) + { + effect_num = 0; + std::vector> temprecord; + std::vector table_fieldname; + std::map table_fieldmap; + + if (rawsql.size() > 10) + { + unsigned int i = 0; + for (; i < rawsql.size(); i++) + { + if (rawsql[i] != 0x20) + { + break; + } + } + if (i < 5) + { + //must be select + if (rawsql[i] != 's' && rawsql[i] != 'S') + { + error_msg = "Query sql string must be select."; + iserror = true; + } + } + else + { + iserror = true; + } + } + else + { + iserror = true; + } + + if (iserror) + { + co_return std::make_tuple(table_fieldname, table_fieldmap, temprecord); + } + + try + { + if (conn_empty()) + { + co_return std::make_tuple(table_fieldname, table_fieldmap, temprecord); + } + if (islock_conn) + { + if (!select_conn) + { + select_conn = co_await conn_obj->async_get_select_conn(); + } + } + else + { + select_conn = co_await conn_obj->async_get_select_conn(); + } + + if (select_conn->isdebug) + { + select_conn->begin_time(); + } + std::size_t n = co_await select_conn->async_write_sql(rawsql); + if (n == 0) + { + error_msg = select_conn->error_msg; + select_conn.reset(); + co_return std::make_tuple(table_fieldname, table_fieldmap, temprecord); + } + + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + bool is_sql_item = false; + std::vector field_array; + + unsigned char action_setup = 0; + unsigned int column_num = 0; + + unsigned int offset = 0; + + std::vector field_pos; + + for (; is_sql_item == false;) + { + n = co_await select_conn->async_read_loop(); + offset = 0; + if (n == 0) + { + select_conn.reset(); + co_return std::make_tuple(table_fieldname, table_fieldmap, temprecord); + } + for (; offset < n;) + { + select_conn->read_field_pack(select_conn->_cache_data, n, offset, temp_pack_data); + if (temp_pack_data.error > 0) + { + iserror = true; + error_msg = temp_pack_data.data; + select_conn.reset(); + co_return std::make_tuple(table_fieldname, table_fieldmap, temprecord); + } + if (temp_pack_data.length == temp_pack_data.current_length && temp_pack_data.current_length > 0) + { + if (select_conn->pack_eof_check(temp_pack_data)) + { + is_sql_item = true; + break; + } + + if (action_setup == 0) + { + if (temp_pack_data.length == 2 && (unsigned char)temp_pack_data.data[0] < 251 && (unsigned char)temp_pack_data.data[0] > 0) + { + action_setup = 1; + column_num = (unsigned char)temp_pack_data.data[0]; + } + } + else if (action_setup == 1) + { + field_info_t temp_filed_col; + select_conn->read_col_info(temp_pack_data.data, temp_filed_col); + + field_array.emplace_back(std::move(temp_filed_col)); + column_num--; + if (column_num == 0) + { + action_setup = 2; + for (unsigned int ii = 0; ii < field_array.size(); ii++) + { + field_pos.push_back(B_BASE::findcolpos(field_array[ii].org_name)); + table_fieldmap.emplace(field_array[ii].org_name, table_fieldname.size()); + table_fieldname.push_back(field_array[ii].org_name); + } + } + } + else if (action_setup == 2) + { + unsigned int column_num = field_array.size(); + unsigned int tempnum = 0; + + std::vector temp_v_record; + for (unsigned int ij = 0; ij < column_num; ij++) + { + unsigned long long name_length = 0; + name_length = select_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], tempnum); + std::string tempstr; + tempstr.resize(name_length); + std::memcpy(tempstr.data(), (unsigned char *)&temp_pack_data.data[tempnum], name_length); + temp_v_record.push_back(std::move(tempstr)); + tempnum = tempnum + name_length; + } + temprecord.push_back(temp_v_record); + effect_num++; + } + } + else + { + if (offset >= n) + { + break; + } + is_sql_item = true; + break; + } + } + } + if (select_conn->isdebug) + { + select_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = select_conn->count_time(); + conn_mar.push_log(rawsql, std::to_string(du_time)); + } + if (!islock_conn) + { + conn_obj->back_select_conn(std::move(select_conn)); + } + co_return std::make_tuple(std::move(table_fieldname), std::move(table_fieldmap), std::move(temprecord)); + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + co_return std::make_tuple(table_fieldname, table_fieldmap, temprecord); + } + + // long long edit_query(const std::string &rawsql, bool isinsert = false) + // { + // if (iserror) + // { + // return 0; + // } + + // return 0; + // } + M_MODEL &clear(bool both = true) + { + selectsql.clear(); + wheresql.clear(); + ordersql.clear(); + groupsql.clear(); + limitsql.clear(); + sqlstring.clear(); + error_msg.clear(); + iskuohao = false; + ishascontent = false; + iscommit = false; + iscache = false; + iserror = false; + effect_num = 0; + if (both) + { + B_BASE::record_reset(); + B_BASE::data_reset(); + } + return *mod; + } + M_MODEL &clearWhere() + { + selectsql.clear(); + wheresql.clear(); + ordersql.clear(); + groupsql.clear(); + limitsql.clear(); + sqlstring.clear(); + error_msg.clear(); + iskuohao = false; + ishascontent = false; + iscommit = false; + iscache = false; + iserror = false; + effect_num = 0; + return *mod; + } + M_MODEL &set_data(typename B_BASE::meta indata) + { + B_BASE::data = indata; + return *mod; + } + M_MODEL &get() { return *mod; } + std::string get_query() { return sqlstring; } + + M_MODEL &begin_commit() + { + if (!conn_empty()) + { + return *mod; + } + islock_conn = true; + + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = conn_obj->get_edit_conn(); + } + } + else + { + edit_conn = conn_obj->get_edit_conn(); + } + sqlstring = "start transaction"; + edit_conn->write_sql(sqlstring); + iscommit = true; + + return *mod; + } + M_MODEL &rollback() + { + if (iscommit == false) + { + error_msg = "not begin_commit"; + iserror = true; + return *mod; + } + if (!conn_empty()) + { + return *mod; + } + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = conn_obj->get_edit_conn(); + } + } + else + { + edit_conn = conn_obj->get_edit_conn(); + } + sqlstring = "rollback"; + edit_conn->write_sql(sqlstring); + + iscommit = false; + islock_conn = false; + return *mod; + } + M_MODEL &commit() + { + if (iscommit == false) + { + error_msg = "not begin_commit"; + iserror = true; + return *mod; + } + if (!conn_empty()) + { + return *mod; + } + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = conn_obj->get_edit_conn(); + } + } + else + { + edit_conn = conn_obj->get_edit_conn(); + } + sqlstring = "commit"; + edit_conn->write_sql(sqlstring); + + iscommit = false; + islock_conn = false; + return *mod; + } + + asio::awaitable async_begin_commit() + { + if (!conn_empty()) + { + co_return false; + } + islock_conn = true; + + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = co_await conn_obj->async_get_edit_conn(); + } + } + else + { + edit_conn = co_await conn_obj->async_get_edit_conn(); + } + sqlstring = "start transaction"; + co_await edit_conn->async_write_sql(sqlstring); + iscommit = true; + + co_return false; + } + asio::awaitable async_rollback() + { + if (iscommit == false) + { + error_msg = "not begin_commit"; + iserror = true; + co_return false; + } + if (!conn_empty()) + { + co_return false; + } + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = co_await conn_obj->async_get_edit_conn(); + } + } + else + { + edit_conn = co_await conn_obj->async_get_edit_conn(); + } + sqlstring = "rollback"; + co_await edit_conn->async_write_sql(sqlstring); + + iscommit = false; + islock_conn = false; + co_return true; + } + + asio::awaitable async_commit() + { + if (iscommit == false) + { + error_msg = "not begin_commit"; + iserror = true; + co_return false; + } + if (!conn_empty()) + { + co_return false; + } + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = co_await conn_obj->async_get_edit_conn(); + } + } + else + { + edit_conn = co_await conn_obj->async_get_edit_conn(); + } + sqlstring = "commit"; + co_await edit_conn->async_write_sql(sqlstring); + + iscommit = false; + islock_conn = false; + co_return true; + } + + unsigned int effect() + { + return effect_num; + } + bool conn_empty() + { + if (conn_obj) + { + return false; + } + error_msg = "conn_obj is null"; + iserror = true; + return true; + } + void lock_conn() + { + islock_conn = true; + } + void unlock_conn() + { + islock_conn = false; + if (conn_obj) + { + if (select_conn) + { + conn_obj->back_select_conn(std::move(select_conn)); + } + if (edit_conn) + { + conn_obj->back_edit_conn(std::move(edit_conn)); + } + } + } + + public: + std::string selectsql; + std::string wheresql; + std::string ordersql; + std::string groupsql; + std::string limitsql; + std::string sqlstring; + std::string dbtag; + std::string error_msg; + std::string original_tablename; + + // std::list commit_sqllist; + bool iskuohao = false; + bool iscommit = false; + bool ishascontent = false; + bool iscache = false; + bool iserror = false; + bool islock_conn = false; + int exptime = 0; + unsigned int effect_num = 0; + + M_MODEL *mod; + + std::shared_ptr select_conn; + std::shared_ptr edit_conn; + std::shared_ptr conn_obj; + }; +//} /*tagnamespace_replace*/ +}// namespace orm +#endif \ No newline at end of file diff --git a/frameworks/C++/paozhu/paozhu_benchmark/orm/include/world_base.h b/frameworks/C++/paozhu/paozhu_benchmark/orm/include/world_base.h new file mode 100644 index 00000000000..7b620ca6952 --- /dev/null +++ b/frameworks/C++/paozhu/paozhu_benchmark/orm/include/world_base.h @@ -0,0 +1,2448 @@ +#ifndef ORM_DEFAULT_WORLDBASEMATA_H +#define ORM_DEFAULT_WORLDBASEMATA_H +/* +*This file is auto create from paozhu_cli +*本文件为自动生成 Sat, 26 Apr 2025 15:58:21 GMT +***/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "unicode.h" + +namespace orm { + + +struct world_base +{ + struct meta{ + unsigned int id = 0; ///**/ + int randomnumber = 0; ///**/ + } data; + std::vector record; +std::string _rmstag="default";//this value must be default or tag value, tag in mysqlconnect config file . +unsigned int _offset=0; +std::vector::iterator begin(){ return record.begin(); } +std::vector::iterator end(){ return record.end(); } +std::vector::const_iterator begin() const{ return record.begin(); } +std::vector::const_iterator end() const{ return record.end(); } +static constexpr std::array col_names={"id","randomnumber"}; +static constexpr std::array col_types={3,3}; +static constexpr std::array col_length={0,0}; +static constexpr std::array col_decimals={0,0}; +std::string tablename="world"; +static constexpr std::string_view modelname="World"; + + unsigned char findcolpos(const std::string &coln){ + if(coln.size()==0) + { + return 255; + } + unsigned char bi=coln[0]; + + + if(bi<91&&bi>64){ + bi+=32; + } + switch(coln[0]){ + + + case 'i': + return 0; +break; +case 'r': + return 1; +break; + + } + return 255; + } + + int size(){ return record.size(); } + + std::string getPKname(){ + return "id"; +} + + void record_reset() + { + record.clear(); + } + void data_reset(){ + world_base::meta metatemp; + data = metatemp; + } + + std::string soft_remove_sql([[maybe_unused]] const std::string &fieldsql){ + std::string temp; + + return temp; + } + + + inline std::string stringaddslash(const std::string &content){ + std::string temp; + for(unsigned int i=0;i0){ + tempsql<<"`,`"; + }else{ + tempsql<<"`"; + } + tempsql<0){ + tempsql<<"`"; + } + tempsql<<") VALUES ("; + + if(data.id==0){ +tempsql<<"null"; + }else{ + tempsql<0){ + tempsql<<"`,`"; + }else{ + tempsql<<"`"; + } + tempsql<0){ + tempsql<<"`"; + } + tempsql<<") VALUES ("; + + if(insert_data.id==0){ +tempsql<<"null"; + }else{ + tempsql< &insert_data){ + unsigned int j=0; + std::ostringstream tempsql; + tempsql<<"INSERT INTO "; + tempsql<0){ + tempsql<<"`,`"; + }else{ + tempsql<<"`"; + } + tempsql<0){ + tempsql<<"`"; + } + tempsql<<") VALUES "; + + for(unsigned int i=0;i0) + { + tempsql<<","; + } + tempsql<<"("; + + + if(insert_data[i].id==0){ + tempsql<<"null"; + }else{ + tempsql<0){ + unsigned char bpos_i=findcolpos(keyname); + #ifdef DEBUG + if (bpos_i == 255) + { + std::cout << "\033[1m\033[31m-----------\n" + << keyname << " not in " << tablename << " table Field.\n-----------\033[0m" + << std::endl; + } +#endif + keypos.emplace_back(bpos_i); + keyname.clear(); + } + for(jj=0;jj0){ tempsql<<","; } +if(data.id==0){ + tempsql<<"`id`=0"; + }else{ + tempsql<<"`id`="<0){ tempsql<<","; } +if(data.randomnumber==0){ + tempsql<<"`randomnumber`=0"; + }else{ + tempsql<<"`randomnumber`="< 0) + { + tempsql << "`,`"; + } + else + { + tempsql << "`"; + } + tempsql << col_names[j]; + } + if (j > 0) + { + tempsql << "`"; + } + tempsql << ") VALUES "; + + for (unsigned int i = 0; i < record.size(); i++) + { + if (i > 0) + { + tempsql << ",\n"; + } + tempsql << "("; + if(record[i].id==0){ + tempsql<<"null"; + }else{ + tempsql< 0) + { + tempsql << "`,`"; + } + else + { + tempsql << "`"; + } + tempsql << col_names[j]; + } + if (j > 0) + { + tempsql << "`"; + } + tempsql << ") VALUES "; + + for (unsigned int i = 0; i < record.size(); i++) + { + if (i > 0) + { + tempsql << ",\n"; + } + tempsql << "("; + if(record[i].id==0){ + tempsql<<"null"; + }else{ + tempsql<0){ + for(;jj0) + { + tempsql<<","; + } + tempsql<0){ + if(findcolpos(keyname)<255) + { + if(j>0) + { + tempsql<<","; + } + tempsql< data_toarray(std::string fileld=""){ + std::vector temparray; + std::string keyname; + unsigned char jj=0; + std::vector keypos; + if(fileld.size()>1){ + for(;jj0){ + keypos.emplace_back(findcolpos(keyname)); + keyname.clear(); + } + }else{ + for(jj=0;jj data_tomap(std::string fileld=""){ + std::map tempsql; + std::string keyname; + unsigned char jj=0; + std::vector keypos; + if(fileld.size()>1){ + for(;jj0){ + keypos.emplace_back(findcolpos(keyname)); + keyname.clear(); + } + }else{ + for(jj=0;jj keypos; + if(fileld.size()>0){ + for(;jj0){ + keypos.emplace_back(findcolpos(keyname)); + keyname.clear(); + } + }else{ + for(jj=0;jj0){ tempsql<<","; } +if(data.id==0){ + tempsql<<"\"id\":0"; + }else{ + tempsql<<"\"id\":"<0){ tempsql<<","; } +if(data.randomnumber==0){ + tempsql<<"\"randomnumber\":0"; + }else{ + tempsql<<"\"randomnumber\":"< list_content; + for(;json_offset0) + { + data=metatemp; + } + if(json_offset>=json_content.size()) + { + break; + } + for(;json_offset=json_content.size()) + { + break; + } + json_value_name.clear(); + if(json_content[json_offset]==0x22) + { + + temp_offset=json_offset; + json_value_name=http::jsonstring_to_utf8(&json_content[json_offset],json_content.size()-json_offset,temp_offset); + json_offset=temp_offset; + if(json_content[json_offset]==0x22) + { + json_offset+=1; + } + } + else + { + if(json_content[json_offset]!='{'&&json_content[json_offset]!=']') + { + for(;json_offset1) + { + data=record[0]; + } + } + else + { + if(json_content[json_offset]=='{') + { + json_offset+=1; + std::string json_key_name,json_value_name; + + + for(;json_offset=json_content.size()) + { + break; + } + json_value_name.clear(); + if(json_content[json_offset]==0x22) + { + + temp_offset=json_offset; + json_value_name=http::jsonstring_to_utf8(&json_content[json_offset],json_content.size()-json_offset,temp_offset); + json_offset=temp_offset; + if(json_content[json_offset]==0x22) + { + json_offset+=1; + } + } + else + { + if(json_content[json_offset]!='{'&&json_content[json_offset]!=']') + { + for(;json_offset keypos; + if(fileld.size()>0){ + for(;jj0){ + keypos.emplace_back(findcolpos(keyname)); + keyname.clear(); + } + }else{ + for(jj=0;jj0){ + tempsql<<",{"; + }else{ + tempsql<<"{"; + } + + for(jj=0;jj0){ tempsql<<","; } +if(record[n].id==0){ + tempsql<<"\"id\":0"; + }else{ + tempsql<<"\"id\":"<0){ tempsql<<","; } +if(record[n].randomnumber==0){ + tempsql<<"\"randomnumber\":0"; + }else{ + tempsql<<"\"randomnumber\":"< func,std::string fileld=""){ + std::ostringstream tempsql; + std::string keyname; + unsigned char jj=0; + std::vector keypos; + if(fileld.size()>0){ + for(;jj0){ + keypos.emplace_back(findcolpos(keyname)); + keyname.clear(); + } + }else{ + for(jj=0;jj0){ + tempsql<<",{"; + }else{ + tempsql<<"{"; + } + tempsql<0){ tempsql<<","; } +if(record[n].id==0){ + tempsql<<"\"id\":0"; + }else{ + tempsql<<"\"id\":"<0){ tempsql<<","; } +if(record[n].randomnumber==0){ + tempsql<<"\"randomnumber\":0"; + }else{ + tempsql<<"\"randomnumber\":"< getRecord(){ + return record; +} + + + template::value,bool>::type = true> + T& ref_meta([[maybe_unused]] std::string key_name) + { + return nullptr; + } + + + template,bool>::type = true> + T& ref_meta([[maybe_unused]] std::string key_name) + { + if(key_name=="id") + { + return data.id; + } + if(key_name=="randomnumber") + { + return data.randomnumber; + } + return nullptr; + } + + + template,bool>::type = true > + T& ref_meta([[maybe_unused]] std::string key_name) + { + return nullptr; + } + + template,bool>::type = true > + std::vector getCol([[maybe_unused]] std::string keyname) + { + std::vector a; + + + unsigned char kpos; + kpos=findcolpos(keyname); + for(auto &iter:record) + { + switch(kpos) + { + case 0: + a.emplace_back(iter.id); + break; + case 1: + a.emplace_back(iter.randomnumber); + break; + + } + } + + return a; + } + + template,bool>::type = true > + std::vector getCol([[maybe_unused]] std::string keyname) + { + std::vector a; + + + return a; + } + + template,bool>::type = true > + T getVal([[maybe_unused]] std::string keyname) + { + + unsigned char kpos; + kpos=findcolpos(keyname); + switch(kpos) + { + + case 0: + return data.id; + break; + case 1: + return data.randomnumber; + break; + } + return 0; + } + + template,bool>::type = true > + T getVal([[maybe_unused]] world_base::meta & iter,[[maybe_unused]] std::string keyname) + { + + + unsigned char kpos; + kpos=findcolpos(keyname); + switch(kpos) + { + case 0: + return iter.id; + break; + case 1: + return iter.randomnumber; + break; + + } + + return 0; + } + + template,bool>::type = true > + T getVal(std::string keyname) + { + unsigned char kpos; + kpos=findcolpos(keyname); + + switch(kpos) + { + + + } + + + return 0.0; + } + + template,bool>::type = true > + T getVal([[maybe_unused]] world_base::meta & iter,std::string keyname) + { + unsigned char kpos; + kpos=findcolpos(keyname); + switch(kpos) + { + + } + + + + return 0.0; + } + + template::value,bool>::type = true > + std::string getVal(std::string keyname) + { + unsigned char kpos; + kpos=findcolpos(keyname); + + switch(kpos) + { + + + } + return ""; + } + + template::value,bool>::type = true > + std::string getVal([[maybe_unused]] world_base::meta & iter,std::string keyname) + { + + unsigned char kpos; + kpos=findcolpos(keyname); + + switch(kpos) + { + + + } + + + + return ""; + } + + template::value,bool>::type = true > + std::vector getCol([[maybe_unused]] std::string keyname) + { + std::vector a; + + + + return a; + } + + std::string getstrCol(std::string keyname,[[maybe_unused]] bool isyinhao=false) + { + std::ostringstream a; + + unsigned char kpos; + kpos=findcolpos(keyname); + int j=0; + if(isyinhao&&record.size()>0) + { + a<<'"'; + } + for(auto &iter:record) + { + if(j>0) + { + if(isyinhao) + { + a<<"\",\""; + }else{ + a<<','; + } + } + switch(kpos) + { + + case 0: + a<0){ + a<<'"'; + } + + return a.str(); + } + + template::value,bool>::type = true,typename std::enable_if::value,bool>::type = true> + std::map getCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname) + { + std::map a; + + return a; + } + + + template::value,bool>::type = true, typename std::enable_if::value,bool>::type = true> + std::map getCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname) + { + std::map a; + + return a; + } + + template,bool>::type = true, typename std::enable_if::value,bool>::type = true> + std::map getCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname) + { + std::map a; + + unsigned char kpos,vpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + T ktemp; + U vtemp; + for(auto &iter:record) + { + switch(kpos) + { + + case 0: + ktemp=iter.id; + break; +case 1: + ktemp=iter.randomnumber; + break; + } + switch(vpos){ + + } + if(ktemp.size()>0) + { + a.emplace(ktemp,vtemp); + } + } + + return a; + } + template,bool>::type = true, typename std::enable_if::value,bool>::type = true> + std::map getCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname) + { + std::map a; + + unsigned char kpos,vpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + T ktemp; + std::string vtemp; + for(auto &iter:record) + { + switch(kpos) + { + + case 0: + ktemp=iter.id; + break; + case 1: + ktemp=iter.randomnumber; + break; + } + switch(vpos){ + + } + if(ktemp.size()>0) + { + a.emplace(ktemp,vtemp); + } + } + + return a; + } + + template::value,bool>::type = true,typename std::enable_if,bool>::type = true> + std::map getCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname) + { + std::map a; + + unsigned char kpos,vpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + std::string ktemp; + U vtemp; + for(auto &iter:record) + { + switch(kpos) + { + + } + switch(vpos){ + case 0: + vtemp=iter.id; + break; + case 1: + vtemp=iter.randomnumber; + break; + + } + if(ktemp.size()>0) + { + a.emplace(ktemp,vtemp); + } + } + + return a; + } + + template,bool>::type = true,typename std::enable_if,bool>::type = true> + std::map getCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname) + { + std::map a; + + unsigned char kpos,vpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + T ktemp; + U vtemp; + for(auto &iter:record) + { + switch(kpos) + { + + case 0: + ktemp=iter.id; + break; + case 1: + ktemp=iter.randomnumber; + break; + } + switch(vpos){ + case 0: + vtemp=iter.id; + break; + case 1: + vtemp=iter.randomnumber; + break; + + } + if(ktemp.size()>0) + { + a.emplace(ktemp,vtemp); + } + } + + return a; + } + + template,bool>::type = true > + std::map getmapRows([[maybe_unused]] std::string keyname) + { + std::map a; + + unsigned char kpos; + kpos=findcolpos(keyname); + for(auto &iter:record) + { + switch(kpos) + { + + case 0: + a.emplace(iter.id,iter); + break; + case 1: + a.emplace(iter.randomnumber,iter); + break; + + } + } + + return a; + } + + template::value,bool>::type = true > + std::map getmapRows([[maybe_unused]] std::string keyname) + { + std::map a; + + + + return a; + } + + template::value,bool>::type = true, typename std::enable_if::value,bool>::type = true> + std::vector> getvecCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname) + { + std::vector> a; + + + return a; + } + + template,bool>::type = true, typename std::enable_if::value,bool>::type = true> + std::vector> getvecCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname) + { + std::vector> a; + + unsigned char kpos,vpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + T ktemp; + U vtemp; + for(auto &iter:record) + { + switch(kpos) + { + + case 0: + ktemp=iter.id; + break; + case 1: + ktemp=iter.randomnumber; + break; + } + switch(vpos){ + + } + + a.emplace_back(ktemp,vtemp); + } + + + + return a; + } + + template,bool>::type = true, typename std::enable_if::value,bool>::type = true> + std::vector> getvecCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname) + { + std::vector> a; + + + unsigned char kpos,vpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + T ktemp; + U vtemp; + for(auto &iter:record) + { + switch(kpos) + { + + case 0: + ktemp=iter.id; + break; + case 1: + ktemp=iter.randomnumber; + break; + } + switch(vpos){ + + } + + a.emplace_back(ktemp,vtemp); + } + + return a; + } + + template::value,bool>::type = true,typename std::enable_if,bool>::type = true> + std::vector> getvecCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname) + { + std::vector> a; + + unsigned char kpos,vpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + T ktemp; + U vtemp; + for(auto &iter:record) + { + + switch(kpos) + { + + } + switch(vpos){ + case 0: + vtemp=iter.id; + break; + case 1: + vtemp=iter.randomnumber; + break; + + } + a.emplace_back(ktemp,vtemp); + } + + return a; + } + + template,bool>::type = true,typename std::enable_if,bool>::type = true> + std::vector> getvecCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname) + { + std::vector> a; + + unsigned char kpos,vpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + T ktemp; + U vtemp; + for(auto &iter:record) + { + switch(kpos) + { + + case 0: + ktemp=iter.id; + break; + case 1: + ktemp=iter.randomnumber; + break; + } + switch(vpos){ + case 0: + vtemp=iter.id; + break; + case 1: + vtemp=iter.randomnumber; + break; + + } + a.emplace_back(ktemp,vtemp); + } + + return a; + } + + template::value,bool>::type = true,typename std::enable_if::value,bool>::type = true> + std::vector> getvecCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname) + { + std::vector> a; + + return a; + } + + template,bool>::type = true > + std::vector> getvecRows([[maybe_unused]] std::string keyname) + { + std::vector> a; + + unsigned char kpos; + kpos=findcolpos(keyname); + for(auto &iter:record) + { + switch(kpos) + { + + case 0: + a.emplace_back(iter.id,iter); + break; +case 1: + a.emplace_back(iter.randomnumber,iter); + break; + + } + } + + return a; + } + template::value,bool>::type = true > + std::vector> getvecRows([[maybe_unused]] std::string keyname) + { + std::vector> a; + + + return a; + } + template,bool>::type = true,typename std::enable_if,bool>::type = true, typename std::enable_if::value,bool>::type = true> + std::map>> getgroupCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname,[[maybe_unused]] std::string dataname) + { + std::map>> a; + + unsigned char kpos,vpos,dpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + dpos=findcolpos(dataname); + T ktemp; + U vtemp; + for(auto &iter:record) + { + switch(kpos) + { + + case 0: + ktemp=iter.id; + break; + case 1: + ktemp=iter.randomnumber; + break; + } + + switch(vpos){ + case 0: + vtemp=iter.id; + break; + case 1: + vtemp=iter.randomnumber; + break; + } + + switch(dpos){ + + } + } + + + return a; + } + + template,bool>::type = true,typename std::enable_if,bool>::type = true, typename std::enable_if,bool>::type = true> + std::map>> getgroupCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname,[[maybe_unused]] std::string dataname) + { + std::map>> a; + + unsigned char kpos,vpos,dpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + dpos=findcolpos(dataname); + T ktemp; + U vtemp; + //D vtemp; + + for(auto &iter:record) + { + switch(kpos) + { + + case 0: + ktemp=iter.id; + break; + case 1: + ktemp=iter.randomnumber; + break; + } + + switch(vpos){ + case 0: + vtemp=iter.id; + break; + case 1: + vtemp=iter.randomnumber; + break; + } + + switch(dpos){ + case 0: + a[ktemp][vtemp].emplace_back(iter.id); + break; + case 1: + a[ktemp][vtemp].emplace_back(iter.randomnumber); + break; + + } + } + + return a; + } + + template,bool>::type = true,typename std::enable_if,bool>::type = true, typename std::enable_if::value,bool>::type = true> + std::map>> getgroupCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname,[[maybe_unused]] std::string dataname) + { + std::map>> a; + + unsigned char kpos,vpos,dpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + dpos=findcolpos(dataname); + T ktemp; + U vtemp; + // D dtemp; + + for(auto &iter:record) + { + switch(kpos) + { + + case 0: + ktemp=iter.id; + break; + case 1: + ktemp=iter.randomnumber; + break; + } + + switch(vpos){ + case 0: + vtemp=iter.id; + break; + case 1: + vtemp=iter.randomnumber; + break; + } + + switch(dpos){ + + } + } + + return a; + } + + template,bool>::type = true, typename std::enable_if::value,bool>::type = true, typename std::enable_if::value,bool>::type = true> + std::map>> getgroupCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname,[[maybe_unused]] std::string dataname) + { + std::map>> a; + + unsigned char kpos,vpos,dpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + dpos=findcolpos(dataname); + T ktemp; + U vtemp; + // D dtemp; + + for(auto &iter:record) + { + + switch(kpos) + { + + case 0: + ktemp=iter.id; + break; + case 1: + ktemp=iter.randomnumber; + break; + } + + switch(vpos){ + } + + switch(dpos){ + + } + } + + return a; + } + + template,bool>::type = true, typename std::enable_if::value,bool>::type = true, typename std::enable_if,bool>::type = true> + std::map>> getgroupCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname,[[maybe_unused]] std::string dataname) + { + std::map>> a; + + + unsigned char kpos,vpos,dpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + dpos=findcolpos(dataname); + T ktemp; + U vtemp; + // D dtemp; + + for(auto &iter:record) + { + switch(kpos) + { + + case 0: + ktemp=iter.id; + break; + case 1: + ktemp=iter.randomnumber; + break; + } + + switch(vpos){ + } + + switch(dpos){ + case 0: + a[ktemp][vtemp].emplace_back(iter.id); + break; + case 1: + a[ktemp][vtemp].emplace_back(iter.randomnumber); + break; + + } + } + + return a; + } + template,bool>::type = true, typename std::enable_if::value,bool>::type = true, typename std::enable_if::value,bool>::type = true> + std::map>> getgroupCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname,[[maybe_unused]] std::string dataname) + { + std::map>> a; + + unsigned char kpos,vpos,dpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + dpos=findcolpos(dataname); + T ktemp; + U vtemp; + // D dtemp; + + for(auto &iter:record) + { + switch(kpos) + { + + case 0: + ktemp=iter.id; + break; + case 1: + ktemp=iter.randomnumber; + break; + } + + switch(vpos){ + } + + switch(dpos){ + + } + } + + return a; + } + + template::value,bool>::type = true,typename std::enable_if,bool>::type = true, typename std::enable_if::value,bool>::type = true> + std::map>> getgroupCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname,[[maybe_unused]] std::string dataname) + { + std::map>> a; + + unsigned char kpos,vpos,dpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + dpos=findcolpos(dataname); + T ktemp; + U vtemp; + //D vtemp; + for(auto &iter:record) + { + switch(kpos) + { + + } + + switch(vpos){ + case 0: + vtemp=iter.id; + break; + case 1: + vtemp=iter.randomnumber; + break; + } + + switch(dpos){ + + } + } + + + return a; + } + + template::value,bool>::type = true,typename std::enable_if,bool>::type = true, typename std::enable_if,bool>::type = true> + std::map>> getgroupCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname,[[maybe_unused]] std::string dataname) + { + std::map>> a; + + unsigned char kpos,vpos,dpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + dpos=findcolpos(dataname); + T ktemp; + U vtemp; + //D vtemp; + + for(auto &iter:record) + { + + switch(kpos) + { + + } + + switch(vpos){ + case 0: + vtemp=iter.id; + break; + case 1: + vtemp=iter.randomnumber; + break; + } + + switch(dpos){ + case 0: + a[ktemp][vtemp].emplace_back(iter.id); + break; + case 1: + a[ktemp][vtemp].emplace_back(iter.randomnumber); + break; + + } + } + + return a; + } + + template::value,bool>::type = true,typename std::enable_if,bool>::type = true, typename std::enable_if::value,bool>::type = true> + std::map>> getgroupCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname,[[maybe_unused]] std::string dataname) + { + std::map>> a; + + + unsigned char kpos,vpos,dpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + dpos=findcolpos(dataname); + T ktemp; + U vtemp; + // D dtemp; + + for(auto &iter:record) + { + + switch(kpos) + { + + } + + switch(vpos){ + case 0: + vtemp=iter.id; + break; + case 1: + vtemp=iter.randomnumber; + break; + } + + switch(dpos){ + + } + } + + return a; + } + + template::value,bool>::type = true, typename std::enable_if::value,bool>::type = true, typename std::enable_if::value,bool>::type = true> + std::map>> getgroupCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname,[[maybe_unused]] std::string dataname) + { + std::map>> a; + + return a; + } + template::value,bool>::type = true, typename std::enable_if::value,bool>::type = true, typename std::enable_if,bool>::type = true> + std::map>> getgroupCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname,[[maybe_unused]] std::string dataname) + { + std::map>> a; + + unsigned char kpos,vpos,dpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + dpos=findcolpos(dataname); + T ktemp; + U vtemp; + // D dtemp; + + for(auto &iter:record) + { + + switch(kpos) + { + + } + + switch(vpos){ + } + + switch(dpos){ + case 0: + a[ktemp][vtemp].emplace_back(iter.id); + break; + case 1: + a[ktemp][vtemp].emplace_back(iter.randomnumber); + break; + + } + } + + return a; + } + + template::value,bool>::type = true, typename std::enable_if::value,bool>::type = true, typename std::enable_if::value,bool>::type = true> + std::map>> getgroupCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname,[[maybe_unused]] std::string dataname) + { + std::map>> a; + + return a; + } + + template::value,bool>::type = true, typename std::enable_if::value,bool>::type = true> + std::map> getgroupCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname) + { + std::map> a; + + + return a; + } + + template::value,bool>::type = true,typename std::enable_if::value,bool>::type = true> + std::map> getgroupCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname) + { + std::map> a; + + return a; + } + + template::value,bool>::type = true,typename std::enable_if,bool>::type = true> + std::map> getgroupCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname) + { + std::map> a; + + unsigned char kpos,vpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + T ktemp; + //U vtemp; + + for(auto &iter:record) + { + + switch(kpos) + { + + } + + switch(vpos){ + case 0: + a[ktemp].emplace_back(iter.id); + break; + case 1: + a[ktemp].emplace_back(iter.randomnumber); + break; + + } + } + + return a; + } + + template,bool>::type = true, typename std::enable_if::value,bool>::type = true> + std::map> getgroupCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname) + { + std::map> a; + + unsigned char kpos,vpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + T ktemp; + //U vtemp; + + for(auto &iter:record) + { + + switch(kpos) + { + + case 0: + ktemp=iter.id; + break; + case 1: + ktemp=iter.randomnumber; + break; + } + + switch(vpos){ + + } + } + + + return a; + } + + template,bool>::type = true,typename std::enable_if::value,bool>::type = true> + std::map> getgroupCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname) + { + std::map> a; + + unsigned char kpos,vpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + T ktemp; + //U vtemp; + + for(auto &iter:record) + { + + switch(kpos) + { + + case 0: + ktemp=iter.id; + break; + case 1: + ktemp=iter.randomnumber; + break; + } + + switch(vpos){ + + } + } + + return a; + } + + template,bool>::type = true,typename std::enable_if,bool>::type = true> + std::map> getgroupCols([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname) + { + std::map> a; + + unsigned char kpos,vpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + T ktemp; + //U vtemp; + + for(auto &iter:record) + { + + switch(kpos) + { + + case 0: + ktemp=iter.id; + break; + case 1: + ktemp=iter.randomnumber; + break; + } + + switch(vpos){ + case 0: + a[ktemp].emplace_back(iter.id); + break; + case 1: + a[ktemp].emplace_back(iter.randomnumber); + break; + + } + } + + return a; + } + + template,bool>::type = true> + std::map> getgroupRows([[maybe_unused]] std::string keyname) + { + std::map> a; + + unsigned char kpos; + kpos=findcolpos(keyname); + + for(auto &iter:record) + { + switch(kpos) + { + + case 0: + a[iter.id].emplace_back(iter); + break; + case 1: + a[iter.randomnumber].emplace_back(iter); + break; + + } + } + + return a; + } + + template::value,bool>::type = true> + std::map> getgroupRows([[maybe_unused]] std::string keyname) + { + std::map> a; + + return a; + } + + template::value,bool>::type = true, typename std::enable_if::value,bool>::type = true> + std::map>> getgroupRows([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname) + { + std::map>> a; + + return a; + } + + template::value,bool>::type = true,typename std::enable_if,bool>::type = true> + std::map>> getgroupRows([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname) + { + std::map>> a; + + unsigned char kpos,vpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + T ktemp; + + for(auto &iter:record) + { + + switch(kpos) + { + + } + + switch(vpos){ + case 0: + a[ktemp][iter.id].emplace_back(iter); + break; + case 1: + a[ktemp][iter.randomnumber].emplace_back(iter); + break; + + } + } + + + return a; + } + + template,bool>::type = true,typename std::enable_if,bool>::type = true> + std::map>> getgroupRows([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname) + { + std::map>> a; + + unsigned char kpos,vpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + T ktemp; + + for(auto &iter:record) + { + + switch(kpos) + { + + case 0: + ktemp=iter.id; + break; + case 1: + ktemp=iter.randomnumber; + break; + } + + switch(vpos){ + case 0: + a[ktemp][iter.id].emplace_back(iter); + break; + case 1: + a[ktemp][iter.randomnumber].emplace_back(iter); + break; + + } + } + + return a; + } + + template,bool>::type = true,typename std::enable_if::value,bool>::type = true> + std::map>> getgroupRows([[maybe_unused]] std::string keyname,[[maybe_unused]] std::string valname) + { + std::map>> a; + + + unsigned char kpos,vpos; + kpos=findcolpos(keyname); + vpos=findcolpos(valname); + T ktemp; + + for(auto &iter:record) + { + + switch(kpos) + { + + case 0: + ktemp=iter.id; + break; + case 1: + ktemp=iter.randomnumber; + break; + } + + switch(vpos){ + + } + } + + return a; + } + + }; + + +} +#endif + \ No newline at end of file diff --git a/frameworks/C++/paozhu/paozhu_benchmark/orm/include/world_mysql.h b/frameworks/C++/paozhu/paozhu_benchmark/orm/include/world_mysql.h new file mode 100644 index 00000000000..c48cbc517f4 --- /dev/null +++ b/frameworks/C++/paozhu/paozhu_benchmark/orm/include/world_mysql.h @@ -0,0 +1,11316 @@ +#ifndef _ORM_DEFAULT_WORLD_OPERATE_H +#define _ORM_DEFAULT_WORLD_OPERATE_H +/* + * @author 黄自权 huangziquan + * @date 2022-05-04 + * @update 2025-03-12 + * @dest ORM MySQL中间连接层 + */ +#include +#include +#include +#include +#include +#include +#include +#include "request.h" +#include "unicode.h" +#include "datetime.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mysql_conn.h" +#include "mysql_conn_pool.h" +#include "orm_cache.hpp" +#include "mysql_connect_mar.h" +/*baseincludefile*/ +namespace orm +{ +// mysql Operational SQL middleware +/*tagnamespace*/ +//{ /*tagnamespace_replace*/ + template + class world_mysql : public B_BASE + { + public: + world_mysql(const std::string &tag) : dbtag(tag) + { + std::map> &conn_pool_obj = get_orm_conn_pool_obj(); + auto iter = conn_pool_obj.find(dbtag); + if (iter != conn_pool_obj.end()) + { + conn_obj = iter->second; + } + else + { + conn_obj = nullptr; + iserror = true; + error_msg = "conn_pool not found " + dbtag; + } + } + world_mysql() : dbtag(B_BASE::_rmstag) + { + std::map> &conn_pool_obj = get_orm_conn_pool_obj(); + auto iter = conn_pool_obj.find(dbtag); + if (iter != conn_pool_obj.end()) + { + conn_obj = iter->second; + } + else + { + conn_obj = nullptr; + iserror = true; + error_msg = "conn_pool not found " + dbtag; + } + } + M_MODEL &switchDB(const std::string &temptag) + { + std::map> &conn_pool_obj = get_orm_conn_pool_obj(); + auto iter = conn_pool_obj.find(temptag); + if (iter != conn_pool_obj.end()) + { + conn_obj = iter->second; + } + else + { + conn_obj = nullptr; + iserror = true; + error_msg = "conn_pool not found " + temptag; + } + } + M_MODEL &set_table(const std::string &table_name) + { + if (original_tablename.empty()) + { + original_tablename = B_BASE::tablename; + } + if (table_name.size() > 0) + { + B_BASE::tablename = table_name; + } + return *mod; + } + M_MODEL &reset_table() + { + if (original_tablename.empty()) + { + return *mod; + } + B_BASE::tablename = original_tablename; + return *mod; + } + unsigned int count() + { + std::string countsql; + countsql = "SELECT count(*) as total_countnum FROM "; + countsql.append(B_BASE::tablename); + countsql.append(" WHERE "); + if (wheresql.empty()) + { + countsql.append(" 1 "); + } + else + { + countsql.append(wheresql); + } + if (!groupsql.empty()) + { + countsql.append(groupsql); + } + if (!limitsql.empty()) + { + countsql.append(limitsql); + } + + if (iserror) + { + return 0; + } + + try + { + effect_num = 0; + if (conn_empty()) + { + return 0; + } + //auto conn = conn_obj->get_select_conn(); + if (islock_conn) + { + if (!select_conn) + { + select_conn = conn_obj->get_select_conn(); + } + } + else + { + select_conn = conn_obj->get_select_conn(); + } + + if (select_conn->isdebug) + { + select_conn->begin_time(); + } + std::size_t n = select_conn->write_sql(countsql); + if (n == 0) + { + error_msg = select_conn->error_msg; + select_conn.reset(); + return 0; + } + + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + bool is_sql_item = false; + //std::vector field_array; + unsigned char action_setup = 0; + unsigned int column_num = 0; + unsigned int offset = 0; + + unsigned int querysql_len = 0; + + for (; is_sql_item == false;) + { + n = select_conn->read_loop(); + offset = 0; + if (n == 0) + { + error_msg = select_conn->error_msg; + select_conn.reset(); + return 0; + } + for (; offset < n;) + { + select_conn->read_field_pack(select_conn->_cache_data, n, offset, temp_pack_data); + if (temp_pack_data.error > 0) + { + iserror = true; + error_msg = temp_pack_data.data; + select_conn.reset(); + return 0; + } + if (temp_pack_data.length == temp_pack_data.current_length && temp_pack_data.current_length > 0) + { + if (select_conn->pack_eof_check(temp_pack_data)) + { + is_sql_item = true; + break; + } + + if (action_setup == 0) + { + if (temp_pack_data.length == 2 && (unsigned char)temp_pack_data.data[0] < 251 && (unsigned char)temp_pack_data.data[0] > 0) + { + action_setup = 1; + column_num = (unsigned char)temp_pack_data.data[0]; + } + } + else if (action_setup == 1) + { + field_info_t temp_filed_col; + select_conn->read_col_info(temp_pack_data.data, temp_filed_col); + + column_num--; + if (column_num == 0) + { + action_setup = 2; + } + } + else if (action_setup == 2) + { + unsigned int tempnum = 0; + + unsigned int name_length = select_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], tempnum); + + querysql_len = 0; + for (unsigned int ik = 0; ik < name_length; ik++) + { + if (temp_pack_data.data[tempnum] >= '0' && temp_pack_data.data[tempnum] <= '9') + { + querysql_len = querysql_len * 10 + (temp_pack_data.data[tempnum] - '0'); + } + tempnum++; + } + effect_num++; + } + } + else + { + if (offset >= n) + { + break; + } + is_sql_item = true; + break; + } + } + } + + if (select_conn->isdebug) + { + select_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = select_conn->count_time(); + conn_mar.push_log(countsql, std::to_string(du_time)); + } + + if (!islock_conn) + { + conn_obj->back_select_conn(std::move(select_conn)); + } + + return querysql_len; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + return 0; + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + return 0; + } + + return 0; + } + std::tuple + page(unsigned int page, unsigned int per_page = 10, unsigned int list_num = 5) + { + unsigned int total_page = count(); + if (per_page == 0) + { + per_page = 10; + } + if (list_num < 1) + { + list_num = 1; + } + total_page = std::ceil((float)total_page / per_page); + + if (total_page < 1) + { + total_page = 1; + } + if (page > total_page) + { + page = total_page; + } + if (page < 1) + { + page = 1; + } + unsigned int mid_num = std::floor(list_num / 2); + unsigned int last_num = list_num - 1; + + int temp_num = page - mid_num; + + unsigned int minpage = temp_num < 1 ? 1 : temp_num; + unsigned int maxpage = minpage + last_num; + + if (maxpage > total_page) + { + maxpage = total_page; + temp_num = (maxpage - last_num); + if (temp_num < 1) + { + minpage = 1; + } + else + { + minpage = temp_num; + } + } + limit((page - 1) * per_page, per_page); + return std::make_tuple(minpage, maxpage, page, total_page); + } + asio::awaitable async_count() + { + std::string countsql; + countsql = "SELECT count(*) as total_countnum FROM "; + countsql.append(B_BASE::tablename); + countsql.append(" WHERE "); + if (wheresql.empty()) + { + countsql.append(" 1 "); + } + else + { + countsql.append(wheresql); + } + if (!groupsql.empty()) + { + countsql.append(groupsql); + } + if (!limitsql.empty()) + { + countsql.append(limitsql); + } + + if (iserror) + { + co_return 0; + } + + try + { + effect_num = 0; + if (conn_empty()) + { + co_return 0; + } + //auto conn = co_await conn_obj->async_get_select_conn(); + if (islock_conn) + { + if (!select_conn) + { + select_conn = co_await conn_obj->async_get_select_conn(); + } + } + else + { + select_conn = co_await conn_obj->async_get_select_conn(); + } + + if (select_conn->isdebug) + { + select_conn->begin_time(); + } + std::size_t n = co_await select_conn->async_write_sql(countsql); + if (n == 0) + { + error_msg = select_conn->error_msg; + select_conn.reset(); + co_return 0; + } + //std::size_t n = co_await asio::async_write(*conn->socket, asio::buffer(conn->send_data), asio::use_awaitable); + + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + bool is_sql_item = false; + //std::vector field_array; + unsigned char action_setup = 0; + unsigned int column_num = 0; + unsigned int offset = 0; + + unsigned int querysql_len = 0; + + for (; is_sql_item == false;) + { + n = co_await select_conn->async_read_loop(); + offset = 0; + if (n == 0) + { + select_conn.reset(); + co_return 0; + } + for (; offset < n;) + { + select_conn->read_field_pack(select_conn->_cache_data, n, offset, temp_pack_data); + if (temp_pack_data.error > 0) + { + iserror = true; + error_msg = temp_pack_data.data; + select_conn.reset(); + co_return 0; + } + if (temp_pack_data.length == temp_pack_data.current_length && temp_pack_data.current_length > 0) + { + if (select_conn->pack_eof_check(temp_pack_data)) + { + is_sql_item = true; + break; + } + + if (action_setup == 0) + { + if (temp_pack_data.length == 2 && (unsigned char)temp_pack_data.data[0] < 251 && (unsigned char)temp_pack_data.data[0] > 0) + { + action_setup = 1; + column_num = (unsigned char)temp_pack_data.data[0]; + } + } + else if (action_setup == 1) + { + field_info_t temp_filed_col; + select_conn->read_col_info(temp_pack_data.data, temp_filed_col); + + column_num--; + if (column_num == 0) + { + action_setup = 2; + } + } + else if (action_setup == 2) + { + unsigned int tempnum = 0; + + unsigned int name_length = select_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], tempnum); + + querysql_len = 0; + for (unsigned int ik = 0; ik < name_length; ik++) + { + if (temp_pack_data.data[tempnum] >= '0' && temp_pack_data.data[tempnum] <= '9') + { + querysql_len = querysql_len * 10 + (temp_pack_data.data[tempnum] - '0'); + } + tempnum++; + } + effect_num++; + } + } + else + { + if (offset >= n) + { + break; + } + is_sql_item = true; + break; + } + } + } + + if (select_conn->isdebug) + { + select_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = select_conn->count_time(); + conn_mar.push_log(countsql, std::to_string(du_time)); + } + if (!islock_conn) + { + conn_obj->back_select_conn(std::move(select_conn)); + } + co_return querysql_len; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + co_return 0; + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + co_return 0; + } + co_return 0; + } + + asio::awaitable> + async_page(unsigned int page, unsigned int per_page = 10, unsigned int list_num = 5) + { + unsigned int total_page = async_count(); + if (per_page == 0) + { + per_page = 10; + } + if (list_num < 1) + { + list_num = 1; + } + total_page = std::ceil((float)total_page / per_page); + + if (total_page < 1) + { + total_page = 1; + } + if (page > total_page) + { + page = total_page; + } + if (page < 1) + { + page = 1; + } + unsigned int mid_num = std::floor(list_num / 2); + unsigned int last_num = list_num - 1; + + int temp_num = page - mid_num; + + unsigned int minpage = temp_num < 1 ? 1 : temp_num; + unsigned int maxpage = minpage + last_num; + + if (maxpage > total_page) + { + maxpage = total_page; + temp_num = (maxpage - last_num); + if (temp_num < 1) + { + minpage = 1; + } + else + { + minpage = temp_num; + } + } + limit((page - 1) * per_page, per_page); + co_return std::make_tuple(minpage, maxpage, page, total_page); + } + + unsigned int update_col(std::string colname, int num, char symbol = '+') + { + effect_num = 0; + std::string countsql; + countsql = "UPDATE "; + countsql.append(B_BASE::tablename); + countsql.append(" SET "); + countsql.append(colname); + if (num > 0) + { + countsql.append(" = "); + countsql.append(colname); + countsql.push_back(' '); + countsql.push_back(symbol); + countsql.append(std::to_string(num)); + } + else + { + countsql.append(" = "); + countsql.append(colname); + countsql.push_back(' '); + countsql.push_back(symbol); + countsql.push_back('('); + countsql.push_back('-'); + countsql.append(std::to_string(std::abs(num))); + countsql.push_back(')'); + } + countsql.append(" where "); + if (wheresql.empty()) + { + if (B_BASE::getPK() > 0) + { + std::ostringstream tempsql; + tempsql << " "; + tempsql << B_BASE::getPKname(); + tempsql << " = '"; + tempsql << B_BASE::getPK(); + tempsql << "' "; + countsql.append(tempsql.str()); + } + else + { + return 0; + } + } + else + { + countsql.append(wheresql); + } + if (!groupsql.empty()) + { + countsql.append(groupsql); + } + if (!limitsql.empty()) + { + countsql.append(limitsql); + } + if (iscommit) + { + iscommit = false; + return 0; + } + + if (iserror) + { + return 0; + } + + try + { + if (conn_empty()) + { + return 0; + } + //auto conn = conn_obj->get_edit_conn(); + + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = conn_obj->get_edit_conn(); + } + } + else + { + edit_conn = conn_obj->get_edit_conn(); + } + + if (edit_conn->isdebug) + { + edit_conn->begin_time(); + } + std::size_t n = edit_conn->write_sql(countsql); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return 0; + } + + unsigned int offset = 0; + n = edit_conn->read_loop(); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return 0; + } + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + edit_conn->read_field_pack(edit_conn->_cache_data, n, offset, temp_pack_data); + if (edit_conn->isdebug) + { + edit_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = edit_conn->count_time(); + conn_mar.push_log(countsql, std::to_string(du_time)); + } + + if ((unsigned char)temp_pack_data.data[0] == 0xFF) + { + error_msg = temp_pack_data.data.substr(3); + } + else if ((unsigned char)temp_pack_data.data[0] == 0x00) + { + + unsigned int d_offset = 1; + effect_num = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + } + if (!islock_conn) + { + conn_obj->back_edit_conn(std::move(edit_conn)); + } + return effect_num; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + return 0; + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + return 0; + } + + asio::awaitable async_update_col(std::string colname, int num, char symbol = '+') + { + effect_num = 0; + std::string countsql; + countsql = "UPDATE "; + countsql.append(B_BASE::tablename); + countsql.append(" SET "); + countsql.append(colname); + if (num > 0) + { + countsql.append(" = "); + countsql.append(colname); + countsql.push_back(' '); + countsql.push_back(symbol); + countsql.append(std::to_string(num)); + } + else + { + countsql.append(" = "); + countsql.append(colname); + countsql.push_back(' '); + countsql.push_back(symbol); + countsql.push_back('('); + countsql.push_back('-'); + countsql.append(std::to_string(std::abs(num))); + countsql.push_back(')'); + } + countsql.append(" where "); + if (wheresql.empty()) + { + if (B_BASE::getPK() > 0) + { + std::ostringstream tempsql; + tempsql << " "; + tempsql << B_BASE::getPKname(); + tempsql << " = '"; + tempsql << B_BASE::getPK(); + tempsql << "' "; + countsql.append(tempsql.str()); + } + else + { + co_return 0; + } + } + else + { + countsql.append(wheresql); + } + if (!groupsql.empty()) + { + countsql.append(groupsql); + } + if (!limitsql.empty()) + { + countsql.append(limitsql); + } + if (iscommit) + { + iscommit = false; + co_return 0; + } + + if (iserror) + { + co_return 0; + } + + try + { + + if (conn_empty()) + { + co_return 0; + } + + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = co_await conn_obj->async_get_edit_conn(); + } + } + else + { + edit_conn = co_await conn_obj->async_get_edit_conn(); + } + + if (edit_conn->isdebug) + { + edit_conn->begin_time(); + } + std::size_t n = co_await edit_conn->async_write_sql(countsql); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + co_return 0; + } + + unsigned int offset = 0; + n = co_await edit_conn->async_read_loop(); + if (n == 0) + { + edit_conn.reset(); + co_return 0; + } + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + edit_conn->read_field_pack(edit_conn->_cache_data, n, offset, temp_pack_data); + if (edit_conn->isdebug) + { + edit_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = edit_conn->count_time(); + conn_mar.push_log(countsql, std::to_string(du_time)); + } + + if ((unsigned char)temp_pack_data.data[0] == 0xFF) + { + error_msg = temp_pack_data.data.substr(3); + } + else if ((unsigned char)temp_pack_data.data[0] == 0x00) + { + + unsigned int d_offset = 1; + effect_num = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + } + if (!islock_conn) + { + conn_obj->back_edit_conn(std::move(edit_conn)); + } + co_return effect_num; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + co_return 0; + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + co_return 0; + } + + int replace_col(std::string colname, const std::string &old_string, const std::string &new_string) + { + effect_num = 0; + std::string countsql; + countsql = "UPDATE "; + countsql.append(B_BASE::tablename); + countsql.append(" SET "); + countsql.append(colname); + + countsql.append(" = REPLACE("); + countsql.append(colname); + countsql.append(",'"); + countsql.append(old_string); + countsql.append("','"); + countsql.append(new_string); + countsql.append("') "); + + countsql.append(" where "); + if (wheresql.empty()) + { + if (B_BASE::getPK() > 0) + { + std::ostringstream tempsql; + tempsql << " "; + tempsql << B_BASE::getPKname(); + tempsql << " = '"; + tempsql << B_BASE::getPK(); + tempsql << "' "; + countsql.append(tempsql.str()); + } + else + { + return 0; + } + } + else + { + countsql.append(wheresql); + } + if (!groupsql.empty()) + { + countsql.append(groupsql); + } + if (!limitsql.empty()) + { + countsql.append(limitsql); + } + if (iscommit) + { + iscommit = false; + return 0; + } + + if (iserror) + { + return 0; + } + + try + { + if (conn_empty()) + { + return 0; + } + //auto conn = conn_obj->get_edit_conn(); + + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = conn_obj->get_edit_conn(); + } + } + else + { + edit_conn = conn_obj->get_edit_conn(); + } + + if (edit_conn->isdebug) + { + edit_conn->begin_time(); + } + + std::size_t n = edit_conn->write_sql(countsql); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return 0; + } + + unsigned int offset = 0; + n = edit_conn->read_loop(); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return 0; + } + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + edit_conn->read_field_pack(edit_conn->_cache_data, n, offset, temp_pack_data); + if (edit_conn->isdebug) + { + edit_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = edit_conn->count_time(); + conn_mar.push_log(countsql, std::to_string(du_time)); + } + + if ((unsigned char)temp_pack_data.data[0] == 0xFF) + { + error_msg = temp_pack_data.data.substr(3); + } + else if ((unsigned char)temp_pack_data.data[0] == 0x00) + { + + unsigned int d_offset = 1; + effect_num = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + } + if (!islock_conn) + { + conn_obj->back_edit_conn(std::move(edit_conn)); + } + return effect_num; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + return 0; + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + return 0; + } + + void assign_field_value(unsigned char index_pos, unsigned char *result_temp_data, unsigned int value_size, typename B_BASE::meta &data_temp) + { + switch(index_pos) + { + case 0: + data_temp.id=0; + + for(unsigned int i=0; i< value_size; i++) + { + if(result_temp_data[i]>='0'&&result_temp_data[i]<='9') + { + + data_temp.id= data_temp.id * 10 + (result_temp_data[i]-'0'); + } + if(i>32) + { + break; + } + } + break; + case 1: + data_temp.randomnumber=0; + + for(unsigned int i=0; i< value_size; i++) + { + if(result_temp_data[i]>='0'&&result_temp_data[i]<='9') + { + + data_temp.randomnumber= data_temp.randomnumber * 10 + (result_temp_data[i]-'0'); + } + if(i>32) + { + break; + } + } + break; + + } + } + + +M_MODEL& eqId(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id = "); + + try + { + wheresql.append(std::to_string(std::stoll(val))); + } + catch (std::invalid_argument const& ex) + { + wheresql.push_back('0'); + } + catch (std::out_of_range const& ex) + { + wheresql.push_back('0'); + } + return *mod; + } + + +M_MODEL& nqId(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id != "); + + try + { + wheresql.append(std::to_string(std::stoll(val))); + } + catch (std::invalid_argument const& ex) + { + wheresql.push_back('0'); + } + catch (std::out_of_range const& ex) + { + wheresql.push_back('0'); + } + return *mod; + } + + +M_MODEL& inId(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id IN("); + + wheresql.append(val); + wheresql.push_back(')'); + return *mod; + } + + +template + requires std::is_integral_v +M_MODEL& inId(const std::vector& val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id IN("); + + for(unsigned int i=0;i 0) + { + wheresql.push_back(','); + } + wheresql.append(std::to_string(val[i])); + } + wheresql.push_back(')'); + + return *mod; + } + + +M_MODEL& inId(const std::vector& val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id IN("); + + for(unsigned int i=0;i 0) + { + wheresql.push_back(','); + } + + try + { + wheresql.append(std::to_string(std::stoll(val[i]))); + } + catch (std::invalid_argument const& ex) + { + wheresql.push_back('0'); + } + catch (std::out_of_range const& ex) + { + wheresql.push_back('0'); + } + } + wheresql.push_back(')'); + + return *mod; + } + + +M_MODEL& ninId(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id NOT IN("); + + wheresql.append(val); + wheresql.push_back(')'); + return *mod; + } + + +template + requires std::is_integral_v +M_MODEL& ninId(const std::vector& val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id NOT IN("); + + for(unsigned int i=0;i 0) + { + wheresql.push_back(','); + } + wheresql.append(std::to_string(val[i])); + } + wheresql.push_back(')'); + + return *mod; + } + + +M_MODEL& ninId(const std::vector& val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id NOT IN("); + + for(unsigned int i=0;i 0) + { + wheresql.push_back(','); + } + + try + { + wheresql.append(std::to_string(std::stoll(val[i]))); + } + catch (std::invalid_argument const& ex) + { + wheresql.push_back('0'); + } + catch (std::out_of_range const& ex) + { + wheresql.push_back('0'); + } + } + wheresql.push_back(')'); + + return *mod; + } + + +M_MODEL& btId(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id > "); + + try + { + wheresql.append(std::to_string(std::stoll(val))); + } + catch (std::invalid_argument const& ex) + { + wheresql.push_back('0'); + } + catch (std::out_of_range const& ex) + { + wheresql.push_back('0'); + } + return *mod; + } + + +M_MODEL& beId(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id >= "); + + try + { + wheresql.append(std::to_string(std::stoll(val))); + } + catch (std::invalid_argument const& ex) + { + wheresql.push_back('0'); + } + catch (std::out_of_range const& ex) + { + wheresql.push_back('0'); + } + return *mod; + } + + +M_MODEL& ltId(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id < "); + + try + { + wheresql.append(std::to_string(std::stoll(val))); + } + catch (std::invalid_argument const& ex) + { + wheresql.push_back('0'); + } + catch (std::out_of_range const& ex) + { + wheresql.push_back('0'); + } + return *mod; + } + + +M_MODEL& leId(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id <= "); + + try + { + wheresql.append(std::to_string(std::stoll(val))); + } + catch (std::invalid_argument const& ex) + { + wheresql.push_back('0'); + } + catch (std::out_of_range const& ex) + { + wheresql.push_back('0'); + } + return *mod; + } + + +M_MODEL& or_eqId(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id = "); + + try + { + wheresql.append(std::to_string(std::stoll(val))); + } + catch (std::invalid_argument const& ex) + { + wheresql.push_back('0'); + } + catch (std::out_of_range const& ex) + { + wheresql.push_back('0'); + } + return *mod; + } + + +M_MODEL& or_nqId(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id != "); + + try + { + wheresql.append(std::to_string(std::stoll(val))); + } + catch (std::invalid_argument const& ex) + { + wheresql.push_back('0'); + } + catch (std::out_of_range const& ex) + { + wheresql.push_back('0'); + } + return *mod; + } + + +M_MODEL& or_inId(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id IN("); + + wheresql.append(val); + wheresql.push_back(')'); + return *mod; + } + + +template + requires std::is_integral_v +M_MODEL& or_inId(const std::vector& val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id IN("); + + for(unsigned int i=0;i 0) + { + wheresql.push_back(','); + } + wheresql.append(std::to_string(val[i])); + } + wheresql.push_back(')'); + + return *mod; + } + + +M_MODEL& or_inId(const std::vector& val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id IN("); + + for(unsigned int i=0;i 0) + { + wheresql.push_back(','); + } + + try + { + wheresql.append(std::to_string(std::stoll(val[i]))); + } + catch (std::invalid_argument const& ex) + { + wheresql.push_back('0'); + } + catch (std::out_of_range const& ex) + { + wheresql.push_back('0'); + } + } + wheresql.push_back(')'); + + return *mod; + } + + +M_MODEL& or_ninId(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id NOT IN("); + + wheresql.append(val); + wheresql.push_back(')'); + return *mod; + } + + +template + requires std::is_integral_v +M_MODEL& or_ninId(const std::vector& val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id NOT IN("); + + for(unsigned int i=0;i 0) + { + wheresql.push_back(','); + } + wheresql.append(std::to_string(val[i])); + } + wheresql.push_back(')'); + + return *mod; + } + + +M_MODEL& or_ninId(const std::vector& val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id NOT IN("); + + for(unsigned int i=0;i 0) + { + wheresql.push_back(','); + } + + try + { + wheresql.append(std::to_string(std::stoll(val[i]))); + } + catch (std::invalid_argument const& ex) + { + wheresql.push_back('0'); + } + catch (std::out_of_range const& ex) + { + wheresql.push_back('0'); + } + } + wheresql.push_back(')'); + + return *mod; + } + + +M_MODEL& or_btId(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id > "); + + try + { + wheresql.append(std::to_string(std::stoll(val))); + } + catch (std::invalid_argument const& ex) + { + wheresql.push_back('0'); + } + catch (std::out_of_range const& ex) + { + wheresql.push_back('0'); + } + return *mod; + } + + +M_MODEL& or_beId(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id >= "); + + try + { + wheresql.append(std::to_string(std::stoll(val))); + } + catch (std::invalid_argument const& ex) + { + wheresql.push_back('0'); + } + catch (std::out_of_range const& ex) + { + wheresql.push_back('0'); + } + return *mod; + } + + +M_MODEL& or_ltId(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id < "); + + try + { + wheresql.append(std::to_string(std::stoll(val))); + } + catch (std::invalid_argument const& ex) + { + wheresql.push_back('0'); + } + catch (std::out_of_range const& ex) + { + wheresql.push_back('0'); + } + return *mod; + } + + +M_MODEL& or_leId(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id <= "); + + try + { + wheresql.append(std::to_string(std::stoll(val))); + } + catch (std::invalid_argument const& ex) + { + wheresql.push_back('0'); + } + catch (std::out_of_range const& ex) + { + wheresql.push_back('0'); + } + return *mod; + } + + +template + requires std::is_integral_v +M_MODEL& eqId(T val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id = "); + + wheresql.append(std::to_string(val)); + return *mod; + } + + +template + requires std::is_integral_v +M_MODEL& nqId(T val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id != "); + + wheresql.append(std::to_string(val)); + return *mod; + } + + +template + requires std::is_integral_v +M_MODEL& btId(T val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id > "); + + wheresql.append(std::to_string(val)); + return *mod; + } + + +template + requires std::is_integral_v +M_MODEL& beId(T val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id >= "); + + wheresql.append(std::to_string(val)); + return *mod; + } + + +template + requires std::is_integral_v +M_MODEL& ltId(T val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id < "); + + wheresql.append(std::to_string(val)); + return *mod; + } + + +template + requires std::is_integral_v +M_MODEL& leId(T val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id <= "); + + wheresql.append(std::to_string(val)); + return *mod; + } + + +template + requires std::is_integral_v +M_MODEL& or_eqId(T val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id = "); + + wheresql.append(std::to_string(val)); + return *mod; + } + + +template + requires std::is_integral_v +M_MODEL& or_nqId(T val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id != "); + + wheresql.append(std::to_string(val)); + return *mod; + } + + +template + requires std::is_integral_v +M_MODEL& or_btId(T val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id > "); + + wheresql.append(std::to_string(val)); + return *mod; + } + + +template + requires std::is_integral_v +M_MODEL& or_beId(T val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id >= "); + + wheresql.append(std::to_string(val)); + return *mod; + } + + +template + requires std::is_integral_v +M_MODEL& or_ltId(T val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id < "); + + wheresql.append(std::to_string(val)); + return *mod; + } + + +template + requires std::is_integral_v +M_MODEL& or_leId(T val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" id <= "); + + wheresql.append(std::to_string(val)); + return *mod; + } + + +M_MODEL& eqRandomnumber(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" randomnumber = "); + + try + { + wheresql.append(std::to_string(std::stoll(val))); + } + catch (std::invalid_argument const& ex) + { + wheresql.push_back('0'); + } + catch (std::out_of_range const& ex) + { + wheresql.push_back('0'); + } + return *mod; + } + + +M_MODEL& nqRandomnumber(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" randomnumber != "); + + try + { + wheresql.append(std::to_string(std::stoll(val))); + } + catch (std::invalid_argument const& ex) + { + wheresql.push_back('0'); + } + catch (std::out_of_range const& ex) + { + wheresql.push_back('0'); + } + return *mod; + } + + +M_MODEL& inRandomnumber(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" randomnumber IN("); + + wheresql.append(val); + wheresql.push_back(')'); + return *mod; + } + + +template + requires std::is_integral_v +M_MODEL& inRandomnumber(const std::vector& val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" randomnumber IN("); + + for(unsigned int i=0;i 0) + { + wheresql.push_back(','); + } + wheresql.append(std::to_string(val[i])); + } + wheresql.push_back(')'); + + return *mod; + } + + +M_MODEL& inRandomnumber(const std::vector& val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" randomnumber IN("); + + for(unsigned int i=0;i 0) + { + wheresql.push_back(','); + } + + try + { + wheresql.append(std::to_string(std::stoll(val[i]))); + } + catch (std::invalid_argument const& ex) + { + wheresql.push_back('0'); + } + catch (std::out_of_range const& ex) + { + wheresql.push_back('0'); + } + } + wheresql.push_back(')'); + + return *mod; + } + + +M_MODEL& ninRandomnumber(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" randomnumber NOT IN("); + + wheresql.append(val); + wheresql.push_back(')'); + return *mod; + } + + +template + requires std::is_integral_v +M_MODEL& ninRandomnumber(const std::vector& val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" randomnumber NOT IN("); + + for(unsigned int i=0;i 0) + { + wheresql.push_back(','); + } + wheresql.append(std::to_string(val[i])); + } + wheresql.push_back(')'); + + return *mod; + } + + +M_MODEL& ninRandomnumber(const std::vector& val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" randomnumber NOT IN("); + + for(unsigned int i=0;i 0) + { + wheresql.push_back(','); + } + + try + { + wheresql.append(std::to_string(std::stoll(val[i]))); + } + catch (std::invalid_argument const& ex) + { + wheresql.push_back('0'); + } + catch (std::out_of_range const& ex) + { + wheresql.push_back('0'); + } + } + wheresql.push_back(')'); + + return *mod; + } + + +M_MODEL& btRandomnumber(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" randomnumber > "); + + try + { + wheresql.append(std::to_string(std::stoll(val))); + } + catch (std::invalid_argument const& ex) + { + wheresql.push_back('0'); + } + catch (std::out_of_range const& ex) + { + wheresql.push_back('0'); + } + return *mod; + } + + +M_MODEL& beRandomnumber(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" randomnumber >= "); + + try + { + wheresql.append(std::to_string(std::stoll(val))); + } + catch (std::invalid_argument const& ex) + { + wheresql.push_back('0'); + } + catch (std::out_of_range const& ex) + { + wheresql.push_back('0'); + } + return *mod; + } + + +M_MODEL& ltRandomnumber(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" randomnumber < "); + + try + { + wheresql.append(std::to_string(std::stoll(val))); + } + catch (std::invalid_argument const& ex) + { + wheresql.push_back('0'); + } + catch (std::out_of_range const& ex) + { + wheresql.push_back('0'); + } + return *mod; + } + + +M_MODEL& leRandomnumber(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" randomnumber <= "); + + try + { + wheresql.append(std::to_string(std::stoll(val))); + } + catch (std::invalid_argument const& ex) + { + wheresql.push_back('0'); + } + catch (std::out_of_range const& ex) + { + wheresql.push_back('0'); + } + return *mod; + } + + +M_MODEL& or_eqRandomnumber(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" randomnumber = "); + + try + { + wheresql.append(std::to_string(std::stoll(val))); + } + catch (std::invalid_argument const& ex) + { + wheresql.push_back('0'); + } + catch (std::out_of_range const& ex) + { + wheresql.push_back('0'); + } + return *mod; + } + + +M_MODEL& or_nqRandomnumber(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" randomnumber != "); + + try + { + wheresql.append(std::to_string(std::stoll(val))); + } + catch (std::invalid_argument const& ex) + { + wheresql.push_back('0'); + } + catch (std::out_of_range const& ex) + { + wheresql.push_back('0'); + } + return *mod; + } + + +M_MODEL& or_inRandomnumber(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" randomnumber IN("); + + wheresql.append(val); + wheresql.push_back(')'); + return *mod; + } + + +template + requires std::is_integral_v +M_MODEL& or_inRandomnumber(const std::vector& val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" randomnumber IN("); + + for(unsigned int i=0;i 0) + { + wheresql.push_back(','); + } + wheresql.append(std::to_string(val[i])); + } + wheresql.push_back(')'); + + return *mod; + } + + +M_MODEL& or_inRandomnumber(const std::vector& val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" randomnumber IN("); + + for(unsigned int i=0;i 0) + { + wheresql.push_back(','); + } + + try + { + wheresql.append(std::to_string(std::stoll(val[i]))); + } + catch (std::invalid_argument const& ex) + { + wheresql.push_back('0'); + } + catch (std::out_of_range const& ex) + { + wheresql.push_back('0'); + } + } + wheresql.push_back(')'); + + return *mod; + } + + +M_MODEL& or_ninRandomnumber(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" randomnumber NOT IN("); + + wheresql.append(val); + wheresql.push_back(')'); + return *mod; + } + + +template + requires std::is_integral_v +M_MODEL& or_ninRandomnumber(const std::vector& val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" randomnumber NOT IN("); + + for(unsigned int i=0;i 0) + { + wheresql.push_back(','); + } + wheresql.append(std::to_string(val[i])); + } + wheresql.push_back(')'); + + return *mod; + } + + +M_MODEL& or_ninRandomnumber(const std::vector& val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" randomnumber NOT IN("); + + for(unsigned int i=0;i 0) + { + wheresql.push_back(','); + } + + try + { + wheresql.append(std::to_string(std::stoll(val[i]))); + } + catch (std::invalid_argument const& ex) + { + wheresql.push_back('0'); + } + catch (std::out_of_range const& ex) + { + wheresql.push_back('0'); + } + } + wheresql.push_back(')'); + + return *mod; + } + + +M_MODEL& or_btRandomnumber(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" randomnumber > "); + + try + { + wheresql.append(std::to_string(std::stoll(val))); + } + catch (std::invalid_argument const& ex) + { + wheresql.push_back('0'); + } + catch (std::out_of_range const& ex) + { + wheresql.push_back('0'); + } + return *mod; + } + + +M_MODEL& or_beRandomnumber(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" randomnumber >= "); + + try + { + wheresql.append(std::to_string(std::stoll(val))); + } + catch (std::invalid_argument const& ex) + { + wheresql.push_back('0'); + } + catch (std::out_of_range const& ex) + { + wheresql.push_back('0'); + } + return *mod; + } + + +M_MODEL& or_ltRandomnumber(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" randomnumber < "); + + try + { + wheresql.append(std::to_string(std::stoll(val))); + } + catch (std::invalid_argument const& ex) + { + wheresql.push_back('0'); + } + catch (std::out_of_range const& ex) + { + wheresql.push_back('0'); + } + return *mod; + } + + +M_MODEL& or_leRandomnumber(const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" randomnumber <= "); + + try + { + wheresql.append(std::to_string(std::stoll(val))); + } + catch (std::invalid_argument const& ex) + { + wheresql.push_back('0'); + } + catch (std::out_of_range const& ex) + { + wheresql.push_back('0'); + } + return *mod; + } + + +template + requires std::is_integral_v +M_MODEL& eqRandomnumber(T val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" randomnumber = "); + + wheresql.append(std::to_string(val)); + return *mod; + } + + +template + requires std::is_integral_v +M_MODEL& nqRandomnumber(T val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" randomnumber != "); + + wheresql.append(std::to_string(val)); + return *mod; + } + + +template + requires std::is_integral_v +M_MODEL& btRandomnumber(T val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" randomnumber > "); + + wheresql.append(std::to_string(val)); + return *mod; + } + + +template + requires std::is_integral_v +M_MODEL& beRandomnumber(T val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" randomnumber >= "); + + wheresql.append(std::to_string(val)); + return *mod; + } + + +template + requires std::is_integral_v +M_MODEL& ltRandomnumber(T val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" randomnumber < "); + + wheresql.append(std::to_string(val)); + return *mod; + } + + +template + requires std::is_integral_v +M_MODEL& leRandomnumber(T val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" randomnumber <= "); + + wheresql.append(std::to_string(val)); + return *mod; + } + + +template + requires std::is_integral_v +M_MODEL& or_eqRandomnumber(T val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" randomnumber = "); + + wheresql.append(std::to_string(val)); + return *mod; + } + + +template + requires std::is_integral_v +M_MODEL& or_nqRandomnumber(T val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" randomnumber != "); + + wheresql.append(std::to_string(val)); + return *mod; + } + + +template + requires std::is_integral_v +M_MODEL& or_btRandomnumber(T val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" randomnumber > "); + + wheresql.append(std::to_string(val)); + return *mod; + } + + +template + requires std::is_integral_v +M_MODEL& or_beRandomnumber(T val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" randomnumber >= "); + + wheresql.append(std::to_string(val)); + return *mod; + } + + +template + requires std::is_integral_v +M_MODEL& or_ltRandomnumber(T val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" randomnumber < "); + + wheresql.append(std::to_string(val)); + return *mod; + } + + +template + requires std::is_integral_v +M_MODEL& or_leRandomnumber(T val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" randomnumber <= "); + + wheresql.append(std::to_string(val)); + return *mod; + } + + + M_MODEL &select(const std::string &fieldname) + { + if (selectsql.size() > 0) + { + selectsql.push_back(','); + } + selectsql.append(fieldname); + return *mod; + } + + M_MODEL &where(const std::string &wq) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + + wheresql.append(wq); + return *mod; + } + template + requires std::is_integral_v<_SQL_Value> || std::is_floating_point_v<_SQL_Value> + M_MODEL &where(const std::string &wq, _SQL_Value val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.push_back('='); + wheresql.append(std::to_string(val)); + return *mod; + } + + M_MODEL &where(const std::string &wq, char bi, http::obj_val &obj) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.push_back(bi); + if (obj.is_string()) + { + wheresql.push_back('\''); + wheresql.append(obj.as_string()); + wheresql.push_back('\''); + } + else + { + + wheresql.append(obj.to_string()); + } + return *mod; + } + M_MODEL &where(const std::string &wq, http::obj_val &obj) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.push_back('='); + + if (obj.is_string()) + { + wheresql.push_back('\''); + wheresql.append(obj.as_string()); + wheresql.push_back('\''); + } + else + { + + wheresql.append(obj.to_string()); + } + return *mod; + } + template + requires std::is_integral_v<_SQL_Value> || std::is_floating_point_v<_SQL_Value> + M_MODEL &where(const std::string &wq, char bi, _SQL_Value val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.push_back(bi); + wheresql.append(std::to_string(val)); + return *mod; + } + + M_MODEL &where(const std::string &wq, char bi, const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.push_back(bi); + wheresql.push_back('\''); + + wheresql.append(val); + wheresql.push_back('\''); + return *mod; + } + M_MODEL &where(const std::string &wq, const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.push_back('='); + + wheresql.push_back('\''); + wheresql.append(val); + wheresql.push_back('\''); + return *mod; + } + + M_MODEL &whereBT(const std::string &wq, const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.push_back('>'); + + wheresql.push_back('\''); + wheresql.append(val); + wheresql.push_back('\''); + return *mod; + } + + M_MODEL &whereBE(const std::string &wq, const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.append(">="); + + wheresql.push_back('\''); + wheresql.append(val); + wheresql.push_back('\''); + return *mod; + } + + M_MODEL &whereLT(const std::string &wq, const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.append(" < "); + + wheresql.push_back('\''); + wheresql.append(val); + wheresql.push_back('\''); + return *mod; + } + + M_MODEL &whereLE(const std::string &wq, const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.append(" <= "); + + wheresql.push_back('\''); + wheresql.append(val); + wheresql.push_back('\''); + return *mod; + } + + M_MODEL &between(const std::string &wq, const std::string &a, const std::string &b) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" ("); + wheresql.append(wq); + wheresql.append(" BETWEEN '"); + std::stringstream _stream; + _stream << a; + _stream << "' AND '"; + _stream << b; + _stream << "' ) "; + wheresql.append(_stream.str()); + return *mod; + } + template + requires std::is_integral_v<_SQL_Value> || std::is_floating_point_v<_SQL_Value> + M_MODEL &between(const std::string &wq, _SQL_Value a, _SQL_Value b) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" ("); + wheresql.append(wq); + wheresql.append(" BETWEEN "); + std::stringstream _stream; + _stream << a; + _stream << " AND "; + _stream << b; + _stream << " ) "; + wheresql.append(_stream.str()); + return *mod; + } + template + requires std::is_integral_v<_SQL_Value> || std::is_floating_point_v<_SQL_Value> + M_MODEL &orBetween(const std::string &wq, _SQL_Value a, _SQL_Value b) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(" ("); + wheresql.append(wq); + wheresql.append(" BETWEEN "); + std::stringstream _stream; + _stream << a; + _stream << " AND "; + _stream << b; + _stream << " ) "; + wheresql.append(_stream.str()); + return *mod; + } + M_MODEL &whereLike(const std::string &wq, const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.append(" like '"); + if (val.size() > 0 && (val[0] == '%' || val.back() == '%')) + { + wheresql.append(val); + wheresql.append("' "); + } + else + { + wheresql.push_back('%'); + wheresql.append(val); + wheresql.append("%' "); + } + return *mod; + } + M_MODEL &whereLikeLeft(const std::string &wq, const std::string &val) + { + + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.append(" like '"); + wheresql.push_back('%'); + wheresql.append(val); + wheresql.append("' "); + return *mod; + } + M_MODEL &whereLikeRight(const std::string &wq, const std::string &val) + { + + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.append(" like '"); + wheresql.append(val); + wheresql.append("%' "); + return *mod; + } + M_MODEL &whereOrLike(const std::string &wq, const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.append(" like '"); + if (val[0] == '%' || val.back() == '%') + { + wheresql.append(val); + wheresql.append("' "); + } + else + { + wheresql.push_back('%'); + wheresql.append(val); + wheresql.append("%' "); + } + return *mod; + } + M_MODEL &whereAnd(const std::string &wq) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + return *mod; + } + template + requires std::is_integral_v<_SQL_Value> || std::is_floating_point_v<_SQL_Value> + M_MODEL &whereAnd(const std::string &wq, _SQL_Value val) + { + + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.push_back('='); + wheresql.append(std::to_string(val)); + return *mod; + } + + template + requires std::is_integral_v<_SQL_Value> || std::is_floating_point_v<_SQL_Value> + M_MODEL &whereBT(const std::string &wq, _SQL_Value val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.append(" > "); + wheresql.append(std::to_string(val)); + return *mod; + } + + template + requires std::is_integral_v<_SQL_Value> || std::is_floating_point_v<_SQL_Value> + M_MODEL &whereBE(const std::string &wq, _SQL_Value val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.append(" >= "); + wheresql.append(std::to_string(val)); + return *mod; + } + + template + requires std::is_integral_v<_SQL_Value> || std::is_floating_point_v<_SQL_Value> + M_MODEL &whereLT(const std::string &wq, _SQL_Value val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.append(" < "); + wheresql.append(std::to_string(val)); + return *mod; + } + + template + requires std::is_integral_v<_SQL_Value> || std::is_floating_point_v<_SQL_Value> + M_MODEL &whereLE(const std::string &wq, _SQL_Value val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.append(" <= "); + wheresql.append(std::to_string(val)); + return *mod; + } + //where and + M_MODEL &whereEQ(const std::string &wq, const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.push_back('='); + wheresql.push_back('\''); + wheresql.append(val); + wheresql.push_back('\''); + + return *mod; + } + + M_MODEL &whereAnd(const std::string &wq, const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.push_back('='); + wheresql.push_back('\''); + wheresql.append(val); + wheresql.push_back('\''); + + return *mod; + } + //where string or + + M_MODEL &whereOrBT(const std::string &wq, const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.push_back('>'); + + wheresql.push_back('\''); + wheresql.append(val); + wheresql.push_back('\''); + return *mod; + } + + M_MODEL &whereOrBE(const std::string &wq, const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.append(">="); + + wheresql.push_back('\''); + wheresql.append(val); + wheresql.push_back('\''); + return *mod; + } + + M_MODEL &whereOrLT(const std::string &wq, const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.append(" < "); + + wheresql.push_back('\''); + wheresql.append(val); + wheresql.push_back('\''); + return *mod; + } + + M_MODEL &whereOrLE(const std::string &wq, const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.append(" <= "); + + wheresql.push_back('\''); + wheresql.append(val); + wheresql.push_back('\''); + return *mod; + } + + //where or + template + requires std::is_integral_v<_SQL_Value> || std::is_floating_point_v<_SQL_Value> + M_MODEL &whereOrBT(const std::string &wq, _SQL_Value val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.append(" > "); + wheresql.append(std::to_string(val)); + return *mod; + } + + template + requires std::is_integral_v<_SQL_Value> || std::is_floating_point_v<_SQL_Value> + M_MODEL &whereOrBE(const std::string &wq, _SQL_Value val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.append(" >= "); + wheresql.append(std::to_string(val)); + return *mod; + } + + template + requires std::is_integral_v<_SQL_Value> || std::is_floating_point_v<_SQL_Value> + M_MODEL &whereOrLT(const std::string &wq, _SQL_Value val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.append(" < "); + wheresql.append(std::to_string(val)); + return *mod; + } + + template + requires std::is_integral_v<_SQL_Value> || std::is_floating_point_v<_SQL_Value> + M_MODEL &whereOrLE(const std::string &wq, _SQL_Value val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.append(" <= "); + wheresql.append(std::to_string(val)); + return *mod; + } + + M_MODEL &whereOr(const std::string &wq) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + return *mod; + } + template + requires std::is_integral_v<_SQL_Value> || std::is_floating_point_v<_SQL_Value> + M_MODEL &whereOr(const std::string &wq, _SQL_Value val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.push_back('='); + wheresql.append(std::to_string(val)); + return *mod; + } + M_MODEL &whereOr(const std::string &wq, const std::string &val) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" OR "); + } + else + { + if (!iskuohao) + { + wheresql.append(" OR "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(wq); + wheresql.push_back('='); + wheresql.push_back('\''); + wheresql.append(val); + wheresql.push_back('\''); + return *mod; + } + M_MODEL &whereIn(const std::string &k) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(k); + return *mod; + } + M_MODEL &whereIn(const std::string &k, const std::string &a) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + + wheresql.append(k); + wheresql.append(" IN("); + wheresql.append(a); + wheresql.append(") "); + return *mod; + } + + M_MODEL &whereIn(const std::string &k, const std::vector &a) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + wheresql.append(k); + wheresql.append(" in("); + int i = 0; + for (auto &key : a) + { + if (i > 0) + { + wheresql.append(",\'"); + } + else + { + wheresql.append("\'"); + } + wheresql.append(key); + wheresql.append("\'"); + i++; + } + wheresql.append(") "); + return *mod; + } + M_MODEL &whereNotIn(const std::string &k, const std::vector &a) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + + wheresql.append(k); + wheresql.append(" NOT IN("); + int i = 0; + for (auto &key : a) + { + if (i > 0) + { + wheresql.append(",\'"); + } + else + { + wheresql.append("\'"); + } + wheresql.append(key); + wheresql.append("\'"); + i++; + } + wheresql.append(") "); + return *mod; + } + template + requires std::is_integral_v<_SQL_Value> || std::is_floating_point_v<_SQL_Value> + M_MODEL &whereIn(const std::string &k, const std::list<_SQL_Value> &a) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + + wheresql.append(k); + wheresql.append(" in("); + int i = 0; + std::stringstream _stream; + for (auto &key : a) + { + if (i > 0) + { + wheresql.append(","); + } + _stream << key; + wheresql.append(_stream.str()); + i++; + _stream.str(""); + } + wheresql.append(") "); + return *mod; + } + + template + requires std::is_integral_v<_SQL_Value> || std::is_floating_point_v<_SQL_Value> + M_MODEL &whereIn(const std::string &k, const std::vector<_SQL_Value> &a) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + + wheresql.append(k); + wheresql.append(" IN("); + int i = 0; + std::stringstream _stream; + for (auto &key : a) + { + if (i > 0) + { + wheresql.append(","); + } + _stream << key; + wheresql.append(_stream.str()); + i++; + _stream.str(""); + } + wheresql.append(") "); + return *mod; + } + template + requires std::is_integral_v<_SQL_Value> || std::is_floating_point_v<_SQL_Value> + M_MODEL &whereNotIn(const std::string &k, const std::vector<_SQL_Value> &a) + { + if (wheresql.empty()) + { + } + else + { + if (ishascontent) + { + wheresql.append(" AND "); + } + else + { + if (!iskuohao) + { + wheresql.append(" AND "); + } + } + } + if (iskuohao) + { + ishascontent = true; + } + + wheresql.append(k); + wheresql.append(" NOT IN("); + int i = 0; + std::stringstream _stream; + for (auto &key : a) + { + if (i > 0) + { + wheresql.append(","); + } + _stream << key; + wheresql.append(_stream.str()); + i++; + _stream.str(""); + } + wheresql.append(") "); + return *mod; + } + + M_MODEL &order(const std::string &wq) + { + ordersql.append(" ORDER by "); + ordersql.append(wq); + return *mod; + } + M_MODEL &asc(const std::string &wq) + { + + ordersql.append(" ORDER by "); + ordersql.append(wq); + ordersql.append(" ASC "); + return *mod; + } + + M_MODEL &desc(const std::string &wq) + { + + ordersql.append(" ORDER by "); + ordersql.append(wq); + ordersql.append(" DESC "); + return *mod; + } + + M_MODEL &having(const std::string &wq) + { + + groupsql.append(" HAVING by "); + groupsql.append(wq); + return *mod; + } + + M_MODEL &group(const std::string &wq) + { + + groupsql.append(" GROUP BY "); + groupsql.append(wq); + return *mod; + } + + M_MODEL &orsub() + { + + if (iskuohao == true) + { + iskuohao = false; + ishascontent = false; + wheresql.append(" )"); + } + else + { + wheresql.append(" OR ("); + iskuohao = true; + ishascontent = false; + } + return *mod; + } + M_MODEL &andsub() + { + + if (iskuohao == true) + { + iskuohao = false; + wheresql.append(" )"); + ishascontent = false; + } + else + { + wheresql.append(" AND ("); + iskuohao = true; + ishascontent = false; + } + + return *mod; + } + + M_MODEL &endsub() + { + if (iskuohao == true) + { + iskuohao = false; + ishascontent = false; + wheresql.append(" )"); + } + return *mod; + } + + M_MODEL &or_b() + { + + if (iskuohao == true) + { + iskuohao = false; + ishascontent = false; + wheresql.append(" )"); + } + else + { + wheresql.append(" OR ("); + iskuohao = true; + ishascontent = false; + } + return *mod; + } + M_MODEL &and_b() + { + + if (iskuohao == true) + { + iskuohao = false; + wheresql.append(" )"); + ishascontent = false; + } + else + { + wheresql.append(" AND ("); + iskuohao = true; + ishascontent = false; + } + + return *mod; + } + + M_MODEL &or_e() + { + if (iskuohao == true) + { + iskuohao = false; + ishascontent = false; + wheresql.append(" )"); + } + return *mod; + } + + M_MODEL &and_e() + { + if (iskuohao == true) + { + iskuohao = false; + ishascontent = false; + wheresql.append(" )"); + } + return *mod; + } + + M_MODEL &limit(unsigned int num) + { + limitsql.clear(); + limitsql.append(" limit "); + limitsql.append(std::to_string(num)); + return *mod; + } + M_MODEL &limit(unsigned int num, unsigned int endnum) + { + limitsql.clear(); + limitsql.append(" limit "); + limitsql.append(std::to_string(num)); + limitsql.push_back(','); + limitsql.append(std::to_string(endnum)); + return *mod; + } + + std::vector> fetch_obj() + { + effect_num = 0; + if (selectsql.empty()) + { + sqlstring = "SELECT * FROM "; + } + else + { + sqlstring = "SELECT "; + sqlstring.append(selectsql); + sqlstring.append(" FROM "); + } + + sqlstring.append(B_BASE::tablename); + sqlstring.append(" WHERE "); + + if (wheresql.empty()) + { + sqlstring.append(" 1 "); + } + else + { + sqlstring.append(wheresql); + } + if (!groupsql.empty()) + { + sqlstring.append(groupsql); + } + if (!ordersql.empty()) + { + sqlstring.append(ordersql); + } + if (!limitsql.empty()) + { + sqlstring.append(limitsql); + } + + std::vector> temprecord; + + if (iserror) + { + return temprecord; + } + + try + { + effect_num = 0; + if (conn_empty()) + { + return temprecord; + } + //auto conn = conn_obj->get_select_conn(); + if (islock_conn) + { + if (!select_conn) + { + select_conn = conn_obj->get_select_conn(); + } + } + else + { + select_conn = conn_obj->get_select_conn(); + } + + if (select_conn->isdebug) + { + select_conn->begin_time(); + } + + std::size_t n = select_conn->write_sql(sqlstring); + if (n == 0) + { + error_msg = select_conn->error_msg; + select_conn.reset(); + return temprecord; + } + + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + bool is_sql_item = false; + std::vector field_array; + unsigned char action_setup = 0; + unsigned int column_num = 0; + unsigned int offset = 0; + + std::vector field_pos; + + for (; is_sql_item == false;) + { + n = select_conn->read_loop(); + offset = 0; + if (n == 0) + { + error_msg = select_conn->error_msg; + select_conn.reset(); + return temprecord; + } + for (; offset < n;) + { + select_conn->read_field_pack(select_conn->_cache_data, n, offset, temp_pack_data); + if (temp_pack_data.error > 0) + { + iserror = true; + error_msg = temp_pack_data.data; + select_conn.reset(); + return temprecord; + } + if (temp_pack_data.length == temp_pack_data.current_length && temp_pack_data.current_length > 0) + { + if (select_conn->pack_eof_check(temp_pack_data)) + { + is_sql_item = true; + break; + } + + if (action_setup == 0) + { + if (temp_pack_data.length == 2 && (unsigned char)temp_pack_data.data[0] < 251 && (unsigned char)temp_pack_data.data[0] > 0) + { + action_setup = 1; + column_num = (unsigned char)temp_pack_data.data[0]; + } + } + else if (action_setup == 1) + { + field_info_t temp_filed_col; + select_conn->read_col_info(temp_pack_data.data, temp_filed_col); + + field_array.emplace_back(std::move(temp_filed_col)); + column_num--; + if (column_num == 0) + { + action_setup = 2; + for (unsigned int ii = 0; ii < field_array.size(); ii++) + { + field_pos.push_back(B_BASE::findcolpos(field_array[ii].org_name)); + } + } + } + else if (action_setup == 2) + { + unsigned int column_num = field_array.size(); + unsigned int tempnum = 0; + + std::map data_temp; + for (unsigned int ij = 0; ij < column_num; ij++) + { + unsigned long long name_length = 0; + name_length = select_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], tempnum); + + std::string temp_str; + temp_str.resize(name_length); + std::memcpy(temp_str.data(), (unsigned char *)&temp_pack_data.data[tempnum], name_length); + if (field_array[ij].name.size() > 0) + { + data_temp.insert({field_array[ij].name, std::move(temp_str)}); + } + else if (field_array[ij].org_name.size() > 0) + { + data_temp.insert({field_array[ij].org_name, std::move(temp_str)}); + } + + tempnum = tempnum + name_length; + } + temprecord.emplace_back(std::move(data_temp)); + effect_num++; + } + } + else + { + if (offset >= n) + { + break; + } + is_sql_item = true; + break; + } + } + } + if (select_conn->isdebug) + { + select_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = select_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + + if (!islock_conn) + { + conn_obj->back_select_conn(std::move(select_conn)); + } + + if (iscache) + { + if (exptime > 0) + { + save_cache(exptime); + exptime = 0; + iscache = false; + } + } + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + return temprecord; + } + std::tuple, std::map, std::vector>> + fetch_row() + { + effect_num = 0; + if (selectsql.empty()) + { + sqlstring = "SELECT * FROM "; + } + else + { + sqlstring = "SELECT "; + sqlstring.append(selectsql); + sqlstring.append(" FROM "); + } + + sqlstring.append(B_BASE::tablename); + sqlstring.append(" WHERE "); + + if (wheresql.empty()) + { + sqlstring.append(" 1 "); + } + else + { + sqlstring.append(wheresql); + } + if (!groupsql.empty()) + { + sqlstring.append(groupsql); + } + if (!ordersql.empty()) + { + sqlstring.append(ordersql); + } + if (!limitsql.empty()) + { + sqlstring.append(limitsql); + } + + std::vector> temprecord; + std::vector table_fieldname; + std::map table_fieldmap; + + if (iscache) + { + std::size_t sqlhashid = std::hash{}(sqlstring); + + model_meta_cache>> &temp_cache = + model_meta_cache>>::getinstance(); + temprecord = temp_cache.get(sqlhashid); + if (temprecord.size() > 0) + { + iscache = false; + model_meta_cache> &table_cache = model_meta_cache>::getinstance(); + table_fieldname = table_cache.get(sqlhashid); + + model_meta_cache> &tablemap_cache = + model_meta_cache>::getinstance(); + table_fieldmap = tablemap_cache.get(sqlhashid); + + return std::make_tuple(table_fieldname, table_fieldmap, temprecord); + } + } + + if (iserror) + { + return std::make_tuple(table_fieldname, table_fieldmap, temprecord); + } + + try + { + if (conn_empty()) + { + return std::make_tuple(table_fieldname, table_fieldmap, temprecord); + } + //auto conn = conn_obj->get_select_conn(); + if (islock_conn) + { + if (!select_conn) + { + select_conn = conn_obj->get_select_conn(); + } + } + else + { + select_conn = conn_obj->get_select_conn(); + } + + if (select_conn->isdebug) + { + select_conn->begin_time(); + } + + std::size_t n = select_conn->write_sql(sqlstring); + if (n == 0) + { + error_msg = select_conn->error_msg; + select_conn.reset(); + return std::make_tuple(table_fieldname, table_fieldmap, temprecord); + } + + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + bool is_sql_item = false; + std::vector field_array; + // std::vector> field_value; + + unsigned char action_setup = 0; + unsigned int column_num = 0; + + unsigned int offset = 0; + + std::vector field_pos; + + for (; is_sql_item == false;) + { + n = select_conn->read_loop(); + offset = 0; + if (n == 0) + { + error_msg = select_conn->error_msg; + select_conn.reset(); + return std::make_tuple(table_fieldname, table_fieldmap, temprecord); + } + for (; offset < n;) + { + select_conn->read_field_pack(select_conn->_cache_data, n, offset, temp_pack_data); + if (temp_pack_data.error > 0) + { + iserror = true; + error_msg = temp_pack_data.data; + select_conn.reset(); + return std::make_tuple(table_fieldname, table_fieldmap, temprecord); + } + if (temp_pack_data.length == temp_pack_data.current_length && temp_pack_data.current_length > 0) + { + if (select_conn->pack_eof_check(temp_pack_data)) + { + is_sql_item = true; + break; + } + + if (action_setup == 0) + { + if (temp_pack_data.length == 2 && (unsigned char)temp_pack_data.data[0] < 251 && (unsigned char)temp_pack_data.data[0] > 0) + { + action_setup = 1; + column_num = (unsigned char)temp_pack_data.data[0]; + } + } + else if (action_setup == 1) + { + field_info_t temp_filed_col; + select_conn->read_col_info(temp_pack_data.data, temp_filed_col); + + field_array.emplace_back(std::move(temp_filed_col)); + column_num--; + if (column_num == 0) + { + action_setup = 2; + for (unsigned int ii = 0; ii < field_array.size(); ii++) + { + field_pos.push_back(B_BASE::findcolpos(field_array[ii].org_name)); + table_fieldmap.emplace(field_array[ii].org_name, table_fieldname.size()); + table_fieldname.push_back(field_array[ii].org_name); + } + } + } + else if (action_setup == 2) + { + unsigned int column_num = field_array.size(); + unsigned int tempnum = 0; + + std::vector temp_v_record; + for (unsigned int ij = 0; ij < column_num; ij++) + { + unsigned long long name_length = 0; + name_length = select_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], tempnum); + std::string tempstr; + tempstr.resize(name_length); + std::memcpy(tempstr.data(), (unsigned char *)&temp_pack_data.data[tempnum], name_length); + temp_v_record.push_back(std::move(tempstr)); + tempnum = tempnum + name_length; + } + temprecord.push_back(temp_v_record); + effect_num++; + } + } + else + { + if (offset >= n) + { + break; + } + is_sql_item = true; + break; + } + } + } + if (select_conn->isdebug) + { + select_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = select_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + + if (!islock_conn) + { + conn_obj->back_select_conn(std::move(select_conn)); + } + + if (iscache) + { + if (exptime > 0) + { + if (temprecord.size() > 0) + { + std::size_t sqlhashid = std::hash{}(sqlstring); + + model_meta_cache>> &temp_cache = + model_meta_cache>>::getinstance(); + temp_cache.save(sqlhashid, temprecord, exptime); + + exptime += 1; + model_meta_cache> &table_cache = model_meta_cache>::getinstance(); + table_cache.save(sqlhashid, table_fieldname, exptime); + + model_meta_cache> &tablemap_cache = + model_meta_cache>::getinstance(); + tablemap_cache.save(sqlhashid, table_fieldmap, exptime); + exptime = 0; + iscache = false; + } + } + } + + return std::make_tuple(std::move(table_fieldname), std::move(table_fieldmap), std::move(temprecord)); + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + return std::make_tuple(table_fieldname, table_fieldmap, temprecord); + } + M_MODEL &fetch() + { + effect_num = 0; + if (selectsql.empty()) + { + sqlstring = "SELECT * FROM "; + } + else + { + sqlstring = "SELECT "; + sqlstring.append(selectsql); + sqlstring.append(" FROM "); + } + + sqlstring.append(B_BASE::tablename); + sqlstring.append(" WHERE "); + + if (wheresql.empty()) + { + sqlstring.append(" 1 "); + } + else + { + sqlstring.append(wheresql); + } + if (!groupsql.empty()) + { + sqlstring.append(groupsql); + } + if (!ordersql.empty()) + { + sqlstring.append(ordersql); + } + if (!limitsql.empty()) + { + sqlstring.append(limitsql); + } + + if (iscache) + { + std::size_t sqlhashid = std::hash{}(sqlstring); + if (get_record_cache(sqlhashid)) + { + iscache = false; + return *mod; + } + } + + B_BASE::record_reset(); + if (iserror) + { + return *mod; + } + + try + { + if (conn_empty()) + { + return *mod; + } + //auto conn = conn_obj->get_select_conn(); + if (islock_conn) + { + if (!select_conn) + { + select_conn = conn_obj->get_select_conn(); + } + } + else + { + select_conn = conn_obj->get_select_conn(); + } + if (select_conn->isdebug) + { + select_conn->begin_time(); + } + + std::size_t n = select_conn->write_sql(sqlstring); + if (n == 0) + { + error_msg = select_conn->error_msg; + select_conn.reset(); + return *mod; + } + + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + bool is_sql_item = false; + std::vector field_array; + + unsigned char action_setup = 0; + unsigned int column_num = 0; + + unsigned int offset = 0; + + std::vector field_pos; + + for (; is_sql_item == false;) + { + n = select_conn->read_loop(); + offset = 0; + if (n == 0) + { + iserror = true; + error_msg = select_conn->error_msg; + select_conn.reset(); + return *mod; + } + for (; offset < n;) + { + select_conn->read_field_pack(select_conn->_cache_data, n, offset, temp_pack_data); + if (temp_pack_data.error > 0) + { + iserror = true; + error_msg = temp_pack_data.data; + select_conn.reset(); + return *mod; + } + if (temp_pack_data.length == temp_pack_data.current_length && temp_pack_data.current_length > 0) + { + if (select_conn->pack_eof_check(temp_pack_data)) + { + is_sql_item = true; + break; + } + + if (action_setup == 0) + { + if (temp_pack_data.length == 2 && (unsigned char)temp_pack_data.data[0] < 251 && (unsigned char)temp_pack_data.data[0] > 0) + { + action_setup = 1; + column_num = (unsigned char)temp_pack_data.data[0]; + } + } + else if (action_setup == 1) + { + field_info_t temp_filed_col; + select_conn->read_col_info(temp_pack_data.data, temp_filed_col); + + field_array.emplace_back(std::move(temp_filed_col)); + column_num--; + if (column_num == 0) + { + action_setup = 2; + for (unsigned int ii = 0; ii < field_array.size(); ii++) + { + field_pos.push_back(B_BASE::findcolpos(field_array[ii].org_name)); + } + } + } + else if (action_setup == 2) + { + unsigned int column_num = field_array.size(); + unsigned int tempnum = 0; + + typename B_BASE::meta data_temp; + for (unsigned int ij = 0; ij < column_num; ij++) + { + unsigned long long name_length = 0; + name_length = select_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], tempnum); + + assign_field_value(field_pos[ij], (unsigned char *)&temp_pack_data.data[tempnum], name_length, data_temp); + tempnum = tempnum + name_length; + } + B_BASE::record.emplace_back(std::move(data_temp)); + effect_num++; + } + } + else + { + if (offset >= n) + { + break; + } + is_sql_item = true; + break; + } + } + } + if (select_conn->isdebug) + { + select_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = select_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + + if (!islock_conn) + { + conn_obj->back_select_conn(std::move(select_conn)); + } + + if (iscache) + { + if (exptime > 0) + { + save_cache(exptime); + exptime = 0; + iscache = false; + } + } + return *mod; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + return *mod; + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + return *mod; + } + + asio::awaitable async_fetch() + { + effect_num = 0; + if (selectsql.empty()) + { + sqlstring = "SELECT * FROM "; + } + else + { + sqlstring = "SELECT "; + sqlstring.append(selectsql); + sqlstring.append(" FROM "); + } + + sqlstring.append(B_BASE::tablename); + sqlstring.append(" WHERE "); + + if (wheresql.empty()) + { + sqlstring.append(" 1 "); + } + else + { + sqlstring.append(wheresql); + } + if (!groupsql.empty()) + { + sqlstring.append(groupsql); + } + if (!ordersql.empty()) + { + sqlstring.append(ordersql); + } + if (!limitsql.empty()) + { + sqlstring.append(limitsql); + } + + if (iscache) + { + std::size_t sqlhashid = std::hash{}(sqlstring); + if (get_record_cache(sqlhashid)) + { + iscache = false; + co_return 0; + } + } + + B_BASE::record_reset(); + if (iserror) + { + co_return 0; + } + + try + { + if (conn_empty()) + { + co_return 0; + } + //auto conn = co_await conn_obj->async_get_select_conn(); + if (islock_conn) + { + if (!select_conn) + { + select_conn = co_await conn_obj->async_get_select_conn(); + } + } + else + { + select_conn = co_await conn_obj->async_get_select_conn(); + } + if (select_conn->isdebug) + { + select_conn->begin_time(); + } + + std::size_t n = co_await select_conn->async_write_sql(sqlstring); + + if (n == 0) + { + error_msg = select_conn->error_msg; + select_conn.reset(); + co_return 0; + } + + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + bool is_sql_item = false; + std::vector field_array; + + unsigned char action_setup = 0; + unsigned int column_num = 0; + + unsigned int offset = 0; + + std::vector field_pos; + + for (; is_sql_item == false;) + { + n = co_await select_conn->async_read_loop(); + offset = 0; + if (n == 0) + { + select_conn.reset(); + co_return 0; + } + for (; offset < n;) + { + select_conn->read_field_pack(select_conn->_cache_data, n, offset, temp_pack_data); + if (temp_pack_data.error > 0) + { + iserror = true; + error_msg = temp_pack_data.data; + select_conn.reset(); + co_return 0; + } + if (temp_pack_data.length == temp_pack_data.current_length && temp_pack_data.current_length > 0) + { + if (select_conn->pack_eof_check(temp_pack_data)) + { + is_sql_item = true; + break; + } + + if (action_setup == 0) + { + if (temp_pack_data.length == 2 && (unsigned char)temp_pack_data.data[0] < 251 && (unsigned char)temp_pack_data.data[0] > 0) + { + action_setup = 1; + column_num = (unsigned char)temp_pack_data.data[0]; + } + } + else if (action_setup == 1) + { + field_info_t temp_filed_col; + select_conn->read_col_info(temp_pack_data.data, temp_filed_col); + + field_array.emplace_back(std::move(temp_filed_col)); + column_num--; + if (column_num == 0) + { + action_setup = 2; + for (unsigned int ii = 0; ii < field_array.size(); ii++) + { + field_pos.push_back(B_BASE::findcolpos(field_array[ii].org_name)); + } + } + } + else if (action_setup == 2) + { + unsigned int column_num = field_array.size(); + unsigned int tempnum = 0; + + typename B_BASE::meta data_temp; + for (unsigned int ij = 0; ij < column_num; ij++) + { + unsigned long long name_length = 0; + name_length = select_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], tempnum); + + assign_field_value(field_pos[ij], (unsigned char *)&temp_pack_data.data[tempnum], name_length, data_temp); + tempnum = tempnum + name_length; + } + B_BASE::record.emplace_back(std::move(data_temp)); + effect_num++; + } + } + else + { + if (offset >= n) + { + break; + } + is_sql_item = true; + break; + } + } + } + if (select_conn->isdebug) + { + select_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = select_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + if (!islock_conn) + { + conn_obj->back_select_conn(std::move(select_conn)); + } + if (iscache) + { + if (exptime > 0) + { + save_cache(exptime); + exptime = 0; + iscache = false; + } + } + co_return effect_num; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + co_return 0; + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + co_return 0; + } + M_MODEL &fetch_append() + { + effect_num = 0; + if (selectsql.empty()) + { + sqlstring = "SELECT * FROM "; + } + else + { + sqlstring = "SELECT "; + sqlstring.append(selectsql); + sqlstring.append(" FROM "); + } + + sqlstring.append(B_BASE::tablename); + sqlstring.append(" WHERE "); + + if (wheresql.empty()) + { + sqlstring.append(" 1 "); + } + else + { + sqlstring.append(wheresql); + } + if (!groupsql.empty()) + { + sqlstring.append(groupsql); + } + if (!ordersql.empty()) + { + sqlstring.append(ordersql); + } + if (!limitsql.empty()) + { + sqlstring.append(limitsql); + } + + if (iscache) + { + std::size_t sqlhashid = std::hash{}(sqlstring); + if (get_record_cache(sqlhashid)) + { + iscache = false; + return *mod; + } + } + + if (iserror) + { + return *mod; + } + + try + { + + if (conn_empty()) + { + return 0; + } + //auto conn = conn_obj->get_select_conn(); + if (islock_conn) + { + if (!select_conn) + { + select_conn = conn_obj->get_select_conn(); + } + } + else + { + select_conn = conn_obj->get_select_conn(); + } + + if (select_conn->isdebug) + { + select_conn->begin_time(); + } + std::size_t n = select_conn->write_sql(sqlstring); + if (n == 0) + { + error_msg = select_conn->error_msg; + select_conn.reset(); + return 0; + } + + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + bool is_sql_item = false; + std::vector field_array; + + unsigned char action_setup = 0; + unsigned int column_num = 0; + + unsigned int offset = 0; + + std::vector field_pos; + + for (; is_sql_item == false;) + { + n = select_conn->read_loop(); + offset = 0; + if (n == 0) + { + error_msg = select_conn->error_msg; + select_conn.reset(); + return 0; + } + for (; offset < n;) + { + select_conn->read_field_pack(select_conn->_cache_data, n, offset, temp_pack_data); + if (temp_pack_data.error > 0) + { + iserror = true; + error_msg = temp_pack_data.data; + select_conn.reset(); + return 0; + } + if (temp_pack_data.length == temp_pack_data.current_length && temp_pack_data.current_length > 0) + { + if (select_conn->pack_eof_check(temp_pack_data)) + { + is_sql_item = true; + break; + } + + if (action_setup == 0) + { + if (temp_pack_data.length == 2 && (unsigned char)temp_pack_data.data[0] < 251 && (unsigned char)temp_pack_data.data[0] > 0) + { + action_setup = 1; + column_num = (unsigned char)temp_pack_data.data[0]; + } + } + else if (action_setup == 1) + { + field_info_t temp_filed_col; + select_conn->read_col_info(temp_pack_data.data, temp_filed_col); + + field_array.emplace_back(std::move(temp_filed_col)); + column_num--; + if (column_num == 0) + { + action_setup = 2; + for (unsigned int ii = 0; ii < field_array.size(); ii++) + { + field_pos.push_back(B_BASE::findcolpos(field_array[ii].org_name)); + } + } + } + else if (action_setup == 2) + { + unsigned int column_num = field_array.size(); + unsigned int tempnum = 0; + + typename B_BASE::meta data_temp; + for (unsigned int ij = 0; ij < column_num; ij++) + { + unsigned long long name_length = 0; + name_length = select_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], tempnum); + + assign_field_value(field_pos[ij], (unsigned char *)&temp_pack_data.data[tempnum], name_length, data_temp); + tempnum = tempnum + name_length; + } + B_BASE::record.emplace_back(std::move(data_temp)); + effect_num++; + } + } + else + { + if (offset >= n) + { + break; + } + is_sql_item = true; + break; + } + } + } + if (select_conn->isdebug) + { + select_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = select_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + + if (!islock_conn) + { + conn_obj->back_select_conn(std::move(select_conn)); + } + + if (iscache) + { + if (exptime > 0) + { + save_cache(exptime); + exptime = 0; + iscache = false; + } + } + return *mod; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + return *mod; + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + return *mod; + } + + asio::awaitable async_fetch_append() + { + effect_num = 0; + if (selectsql.empty()) + { + sqlstring = "SELECT * FROM "; + } + else + { + sqlstring = "SELECT "; + sqlstring.append(selectsql); + sqlstring.append(" FROM "); + } + + sqlstring.append(B_BASE::tablename); + sqlstring.append(" WHERE "); + + if (wheresql.empty()) + { + sqlstring.append(" 1 "); + } + else + { + sqlstring.append(wheresql); + } + if (!groupsql.empty()) + { + sqlstring.append(groupsql); + } + if (!ordersql.empty()) + { + sqlstring.append(ordersql); + } + if (!limitsql.empty()) + { + sqlstring.append(limitsql); + } + + if (iscache) + { + std::size_t sqlhashid = std::hash{}(sqlstring); + if (get_record_cache(sqlhashid)) + { + iscache = false; + co_return 1; + } + } + + if (iserror) + { + co_return 0; + } + + try + { + effect_num = 0; + + if (conn_empty()) + { + co_return 0; + } + //auto conn = co_await conn_obj->async_get_select_conn(); + if (islock_conn) + { + if (!select_conn) + { + select_conn = co_await conn_obj->async_get_select_conn(); + } + } + else + { + select_conn = co_await conn_obj->async_get_select_conn(); + } + + if (select_conn->isdebug) + { + select_conn->begin_time(); + } + std::size_t n = co_await select_conn->async_write_sql(sqlstring); + if (n == 0) + { + error_msg = select_conn->error_msg; + select_conn.reset(); + co_return 0; + } + + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + bool is_sql_item = false; + std::vector field_array; + // std::vector> field_value; + + unsigned char action_setup = 0; + unsigned int column_num = 0; + + unsigned int offset = 0; + + std::vector field_pos; + // std::map other_col; + + for (; is_sql_item == false;) + { + n = co_await select_conn->async_read_loop(); + offset = 0; + if (n == 0) + { + select_conn.reset(); + co_return 0; + } + for (; offset < n;) + { + select_conn->read_field_pack(select_conn->_cache_data, n, offset, temp_pack_data); + if (temp_pack_data.error > 0) + { + iserror = true; + error_msg = temp_pack_data.data; + select_conn.reset(); + co_return 0; + } + if (temp_pack_data.length == temp_pack_data.current_length && temp_pack_data.current_length > 0) + { + if (select_conn->pack_eof_check(temp_pack_data)) + { + is_sql_item = true; + break; + } + + if (action_setup == 0) + { + if (temp_pack_data.length == 2 && (unsigned char)temp_pack_data.data[0] < 251 && (unsigned char)temp_pack_data.data[0] > 0) + { + action_setup = 1; + column_num = (unsigned char)temp_pack_data.data[0]; + } + } + else if (action_setup == 1) + { + field_info_t temp_filed_col; + select_conn->read_col_info(temp_pack_data.data, temp_filed_col); + + field_array.emplace_back(std::move(temp_filed_col)); + column_num--; + if (column_num == 0) + { + action_setup = 2; + for (unsigned int ii = 0; ii < field_array.size(); ii++) + { + field_pos.push_back(B_BASE::findcolpos(field_array[ii].org_name)); + } + } + } + else if (action_setup == 2) + { + unsigned int column_num = field_array.size(); + unsigned int tempnum = 0; + + typename B_BASE::meta data_temp; + for (unsigned int ij = 0; ij < column_num; ij++) + { + unsigned long long name_length = 0; + name_length = select_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], tempnum); + + assign_field_value(field_pos[ij], (unsigned char *)&temp_pack_data.data[tempnum], name_length, data_temp); + tempnum = tempnum + name_length; + } + effect_num++; + B_BASE::record.emplace_back(std::move(data_temp)); + } + } + else + { + if (offset >= n) + { + break; + } + is_sql_item = true; + break; + } + } + } + if (select_conn->isdebug) + { + select_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = select_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + if (!islock_conn) + { + conn_obj->back_select_conn(std::move(select_conn)); + } + if (iscache) + { + if (exptime > 0) + { + save_cache(exptime); + exptime = 0; + iscache = false; + } + } + co_return effect_num; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + co_return 0; + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + co_return 0; + } + unsigned int fetch_one(bool isappend = false) + { + effect_num = 0; + if (selectsql.empty()) + { + sqlstring = "SELECT * FROM "; + } + else + { + sqlstring = "SELECT "; + sqlstring.append(selectsql); + sqlstring.append(" FROM "); + } + + sqlstring.append(B_BASE::tablename); + sqlstring.append(" WHERE "); + + if (wheresql.empty()) + { + sqlstring.append(" 1 "); + } + else + { + sqlstring.append(wheresql); + } + if (!groupsql.empty()) + { + sqlstring.append(groupsql); + } + if (!ordersql.empty()) + { + sqlstring.append(ordersql); + } + + sqlstring.append(" limit 1"); + + if (iscache) + { + std::size_t sqlhashid = std::hash{}(sqlstring); + if (get_data_cache(sqlhashid)) + { + iscache = false; + return 0; + } + } + + B_BASE::data_reset(); + if (iserror) + { + return 0; + } + + try + { + effect_num = 0; + if (conn_empty()) + { + return 0; + } + //auto conn = conn_obj->get_select_conn(); + if (islock_conn) + { + if (!select_conn) + { + select_conn = conn_obj->get_select_conn(); + } + } + else + { + select_conn = conn_obj->get_select_conn(); + } + + if (select_conn->isdebug) + { + select_conn->begin_time(); + } + + std::size_t n = select_conn->write_sql(sqlstring); + if (n == 0) + { + error_msg = select_conn->error_msg; + select_conn.reset(); + return 0; + } + + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + bool is_sql_item = false; + std::vector field_array; + unsigned char action_setup = 0; + unsigned int column_num = 0; + unsigned int offset = 0; + + std::vector field_pos; + + for (; is_sql_item == false;) + { + n = select_conn->read_loop(); + offset = 0; + if (n == 0) + { + error_msg = select_conn->error_msg; + select_conn.reset(); + return 0; + } + for (; offset < n;) + { + select_conn->read_field_pack(select_conn->_cache_data, n, offset, temp_pack_data); + if (temp_pack_data.error > 0) + { + iserror = true; + error_msg = temp_pack_data.data; + select_conn.reset(); + return 0; + } + if (temp_pack_data.length == temp_pack_data.current_length && temp_pack_data.current_length > 0) + { + if (select_conn->pack_eof_check(temp_pack_data)) + { + is_sql_item = true; + break; + } + + if (action_setup == 0) + { + if (temp_pack_data.length == 2 && (unsigned char)temp_pack_data.data[0] < 251 && (unsigned char)temp_pack_data.data[0] > 0) + { + action_setup = 1; + column_num = (unsigned char)temp_pack_data.data[0]; + } + } + else if (action_setup == 1) + { + field_info_t temp_filed_col; + select_conn->read_col_info(temp_pack_data.data, temp_filed_col); + + field_array.emplace_back(std::move(temp_filed_col)); + column_num--; + if (column_num == 0) + { + action_setup = 2; + for (unsigned int ii = 0; ii < field_array.size(); ii++) + { + field_pos.push_back(B_BASE::findcolpos(field_array[ii].org_name)); + } + } + } + else if (action_setup == 2) + { + unsigned int column_num = field_array.size(); + unsigned int tempnum = 0; + + if (isappend) + { + typename B_BASE::meta data_temp; + for (unsigned int ij = 0; ij < column_num; ij++) + { + unsigned long long name_length = 0; + name_length = select_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], tempnum); + + assign_field_value(field_pos[ij], (unsigned char *)&temp_pack_data.data[tempnum], name_length, data_temp); + tempnum = tempnum + name_length; + } + B_BASE::record.emplace_back(std::move(data_temp)); + effect_num++; + } + else + { + for (unsigned int ij = 0; ij < column_num; ij++) + { + unsigned long long name_length = 0; + name_length = select_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], tempnum); + + assign_field_value(field_pos[ij], (unsigned char *)&temp_pack_data.data[tempnum], name_length, B_BASE::data); + tempnum = tempnum + name_length; + } + effect_num++; + } + } + } + else + { + if (offset >= n) + { + break; + } + is_sql_item = true; + break; + } + } + } + if (select_conn->isdebug) + { + select_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = select_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + + if (!islock_conn) + { + conn_obj->back_select_conn(std::move(select_conn)); + } + + if (iscache) + { + if (exptime > 0) + { + save_data_cache(exptime); + exptime = 0; + iscache = false; + } + } + return effect_num; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + return 0; + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + return 0; + } + + asio::awaitable async_fetch_one(bool isappend = false) + { + effect_num = 0; + if (selectsql.empty()) + { + sqlstring = "SELECT * FROM "; + } + else + { + sqlstring = "SELECT "; + sqlstring.append(selectsql); + sqlstring.append(" FROM "); + } + + sqlstring.append(B_BASE::tablename); + sqlstring.append(" WHERE "); + + if (wheresql.empty()) + { + sqlstring.append(" 1 "); + } + else + { + sqlstring.append(wheresql); + } + if (!groupsql.empty()) + { + sqlstring.append(groupsql); + } + if (!ordersql.empty()) + { + sqlstring.append(ordersql); + } + + sqlstring.append(" limit 1"); + + if (iscache) + { + std::size_t sqlhashid = std::hash{}(sqlstring); + if (get_data_cache(sqlhashid)) + { + iscache = false; + co_return 0; + } + } + + B_BASE::data_reset(); + if (iserror) + { + co_return 0; + } + + try + { + effect_num = 0; + + if (conn_empty()) + { + co_return 0; + } + //auto conn = co_await conn_obj->async_get_select_conn(); + if (islock_conn) + { + if (!select_conn) + { + select_conn = co_await conn_obj->async_get_select_conn(); + } + } + else + { + select_conn = co_await conn_obj->async_get_select_conn(); + } + if (select_conn->isdebug) + { + select_conn->begin_time(); + } + + std::size_t n = co_await select_conn->async_write_sql(sqlstring); + + if (n == 0) + { + error_msg = select_conn->error_msg; + select_conn.reset(); + co_return 0; + } + + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + bool is_sql_item = false; + std::vector field_array; + + unsigned char action_setup = 0; + unsigned int column_num = 0; + + unsigned int offset = 0; + + std::vector field_pos; + + for (; is_sql_item == false;) + { + n = co_await select_conn->async_read_loop(); + offset = 0; + if (n == 0) + { + select_conn.reset(); + co_return 0; + } + for (; offset < n;) + { + select_conn->read_field_pack(select_conn->_cache_data, n, offset, temp_pack_data); + if (temp_pack_data.error > 0) + { + iserror = true; + error_msg = temp_pack_data.data; + select_conn.reset(); + co_return 0; + } + if (temp_pack_data.length == temp_pack_data.current_length && temp_pack_data.current_length > 0) + { + if (select_conn->pack_eof_check(temp_pack_data)) + { + is_sql_item = true; + break; + } + + if (action_setup == 0) + { + if (temp_pack_data.length == 2 && (unsigned char)temp_pack_data.data[0] < 251 && (unsigned char)temp_pack_data.data[0] > 0) + { + action_setup = 1; + column_num = (unsigned char)temp_pack_data.data[0]; + } + } + else if (action_setup == 1) + { + field_info_t temp_filed_col; + select_conn->read_col_info(temp_pack_data.data, temp_filed_col); + + field_array.emplace_back(std::move(temp_filed_col)); + column_num--; + if (column_num == 0) + { + action_setup = 2; + for (unsigned int ii = 0; ii < field_array.size(); ii++) + { + field_pos.push_back(B_BASE::findcolpos(field_array[ii].org_name)); + } + } + } + else if (action_setup == 2) + { + unsigned int column_num = field_array.size(); + unsigned int tempnum = 0; + + if (isappend) + { + typename B_BASE::meta data_temp; + for (unsigned int ij = 0; ij < column_num; ij++) + { + unsigned long long name_length = 0; + name_length = select_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], tempnum); + + assign_field_value(field_pos[ij], (unsigned char *)&temp_pack_data.data[tempnum], name_length, data_temp); + tempnum = tempnum + name_length; + } + B_BASE::record.emplace_back(std::move(data_temp)); + effect_num++; + } + else + { + for (unsigned int ij = 0; ij < column_num; ij++) + { + unsigned long long name_length = 0; + name_length = select_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], tempnum); + + assign_field_value(field_pos[ij], (unsigned char *)&temp_pack_data.data[tempnum], name_length, B_BASE::data); + tempnum = tempnum + name_length; + } + effect_num++; + } + } + } + else + { + if (offset >= n) + { + break; + } + is_sql_item = true; + break; + } + } + } + if (select_conn->isdebug) + { + select_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = select_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + if (!islock_conn) + { + conn_obj->back_select_conn(std::move(select_conn)); + } + if (iscache) + { + if (exptime > 0) + { + save_data_cache(exptime); + exptime = 0; + iscache = false; + } + } + co_return effect_num; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + co_return 0; + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + co_return 0; + } + + M_MODEL &use_cache(int cache_time = 0) + { + iscache = true; + exptime = cache_time; + return *mod; + } + bool isuse_cache(bool iscachedate = false) + { + if (iscachedate) + { + return exptime == 0 && iscache == false; + } + return iscache; + } + void set_cache_state(bool isrestatus = false) { iscache = isrestatus; } + void remove_exptime_cache() + { + model_meta_cache &temp_cache = model_meta_cache::getinstance(); + temp_cache.remove_exptime(); + } + void clear_cache() + { + model_meta_cache &temp_cache = model_meta_cache::getinstance(); + temp_cache.clear(); + } + bool remove_cache() + { + model_meta_cache &temp_cache = model_meta_cache::getinstance(); + std::size_t sqlhashid = std::hash{}(sqlstring); + return temp_cache.remove(sqlhashid); + } + bool remove_cache(std::size_t cache_key_name) + { + model_meta_cache &temp_cache = model_meta_cache::getinstance(); + return temp_cache.remove(cache_key_name); + } + int check_cache(std::size_t cache_key_name) + { + model_meta_cache &temp_cache = model_meta_cache::getinstance(); + return temp_cache.check(cache_key_name); + } + + bool get_data_cache(std::size_t cache_key_name) + { + try + { + model_meta_cache &temp_cache = model_meta_cache::getinstance(); + B_BASE::data = temp_cache.get(cache_key_name); + return true; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + } + catch (const std::string &e) + { + error_msg = e; + } + catch (const char *e) + { + error_msg = e; + } + catch (...) + { + } + B_BASE::data_reset(); + return false; + } + int update_cache(int exp_time = 0) + { + model_meta_cache> &temp_cache = model_meta_cache>::getinstance(); + std::size_t sqlhashid = std::hash{}(sqlstring); + return temp_cache.update(sqlhashid, exp_time); + } + int update_cache(std::size_t cache_key_name, int exp_time) + { + model_meta_cache> &temp_cache = model_meta_cache>::getinstance(); + return temp_cache.update(cache_key_name, exp_time); + } + bool save_cache(int exp_time = 0) + { + model_meta_cache> &temp_cache = model_meta_cache>::getinstance(); + std::size_t sqlhashid = std::hash{}(sqlstring); + temp_cache.save(sqlhashid, B_BASE::record, exp_time); + return true; + } + + bool save_data_cache(int exp_time = 0) + { + model_meta_cache &temp_cache = model_meta_cache::getinstance(); + std::size_t sqlhashid = std::hash{}(sqlstring); + temp_cache.save(sqlhashid, B_BASE::data, exp_time); + return true; + } + + bool save_data_cache(const std::string &cache_key_name, const typename B_BASE::meta &cache_data, int exp_time = 0) + { + model_meta_cache &temp_cache = model_meta_cache::getinstance(); + std::size_t sqlhashid = std::hash{}(cache_key_name); + temp_cache.save(sqlhashid, cache_data, exp_time); + return true; + } + + bool save_cache(std::size_t cache_key_name, const std::vector &cache_data, int exp_time = 0) + { + model_meta_cache> &temp_cache = model_meta_cache>::getinstance(); + temp_cache.save(cache_key_name, cache_data, exp_time); + return true; + } + bool save_cache(const std::string cache_key_name, const std::vector &cache_data, int exp_time = 0) + { + model_meta_cache> &temp_cache = model_meta_cache>::getinstance(); + std::size_t sqlhashid = std::hash{}(cache_key_name); + temp_cache.save(sqlhashid, cache_data, exp_time); + return true; + } + bool save_vector_cache(const std::string cache_key_name, const std::vector &cache_data, int exp_time = 0) + { + model_meta_cache> &temp_cache = model_meta_cache>::getinstance(); + std::size_t sqlhashid = std::hash{}(cache_key_name); + temp_cache.save(sqlhashid, cache_data, exp_time); + return true; + } + bool save_cache(const std::string cache_key_name, const typename B_BASE::meta &cache_data, int exp_time = 0) + { + model_meta_cache &temp_cache = model_meta_cache::getinstance(); + std::size_t sqlhashid = std::hash{}(cache_key_name); + temp_cache.save(sqlhashid, cache_data, exp_time); + return true; + } + typename B_BASE::meta &get_cache(const std::string &cache_key_name) + { + try + { + model_meta_cache &temp_cache = model_meta_cache::getinstance(); + std::size_t sqlhashid = std::hash{}(cache_key_name); + return temp_cache.get(sqlhashid); + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + } + catch (const std::string &e) + { + error_msg = e; + } + catch (const char *e) + { + error_msg = e; + } + catch (...) + { + } + throw "Not in cache"; + } + + std::vector &get_vector_cache(const std::string &cache_key_name) + { + try + { + model_meta_cache> &temp_cache = model_meta_cache>::getinstance(); + std::size_t sqlhashid = std::hash{}(cache_key_name); + return temp_cache.get(sqlhashid); + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + } + catch (const std::string &e) + { + error_msg = e; + } + catch (const char *e) + { + error_msg = e; + } + catch (...) + { + } + throw "Not in cache"; + } + + bool get_record_cache(std::size_t cache_key_name) + { + try + { + model_meta_cache> &temp_cache = model_meta_cache>::getinstance(); + B_BASE::record = temp_cache.get(cache_key_name); + return true; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + } + catch (const std::string &e) + { + error_msg = e; + } + catch (const char *e) + { + error_msg = e; + } + catch (...) + { + } + B_BASE::record.clear(); + return false; + } + http::obj_val fetch_json() + { + effect_num = 0; + if (selectsql.empty()) + { + sqlstring = "SELECT * FROM "; + } + else + { + sqlstring = "SELECT "; + sqlstring.append(selectsql); + sqlstring.append(" FROM "); + } + + sqlstring.append(B_BASE::tablename); + sqlstring.append(" WHERE "); + + if (wheresql.empty()) + { + sqlstring.append(" 1 "); + } + else + { + sqlstring.append(wheresql); + } + if (!groupsql.empty()) + { + sqlstring.append(groupsql); + } + if (!ordersql.empty()) + { + sqlstring.append(ordersql); + } + if (!limitsql.empty()) + { + sqlstring.append(limitsql); + } + + http::obj_val valuetemp; + valuetemp.set_array(); + + if (iserror) + { + return valuetemp; + } + + try + { + if (conn_empty()) + { + return 0; + } + //auto conn = conn_obj->get_select_conn(); + if (islock_conn) + { + if (!select_conn) + { + select_conn = conn_obj->get_select_conn(); + } + } + else + { + select_conn = conn_obj->get_select_conn(); + } + + if (select_conn->isdebug) + { + select_conn->begin_time(); + } + + std::size_t n = select_conn->write_sql(sqlstring); + if (n == 0) + { + error_msg = select_conn->error_msg; + select_conn.reset(); + return 0; + } + + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + bool is_sql_item = false; + std::vector field_array; + + unsigned char action_setup = 0; + unsigned int column_num = 0; + + unsigned int offset = 0; + + for (; is_sql_item == false;) + { + n = select_conn->read_loop(); + offset = 0; + if (n == 0) + { + error_msg = select_conn->error_msg; + select_conn.reset(); + return 0; + } + for (; offset < n;) + { + select_conn->read_field_pack(select_conn->_cache_data, n, offset, temp_pack_data); + if (temp_pack_data.error > 0) + { + iserror = true; + error_msg = temp_pack_data.data; + select_conn.reset(); + return 0; + } + if (temp_pack_data.length == temp_pack_data.current_length && temp_pack_data.current_length > 0) + { + if (select_conn->pack_eof_check(temp_pack_data)) + { + is_sql_item = true; + break; + } + + if (action_setup == 0) + { + if (temp_pack_data.length == 2 && (unsigned char)temp_pack_data.data[0] < 251 && (unsigned char)temp_pack_data.data[0] > 0) + { + action_setup = 1; + column_num = (unsigned char)temp_pack_data.data[0]; + } + } + else if (action_setup == 1) + { + field_info_t temp_filed_col; + select_conn->read_col_info(temp_pack_data.data, temp_filed_col); + + field_array.emplace_back(std::move(temp_filed_col)); + column_num--; + if (column_num == 0) + { + action_setup = 2; + } + } + else if (action_setup == 2) + { + unsigned int column_num = field_array.size(); + unsigned int tempnum = 0; + + http::obj_val json_temp_v; + for (unsigned int ij = 0; ij < column_num; ij++) + { + unsigned long long name_length = 0; + name_length = select_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], tempnum); + + std::string temp_str; + temp_str.resize(name_length); + std::memcpy(temp_str.data(), (unsigned char *)&temp_pack_data.data[tempnum], name_length); + if (field_array[ij].name.size() > 0) + { + //or alias name + json_temp_v[field_array[ij].name] = std::move(temp_str); + } + else if (field_array[ij].org_name.size() > 0) + { + json_temp_v[field_array[ij].org_name] = std::move(temp_str); + } + tempnum = tempnum + name_length; + } + valuetemp.push(json_temp_v); + effect_num++; + } + } + else + { + if (offset >= n) + { + break; + } + is_sql_item = true; + break; + } + } + } + if (select_conn->isdebug) + { + select_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = select_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + if (!islock_conn) + { + conn_obj->back_select_conn(std::move(select_conn)); + } + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + return valuetemp; + } + + asio::awaitable async_fetch_json() + { + effect_num = 0; + if (selectsql.empty()) + { + sqlstring = "SELECT * FROM "; + } + else + { + sqlstring = "SELECT "; + sqlstring.append(selectsql); + sqlstring.append(" FROM "); + } + + sqlstring.append(B_BASE::tablename); + sqlstring.append(" WHERE "); + + if (wheresql.empty()) + { + sqlstring.append(" 1 "); + } + else + { + sqlstring.append(wheresql); + } + if (!groupsql.empty()) + { + sqlstring.append(groupsql); + } + if (!ordersql.empty()) + { + sqlstring.append(ordersql); + } + if (!limitsql.empty()) + { + sqlstring.append(limitsql); + } + + http::obj_val valuetemp; + valuetemp.set_array(); + + if (iserror) + { + co_return valuetemp; + } + + try + { + if (conn_empty()) + { + co_return valuetemp; + } + //auto conn = co_await conn_obj->async_get_select_conn(); + if (islock_conn) + { + if (!select_conn) + { + select_conn = co_await conn_obj->async_get_select_conn(); + } + } + else + { + select_conn = co_await conn_obj->async_get_select_conn(); + } + + if (select_conn->isdebug) + { + select_conn->begin_time(); + } + std::size_t n = co_await select_conn->async_write_sql(sqlstring); + if (n == 0) + { + error_msg = select_conn->error_msg; + select_conn.reset(); + co_return valuetemp; + } + + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + bool is_sql_item = false; + std::vector field_array; + + unsigned char action_setup = 0; + unsigned int column_num = 0; + + unsigned int offset = 0; + + for (; is_sql_item == false;) + { + n = co_await select_conn->async_read_loop(); + offset = 0; + if (n == 0) + { + select_conn.reset(); + co_return valuetemp; + } + for (; offset < n;) + { + select_conn->read_field_pack(select_conn->_cache_data, n, offset, temp_pack_data); + if (temp_pack_data.error > 0) + { + iserror = true; + error_msg = temp_pack_data.data; + select_conn.reset(); + co_return 0; + } + if (temp_pack_data.length == temp_pack_data.current_length && temp_pack_data.current_length > 0) + { + if (select_conn->pack_eof_check(temp_pack_data)) + { + is_sql_item = true; + break; + } + + if (action_setup == 0) + { + if (temp_pack_data.length == 2 && (unsigned char)temp_pack_data.data[0] < 251 && (unsigned char)temp_pack_data.data[0] > 0) + { + action_setup = 1; + column_num = (unsigned char)temp_pack_data.data[0]; + } + } + else if (action_setup == 1) + { + field_info_t temp_filed_col; + select_conn->read_col_info(temp_pack_data.data, temp_filed_col); + + field_array.emplace_back(std::move(temp_filed_col)); + column_num--; + if (column_num == 0) + { + action_setup = 2; + } + } + else if (action_setup == 2) + { + unsigned int column_num = field_array.size(); + unsigned int tempnum = 0; + + http::obj_val json_temp_v; + for (unsigned int ij = 0; ij < column_num; ij++) + { + unsigned long long name_length = 0; + name_length = select_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], tempnum); + + std::string temp_str; + temp_str.resize(name_length); + std::memcpy(temp_str.data(), (unsigned char *)&temp_pack_data.data[tempnum], name_length); + if (field_array[ij].name.size() > 0) + { + //or alias name + json_temp_v[field_array[ij].name] = std::move(temp_str); + } + else if (field_array[ij].org_name.size() > 0) + { + json_temp_v[field_array[ij].org_name] = std::move(temp_str); + } + tempnum = tempnum + name_length; + } + valuetemp.push(json_temp_v); + effect_num++; + } + } + else + { + if (offset >= n) + { + break; + } + is_sql_item = true; + break; + } + } + } + if (select_conn->isdebug) + { + select_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = select_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + if (!islock_conn) + { + conn_obj->back_select_conn(std::move(select_conn)); + } + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + co_return valuetemp; + } + + long long get_one(long long id) + { + effect_num = 0; + if (selectsql.empty()) + { + sqlstring = "SELECT * FROM "; + } + else + { + sqlstring = "SELECT "; + sqlstring.append(selectsql); + sqlstring.append(" FROM "); + } + + sqlstring.append(B_BASE::tablename); + sqlstring.append(" WHERE "); + + sqlstring.append(B_BASE::getPKname()); + sqlstring.append("="); + sqlstring.append(std::to_string(id)); + sqlstring.append(" limit 1"); + if (iscache) + { + std::size_t sqlhashid = std::hash{}(sqlstring); + if (get_data_cache(sqlhashid)) + { + iscache = false; + return 0; + } + } + + B_BASE::data_reset(); + + if (iserror) + { + return 0; + } + + try + { + if (conn_empty()) + { + return 0; + } + //auto conn = conn_obj->get_select_conn(); + if (islock_conn) + { + if (!select_conn) + { + select_conn = conn_obj->get_select_conn(); + } + } + else + { + select_conn = conn_obj->get_select_conn(); + } + + if (select_conn->isdebug) + { + select_conn->begin_time(); + } + + std::size_t n = select_conn->write_sql(sqlstring); + if (n == 0) + { + error_msg = select_conn->error_msg; + select_conn.reset(); + return 0; + } + + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + bool is_sql_item = false; + std::vector field_array; + + unsigned char action_setup = 0; + unsigned int column_num = 0; + + unsigned int offset = 0; + + std::vector field_pos; + + for (; is_sql_item == false;) + { + n = select_conn->read_loop(); + offset = 0; + if (n == 0) + { + error_msg = select_conn->error_msg; + select_conn.reset(); + return 0; + } + for (; offset < n;) + { + select_conn->read_field_pack(select_conn->_cache_data, n, offset, temp_pack_data); + if (temp_pack_data.error > 0) + { + iserror = true; + error_msg = temp_pack_data.data; + select_conn.reset(); + return 0; + } + if (temp_pack_data.length == temp_pack_data.current_length && temp_pack_data.current_length > 0) + { + if (select_conn->pack_eof_check(temp_pack_data)) + { + is_sql_item = true; + break; + } + + if (action_setup == 0) + { + if (temp_pack_data.length == 2 && (unsigned char)temp_pack_data.data[0] < 251 && (unsigned char)temp_pack_data.data[0] > 0) + { + action_setup = 1; + column_num = (unsigned char)temp_pack_data.data[0]; + } + } + else if (action_setup == 1) + { + field_info_t temp_filed_col; + select_conn->read_col_info(temp_pack_data.data, temp_filed_col); + + field_array.emplace_back(std::move(temp_filed_col)); + column_num--; + if (column_num == 0) + { + action_setup = 2; + for (unsigned int ii = 0; ii < field_array.size(); ii++) + { + field_pos.push_back(B_BASE::findcolpos(field_array[ii].org_name)); + } + } + } + else if (action_setup == 2) + { + unsigned int column_num = field_array.size(); + unsigned int tempnum = 0; + + for (unsigned int ij = 0; ij < column_num; ij++) + { + unsigned long long name_length = 0; + name_length = select_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], tempnum); + + assign_field_value(field_pos[ij], (unsigned char *)&temp_pack_data.data[tempnum], name_length, B_BASE::data); + tempnum = tempnum + name_length; + } + + effect_num++; + } + } + else + { + if (offset >= n) + { + break; + } + is_sql_item = true; + break; + } + } + } + if (select_conn->isdebug) + { + select_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = select_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + if (!islock_conn) + { + conn_obj->back_select_conn(std::move(select_conn)); + } + if (iscache) + { + if (exptime > 0) + { + save_data_cache(exptime); + exptime = 0; + iscache = false; + } + } + return 0; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + return 0; + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + return 0; + } + + asio::awaitable async_get_one(long long id) + { + effect_num = 0; + if (selectsql.empty()) + { + sqlstring = "SELECT * FROM "; + } + else + { + sqlstring = "SELECT "; + sqlstring.append(selectsql); + sqlstring.append(" FROM "); + } + + sqlstring.append(B_BASE::tablename); + sqlstring.append(" WHERE "); + + sqlstring.append(B_BASE::getPKname()); + sqlstring.append("="); + sqlstring.append(std::to_string(id)); + sqlstring.append(" limit 1"); + if (iscache) + { + std::size_t sqlhashid = std::hash{}(sqlstring); + if (get_data_cache(sqlhashid)) + { + iscache = false; + co_return 0; + } + } + + B_BASE::data_reset(); + + if (iserror) + { + co_return 0; + } + + try + { + if (conn_empty()) + { + co_return 0; + } + //auto conn = co_await conn_obj->async_get_select_conn(); + if (islock_conn) + { + if (!select_conn) + { + select_conn = co_await conn_obj->async_get_select_conn(); + } + } + else + { + select_conn = co_await conn_obj->async_get_select_conn(); + } + + if (select_conn->isdebug) + { + select_conn->begin_time(); + } + std::size_t n = co_await select_conn->async_write_sql(sqlstring); + if (n == 0) + { + error_msg = select_conn->error_msg; + select_conn.reset(); + co_return 0; + } + + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + bool is_sql_item = false; + std::vector field_array; + + unsigned char action_setup = 0; + unsigned int column_num = 0; + + unsigned int offset = 0; + + std::vector field_pos; + + for (; is_sql_item == false;) + { + n = co_await select_conn->async_read_loop(); + offset = 0; + if (n == 0) + { + select_conn.reset(); + co_return 0; + } + for (; offset < n;) + { + select_conn->read_field_pack(select_conn->_cache_data, n, offset, temp_pack_data); + if (temp_pack_data.error > 0) + { + iserror = true; + error_msg = temp_pack_data.data; + select_conn.reset(); + co_return 0; + } + if (temp_pack_data.length == temp_pack_data.current_length && temp_pack_data.current_length > 0) + { + if (select_conn->pack_eof_check(temp_pack_data)) + { + is_sql_item = true; + break; + } + + if (action_setup == 0) + { + if (temp_pack_data.length == 2 && (unsigned char)temp_pack_data.data[0] < 251 && (unsigned char)temp_pack_data.data[0] > 0) + { + action_setup = 1; + column_num = (unsigned char)temp_pack_data.data[0]; + } + } + else if (action_setup == 1) + { + field_info_t temp_filed_col; + select_conn->read_col_info(temp_pack_data.data, temp_filed_col); + + field_array.emplace_back(std::move(temp_filed_col)); + column_num--; + if (column_num == 0) + { + action_setup = 2; + for (unsigned int ii = 0; ii < field_array.size(); ii++) + { + field_pos.push_back(B_BASE::findcolpos(field_array[ii].org_name)); + } + } + } + else if (action_setup == 2) + { + unsigned int column_num = field_array.size(); + unsigned int tempnum = 0; + + for (unsigned int ij = 0; ij < column_num; ij++) + { + unsigned long long name_length = 0; + name_length = select_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], tempnum); + + assign_field_value(field_pos[ij], (unsigned char *)&temp_pack_data.data[tempnum], name_length, B_BASE::data); + tempnum = tempnum + name_length; + } + + effect_num++; + } + } + else + { + if (offset >= n) + { + break; + } + is_sql_item = true; + break; + } + } + } + if (select_conn->isdebug) + { + select_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = select_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + if (!islock_conn) + { + conn_obj->back_select_conn(std::move(select_conn)); + } + if (iscache) + { + if (exptime > 0) + { + save_data_cache(exptime); + exptime = 0; + iscache = false; + } + } + co_return effect_num; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + co_return 0; + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + co_return 0; + } + + int update() + { + effect_num = 0; + if (wheresql.empty()) + { + if (B_BASE::getPK() > 0) + { + std::ostringstream tempsql; + tempsql << " "; + tempsql << B_BASE::getPKname(); + tempsql << " = '"; + tempsql << B_BASE::getPK(); + tempsql << "' "; + wheresql = tempsql.str(); + } + else + { + return 0; + } + } + sqlstring = B_BASE::_makeupdatesql(""); + sqlstring.append(" where "); + if (wheresql.empty()) + { + return 0; + } + else + { + sqlstring.append(wheresql); + } + if (!groupsql.empty()) + { + sqlstring.append(groupsql); + } + if (!ordersql.empty()) + { + sqlstring.append(ordersql); + } + if (!limitsql.empty()) + { + sqlstring.append(limitsql); + } + + if (iscommit) + { + iscommit = false; + return 0; + } + + if (iserror) + { + return 0; + } + + try + { + if (conn_empty()) + { + return 0; + } + //auto conn = conn_obj->get_edit_conn(); + + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = conn_obj->get_edit_conn(); + } + } + else + { + edit_conn = conn_obj->get_edit_conn(); + } + + if (edit_conn->isdebug) + { + edit_conn->begin_time(); + } + + std::size_t n = edit_conn->write_sql(sqlstring); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return 0; + } + + unsigned int offset = 0; + n = edit_conn->read_loop(); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return 0; + } + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + edit_conn->read_field_pack(edit_conn->_cache_data, n, offset, temp_pack_data); + + if (edit_conn->isdebug) + { + edit_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = edit_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + + if ((unsigned char)temp_pack_data.data[0] == 0xFF) + { + error_msg = temp_pack_data.data.substr(3); + } + else if ((unsigned char)temp_pack_data.data[0] == 0x00) + { + + unsigned int d_offset = 1; + effect_num = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + } + if (!islock_conn) + { + conn_obj->back_edit_conn(std::move(edit_conn)); + } + return effect_num; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + return 0; + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + return 0; + } + int update(const std::string &fieldname) + { + effect_num = 0; + if (wheresql.empty()) + { + if (B_BASE::getPK() > 0) + { + std::ostringstream tempsql; + tempsql << " "; + tempsql << B_BASE::getPKname(); + tempsql << " = '"; + tempsql << B_BASE::getPK(); + tempsql << "' "; + wheresql = tempsql.str(); + } + else + { + error_msg = "warning empty where sql!"; + return 0; + } + } + + sqlstring = B_BASE::_makeupdatesql(fieldname); + sqlstring.append(" where "); + if (wheresql.empty()) + { + return 0; + } + else + { + sqlstring.append(wheresql); + } + if (!groupsql.empty()) + { + sqlstring.append(groupsql); + } + if (!ordersql.empty()) + { + sqlstring.append(ordersql); + } + if (!limitsql.empty()) + { + sqlstring.append(limitsql); + } + + if (iscommit) + { + iscommit = false; + return 0; + } + + if (iserror) + { + return 0; + } + + try + { + if (conn_empty()) + { + return 0; + } + //auto conn = conn_obj->get_edit_conn(); + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = conn_obj->get_edit_conn(); + } + } + else + { + edit_conn = conn_obj->get_edit_conn(); + } + if (edit_conn->isdebug) + { + edit_conn->begin_time(); + } + + std::size_t n = edit_conn->write_sql(sqlstring); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return 0; + } + + unsigned int offset = 0; + n = edit_conn->read_loop(); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return 0; + } + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + edit_conn->read_field_pack(edit_conn->_cache_data, n, offset, temp_pack_data); + + if (edit_conn->isdebug) + { + edit_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = edit_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + + if ((unsigned char)temp_pack_data.data[0] == 0xFF) + { + error_msg = temp_pack_data.data.substr(3); + } + else if ((unsigned char)temp_pack_data.data[0] == 0x00) + { + + unsigned int d_offset = 1; + effect_num = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + } + if (!islock_conn) + { + conn_obj->back_edit_conn(std::move(edit_conn)); + } + return effect_num; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + return 0; + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + return 0; + } + + asio::awaitable async_update(const std::string &fieldname) + { + effect_num = 0; + if (wheresql.empty()) + { + if (B_BASE::getPK() > 0) + { + std::ostringstream tempsql; + tempsql << " "; + tempsql << B_BASE::getPKname(); + tempsql << " = '"; + tempsql << B_BASE::getPK(); + tempsql << "' "; + wheresql = tempsql.str(); + } + else + { + error_msg = "warning empty where sql!"; + co_return 0; + } + } + + sqlstring = B_BASE::_makeupdatesql(fieldname); + sqlstring.append(" where "); + if (wheresql.empty()) + { + co_return 0; + } + else + { + sqlstring.append(wheresql); + } + if (!groupsql.empty()) + { + sqlstring.append(groupsql); + } + if (!ordersql.empty()) + { + sqlstring.append(ordersql); + } + if (!limitsql.empty()) + { + sqlstring.append(limitsql); + } + + if (iscommit) + { + iscommit = false; + co_return 0; + } + + if (iserror) + { + co_return 0; + } + try + { + + if (conn_empty()) + { + co_return 0; + } + + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = co_await conn_obj->async_get_edit_conn(); + } + } + else + { + edit_conn = co_await conn_obj->async_get_edit_conn(); + } + + if (edit_conn->isdebug) + { + edit_conn->begin_time(); + } + std::size_t n = co_await edit_conn->async_write_sql(sqlstring); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + co_return 0; + } + + unsigned int offset = 0; + n = co_await edit_conn->async_read_loop(); + if (n == 0) + { + edit_conn.reset(); + co_return 0; + } + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + edit_conn->read_field_pack(edit_conn->_cache_data, n, offset, temp_pack_data); + if (edit_conn->isdebug) + { + edit_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = edit_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + + if ((unsigned char)temp_pack_data.data[0] == 0xFF) + { + error_msg = temp_pack_data.data.substr(3); + iserror = true; + } + else if ((unsigned char)temp_pack_data.data[0] == 0x00) + { + + unsigned int d_offset = 1; + effect_num = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + } + if (!islock_conn) + { + conn_obj->back_edit_conn(std::move(edit_conn)); + } + co_return effect_num; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + co_return 0; + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + co_return 0; + } + asio::awaitable async_update() + { + effect_num = 0; + if (wheresql.empty()) + { + if (B_BASE::getPK() > 0) + { + std::ostringstream tempsql; + tempsql << " "; + tempsql << B_BASE::getPKname(); + tempsql << " = '"; + tempsql << B_BASE::getPK(); + tempsql << "' "; + wheresql = tempsql.str(); + } + else + { + error_msg = "warning empty where sql!"; + co_return 0; + } + } + + sqlstring = B_BASE::_makeupdatesql(""); + sqlstring.append(" where "); + if (wheresql.empty()) + { + co_return 0; + } + else + { + sqlstring.append(wheresql); + } + if (!groupsql.empty()) + { + sqlstring.append(groupsql); + } + if (!ordersql.empty()) + { + sqlstring.append(ordersql); + } + if (!limitsql.empty()) + { + sqlstring.append(limitsql); + } + + if (iscommit) + { + iscommit = false; + co_return 0; + } + + if (iserror) + { + co_return 0; + } + try + { + + if (conn_empty()) + { + co_return 0; + } + + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = co_await conn_obj->async_get_edit_conn(); + } + } + else + { + edit_conn = co_await conn_obj->async_get_edit_conn(); + } + + if (edit_conn->isdebug) + { + edit_conn->begin_time(); + } + std::size_t n = co_await edit_conn->async_write_sql(sqlstring); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + co_return 0; + } + + unsigned int offset = 0; + n = co_await edit_conn->async_read_loop(); + if (n == 0) + { + edit_conn.reset(); + co_return 0; + } + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + edit_conn->read_field_pack(edit_conn->_cache_data, n, offset, temp_pack_data); + if (edit_conn->isdebug) + { + edit_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = edit_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + + if ((unsigned char)temp_pack_data.data[0] == 0xFF) + { + error_msg = temp_pack_data.data.substr(3); + iserror = true; + } + else if ((unsigned char)temp_pack_data.data[0] == 0x00) + { + + unsigned int d_offset = 1; + effect_num = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + } + if (!islock_conn) + { + conn_obj->back_edit_conn(std::move(edit_conn)); + } + co_return effect_num; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + co_return 0; + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + co_return 0; + } + + int update_batch(const std::string &fieldname) + { + effect_num = 0; + if (B_BASE::record.size() == 0) + { + return 0; + } + if (fieldname.size() > 0) + { + sqlstring = B_BASE::_make_insert_into_sql(fieldname); + } + else + { + sqlstring = B_BASE::_make_replace_into_sql(); + } + + if (iserror) + { + return 0; + } + + try + { + if (conn_empty()) + { + return 0; + } + //auto conn = conn_obj->get_edit_conn(); + + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = conn_obj->get_edit_conn(); + } + } + else + { + edit_conn = conn_obj->get_edit_conn(); + } + + if (edit_conn->isdebug) + { + edit_conn->begin_time(); + } + std::size_t n = edit_conn->write_sql(sqlstring); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return 0; + } + + unsigned int offset = 0; + n = edit_conn->read_loop(); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return 0; + } + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + edit_conn->read_field_pack(edit_conn->_cache_data, n, offset, temp_pack_data); + if (edit_conn->isdebug) + { + edit_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = edit_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + + if ((unsigned char)temp_pack_data.data[0] == 0xFF) + { + error_msg = temp_pack_data.data.substr(3); + } + else if ((unsigned char)temp_pack_data.data[0] == 0x00) + { + + unsigned int d_offset = 1; + effect_num = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + } + if (!islock_conn) + { + conn_obj->back_edit_conn(std::move(edit_conn)); + } + return effect_num; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + return 0; + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + return 0; + } + int remove() + { + effect_num = 0; + if (wheresql.empty()) + { + if (B_BASE::getPK() > 0) + { + std::ostringstream tempsql; + tempsql << " "; + tempsql << B_BASE::getPKname(); + tempsql << " = '"; + tempsql << B_BASE::getPK(); + tempsql << "' "; + wheresql = tempsql.str(); + } + else + { + return 0; + } + } + + sqlstring = "DELETE FROM "; + sqlstring.append(B_BASE::tablename); + sqlstring.append(" WHERE "); + + if (wheresql.empty()) + { + return 0; + } + else + { + sqlstring.append(wheresql); + } + if (!groupsql.empty()) + { + sqlstring.append(groupsql); + } + if (!ordersql.empty()) + { + sqlstring.append(ordersql); + } + if (!limitsql.empty()) + { + sqlstring.append(limitsql); + } + + if (iscommit) + { + iscommit = false; + return 0; + } + + if (iserror) + { + return 0; + } + + try + { + if (conn_empty()) + { + return 0; + } + //auto conn = conn_obj->get_edit_conn(); + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = conn_obj->get_edit_conn(); + } + } + else + { + edit_conn = conn_obj->get_edit_conn(); + } + + if (edit_conn->isdebug) + { + edit_conn->begin_time(); + } + std::size_t n = edit_conn->write_sql(sqlstring); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return 0; + } + + unsigned int offset = 0; + n = edit_conn->read_loop(); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return 0; + } + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + edit_conn->read_field_pack(edit_conn->_cache_data, n, offset, temp_pack_data); + if (edit_conn->isdebug) + { + edit_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = edit_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + + if ((unsigned char)temp_pack_data.data[0] == 0xFF) + { + error_msg = temp_pack_data.data.substr(3); + } + else if ((unsigned char)temp_pack_data.data[0] == 0x00) + { + + unsigned int d_offset = 1; + effect_num = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + } + if (!islock_conn) + { + conn_obj->back_edit_conn(std::move(edit_conn)); + } + return effect_num; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + return 0; + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + return 0; + } + + asio::awaitable async_remove() + { + effect_num = 0; + if (wheresql.empty()) + { + if (B_BASE::getPK() > 0) + { + std::ostringstream tempsql; + tempsql << " "; + tempsql << B_BASE::getPKname(); + tempsql << " = '"; + tempsql << B_BASE::getPK(); + tempsql << "' "; + wheresql = tempsql.str(); + } + else + { + co_return 0; + } + } + + sqlstring = "DELETE FROM "; + sqlstring.append(B_BASE::tablename); + sqlstring.append(" WHERE "); + + if (wheresql.empty()) + { + co_return 0; + } + else + { + sqlstring.append(wheresql); + } + if (!groupsql.empty()) + { + sqlstring.append(groupsql); + } + if (!ordersql.empty()) + { + sqlstring.append(ordersql); + } + if (!limitsql.empty()) + { + sqlstring.append(limitsql); + } + + if (iscommit) + { + iscommit = false; + co_return 0; + } + + if (iserror) + { + co_return 0; + } + + try + { + if (conn_empty()) + { + co_return 0; + } + + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = co_await conn_obj->async_get_edit_conn(); + } + } + else + { + edit_conn = co_await conn_obj->async_get_edit_conn(); + } + + if (edit_conn->isdebug) + { + edit_conn->begin_time(); + } + std::size_t n = co_await edit_conn->async_write_sql(sqlstring); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + co_return 0; + } + + unsigned int offset = 0; + n = co_await edit_conn->async_read_loop(); + if (n == 0) + { + edit_conn.reset(); + co_return 0; + } + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + edit_conn->read_field_pack(edit_conn->_cache_data, n, offset, temp_pack_data); + if (edit_conn->isdebug) + { + edit_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = edit_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + + if ((unsigned char)temp_pack_data.data[0] == 0xFF) + { + error_msg = temp_pack_data.data.substr(3); + } + else if ((unsigned char)temp_pack_data.data[0] == 0x00) + { + + unsigned int d_offset = 1; + effect_num = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + } + if (!islock_conn) + { + conn_obj->back_edit_conn(std::move(edit_conn)); + } + co_return effect_num; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + co_return 0; + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + co_return 0; + } + + int remove(long long id) + { + effect_num = 0; + sqlstring = "DELETE FROM "; + sqlstring.append(B_BASE::tablename); + sqlstring.append(" WHERE "); + + sqlstring.append(B_BASE::getPKname()); + sqlstring.append("="); + sqlstring.append(std::to_string(id)); + + if (iscommit) + { + iscommit = false; + return 0; + } + + if (iserror) + { + return 0; + } + + try + { + if (conn_empty()) + { + return 0; + } + //auto conn = conn_obj->get_edit_conn(); + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = conn_obj->get_edit_conn(); + } + } + else + { + edit_conn = conn_obj->get_edit_conn(); + } + + if (edit_conn->isdebug) + { + edit_conn->begin_time(); + } + std::size_t n = edit_conn->write_sql(sqlstring); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return 0; + } + + unsigned int offset = 0; + n = edit_conn->read_loop(); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return 0; + } + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + edit_conn->read_field_pack(edit_conn->_cache_data, n, offset, temp_pack_data); + if (edit_conn->isdebug) + { + edit_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = edit_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + + if ((unsigned char)temp_pack_data.data[0] == 0xFF) + { + error_msg = temp_pack_data.data.substr(3); + } + else if ((unsigned char)temp_pack_data.data[0] == 0x00) + { + + unsigned int d_offset = 1; + effect_num = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + } + if (!islock_conn) + { + conn_obj->back_edit_conn(std::move(edit_conn)); + } + return effect_num; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + return 0; + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + return 0; + } + + asio::awaitable async_remove(long long id) + { + effect_num = 0; + sqlstring = "DELETE FROM "; + sqlstring.append(B_BASE::tablename); + sqlstring.append(" WHERE "); + + sqlstring.append(B_BASE::getPKname()); + sqlstring.append("="); + sqlstring.append(std::to_string(id)); + + if (iscommit) + { + iscommit = false; + co_return 0; + } + + if (iserror) + { + co_return 0; + } + + try + { + if (conn_empty()) + { + co_return 0; + } + + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = co_await conn_obj->async_get_edit_conn(); + } + } + else + { + edit_conn = co_await conn_obj->async_get_edit_conn(); + } + + if (edit_conn->isdebug) + { + edit_conn->begin_time(); + } + std::size_t n = co_await edit_conn->async_write_sql(sqlstring); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + co_return 0; + } + + unsigned int offset = 0; + n = co_await edit_conn->async_read_loop(); + if (n == 0) + { + edit_conn.reset(); + co_return 0; + } + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + edit_conn->read_field_pack(edit_conn->_cache_data, n, offset, temp_pack_data); + if (edit_conn->isdebug) + { + edit_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = edit_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + + if ((unsigned char)temp_pack_data.data[0] == 0xFF) + { + error_msg = temp_pack_data.data.substr(3); + } + else if ((unsigned char)temp_pack_data.data[0] == 0x00) + { + + unsigned int d_offset = 1; + effect_num = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + } + if (!islock_conn) + { + conn_obj->back_edit_conn(std::move(edit_conn)); + } + co_return effect_num; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + co_return 0; + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + co_return 0; + } + + int soft_remove(const std::string &fieldsql) + { + effect_num = 0; + if (wheresql.empty()) + { + if (B_BASE::getPK() > 0) + { + std::ostringstream tempsql; + tempsql << " "; + tempsql << B_BASE::getPKname(); + tempsql << " = '"; + tempsql << B_BASE::getPK(); + tempsql << "' "; + wheresql = tempsql.str(); + } + else + { + return 0; + } + } + + sqlstring = B_BASE::soft_remove_sql(fieldsql); + if (sqlstring.empty()) + { + error_msg = "soft delete field empty."; + return 0; + } + sqlstring.append(" where "); + if (wheresql.empty()) + { + return 0; + } + else + { + sqlstring.append(wheresql); + } + if (!groupsql.empty()) + { + sqlstring.append(groupsql); + } + if (!ordersql.empty()) + { + sqlstring.append(ordersql); + } + if (!limitsql.empty()) + { + sqlstring.append(limitsql); + } + + if (iscommit) + { + iscommit = false; + return 0; + } + + if (iserror) + { + return 0; + } + + try + { + if (conn_empty()) + { + return 0; + } + //auto conn = conn_obj->get_edit_conn(); + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = conn_obj->get_edit_conn(); + } + } + else + { + edit_conn = conn_obj->get_edit_conn(); + } + + if (edit_conn->isdebug) + { + edit_conn->begin_time(); + } + std::size_t n = edit_conn->write_sql(sqlstring); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return 0; + } + + unsigned int offset = 0; + n = edit_conn->read_loop(); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return 0; + } + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + edit_conn->read_field_pack(edit_conn->_cache_data, n, offset, temp_pack_data); + if (edit_conn->isdebug) + { + edit_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = edit_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + + if ((unsigned char)temp_pack_data.data[0] == 0xFF) + { + error_msg = temp_pack_data.data.substr(3); + } + else if ((unsigned char)temp_pack_data.data[0] == 0x00) + { + + unsigned int d_offset = 1; + effect_num = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + } + if (!islock_conn) + { + conn_obj->back_edit_conn(std::move(edit_conn)); + } + return effect_num; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + return 0; + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + return 0; + } + int soft_remove() + { + effect_num = 0; + if (wheresql.empty()) + { + if (B_BASE::getPK() > 0) + { + std::ostringstream tempsql; + effect_num = 1; + tempsql << " "; + tempsql << B_BASE::getPKname(); + tempsql << " = '"; + tempsql << B_BASE::getPK(); + tempsql << "' "; + wheresql = tempsql.str(); + } + else + { + return 0; + } + } + if (effect_num == 1) + { + sqlstring = B_BASE::soft_remove_sql(" "); + } + else + { + sqlstring = B_BASE::soft_remove_sql(""); + } + effect_num = 0; + if (sqlstring.empty()) + { + error_msg = "soft delete field empty."; + return 0; + } + sqlstring.append(" where "); + if (wheresql.empty()) + { + return 0; + } + else + { + sqlstring.append(wheresql); + } + if (!groupsql.empty()) + { + sqlstring.append(groupsql); + } + if (!ordersql.empty()) + { + sqlstring.append(ordersql); + } + if (!limitsql.empty()) + { + sqlstring.append(limitsql); + } + + if (iscommit) + { + iscommit = false; + return 0; + } + + if (iserror) + { + return 0; + } + + try + { + if (conn_empty()) + { + return 0; + } + //auto conn = conn_obj->get_edit_conn(); + + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = conn_obj->get_edit_conn(); + } + } + else + { + edit_conn = conn_obj->get_edit_conn(); + } + + if (edit_conn->isdebug) + { + edit_conn->begin_time(); + } + std::size_t n = edit_conn->write_sql(sqlstring); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return 0; + } + + unsigned int offset = 0; + n = edit_conn->read_loop(); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return 0; + } + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + edit_conn->read_field_pack(edit_conn->_cache_data, n, offset, temp_pack_data); + if (edit_conn->isdebug) + { + edit_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = edit_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + + if ((unsigned char)temp_pack_data.data[0] == 0xFF) + { + error_msg = temp_pack_data.data.substr(3); + } + else if ((unsigned char)temp_pack_data.data[0] == 0x00) + { + + unsigned int d_offset = 1; + effect_num = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + } + if (!islock_conn) + { + conn_obj->back_edit_conn(std::move(edit_conn)); + } + return effect_num; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + return 0; + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + return 0; + } + std::tuple insert(typename B_BASE::meta &insert_data) + { + effect_num = 0; + sqlstring = B_BASE::_makerecordinsertsql(insert_data); + if (iscommit) + { + iscommit = false; + return std::make_tuple(0, 0); + } + + if (iserror) + { + return std::make_tuple(0, 0); + } + + try + { + if (conn_empty()) + { + return std::make_tuple(0, 0); + } + //auto conn = conn_obj->get_edit_conn(); + + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = conn_obj->get_edit_conn(); + } + } + else + { + edit_conn = conn_obj->get_edit_conn(); + } + + if (edit_conn->isdebug) + { + edit_conn->begin_time(); + } + std::size_t n = edit_conn->write_sql(sqlstring); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return std::make_tuple(0, 0); + } + + unsigned int offset = 0; + n = edit_conn->read_loop(); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return std::make_tuple(0, 0); + } + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + edit_conn->read_field_pack(edit_conn->_cache_data, n, offset, temp_pack_data); + if (edit_conn->isdebug) + { + edit_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = edit_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + + long long insert_last_id = 0; + if ((unsigned char)temp_pack_data.data[0] == 0xFF) + { + error_msg = temp_pack_data.data.substr(3); + } + else if ((unsigned char)temp_pack_data.data[0] == 0x00) + { + + unsigned int d_offset = 1; + effect_num = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + insert_last_id = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + B_BASE::setPK(insert_last_id); + } + if (!islock_conn) + { + conn_obj->back_edit_conn(std::move(edit_conn)); + } + //return insert_last_id; + return std::make_tuple(effect_num, insert_last_id); + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + return std::make_tuple(0, 0); + } + + asio::awaitable> async_insert(typename B_BASE::meta &insert_data) + { + effect_num = 0; + sqlstring = B_BASE::_makerecordinsertsql(insert_data); + if (iscommit) + { + iscommit = false; + co_return std::make_tuple(0, 0); + } + + if (iserror) + { + co_return std::make_tuple(0, 0); + } + + try + { + if (conn_empty()) + { + co_return std::make_tuple(0, 0); + } + + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = co_await conn_obj->async_get_edit_conn(); + } + } + else + { + edit_conn = co_await conn_obj->async_get_edit_conn(); + } + + if (edit_conn->isdebug) + { + edit_conn->begin_time(); + } + std::size_t n = co_await edit_conn->async_write_sql(sqlstring); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + co_return std::make_tuple(0, 0); + } + + unsigned int offset = 0; + n = co_await edit_conn->async_read_loop(); + if (n == 0) + { + edit_conn.reset(); + co_return std::make_tuple(0, 0); + } + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + edit_conn->read_field_pack(edit_conn->_cache_data, n, offset, temp_pack_data); + if (edit_conn->isdebug) + { + edit_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = edit_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + + long long insert_last_id = 0; + if ((unsigned char)temp_pack_data.data[0] == 0xFF) + { + error_msg = temp_pack_data.data.substr(3); + } + else if ((unsigned char)temp_pack_data.data[0] == 0x00) + { + + unsigned int d_offset = 1; + effect_num = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + insert_last_id = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + B_BASE::setPK(insert_last_id); + } + if (!islock_conn) + { + conn_obj->back_edit_conn(std::move(edit_conn)); + } + //co_return insert_last_id; + co_return std::make_tuple(effect_num, insert_last_id); + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + co_return std::make_tuple(0, 0); + } + + std::tuple insert(std::vector &insert_data) + { + effect_num = 0; + sqlstring = B_BASE::_makerecordinsertsql(insert_data); + if (iscommit) + { + iscommit = false; + return std::make_tuple(0, 0); + } + + if (iserror) + { + return std::make_tuple(0, 0); + } + + try + { + if (conn_empty()) + { + return std::make_tuple(0, 0); + } + //auto conn = conn_obj->get_edit_conn(); + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = conn_obj->get_edit_conn(); + } + } + else + { + edit_conn = conn_obj->get_edit_conn(); + } + + if (edit_conn->isdebug) + { + edit_conn->begin_time(); + } + std::size_t n = edit_conn->write_sql(sqlstring); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return std::make_tuple(0, 0); + } + + unsigned int offset = 0; + n = edit_conn->read_loop(); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return std::make_tuple(0, 0); + } + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + edit_conn->read_field_pack(edit_conn->_cache_data, n, offset, temp_pack_data); + if (edit_conn->isdebug) + { + edit_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = edit_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + + long long insert_last_id = 0; + if ((unsigned char)temp_pack_data.data[0] == 0xFF) + { + error_msg = temp_pack_data.data.substr(3); + } + else if ((unsigned char)temp_pack_data.data[0] == 0x00) + { + + unsigned int d_offset = 1; + effect_num = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + insert_last_id = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + B_BASE::setPK(insert_last_id); + } + if (!islock_conn) + { + conn_obj->back_edit_conn(std::move(edit_conn)); + } + //return insert_last_id; + return std::make_tuple(effect_num, insert_last_id); + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + return std::make_tuple(0, 0); + } + + asio::awaitable> async_insert(std::vector &insert_data) + { + effect_num = 0; + sqlstring = B_BASE::_makerecordinsertsql(insert_data); + if (iscommit) + { + iscommit = false; + co_return std::make_tuple(0, 0); + } + + if (iserror) + { + co_return std::make_tuple(0, 0); + } + + try + { + if (conn_empty()) + { + co_return std::make_tuple(0, 0); + } + + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = co_await conn_obj->async_get_edit_conn(); + } + } + else + { + edit_conn = co_await conn_obj->async_get_edit_conn(); + } + + if (edit_conn->isdebug) + { + edit_conn->begin_time(); + } + std::size_t n = co_await edit_conn->async_write_sql(sqlstring); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + co_return std::make_tuple(0, 0); + } + + unsigned int offset = 0; + n = co_await edit_conn->async_read_loop(); + if (n == 0) + { + edit_conn.reset(); + co_return std::make_tuple(0, 0); + } + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + edit_conn->read_field_pack(edit_conn->_cache_data, n, offset, temp_pack_data); + if (edit_conn->isdebug) + { + edit_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = edit_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + + long long insert_last_id = 0; + if ((unsigned char)temp_pack_data.data[0] == 0xFF) + { + error_msg = temp_pack_data.data.substr(3); + } + else if ((unsigned char)temp_pack_data.data[0] == 0x00) + { + unsigned int d_offset = 1; + effect_num = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + insert_last_id = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + B_BASE::setPK(insert_last_id); + } + if (!islock_conn) + { + conn_obj->back_edit_conn(std::move(edit_conn)); + } + //co_return insert_last_id; + co_return std::make_tuple(effect_num, insert_last_id); + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + co_return std::make_tuple(0, 0); + } + + std::tuple insert() + { + effect_num = 0; + sqlstring = B_BASE::_makeinsertsql(); + if (iscommit) + { + iscommit = false; + return std::make_tuple(0, 0); + } + + if (iserror) + { + return std::make_tuple(0, 0); + } + + try + { + if (conn_empty()) + { + return std::make_tuple(0, 0); + } + //auto conn = conn_obj->get_edit_conn(); + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = conn_obj->get_edit_conn(); + } + } + else + { + edit_conn = conn_obj->get_edit_conn(); + } + + if (edit_conn->isdebug) + { + edit_conn->begin_time(); + } + std::size_t n = edit_conn->write_sql(sqlstring); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return std::make_tuple(0, 0); + } + + unsigned int offset = 0; + n = edit_conn->read_loop(); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return std::make_tuple(0, 0); + } + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + edit_conn->read_field_pack(edit_conn->_cache_data, n, offset, temp_pack_data); + if (edit_conn->isdebug) + { + edit_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = edit_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + + long long insert_last_id = 0; + if ((unsigned char)temp_pack_data.data[0] == 0xFF) + { + error_msg = temp_pack_data.data.substr(3); + } + else if ((unsigned char)temp_pack_data.data[0] == 0x00) + { + unsigned int d_offset = 1; + effect_num = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + insert_last_id = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + B_BASE::setPK(insert_last_id); + } + if (!islock_conn) + { + conn_obj->back_edit_conn(std::move(edit_conn)); + } + //return insert_last_id; + return std::make_tuple(effect_num, insert_last_id); + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + return std::make_tuple(0, 0); + } + + asio::awaitable> async_insert() + { + effect_num = 0; + sqlstring = B_BASE::_makeinsertsql(); + if (iscommit) + { + iscommit = false; + co_return std::make_tuple(0, 0); + } + + if (iserror) + { + co_return std::make_tuple(0, 0); + } + + try + { + if (conn_empty()) + { + co_return std::make_tuple(0, 0); + } + + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = co_await conn_obj->async_get_edit_conn(); + } + } + else + { + edit_conn = co_await conn_obj->async_get_edit_conn(); + } + + if (edit_conn->isdebug) + { + edit_conn->begin_time(); + } + std::size_t n = co_await edit_conn->async_write_sql(sqlstring); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + co_return std::make_tuple(0, 0); + } + + unsigned int offset = 0; + n = co_await edit_conn->async_read_loop(); + if (n == 0) + { + edit_conn.reset(); + co_return std::make_tuple(0, 0); + } + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + edit_conn->read_field_pack(edit_conn->_cache_data, n, offset, temp_pack_data); + if (edit_conn->isdebug) + { + edit_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = edit_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + + long long insert_last_id = 0; + if ((unsigned char)temp_pack_data.data[0] == 0xFF) + { + error_msg = temp_pack_data.data.substr(3); + } + else if ((unsigned char)temp_pack_data.data[0] == 0x00) + { + + unsigned int d_offset = 1; + effect_num = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + insert_last_id = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + B_BASE::setPK(insert_last_id); + } + if (!islock_conn) + { + conn_obj->back_edit_conn(std::move(edit_conn)); + } + //co_return insert_last_id; + co_return std::make_tuple(effect_num, insert_last_id); + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + co_return std::make_tuple(0, 0); + } + + std::tuple save(bool isrealnew = false) + { + effect_num = 0; + if (B_BASE::getPK() > 0 && isrealnew == false) + { + if (wheresql.empty()) + { + std::ostringstream tempsql; + tempsql << " "; + tempsql << B_BASE::getPKname(); + tempsql << " = '"; + tempsql << B_BASE::getPK(); + tempsql << "' "; + wheresql = tempsql.str(); + } + sqlstring = B_BASE::_makeupdatesql(""); + sqlstring.append(" where "); + if (wheresql.empty()) + { + return std::make_tuple(0, 0); + } + else + { + sqlstring.append(wheresql); + } + if (!groupsql.empty()) + { + sqlstring.append(groupsql); + } + if (!ordersql.empty()) + { + sqlstring.append(ordersql); + } + if (!limitsql.empty()) + { + sqlstring.append(limitsql); + } + if (iscommit) + { + iscommit = false; + return std::make_tuple(0, 0); + } + + if (iserror) + { + return std::make_tuple(0, 0); + } + if (conn_empty()) + { + return std::make_tuple(0, 0); + } + //auto conn = conn_obj->get_edit_conn(); + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = conn_obj->get_edit_conn(); + } + } + else + { + edit_conn = conn_obj->get_edit_conn(); + } + + if (edit_conn->isdebug) + { + edit_conn->begin_time(); + } + std::size_t n = edit_conn->write_sql(sqlstring); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return std::make_tuple(0, 0); + } + + unsigned int offset = 0; + n = edit_conn->read_loop(); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return std::make_tuple(0, 0); + } + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + edit_conn->read_field_pack(edit_conn->_cache_data, n, offset, temp_pack_data); + if (edit_conn->isdebug) + { + edit_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = edit_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + + if ((unsigned char)temp_pack_data.data[0] == 0xFF) + { + error_msg = temp_pack_data.data.substr(3); + } + else if ((unsigned char)temp_pack_data.data[0] == 0x00) + { + + unsigned int d_offset = 1; + effect_num = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + } + if (!islock_conn) + { + conn_obj->back_edit_conn(std::move(edit_conn)); + } + //return effect_num; + return std::make_tuple(effect_num, 0); + } + else + { + sqlstring = B_BASE::_makeinsertsql(); + if (conn_empty()) + { + return std::make_tuple(0, 0); + } + //auto conn = conn_obj->get_edit_conn(); + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = conn_obj->get_edit_conn(); + } + } + else + { + edit_conn = conn_obj->get_edit_conn(); + } + + if (edit_conn->isdebug) + { + edit_conn->begin_time(); + } + std::size_t n = edit_conn->write_sql(sqlstring); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return std::make_tuple(0, 0); + } + + unsigned int offset = 0; + n = edit_conn->read_loop(); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + return std::make_tuple(0, 0); + } + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + edit_conn->read_field_pack(edit_conn->_cache_data, n, offset, temp_pack_data); + if (edit_conn->isdebug) + { + edit_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = edit_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + + long long insert_last_id = 0; + if ((unsigned char)temp_pack_data.data[0] == 0xFF) + { + error_msg = temp_pack_data.data.substr(3); + } + else if ((unsigned char)temp_pack_data.data[0] == 0x00) + { + + unsigned int d_offset = 1; + effect_num = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + insert_last_id = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + B_BASE::setPK(insert_last_id); + } + if (!islock_conn) + { + conn_obj->back_edit_conn(std::move(edit_conn)); + } + //return insert_last_id; + return std::make_tuple(effect_num, insert_last_id); + } + return std::make_tuple(0, 0); + } + + asio::awaitable> async_save(bool isrealnew = false) + { + effect_num = 0; + if (B_BASE::getPK() > 0 && isrealnew == false) + { + if (wheresql.empty()) + { + std::ostringstream tempsql; + tempsql << " "; + tempsql << B_BASE::getPKname(); + tempsql << " = '"; + tempsql << B_BASE::getPK(); + tempsql << "' "; + wheresql = tempsql.str(); + } + sqlstring = B_BASE::_makeupdatesql(""); + sqlstring.append(" where "); + if (wheresql.empty()) + { + co_return std::make_tuple(0, 0); + } + else + { + sqlstring.append(wheresql); + } + if (!groupsql.empty()) + { + sqlstring.append(groupsql); + } + if (!ordersql.empty()) + { + sqlstring.append(ordersql); + } + if (!limitsql.empty()) + { + sqlstring.append(limitsql); + } + if (iscommit) + { + iscommit = false; + co_return std::make_tuple(0, 0); + } + + if (iserror) + { + co_return std::make_tuple(0, 0); + } + + try + { + if (conn_empty()) + { + co_return std::make_tuple(0, 0); + } + + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = co_await conn_obj->async_get_edit_conn(); + } + } + else + { + edit_conn = co_await conn_obj->async_get_edit_conn(); + } + + if (edit_conn->isdebug) + { + edit_conn->begin_time(); + } + std::size_t n = co_await edit_conn->async_write_sql(sqlstring); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + co_return std::make_tuple(0, 0); + } + + unsigned int offset = 0; + n = co_await edit_conn->async_read_loop(); + if (n == 0) + { + edit_conn.reset(); + co_return std::make_tuple(0, 0); + } + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + edit_conn->read_field_pack(edit_conn->_cache_data, n, offset, temp_pack_data); + if (edit_conn->isdebug) + { + edit_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = edit_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + + if ((unsigned char)temp_pack_data.data[0] == 0xFF) + { + error_msg = temp_pack_data.data.substr(3); + iserror = true; + } + else if ((unsigned char)temp_pack_data.data[0] == 0x00) + { + + unsigned int d_offset = 1; + effect_num = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + } + if (!islock_conn) + { + conn_obj->back_edit_conn(std::move(edit_conn)); + } + co_return std::make_tuple(effect_num, 0); + //co_return effect_num; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + co_return std::make_tuple(0, 0); + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + co_return std::make_tuple(0, 0); + } + co_return std::make_tuple(0, 0); + } + else + { + sqlstring = B_BASE::_makeinsertsql(); + try + { + if (conn_empty()) + { + co_return std::make_tuple(0, 0); + } + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = co_await conn_obj->async_get_edit_conn(); + } + } + else + { + edit_conn = co_await conn_obj->async_get_edit_conn(); + } + + if (edit_conn->isdebug) + { + edit_conn->begin_time(); + } + std::size_t n = co_await edit_conn->async_write_sql(sqlstring); + if (n == 0) + { + error_msg = edit_conn->error_msg; + edit_conn.reset(); + co_return std::make_tuple(0, 0); + } + + unsigned int offset = 0; + n = co_await edit_conn->async_read_loop(); + if (n == 0) + { + edit_conn.reset(); + co_return std::make_tuple(0, 0); + } + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + edit_conn->read_field_pack(edit_conn->_cache_data, n, offset, temp_pack_data); + if (edit_conn->isdebug) + { + edit_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = edit_conn->count_time(); + conn_mar.push_log(sqlstring, std::to_string(du_time)); + } + + long long insert_last_id = 0; + if ((unsigned char)temp_pack_data.data[0] == 0xFF) + { + error_msg = temp_pack_data.data.substr(3); + } + else if ((unsigned char)temp_pack_data.data[0] == 0x00) + { + + unsigned int d_offset = 1; + effect_num = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + insert_last_id = edit_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], d_offset); + B_BASE::setPK(insert_last_id); + } + if (!islock_conn) + { + conn_obj->back_edit_conn(std::move(edit_conn)); + } + co_return std::make_tuple(effect_num, insert_last_id); + //co_return insert_last_id; + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + co_return std::make_tuple(0, 0); + } + co_return std::make_tuple(0, 0); + } + + std::tuple, std::map, std::vector>> + query(const std::string &rawsql) + { + effect_num = 0; + std::vector> temprecord; + std::vector table_fieldname; + std::map table_fieldmap; + + if (rawsql.size() > 10) + { + unsigned int i = 0; + for (; i < rawsql.size(); i++) + { + if (rawsql[i] != 0x20) + { + break; + } + } + if (i < 5) + { + //must be select + if (rawsql[i] != 's' && rawsql[i] != 'S') + { + error_msg = "Query sql string must be select."; + iserror = true; + } + } + else + { + iserror = true; + } + } + else + { + iserror = true; + } + + if (iserror) + { + return std::make_tuple(table_fieldname, table_fieldmap, temprecord); + } + + try + { + if (conn_empty()) + { + return std::make_tuple(table_fieldname, table_fieldmap, temprecord); + } + //auto conn = conn_obj->get_select_conn(); + if (islock_conn) + { + if (!select_conn) + { + select_conn = conn_obj->get_select_conn(); + } + } + else + { + select_conn = conn_obj->get_select_conn(); + } + + if (select_conn->isdebug) + { + select_conn->begin_time(); + } + std::size_t n = select_conn->write_sql(rawsql); + if (n == 0) + { + error_msg = select_conn->error_msg; + select_conn.reset(); + return std::make_tuple(table_fieldname, table_fieldmap, temprecord); + } + + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + bool is_sql_item = false; + std::vector field_array; + + unsigned char action_setup = 0; + unsigned int column_num = 0; + + unsigned int offset = 0; + + std::vector field_pos; + + for (; is_sql_item == false;) + { + n = select_conn->read_loop(); + offset = 0; + if (n == 0) + { + error_msg = select_conn->error_msg; + select_conn.reset(); + return std::make_tuple(table_fieldname, table_fieldmap, temprecord); + } + for (; offset < n;) + { + select_conn->read_field_pack(select_conn->_cache_data, n, offset, temp_pack_data); + if (temp_pack_data.error > 0) + { + iserror = true; + error_msg = temp_pack_data.data; + select_conn.reset(); + return std::make_tuple(table_fieldname, table_fieldmap, temprecord); + } + if (temp_pack_data.length == temp_pack_data.current_length && temp_pack_data.current_length > 0) + { + if (select_conn->pack_eof_check(temp_pack_data)) + { + is_sql_item = true; + break; + } + + if (action_setup == 0) + { + if (temp_pack_data.length == 2 && (unsigned char)temp_pack_data.data[0] < 251 && (unsigned char)temp_pack_data.data[0] > 0) + { + action_setup = 1; + column_num = (unsigned char)temp_pack_data.data[0]; + } + } + else if (action_setup == 1) + { + field_info_t temp_filed_col; + select_conn->read_col_info(temp_pack_data.data, temp_filed_col); + + field_array.emplace_back(std::move(temp_filed_col)); + column_num--; + if (column_num == 0) + { + action_setup = 2; + for (unsigned int ii = 0; ii < field_array.size(); ii++) + { + field_pos.push_back(B_BASE::findcolpos(field_array[ii].org_name)); + table_fieldmap.emplace(field_array[ii].org_name, table_fieldname.size()); + table_fieldname.push_back(field_array[ii].org_name); + } + } + } + else if (action_setup == 2) + { + unsigned int column_num = field_array.size(); + unsigned int tempnum = 0; + + std::vector temp_v_record; + for (unsigned int ij = 0; ij < column_num; ij++) + { + unsigned long long name_length = 0; + name_length = select_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], tempnum); + std::string tempstr; + tempstr.resize(name_length); + std::memcpy(tempstr.data(), (unsigned char *)&temp_pack_data.data[tempnum], name_length); + temp_v_record.push_back(std::move(tempstr)); + tempnum = tempnum + name_length; + } + temprecord.push_back(temp_v_record); + effect_num++; + } + } + else + { + if (offset >= n) + { + break; + } + is_sql_item = true; + break; + } + } + } + if (select_conn->isdebug) + { + select_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = select_conn->count_time(); + conn_mar.push_log(rawsql, std::to_string(du_time)); + } + if (!islock_conn) + { + conn_obj->back_select_conn(std::move(select_conn)); + } + return std::make_tuple(std::move(table_fieldname), std::move(table_fieldmap), std::move(temprecord)); + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + return std::make_tuple(table_fieldname, table_fieldmap, temprecord); + } + + asio::awaitable, std::map, std::vector>>> + async_query(const std::string &rawsql) + { + effect_num = 0; + std::vector> temprecord; + std::vector table_fieldname; + std::map table_fieldmap; + + if (rawsql.size() > 10) + { + unsigned int i = 0; + for (; i < rawsql.size(); i++) + { + if (rawsql[i] != 0x20) + { + break; + } + } + if (i < 5) + { + //must be select + if (rawsql[i] != 's' && rawsql[i] != 'S') + { + error_msg = "Query sql string must be select."; + iserror = true; + } + } + else + { + iserror = true; + } + } + else + { + iserror = true; + } + + if (iserror) + { + co_return std::make_tuple(table_fieldname, table_fieldmap, temprecord); + } + + try + { + if (conn_empty()) + { + co_return std::make_tuple(table_fieldname, table_fieldmap, temprecord); + } + if (islock_conn) + { + if (!select_conn) + { + select_conn = co_await conn_obj->async_get_select_conn(); + } + } + else + { + select_conn = co_await conn_obj->async_get_select_conn(); + } + + if (select_conn->isdebug) + { + select_conn->begin_time(); + } + std::size_t n = co_await select_conn->async_write_sql(rawsql); + if (n == 0) + { + error_msg = select_conn->error_msg; + select_conn.reset(); + co_return std::make_tuple(table_fieldname, table_fieldmap, temprecord); + } + + pack_info_t temp_pack_data; + temp_pack_data.seq_id = 1; + bool is_sql_item = false; + std::vector field_array; + + unsigned char action_setup = 0; + unsigned int column_num = 0; + + unsigned int offset = 0; + + std::vector field_pos; + + for (; is_sql_item == false;) + { + n = co_await select_conn->async_read_loop(); + offset = 0; + if (n == 0) + { + select_conn.reset(); + co_return std::make_tuple(table_fieldname, table_fieldmap, temprecord); + } + for (; offset < n;) + { + select_conn->read_field_pack(select_conn->_cache_data, n, offset, temp_pack_data); + if (temp_pack_data.error > 0) + { + iserror = true; + error_msg = temp_pack_data.data; + select_conn.reset(); + co_return std::make_tuple(table_fieldname, table_fieldmap, temprecord); + } + if (temp_pack_data.length == temp_pack_data.current_length && temp_pack_data.current_length > 0) + { + if (select_conn->pack_eof_check(temp_pack_data)) + { + is_sql_item = true; + break; + } + + if (action_setup == 0) + { + if (temp_pack_data.length == 2 && (unsigned char)temp_pack_data.data[0] < 251 && (unsigned char)temp_pack_data.data[0] > 0) + { + action_setup = 1; + column_num = (unsigned char)temp_pack_data.data[0]; + } + } + else if (action_setup == 1) + { + field_info_t temp_filed_col; + select_conn->read_col_info(temp_pack_data.data, temp_filed_col); + + field_array.emplace_back(std::move(temp_filed_col)); + column_num--; + if (column_num == 0) + { + action_setup = 2; + for (unsigned int ii = 0; ii < field_array.size(); ii++) + { + field_pos.push_back(B_BASE::findcolpos(field_array[ii].org_name)); + table_fieldmap.emplace(field_array[ii].org_name, table_fieldname.size()); + table_fieldname.push_back(field_array[ii].org_name); + } + } + } + else if (action_setup == 2) + { + unsigned int column_num = field_array.size(); + unsigned int tempnum = 0; + + std::vector temp_v_record; + for (unsigned int ij = 0; ij < column_num; ij++) + { + unsigned long long name_length = 0; + name_length = select_conn->pack_real_num((unsigned char *)&temp_pack_data.data[0], tempnum); + std::string tempstr; + tempstr.resize(name_length); + std::memcpy(tempstr.data(), (unsigned char *)&temp_pack_data.data[tempnum], name_length); + temp_v_record.push_back(std::move(tempstr)); + tempnum = tempnum + name_length; + } + temprecord.push_back(temp_v_record); + effect_num++; + } + } + else + { + if (offset >= n) + { + break; + } + is_sql_item = true; + break; + } + } + } + if (select_conn->isdebug) + { + select_conn->finish_time(); + auto &conn_mar = get_orm_connect_mar(); + long long du_time = select_conn->count_time(); + conn_mar.push_log(rawsql, std::to_string(du_time)); + } + if (!islock_conn) + { + conn_obj->back_select_conn(std::move(select_conn)); + } + co_return std::make_tuple(std::move(table_fieldname), std::move(table_fieldmap), std::move(temprecord)); + } + catch (const std::exception &e) + { + error_msg = std::string(e.what()); + } + catch (const std::string &e) + { + error_msg = e; + } + catch (...) + { + } + co_return std::make_tuple(table_fieldname, table_fieldmap, temprecord); + } + + // long long edit_query(const std::string &rawsql, bool isinsert = false) + // { + // if (iserror) + // { + // return 0; + // } + + // return 0; + // } + M_MODEL &clear(bool both = true) + { + selectsql.clear(); + wheresql.clear(); + ordersql.clear(); + groupsql.clear(); + limitsql.clear(); + sqlstring.clear(); + error_msg.clear(); + iskuohao = false; + ishascontent = false; + iscommit = false; + iscache = false; + iserror = false; + effect_num = 0; + if (both) + { + B_BASE::record_reset(); + B_BASE::data_reset(); + } + return *mod; + } + M_MODEL &clearWhere() + { + selectsql.clear(); + wheresql.clear(); + ordersql.clear(); + groupsql.clear(); + limitsql.clear(); + sqlstring.clear(); + error_msg.clear(); + iskuohao = false; + ishascontent = false; + iscommit = false; + iscache = false; + iserror = false; + effect_num = 0; + return *mod; + } + M_MODEL &set_data(typename B_BASE::meta indata) + { + B_BASE::data = indata; + return *mod; + } + M_MODEL &get() { return *mod; } + std::string get_query() { return sqlstring; } + + M_MODEL &begin_commit() + { + if (!conn_empty()) + { + return *mod; + } + islock_conn = true; + + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = conn_obj->get_edit_conn(); + } + } + else + { + edit_conn = conn_obj->get_edit_conn(); + } + sqlstring = "start transaction"; + edit_conn->write_sql(sqlstring); + iscommit = true; + + return *mod; + } + M_MODEL &rollback() + { + if (iscommit == false) + { + error_msg = "not begin_commit"; + iserror = true; + return *mod; + } + if (!conn_empty()) + { + return *mod; + } + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = conn_obj->get_edit_conn(); + } + } + else + { + edit_conn = conn_obj->get_edit_conn(); + } + sqlstring = "rollback"; + edit_conn->write_sql(sqlstring); + + iscommit = false; + islock_conn = false; + return *mod; + } + M_MODEL &commit() + { + if (iscommit == false) + { + error_msg = "not begin_commit"; + iserror = true; + return *mod; + } + if (!conn_empty()) + { + return *mod; + } + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = conn_obj->get_edit_conn(); + } + } + else + { + edit_conn = conn_obj->get_edit_conn(); + } + sqlstring = "commit"; + edit_conn->write_sql(sqlstring); + + iscommit = false; + islock_conn = false; + return *mod; + } + + asio::awaitable async_begin_commit() + { + if (!conn_empty()) + { + co_return false; + } + islock_conn = true; + + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = co_await conn_obj->async_get_edit_conn(); + } + } + else + { + edit_conn = co_await conn_obj->async_get_edit_conn(); + } + sqlstring = "start transaction"; + co_await edit_conn->async_write_sql(sqlstring); + iscommit = true; + + co_return false; + } + asio::awaitable async_rollback() + { + if (iscommit == false) + { + error_msg = "not begin_commit"; + iserror = true; + co_return false; + } + if (!conn_empty()) + { + co_return false; + } + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = co_await conn_obj->async_get_edit_conn(); + } + } + else + { + edit_conn = co_await conn_obj->async_get_edit_conn(); + } + sqlstring = "rollback"; + co_await edit_conn->async_write_sql(sqlstring); + + iscommit = false; + islock_conn = false; + co_return true; + } + + asio::awaitable async_commit() + { + if (iscommit == false) + { + error_msg = "not begin_commit"; + iserror = true; + co_return false; + } + if (!conn_empty()) + { + co_return false; + } + if (islock_conn) + { + if (!edit_conn) + { + edit_conn = co_await conn_obj->async_get_edit_conn(); + } + } + else + { + edit_conn = co_await conn_obj->async_get_edit_conn(); + } + sqlstring = "commit"; + co_await edit_conn->async_write_sql(sqlstring); + + iscommit = false; + islock_conn = false; + co_return true; + } + + unsigned int effect() + { + return effect_num; + } + bool conn_empty() + { + if (conn_obj) + { + return false; + } + error_msg = "conn_obj is null"; + iserror = true; + return true; + } + void lock_conn() + { + islock_conn = true; + } + void unlock_conn() + { + islock_conn = false; + if (conn_obj) + { + if (select_conn) + { + conn_obj->back_select_conn(std::move(select_conn)); + } + if (edit_conn) + { + conn_obj->back_edit_conn(std::move(edit_conn)); + } + } + } + + public: + std::string selectsql; + std::string wheresql; + std::string ordersql; + std::string groupsql; + std::string limitsql; + std::string sqlstring; + std::string dbtag; + std::string error_msg; + std::string original_tablename; + + // std::list commit_sqllist; + bool iskuohao = false; + bool iscommit = false; + bool ishascontent = false; + bool iscache = false; + bool iserror = false; + bool islock_conn = false; + int exptime = 0; + unsigned int effect_num = 0; + + M_MODEL *mod; + + std::shared_ptr select_conn; + std::shared_ptr edit_conn; + std::shared_ptr conn_obj; + }; +//} /*tagnamespace_replace*/ +}// namespace orm +#endif \ No newline at end of file diff --git a/frameworks/C++/paozhu/paozhu_benchmark/orm/orm.h b/frameworks/C++/paozhu/paozhu_benchmark/orm/orm.h new file mode 100755 index 00000000000..816b9ae4dc9 --- /dev/null +++ b/frameworks/C++/paozhu/paozhu_benchmark/orm/orm.h @@ -0,0 +1,4 @@ +/*build this file time Tue, 20 Dec 2022 11:40:56 GMT*/ + +#include "Fortune.h" +#include "World.h" diff --git a/frameworks/C++/paozhu/paozhu_benchmark/view/techempower/fortunes.html b/frameworks/C++/paozhu/paozhu_benchmark/view/techempower/fortunes.html new file mode 100755 index 00000000000..49eba6d9cb6 --- /dev/null +++ b/frameworks/C++/paozhu/paozhu_benchmark/view/techempower/fortunes.html @@ -0,0 +1,5 @@ +Fortunes<%c + for(auto &a:obj["list"].as_array()){ +%><%c + } +%>
idmessage
<%c echo<<%c echo<
\ No newline at end of file diff --git a/frameworks/C++/paozhu/paozhu_benchmark/viewsrc/include/regviewmethod.hpp b/frameworks/C++/paozhu/paozhu_benchmark/viewsrc/include/regviewmethod.hpp new file mode 100755 index 00000000000..de0d64c6dc9 --- /dev/null +++ b/frameworks/C++/paozhu/paozhu_benchmark/viewsrc/include/regviewmethod.hpp @@ -0,0 +1,26 @@ +#ifndef __HTTP_REG_VIEW_METHOD_HPP +#define __HTTP_REG_VIEW_METHOD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +#pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include "request.h" +#include "viewso_param.h" +#include "viewmethold_reg.h" +#include "viewsrc.h" + +namespace http +{ + void _initview_method_regto(VIEW_REG &_viewmetholdreg) + { + //create time: Thu, 27 Mar 2025 01:00:54 GMT + + _viewmetholdreg.emplace("techempower/fortunes",http::view::techempower::fortunes); + + } +} +#endif \ No newline at end of file diff --git a/frameworks/C++/paozhu/paozhu_benchmark/viewsrc/include/viewsrc.h b/frameworks/C++/paozhu/paozhu_benchmark/viewsrc/include/viewsrc.h new file mode 100755 index 00000000000..cb67a0bc66a --- /dev/null +++ b/frameworks/C++/paozhu/paozhu_benchmark/viewsrc/include/viewsrc.h @@ -0,0 +1,26 @@ +#ifndef __HTTP_VIEWSRC_ALL_METHOD_H +#define __HTTP_VIEWSRC_ALL_METHOD_H + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +#pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include "request.h" +#include "viewso_param.h" + +namespace http { +namespace view { + +namespace techempower{ + + std::string fortunes(const struct view_param &vinfo,http::obj_val &obj); +} + + +} + +} +#endif \ No newline at end of file diff --git a/frameworks/C++/paozhu/paozhu_benchmark/viewsrc/view/techempower/fortunes.cpp b/frameworks/C++/paozhu/paozhu_benchmark/viewsrc/view/techempower/fortunes.cpp new file mode 100755 index 00000000000..caada3e2e47 --- /dev/null +++ b/frameworks/C++/paozhu/paozhu_benchmark/viewsrc/view/techempower/fortunes.cpp @@ -0,0 +1,50 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "request.h" +#include "datetime.h" +#include "cookie.h" +#include "urlcode.h" +#include "loadviewso.h" +#include "viewso_param.h" +#include "http_so_common_api.h" +#include "viewsrc.h" +//g++ viewsrc/view/techempower/fortunes.cpp +namespace http { + +namespace view { + namespace techempower{ + std::string fortunes([[maybe_unused]] const struct view_param &vinfo,[[maybe_unused]] http::obj_val &obj) + { + + std::ostringstream echo; + + + echo<<"Fortunes"; + + for(auto &a:obj["list"].as_array()){ + + echo<<""; + + } + + echo<<"
idmessage
"; + echo<"; + echo<
"; + + return echo.str(); + } + + } + } + } + \ No newline at end of file diff --git a/frameworks/C++/paozhu/paozhu_benchmark/websockets/include/loopwebsockets.hpp b/frameworks/C++/paozhu/paozhu_benchmark/websockets/include/loopwebsockets.hpp new file mode 100755 index 00000000000..388449b6a33 --- /dev/null +++ b/frameworks/C++/paozhu/paozhu_benchmark/websockets/include/loopwebsockets.hpp @@ -0,0 +1,66 @@ +#include +#include +#include + +#include "orm.h" +#include "httppeer.h" +#include "websockets.h" + +namespace http +{ + +class loopwebsockets : public websockets_api +{ + public: + unsigned int outcount = 0; + loopwebsockets(std::weak_ptr p) : websockets_api(4, 0, p) {} + ~loopwebsockets() { std::cout << "~loopwebsockets" << std::endl; } + + public: + void onopen() { std::cout << "onopen" << std::endl; } + void onclose() { std::cout << "onclose" << std::endl; } + void onpong() {} + void pushloop() + { + std::shared_ptr peer = weakpeer.lock(); + if (peer) + { + std::cout << "timeloop:" << std::endl; + std::string aa = "looptests"; + std::string outhello; + peer->ws->makeWSText(aa, outhello); + peer->send(outhello); + + // peer->send(aa); + if (outcount == 4) + { + timeloop_num = 0; + outcount = 0; + return; + } + outcount++; + } + else + { + std::cout << "peer is die!" << std::endl; + } + } + void onfiles(std::string_view filename) { std::cout << "--------onfiles:--------" << filename << std::endl; } + void onmessage(std::string_view data) + { + std::cout << "onmessage:" << data << std::endl; + std::shared_ptr peer = weak_peer.lock(); + if (peer) + { + std::string outhello; + peer->ws->makeWSText(data, outhello); + peer->send(outhello); + } + } + static std::shared_ptr create(std::weak_ptr p) + { + return std::make_shared(p); + } +}; + +}// namespace http diff --git a/frameworks/C++/paozhu/paozhu_benchmark/websockets/include/mywebsockets.hpp b/frameworks/C++/paozhu/paozhu_benchmark/websockets/include/mywebsockets.hpp new file mode 100755 index 00000000000..4ebd42b88f3 --- /dev/null +++ b/frameworks/C++/paozhu/paozhu_benchmark/websockets/include/mywebsockets.hpp @@ -0,0 +1,83 @@ +#include +#include +#include + +#include "orm.h" +#include "httppeer.h" +#include "websockets.h" +#include "terminal_color.h" +// g++ -shared -fPIC mywebsockets.cpp -o mywebsockets.so +namespace http +{ + +class mywebsockets : public websockets_api +{ + public: + // unsigned int timeloop_num; + // unsigned char state; + unsigned int outcount = 0; + mywebsockets(std::weak_ptr p) : websockets_api(4, 0, p) {} + ~mywebsockets() { DEBUG_LOG(" ~mywebsockets "); } + + public: + void onopen() { DEBUG_LOG(" onopen "); } + void onclose() { DEBUG_LOG(" onclose "); } + void onpong() {} + void pushloop() + { + std::shared_ptr peer = weak_peer.lock(); + if (peer) + { + DEBUG_LOG(" timeloop "); + std::string aa = "This server push msg or subscribe msg"; + std::string outhello; + peer->ws->makeWSText(aa.data(), aa.length(), outhello); + peer->send(outhello); + + // peer->send(aa); + if (outcount == 4) + { + timeloop_num = 0; + outcount = 0; + return; + } + outcount++; + } + else + { + DEBUG_LOG(" peer is die! "); + } + } + + void onfiles([[maybe_unused]] std::string_view filename) { DEBUG_LOG("onfiles %zu", filename.size()); } + void onmessage(std::string_view data) + { + std::ostringstream oss; + oss << std::this_thread::get_id(); + oss << " onmessage:" << data << std::endl; + std::string temp = oss.str(); + DEBUG_LOG("%s", temp.c_str()); + std::shared_ptr peer = weak_peer.lock(); + if (peer) + { + std::string outhello; + if(data=="html") + { + std::string html_data="

Websocket test 测试h3

"; + peer->ws->makeWSText(html_data, outhello); + } + else + { + peer->ws->makeWSText(data, outhello); + } + + peer->send(outhello); + } + } + static std::shared_ptr create(std::weak_ptr p) + { + return std::make_shared(p); + } +}; + +}// namespace http \ No newline at end of file diff --git a/frameworks/C++/poco/README.md b/frameworks/C++/poco/README.md new file mode 100644 index 00000000000..54086c5e482 --- /dev/null +++ b/frameworks/C++/poco/README.md @@ -0,0 +1,15 @@ +# POCO C++ Libraries Benchmarking Test + +- [POCO Github Repository](https://github.com/pocoproject/poco) +- [POCO Website](https://pocoproject.org/) + +## Software Versions + +- [buildpack-deps noble](https://hub.docker.com/_/buildpack-deps) +- [g++ 14](https://gcc.gnu.org/gcc-14/) +- [c++17](https://en.cppreference.com/w/cpp/17) +- [POCO 1.13.1](https://pocoproject.org/releases/poco-1.13.1/poco-1.13.1-all.zip) + +## Test URLs + +- `PLAINTEXT` - [http://127.0.0.1:8080/plaintext](http://127.0.0.1:8080/plaintext) diff --git a/frameworks/C++/poco/benchmark.cpp b/frameworks/C++/poco/benchmark.cpp index 4032a08f9f5..9277b02b4d1 100644 --- a/frameworks/C++/poco/benchmark.cpp +++ b/frameworks/C++/poco/benchmark.cpp @@ -6,6 +6,8 @@ #include #include #include +#include +#include #include #include @@ -15,7 +17,9 @@ #define PLAIN_CONTENT_TYPE "text/plain" #define RES_BODY "Hello, World!" #define SERVER_NAME "poco" +#define MAX_CONNECTIONS 16384 +using namespace Poco; using namespace Poco::Net; using namespace Poco::Util; using namespace std; @@ -58,7 +62,12 @@ class MyServerApp : public ServerApplication { HTTPServerParams* hsp = new HTTPServerParams; hsp->setMaxThreads(stoi(args[1])); hsp->setKeepAlive(true); - HTTPServer s(new MyRequestHandlerFactory, ServerSocket(stoi(args[0]), 4000), hsp); + hsp->setMaxKeepAliveRequests(MAX_CONNECTIONS); + hsp->setMaxQueued(MAX_CONNECTIONS); + hsp->setThreadPriority(Thread::PRIO_HIGHEST); + ServerSocket socket(stoi(args[0]), MAX_CONNECTIONS); + socket.setBlocking(false); + HTTPServer s(new MyRequestHandlerFactory, socket, hsp); s.start(); waitForTerminationRequest(); s.stop(); diff --git a/frameworks/C++/poco/poco.dockerfile b/frameworks/C++/poco/poco.dockerfile index 1f592e48872..53aef0a5650 100644 --- a/frameworks/C++/poco/poco.dockerfile +++ b/frameworks/C++/poco/poco.dockerfile @@ -1,11 +1,11 @@ -FROM buildpack-deps:xenial +FROM buildpack-deps:noble RUN apt-get update -yqq && apt-get install -yqq software-properties-common unzip cmake -RUN apt-get install -yqq g++-4.8 libjson0-dev -RUN update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 50 +RUN apt-get install -yqq g++-14 +RUN update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-14 50 -ENV POCO_VERSION 1.6.1 +ENV POCO_VERSION 1.13.3 ENV POCO_HOME /poco WORKDIR ${POCO_HOME} @@ -20,10 +20,10 @@ ENV LD_LIBRARY_PATH ${POCO_HOME}/lib/Linux/x86_64 COPY benchmark.cpp benchmark.cpp -RUN g++-4.8 \ +RUN g++-14 \ -O3 \ -DNDEBUG \ - -std=c++0x \ + -std=c++17 \ -o \ poco \ benchmark.cpp \ diff --git a/frameworks/C++/silicon/CMakeLists.txt b/frameworks/C++/silicon/CMakeLists.txt deleted file mode 100644 index 54ea5b6ee8e..00000000000 --- a/frameworks/C++/silicon/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ -cmake_minimum_required(VERSION 2.8) - -project(silicon) - -include_directories(/include $ENV{MICROHTTPD_HOME}/include) - -link_directories(/lib $ENV{MICROHTTPD_HOME}/lib) - -add_definitions(-std=c++14 -ftemplate-depth=1024 -DNDEBUG -O3) - -add_executable(silicon_tpc_mysql techempower_microhttpd.cc) -target_link_libraries(silicon_tpc_mysql microhttpd mysqlclient) - -add_executable(silicon_epoll_mysql techempower_microhttpd.cc) -set_target_properties(silicon_epoll_mysql PROPERTIES COMPILE_FLAGS "-DTFB_USE_EPOLL") -target_link_libraries(silicon_epoll_mysql microhttpd mysqlclient) - -add_executable(silicon_lwan_mysql techempower_lwan.cc) -target_link_libraries(silicon_lwan_mysql mysqlclient lwan ubsan curl z pthread dl luajit-5.1) diff --git a/frameworks/C++/silicon/README.md b/frameworks/C++/silicon/README.md deleted file mode 100644 index 9c4e3badcfa..00000000000 --- a/frameworks/C++/silicon/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# C++/silicon Benchmarking test - -Silicon is a C++ web framework located at https://github.com/matt-42/silicon - -### Note - -The `silicon-epoll-mysql` and `silicon-lwan-mysql` tests are currently not working. They have been removed from the `benchmark_config.json` file but the implementations still exist. You can see the old `benchmark_config.json` [here](https://github.com/TechEmpower/FrameworkBenchmarks/blob/5d44d57cbb5cbc209a2d6aeb23010b466c055200/frameworks/C%2B%2B/silicon/benchmark_config.json). - diff --git a/frameworks/C++/silicon/benchmark_config.json b/frameworks/C++/silicon/benchmark_config.json deleted file mode 100644 index 408a7483ba3..00000000000 --- a/frameworks/C++/silicon/benchmark_config.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "framework": "silicon", - "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": "MySQL", - "framework": "silicon", - "language": "C++", - "flavor": "None", - "orm": "Full", - "platform": "None", - "webserver": "microhttpd", - "os": "Linux", - "database_os": "Linux", - "display_name": "silicon-tpc-mysql", - "notes": "", - "versus": "silicon" - } - }] -} diff --git a/frameworks/C++/silicon/build/symbols.hh b/frameworks/C++/silicon/build/symbols.hh deleted file mode 100644 index 9d973373ac5..00000000000 --- a/frameworks/C++/silicon/build/symbols.hh +++ /dev/null @@ -1,47 +0,0 @@ -// Generated by iod_generate_symbols. -#include -#ifndef IOD_SYMBOL_db -#define IOD_SYMBOL_db - iod_define_symbol(db) -#endif - -#ifndef IOD_SYMBOL_fortunes -#define IOD_SYMBOL_fortunes - iod_define_symbol(fortunes) -#endif - -#ifndef IOD_SYMBOL_id -#define IOD_SYMBOL_id - iod_define_symbol(id) -#endif - -#ifndef IOD_SYMBOL_json -#define IOD_SYMBOL_json - iod_define_symbol(json) -#endif - -#ifndef IOD_SYMBOL_message -#define IOD_SYMBOL_message - iod_define_symbol(message) -#endif - -#ifndef IOD_SYMBOL_plaintext -#define IOD_SYMBOL_plaintext - iod_define_symbol(plaintext) -#endif - -#ifndef IOD_SYMBOL_queries -#define IOD_SYMBOL_queries - iod_define_symbol(queries) -#endif - -#ifndef IOD_SYMBOL_randomNumber -#define IOD_SYMBOL_randomNumber - iod_define_symbol(randomNumber) -#endif - -#ifndef IOD_SYMBOL_updates -#define IOD_SYMBOL_updates - iod_define_symbol(updates) -#endif - diff --git a/frameworks/C++/silicon/build/techempower.hh b/frameworks/C++/silicon/build/techempower.hh deleted file mode 100644 index 3ecbfa1834f..00000000000 --- a/frameworks/C++/silicon/build/techempower.hh +++ /dev/null @@ -1,102 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include "symbols.hh" - -using namespace s; -using namespace sl; - -typedef decltype(D(_id(_auto_increment, _primary_key) = int(), - _randomNumber = int())) random_number; - -typedef decltype(D(_id(_auto_increment, _primary_key) = int(), - _message = std::string())) fortune; - -typedef mysql_orm_factory rn_orm_factory; -typedef mysql_orm rn_orm; - -typedef mysql_orm_factory fortune_orm_factory; -typedef mysql_orm fortune_orm; - - -std::string escape_html_entities(std::string& data) -{ - std::string buffer; - buffer.reserve(data.size()); - for(size_t pos = 0; pos != data.size(); ++pos) { - switch(data[pos]) { - case '&': buffer.append("&"); break; - case '\"': buffer.append("""); break; - case '\'': buffer.append("'"); break; - case '<': buffer.append("<"); break; - case '>': buffer.append(">"); break; - default: buffer.append(&data[pos], 1); break; - } - } - return std::move(buffer); -} - -auto techempower_api = http_api( - - GET / _plaintext = [] () { return response(_content_type = string_ref("text/plain"), - _body = string_ref("Hello, World!")); }, - - GET / _json = [] () { return response(_content_type = string_ref("application/json"), - _body = D(_message = "Hello, World!")); }, - - GET / _db = [] (rn_orm& orm) { - random_number r; - orm.find_by_id(1245, r); - return response(_content_type = "application/json", - _body = r); - }, - - GET / _queries * get_parameters(_queries = optional(std::string("1"))) = [] (auto param, rn_orm& orm) { - int N = atoi(param.queries.c_str()); - N = std::max(1, std::min(N, 500)); - - std::vector qs(N); - for (int i = 0; i < N; i++) - orm.find_by_id(1 + rand() % 9999, qs[i]); - return response(_content_type = "application/json", - _body = std::move(qs)); - }, - - GET / _updates * get_parameters(_queries = optional(std::string("1"))) = [] (auto param, rn_orm& orm) { - int N = atoi(param.queries.c_str()); - N = std::max(1, std::min(N, 500)); - - std::vector qs(N); - for (int i = 0; i < N; i++) - { - orm.find_by_id(1 + rand() % 9999, qs[i]); - qs[i].randomNumber = 1 + rand() % 9999; - orm.update(qs[i]); - } - return response(_content_type = "application/json", - _body = std::move(qs)); - }, - - GET / _fortunes = [] (fortune_orm& orm) { - std::vector table; - orm.forall([&] (fortune& f) { table.push_back(f); }); - table.push_back(fortune(0, "Additional fortune added at request time.")); - - std::sort(table.begin(), table.end(), - [] (const fortune& a, const fortune& b) { return a.message < b.message; }); - - std::stringstream ss; - - ss << "Fortunes"; - for(auto& f : table) - ss << ""; - ss << "
idmessage
" << f.id << "" << escape_html_entities(f.message) << "
"; - - return response(_content_type = "text/html; charset=utf-8", - _body = ss.str()); - } - - ); diff --git a/frameworks/C++/silicon/build/techempower_lwan.cc b/frameworks/C++/silicon/build/techempower_lwan.cc deleted file mode 100644 index 12be2db22f4..00000000000 --- a/frameworks/C++/silicon/build/techempower_lwan.cc +++ /dev/null @@ -1,41 +0,0 @@ -#include - -#include "techempower.hh" - -using namespace s; -using namespace sl; - -int main(int argc, char* argv[]) -{ - if (argc != 3) - { - std::cerr << "Usage: " << argv[0] << " mysql_host port" << std::endl; - return 1; - } - - auto techempower_middlewares = middleware_factories( - mysql_connection_factory(argv[1], "benchmarkdbuser", "benchmarkdbpass", "hello_world"), - fortune_orm_factory("Fortune"), - rn_orm_factory("World") - ); - - try - { - - // Write the pid. - std::ofstream pidfile(argv[3]); - pidfile << getpid() << std::endl; - pidfile.close(); - - // Start the server. - sl::lwan_json_serve(techempower_api, techempower_middlewares, atoi(argv[2])); - } - catch (std::exception& e) - { - std::cerr << e.what() << std::endl; - } - catch (sl::error::error& e) - { - std::cerr << e.what() << std::endl; - } -} diff --git a/frameworks/C++/silicon/build/techempower_microhttpd.cc b/frameworks/C++/silicon/build/techempower_microhttpd.cc deleted file mode 100644 index 984af647f03..00000000000 --- a/frameworks/C++/silicon/build/techempower_microhttpd.cc +++ /dev/null @@ -1,48 +0,0 @@ -#include - -#include "techempower.hh" - -using namespace s; -using namespace sl; - -int main(int argc, char* argv[]) -{ - - if (argc != 4) - { - std::cerr << "Usage: " << argv[0] << " mysql_host port nthreads" << std::endl; - return 1; - } - - auto techempower_middlewares = middleware_factories( - mysql_connection_factory(argv[1], "benchmarkdbuser", "benchmarkdbpass", "hello_world"), - fortune_orm_factory("Fortune"), - rn_orm_factory("World") - ); - - try - { - // Write the pid. - std::ofstream pidfile(argv[3]); - pidfile << getpid() << std::endl; - pidfile.close(); - - // Start the server. - sl::mhd_json_serve(techempower_api, techempower_middlewares, atoi(argv[2]), _blocking -#ifdef TFB_USE_EPOLL - , _linux_epoll, _nthreads = atoi(argv[3]) -#else - , _one_thread_per_connection -#endif - ); - - } - catch (std::exception& e) - { - std::cerr << e.what() << std::endl; - } - catch (sl::error::error& e) - { - std::cerr << e.what() << std::endl; - } -} diff --git a/frameworks/C++/silicon/config.toml b/frameworks/C++/silicon/config.toml deleted file mode 100644 index 745d5778ea8..00000000000 --- a/frameworks/C++/silicon/config.toml +++ /dev/null @@ -1,19 +0,0 @@ -[framework] -name = "silicon" - -[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 = "MySQL" -database_os = "Linux" -os = "Linux" -orm = "Full" -platform = "None" -webserver = "microhttpd" -versus = "silicon" diff --git a/frameworks/C++/silicon/silicon.dockerfile b/frameworks/C++/silicon/silicon.dockerfile deleted file mode 100644 index b7abb7e57c9..00000000000 --- a/frameworks/C++/silicon/silicon.dockerfile +++ /dev/null @@ -1,39 +0,0 @@ -FROM buildpack-deps:xenial - -RUN apt-get update -yqq && apt-get install -yqq software-properties-common cmake apt-transport-https - -RUN add-apt-repository -s "deb http://apt.llvm.org/`lsb_release -cs`/ llvm-toolchain-`lsb_release -cs`-3.9 main" -RUN wget -O - http://apt.llvm.org/llvm-snapshot.gpg.key| apt-key add - -RUN apt-get update -yqq -RUN apt-get install -yqq clang-3.9 lldb-3.9 - -ENV MICROHTTPD_VERSION=0.9.39 -ENV MICROHTTPD=/libmicrohttpd -ENV MICROHTTPD_HOME=$MICROHTTPD-$VERSION - -RUN wget http://mirror.ibcp.fr/pub/gnu/libmicrohttpd/libmicrohttpd-$MICROHTTPD_VERSION.tar.gz -RUN tar xf libmicrohttpd-$MICROHTTPD_VERSION.tar.gz -RUN cd libmicrohttpd-$MICROHTTPD_VERSION && \ - ./configure --prefix=$MICROHTTPD_HOME && \ - make install - -ENV PATH=${MICROHTTPD_HOME}/bin:${PATH} - -RUN apt-get install -yqq libboost-dev cmake - -ENV SILICON=/silicon - -COPY ./ ./ - -RUN git clone https://github.com/matt-42/silicon.git && \ - cd silicon && \ - git checkout ecaf04887c9dbbf0f457afab1f487268f6aeffab && \ - CC=clang-3.9 CXX=clang++-3.9 ./install.sh / - -RUN cd build && \ - cmake .. -DCMAKE_CXX_COMPILER=clang++-3.9 && \ - make silicon_tpc_mysql - -EXPOSE 8080 - -CMD /build/silicon_tpc_mysql tfb-database 8080 $(nproc) diff --git a/frameworks/C++/treefrog/controllers/worldcontroller.cpp b/frameworks/C++/treefrog/controllers/worldcontroller.cpp index 61068dcce9b..3f3f71d484d 100644 --- a/frameworks/C++/treefrog/controllers/worldcontroller.cpp +++ b/frameworks/C++/treefrog/controllers/worldcontroller.cpp @@ -3,6 +3,7 @@ #include "pworld.h" #include "mngworld.h" #include +#include void WorldController::index() @@ -246,17 +247,48 @@ void WorldController::cached_pqueries(const QString &num) void WorldController::pupdates(const QString &num) { + const QString statement("UPDATE world SET randomnumber = CASE id"); QVariantList worlds; + QString ids; + QString q = statement; + q.reserve(4096); int d = std::min(std::max(num.toInt(), 1), 500); PWorld world; + auto blkupdate = [&q, &ids, &statement]() { + if (!ids.isEmpty()) { + ids.chop(1); + q += QStringLiteral(" END WHERE id IN (%1)").arg(ids); + TSqlQuery query; + query.exec(q); + ids.clear(); + q = statement; + } + }; + for (int i = 0; i < d; ++i) { int id = Tf::random(1, 10000); world = PWorld::get(id); world.setRandomNumber( Tf::random(1, 10000) ); - world.update(); + q += QLatin1String(" WHEN "); + q += QString::number(world.id()); + q += QLatin1String(" THEN "); + q += QString::number(world.randomNumber()); + ids += QString::number(world.id()); + ids += ','; worlds << world.toVariantMap(); + + if (!((i + 1) % 200)) { + blkupdate(); + } } + + if (d == 1) { + world.update(); + } else { + blkupdate(); + } + renderJson(worlds); } diff --git a/frameworks/C++/treefrog/models/world.cpp b/frameworks/C++/treefrog/models/world.cpp index 13d65a7c97f..3c08e17e827 100644 --- a/frameworks/C++/treefrog/models/world.cpp +++ b/frameworks/C++/treefrog/models/world.cpp @@ -46,10 +46,7 @@ World &World::operator=(const World &other) bool World::update() { - TSqlQueryORMapper mapper; - mapper.prepare(QStringLiteral("UPDATE world SET randomNumber=? WHERE id=?")); - mapper.addBind(randomNumber()).addBind(id()); - return mapper.exec(); + return TAbstractModel::update(); } World World::create(int randomNumber) @@ -74,10 +71,8 @@ World World::create(const QVariantMap &values) World World::get(uint id) { - TSqlQueryORMapper mapper; - mapper.prepare(QStringLiteral("SELECT * from world WHERE id=?")); - mapper.addBind(id); - return World(mapper.execFirst()); + TSqlORMapper mapper; + return World(mapper.findByPrimaryKey(id)); } int World::count() diff --git a/frameworks/C++/treefrog/treefrog-epoll.dockerfile b/frameworks/C++/treefrog/treefrog-epoll.dockerfile index 0e962dc03be..9eb910f4e9d 100644 --- a/frameworks/C++/treefrog/treefrog-epoll.dockerfile +++ b/frameworks/C++/treefrog/treefrog-epoll.dockerfile @@ -2,7 +2,7 @@ FROM buildpack-deps:jammy ENV DEBIAN_FRONTEND noninteractive ENV DEBCONF_NOWARNINGS yes -ENV TFVER=2.7.1 +ENV TFVER=2.8.0 RUN apt-get update -yqq && apt-get upgrade -yq && \ apt-get install -yqq --no-install-recommends software-properties-common unzip wget libjemalloc-dev \ diff --git a/frameworks/C++/treefrog/treefrog-mongodb.dockerfile b/frameworks/C++/treefrog/treefrog-mongodb.dockerfile index c930ee9449a..df5a3694cdf 100644 --- a/frameworks/C++/treefrog/treefrog-mongodb.dockerfile +++ b/frameworks/C++/treefrog/treefrog-mongodb.dockerfile @@ -2,7 +2,7 @@ FROM buildpack-deps:jammy ENV DEBIAN_FRONTEND noninteractive ENV DEBCONF_NOWARNINGS yes -ENV TFVER=2.7.1 +ENV TFVER=2.8.0 RUN apt-get update -yqq && apt-get upgrade -yq && \ apt-get install -yqq --no-install-recommends software-properties-common unzip wget libjemalloc-dev \ diff --git a/frameworks/C++/treefrog/treefrog-mysql.dockerfile b/frameworks/C++/treefrog/treefrog-mysql.dockerfile index f0b263b6573..a9b6a7d4b2c 100644 --- a/frameworks/C++/treefrog/treefrog-mysql.dockerfile +++ b/frameworks/C++/treefrog/treefrog-mysql.dockerfile @@ -2,7 +2,7 @@ FROM buildpack-deps:jammy ENV DEBIAN_FRONTEND noninteractive ENV DEBCONF_NOWARNINGS yes -ENV TFVER=2.7.1 +ENV TFVER=2.8.0 RUN apt-get update -yqq && apt-get upgrade -yq && \ apt-get install -yqq --no-install-recommends software-properties-common unzip wget libjemalloc-dev \ diff --git a/frameworks/C++/treefrog/treefrog.dockerfile b/frameworks/C++/treefrog/treefrog.dockerfile index c930ee9449a..df5a3694cdf 100644 --- a/frameworks/C++/treefrog/treefrog.dockerfile +++ b/frameworks/C++/treefrog/treefrog.dockerfile @@ -2,7 +2,7 @@ FROM buildpack-deps:jammy ENV DEBIAN_FRONTEND noninteractive ENV DEBCONF_NOWARNINGS yes -ENV TFVER=2.7.1 +ENV TFVER=2.8.0 RUN apt-get update -yqq && apt-get upgrade -yq && \ apt-get install -yqq --no-install-recommends software-properties-common unzip wget libjemalloc-dev \ diff --git a/frameworks/C++/ulib/README.md b/frameworks/C++/ulib/README.md deleted file mode 100644 index 6fc50e63b7f..00000000000 --- a/frameworks/C++/ulib/README.md +++ /dev/null @@ -1,134 +0,0 @@ -#ULib Benchmarking Test - -This is the [ULib](http://stefanocasazza.github.io/ULib/) portion of a [benchmarking test suite](https://github.com/TechEmpower/FrameworkBenchmarks) comparing a variety of web development platforms. - -### JSON Encoding Test - -* [JSON test source](src/json.usp) - -### Data-Store/Database Mapping Test - -* [Database test source (SQL)](src/db.usp) -* [Database test source (REDIS)](src/rdb.usp) -* [Database test source (MONGODB)](src/mdb.usp) -* [Database test source (ELASTICSEARCH)](src/edb.usp) - -### Variable Query Test - -* [Variable Query test source (SQL)](src/query.usp) -* [Variable Query test source (REDIS)](src/rquery.usp) -* [Variable Query test source (MONGODB)](src/mquery.usp) -* [Variable Query test source (ELASTICSEARCH)](src/equery.usp) - -### Variable Query (caching) Test - -* [Variable Query caching test source (SQL)](src/cached_worlds.usp) - -### Fortune Query Test - -* [Fortune Query test source (SQL)](src/fortune.usp) -* [Fortune Query test source (REDIS)](src/rfortune.usp) -* [Fortune Query test source (MONGODB)](src/mfortune.usp) - -### Variable Query (update) Test - -* [Variable Query (update) test source (SQL)](src/update.usp) -* [Variable Query (update) test source (REDIS)](src/rupdate.usp) -* [Variable Query (update) test source (MONGODB)](src/mupdate.usp) -* [Variable Query (update) test source (ELASTICSEARCH)](src/eupdate.usp) - -### Plaintext Test - -* [Plaintext test source](src/plaintext.usp) - -## Infrastructure Software Versions -The tests were run with: - -* [ULib Version 2.4.2](https://github.com/stefanocasazza/ULib/archive/v2.4.2.tar.gz) - -Output -====== - -[/json](http://www.techempower.com/benchmarks/#section=json) ------ -``` -HTTP/1.1 200 OK -Date: Thu, 03 Jul 2014 10:11:10 GMT -Server: ULib -Content-Length: 27 -Content-Type: application/json - -{"message":"Hello, World!"} -``` - -[/db](http://www.techempower.com/benchmarks/#section=db) ---- -``` -HTTP/1.1 200 OK -Date: Thu, 03 Jul 2014 10:14:51 GMT -Server: ULib -Content-Length: 31 -Content-Type: application/json - -{"id":6227,"randomNumber":8489} -``` - -[/query?queries=10](http://www.techempower.com/benchmarks/#section=query) -------------------- -``` -HTTP/1.1 200 OK -Date: Thu, 03 Jul 2014 10:14:51 GMT -Server: ULib -Content-Length: 320 -Content-Type: application/json - -[{"id":6851,"randomNumber":7598},{"id":3968,"randomNumber":7325},{"id":8159,"randomNumber":348},{"id":9560,"randomNumber":7333},{"id":9938,"randomNumber":9080},{"id":1598,"randomNumber":1623},{"id":3280,"randomNumber":8707},{"id":4521,"randomNumber":6063},{"id":8173,"randomNumber":3690},{"id":3648,"randomNumber":8803}] -``` - -[/cached_worlds?queries=10](http://www.techempower.com/benchmarks/#section=caching) -------------------- -``` -HTTP/1.1 200 OK -Date: Thu, 03 Jul 2014 10:14:51 GMT -Server: ULib -Content-Length: 320 -Content-Type: application/json - -[{"id":6851,"randomNumber":7598},{"id":3968,"randomNumber":7325},{"id":8159,"randomNumber":348},{"id":9560,"randomNumber":7333},{"id":9938,"randomNumber":9080},{"id":1598,"randomNumber":1623},{"id":3280,"randomNumber":8707},{"id":4521,"randomNumber":6063},{"id":8173,"randomNumber":3690},{"id":3648,"randomNumber":8803}] -``` - -[/fortune](http://www.techempower.com/benchmarks/#section=fortune) ---------- -``` -HTTP/1.1 200 OK -Date: Thu, 03 Jul 2014 10:14:51 GMT -Server: ULib -Content-Type: text/html; charset=UTF-8 -Content-Length: 1227 - -Fortunes
idmessage
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.
8A list is only as strong as its weakest link. — Donald Knuth
0Additional fortune added at request time.
3After enough decimal places, nobody gives a damn.
7Any program that runs right is obsolete.
10Computers make very fast, very accurate mistakes.
6Emacs is a nice operating system, but I prefer UNIX. — Tom Christaensen
9Feature: A bug with seniority.
1fortune: No such file or directory
12フレームワークのベンチマーク
-``` - -[/update?queries=10](http://www.techempower.com/benchmarks/#section=update) -------------------- -``` -HTTP/1.1 200 OK -Date: Thu, 03 Jul 2014 10:14:51 GMT -Server: ULib -Content-Length: 319 -Content-Type: application/json - -[{"id":7171,"randomNumber":351},{"id":6019,"randomNumber":9725},{"id":8118,"randomNumber":4023},{"id":7965,"randomNumber":1388},{"id":7797,"randomNumber":2249},{"id":112,"randomNumber":1108},{"id":6127,"randomNumber":4323},{"id":2597,"randomNumber":7509},{"id":2978,"randomNumber":7883},{"id":1111,"randomNumber":2228}] -``` - -[/plaintext](http://www.techempower.com/benchmarks/#section=plaintext) ----------- -``` -HTTP/1.1 200 OK -Date: Thu, 03 Jul 2014 10:14:51 GMT -Server: ULib -Content-Type: text/plain -Content-Length: 13 - -Hello, World! -``` diff --git a/frameworks/C++/ulib/benchmark_config.json b/frameworks/C++/ulib/benchmark_config.json deleted file mode 100644 index 86e4e513f40..00000000000 --- a/frameworks/C++/ulib/benchmark_config.json +++ /dev/null @@ -1,160 +0,0 @@ -{ - "framework": "ulib", - "tests": [{ - "default": { - "plaintext_url": "/plaintext", - "port": 8080, - "approach": "Realistic", - "classification": "Platform", - "database": "None", - "framework": "None", - "language": "C++", - "orm": "Micro", - "platform": "None", - "webserver": "ULib", - "os": "Linux", - "database_os": "Linux", - "display_name": "ULib", - "notes": "", - "versus": "", - "tags": ["broken"] - }, - "plaintext_fit": { - "plaintext_url": "/plaintext", - "port": 8080, - "approach": "Realistic", - "classification": "Platform", - "database": "None", - "framework": "None", - "language": "C++", - "orm": "Micro", - "platform": "None", - "webserver": "ULib", - "os": "Linux", - "database_os": "Linux", - "display_name": "ULib-fit", - "notes": "", - "versus": "", - "tags": ["broken"] - }, - "json": { - "json_url": "/json", - "port": 8080, - "approach": "Realistic", - "classification": "Platform", - "database": "None", - "framework": "None", - "language": "C++", - "orm": "Micro", - "platform": "None", - "webserver": "ULib", - "os": "Linux", - "database_os": "Linux", - "display_name": "ULib", - "notes": "", - "versus": "", - "tags": ["broken"] - }, - "json_fit": { - "json_url": "/json", - "port": 8080, - "approach": "Realistic", - "classification": "Platform", - "database": "None", - "framework": "None", - "language": "C++", - "orm": "Micro", - "platform": "None", - "webserver": "ULib", - "os": "Linux", - "database_os": "Linux", - "display_name": "ULib-fit", - "notes": "", - "versus": "", - "tags": ["broken"] - }, - "mysql": { - "db_url": "/db", - "query_url": "/query?queries=", - "fortune_url": "/fortune", - "cached_query_url": "/cached_worlds?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Platform", - "database": "MySQL", - "framework": "None", - "language": "C++", - "orm": "Micro", - "platform": "None", - "webserver": "ULib", - "os": "Linux", - "database_os": "Linux", - "display_name": "ULib-mysql", - "notes": "", - "versus": "", - "tags": ["broken"] - }, - "postgres": { - "db_url": "/db", - "fortune_url": "/fortune", - "update_url": "/update?queries=", - "cached_query_url": "/cached_worlds?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Platform", - "database": "Postgres", - "framework": "None", - "language": "C++", - "orm": "Micro", - "platform": "None", - "webserver": "ULib", - "os": "Linux", - "database_os": "Linux", - "display_name": "ULib-postgres", - "notes": "", - "versus": "", - "tags": ["broken"] - }, - "postgres_fit": { - "db_url": "/db", - "fortune_url": "/fortune", - "port": 8080, - "approach": "Realistic", - "classification": "Platform", - "database": "Postgres", - "framework": "None", - "language": "C++", - "orm": "Micro", - "platform": "None", - "webserver": "ULib", - "os": "Linux", - "database_os": "Linux", - "display_name": "ULib-fit", - "notes": "", - "versus": "", - "tags": ["broken"] - }, - "mongodb": { - "setup_file": "setup_mongodb", - "db_url": "/mdb", - "query_url": "/mquery?queries=", - "fortune_url": "/mfortune", - "update_url": "/mupdate?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Platform", - "database": "MongoDB", - "framework": "None", - "language": "C++", - "orm": "Micro", - "platform": "None", - "webserver": "ULib", - "os": "Linux", - "database_os": "Linux", - "display_name": "ULib-mongodb", - "notes": "", - "versus": "", - "tags": ["broken"] - } - }] -} diff --git a/frameworks/C++/ulib/config.toml b/frameworks/C++/ulib/config.toml deleted file mode 100644 index 4288ea05d7d..00000000000 --- a/frameworks/C++/ulib/config.toml +++ /dev/null @@ -1,108 +0,0 @@ -[framework] -name = "ulib" - -[plaintext_fit] -urls.plaintext = "/plaintext" -approach = "Realistic" -classification = "Platform" -database = "None" -database_os = "Linux" -os = "Linux" -orm = "Micro" -platform = "None" -webserver = "ULib" -versus = "" - -[postgres] -urls.db = "/db" -urls.update = "/update?queries=" -urls.fortune = "/fortune" -urls.cached_query = "/cached_worlds?queries=" -approach = "Realistic" -classification = "Platform" -database = "Postgres" -database_os = "Linux" -os = "Linux" -orm = "Micro" -platform = "None" -webserver = "ULib" -versus = "" - -[main] -urls.plaintext = "/plaintext" -approach = "Realistic" -classification = "Platform" -database = "None" -database_os = "Linux" -os = "Linux" -orm = "Micro" -platform = "None" -webserver = "ULib" -versus = "" - -[mongodb] -urls.db = "/mdb" -urls.query = "/mquery?queries=" -urls.update = "/mupdate?queries=" -urls.fortune = "/mfortune" -approach = "Realistic" -classification = "Platform" -database = "MongoDB" -database_os = "Linux" -os = "Linux" -orm = "Micro" -platform = "None" -webserver = "ULib" -versus = "" - -[json_fit] -urls.json = "/json" -approach = "Realistic" -classification = "Platform" -database = "None" -database_os = "Linux" -os = "Linux" -orm = "Micro" -platform = "None" -webserver = "ULib" -versus = "" - -[postgres_fit] -urls.db = "/db" -urls.fortune = "/fortune" -approach = "Realistic" -classification = "Platform" -database = "Postgres" -database_os = "Linux" -os = "Linux" -orm = "Micro" -platform = "None" -webserver = "ULib" -versus = "" - -[json] -urls.json = "/json" -approach = "Realistic" -classification = "Platform" -database = "None" -database_os = "Linux" -os = "Linux" -orm = "Micro" -platform = "None" -webserver = "ULib" -versus = "" - -[mysql] -urls.db = "/db" -urls.query = "/query?queries=" -urls.fortune = "/fortune" -urls.cached_query = "/cached_worlds?queries=" -approach = "Realistic" -classification = "Platform" -database = "MySQL" -database_os = "Linux" -os = "Linux" -orm = "Micro" -platform = "None" -webserver = "ULib" -versus = "" diff --git a/frameworks/C++/ulib/src/cached_worlds.usp b/frameworks/C++/ulib/src/cached_worlds.usp deleted file mode 100644 index aa9025ba32a..00000000000 --- a/frameworks/C++/ulib/src/cached_worlds.usp +++ /dev/null @@ -1,56 +0,0 @@ - - - - diff --git a/frameworks/C++/ulib/src/db.usp b/frameworks/C++/ulib/src/db.usp deleted file mode 100644 index f1f8f9d2abe..00000000000 --- a/frameworks/C++/ulib/src/db.usp +++ /dev/null @@ -1,45 +0,0 @@ - - - - diff --git a/frameworks/C++/ulib/src/edb.usp b/frameworks/C++/ulib/src/edb.usp deleted file mode 100644 index 5e87c864293..00000000000 --- a/frameworks/C++/ulib/src/edb.usp +++ /dev/null @@ -1,14 +0,0 @@ - - - - diff --git a/frameworks/C++/ulib/src/equery.usp b/frameworks/C++/ulib/src/equery.usp deleted file mode 100644 index f05bcfbfebc..00000000000 --- a/frameworks/C++/ulib/src/equery.usp +++ /dev/null @@ -1,14 +0,0 @@ - - - - diff --git a/frameworks/C++/ulib/src/eupdate.usp b/frameworks/C++/ulib/src/eupdate.usp deleted file mode 100644 index 483fd82c825..00000000000 --- a/frameworks/C++/ulib/src/eupdate.usp +++ /dev/null @@ -1,28 +0,0 @@ - - - - diff --git a/frameworks/C++/ulib/src/fortune.h b/frameworks/C++/ulib/src/fortune.h deleted file mode 100644 index af237428531..00000000000 --- a/frameworks/C++/ulib/src/fortune.h +++ /dev/null @@ -1,316 +0,0 @@ -// fortune.h - -#ifndef FORTUNE_H -#define FORTUNE_H 1 - -#include -#include -#include -#include -#include -#include - -#ifdef U_STATIC_ORM_DRIVER_PGSQL -# include -# include -#endif - -class U_EXPORT Fortune { -public: - uint32_t id; - UString message; - - Fortune(uint32_t _id) : id(_id), message(101U) - { - U_TRACE_CTOR(5, Fortune, "%u", _id) - } - - Fortune(uint32_t _id, const UString& _message) : id(_id), message(_message) - { - U_TRACE_CTOR(5, Fortune, "%u,%V", _id, _message.rep) - } - - Fortune(const Fortune& f) : id(f.id), message(f.message) - { - U_TRACE_CTOR(5, Fortune, "%p", &f) - } - - ~Fortune() - { - U_TRACE_DTOR(5, Fortune) - } - - // SERVICE - - bool operator<(const Fortune& other) const { return cmp_obj(&message, &other.message); } - - static int cmp_obj(const void* a, const void* b) - { - U_TRACE(5, "Fortune::cmp_obj(%p,%p)", a, b) - -# ifdef U_STDCPP_ENABLE - /** - * The comparison function must follow a strict-weak-ordering - * - * 1) For all x, it is not the case that x < x (irreflexivity) - * 2) For all x, y, if x < y then it is not the case that y < x (asymmetry) - * 3) For all x, y, and z, if x < y and y < z then x < z (transitivity) - * 4) For all x, y, and z, if x is incomparable with y, and y is incomparable with z, then x is incomparable with z (transitivity of incomparability) - */ - - return (((const Fortune*)a)->message.compare(((const Fortune*)b)->message) < 0); -# else - return (*(const Fortune**)a)->message.compare((*(const Fortune**)b)->message); -# endif - } - - // JSON - - void toJSON(UString& json) - { - U_TRACE(5, "Fortune::toJSON(%V)", json.rep) - - json.toJSON(U_JSON_METHOD_HANDLER(id, unsigned int)); - json.toJSON(U_JSON_METHOD_HANDLER(message, UString)); - } - - void fromJSON(UValue& json) - { - U_TRACE(5, "Fortune::fromJSON(%p)", &json) - - json.fromJSON(U_JSON_METHOD_HANDLER(id, unsigned int)); - json.fromJSON(U_JSON_METHOD_HANDLER(message, UString)); - } - - // ORM - - void bindParam(UOrmStatement* stmt) - { - U_TRACE(5, "Fortune::bindParam(%p)", stmt) - - stmt->bindParam(U_ORM_TYPE_HANDLER(id, unsigned int)); - stmt->bindParam(U_ORM_TYPE_HANDLER(message, UString)); - } - - void bindResult(UOrmStatement* stmt) - { - U_TRACE(5, "Fortune::bindResult(%p)", stmt) - - stmt->bindResult(U_ORM_TYPE_HANDLER(id, unsigned int)); - stmt->bindResult(U_ORM_TYPE_HANDLER(message, UString)); - } - - static uint32_t uid; - static char* pwbuffer; - static UString* pmessage; - static UVector* pvfortune; - - static UOrmSession* psql_fortune; - static UOrmStatement* pstmt_fortune; - -#ifdef U_STATIC_ORM_DRIVER_PGSQL - static PGconn* conn; - static UPgSqlStatement* pstmt; - - static void sendQueryPrepared() - { - U_TRACE_NO_PARAM(5, "Fortune::sendQueryPrepared()") - - (void) U_SYSCALL(PQsendQueryPrepared, "%p,%S,%u,%p,%p,%p,%u", conn, pstmt->stmtName, 0, 0, 0, 0, 1); - } -#endif - - static void replace(uint32_t i, uint32_t _id, const char* msg, uint32_t len) - { - U_TRACE(5, "Fortune::replace(%u,%u,%.*S,%u)", i, _id, len, msg, len) - - U_INTERNAL_ASSERT_POINTER(pvfortune) - - Fortune* elem = pvfortune->at(i); - - elem->id = _id; - - UXMLEscape::encode(msg, len, elem->message); - } - - static void replace(uint32_t i) { replace(i, uid, U_STRING_TO_PARAM(*pmessage)); } - static void replace(uint32_t i, uint32_t _id) { replace(i, _id, U_STRING_TO_PARAM(*pmessage)); } - static void replace(uint32_t i, const UString& message) { replace(i, i+1, U_STRING_TO_PARAM(message)); } - static void replace(uint32_t i, uint32_t _id, const UString& message) { replace(i, _id, U_STRING_TO_PARAM(message)); } - - static void initQuery() - { - U_TRACE_NO_PARAM(5, "::initQuery()") - - char* ptr = UClientImage_Base::wbuffer->data(); - - U_INTERNAL_DUMP("wbuffer(%u) = %#.10S", UClientImage_Base::wbuffer->size(), ptr) - - if (u_get_unalignedp64(ptr+48) != U_MULTICHAR_CONSTANT64('h','a','r','s','e','t','=','U')) - { - u_put_unalignedp64(ptr, U_MULTICHAR_CONSTANT64('C','o','n','t','e','n','t','-')); - u_put_unalignedp64(ptr+8, U_MULTICHAR_CONSTANT64('L','e','n','g','t','h',':',' ')); - u_put_unalignedp64(ptr+16, U_MULTICHAR_CONSTANT64('x','x','x','x','x','x','x','x')); - u_put_unalignedp64(ptr+24, U_MULTICHAR_CONSTANT64('\r','\n','C','o','n','t','e','n')); - u_put_unalignedp64(ptr+32, U_MULTICHAR_CONSTANT64('t','-','T','y','p','e',':',' ')); - u_put_unalignedp64(ptr+40, U_MULTICHAR_CONSTANT64('t','e','x','t','/','h','t','m')); - u_put_unalignedp64(ptr+48, U_MULTICHAR_CONSTANT64('l',';',' ','c','h','a','r','s')); - u_put_unalignedp64(ptr+56, U_MULTICHAR_CONSTANT64('e','t','=','U','T','F','-','8')); - u_put_unalignedp64(ptr+64, U_MULTICHAR_CONSTANT64('\r','\n','\r','\n','<','!','d','o')); - u_put_unalignedp64(ptr+72, U_MULTICHAR_CONSTANT64('c','t','y','p','e',' ','h','t')); - u_put_unalignedp64(ptr+80, U_MULTICHAR_CONSTANT64('m','l','>','<','h','t','m','l')); - u_put_unalignedp64(ptr+88, U_MULTICHAR_CONSTANT64('>','<','h','e','a','d','>','<')); - u_put_unalignedp64(ptr+96, U_MULTICHAR_CONSTANT64('t','i','t','l','e','>','F','o')); - u_put_unalignedp64(ptr+104, U_MULTICHAR_CONSTANT64('r','t','u','n','e','s','<','/')); - u_put_unalignedp64(ptr+112, U_MULTICHAR_CONSTANT64('t','i','t','l','e','>','<','/')); - u_put_unalignedp64(ptr+120, U_MULTICHAR_CONSTANT64('h','e','a','d','>','<','b','o')); - u_put_unalignedp64(ptr+128, U_MULTICHAR_CONSTANT64('d','y','>','<','t','a','b','l')); - u_put_unalignedp64(ptr+136, U_MULTICHAR_CONSTANT64('e','>','<','t','r','>','<','t')); - u_put_unalignedp64(ptr+144, U_MULTICHAR_CONSTANT64('h','>','i','d','<','/','t','h')); - u_put_unalignedp64(ptr+152, U_MULTICHAR_CONSTANT64('>','<','t','h','>','m','e','s')); - u_put_unalignedp64(ptr+160, U_MULTICHAR_CONSTANT64('s','a','g','e','<','/','t','h')); - u_put_unalignedp64(ptr+168, U_MULTICHAR_CONSTANT64('>','<','/','t','r','>','\0','\0')); - - pwbuffer = ptr + U_CONSTANT_SIZE("Content-Length: xxxxxxxx\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n" - "Fortunes"); - } - - U_INTERNAL_ASSERT_EQUALS(u_get_unalignedp64(UClientImage_Base::wbuffer->data()), U_MULTICHAR_CONSTANT64('C','o','n','t','e','n','t','-')) - } - - static void endQuery() - { - U_TRACE_NO_PARAM(5, "::endQuery()") - - U_INTERNAL_ASSERT_POINTER(pvfortune) - - Fortune* elem = pvfortune->last(); - - elem->id = 0; - elem->message.rep->replace(U_CONSTANT_TO_PARAM("Additional fortune added at request time.")); - - pvfortune->sort(Fortune::cmp_obj); - - char* ptr = pwbuffer; - uint32_t content_length = U_CONSTANT_SIZE("Fortunes
idmessage
"); - - for (uint32_t sz, i = 0, n = pvfortune->size(); i < n; ++i) - { - elem = pvfortune->at(i); - - u_put_unalignedp64(ptr, U_MULTICHAR_CONSTANT64('<','t','r','>','<','t','d','>')); - - ptr = u_num2str32(elem->id, ptr+8); - - u_put_unalignedp64(ptr, U_MULTICHAR_CONSTANT64('<','/','t','d','>','<','t','d')); - ptr += 8; - - *ptr++ = '>'; - - (void) memcpy(ptr, elem->message.data(), sz = elem->message.size()); - ptr += sz; - - u_put_unalignedp64(ptr, U_MULTICHAR_CONSTANT64('<','/','t','d','>','<','/','t')); - u_put_unalignedp16(ptr+8, U_MULTICHAR_CONSTANT16('r','>')); - ptr += 8+2; - } - - u_put_unalignedp64(ptr, U_MULTICHAR_CONSTANT64('<','/','t','a','b','l','e','>')); - u_put_unalignedp64(ptr+8, U_MULTICHAR_CONSTANT64('<','/','b','o','d','y','>','<')); - u_put_unalignedp64(ptr+16, U_MULTICHAR_CONSTANT64('/','h','t','m','l','>','\0','\0')); - - content_length += (ptr - pwbuffer) + U_CONSTANT_SIZE("
idmessage
"); - - ptr = pwbuffer - U_CONSTANT_SIZE("xxxxxxxx\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n" - "Fortunes"); - - u_put_unalignedp64(ptr, U_MULTICHAR_CONSTANT64(' ',' ',' ',' ',' ',' ',' ',' ')); - - (void) u_num2str32(content_length, ptr); - - UClientImage_Base::wbuffer->size_adjust_constant(U_CONSTANT_SIZE("Content-Length: xxxxxxxx\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n") + content_length); - } - - static void doQuery(vPF handlerQuery) - { - U_TRACE(5, "Fortune::doQuery(%p)", handlerQuery) - - initQuery(); - handlerQuery(); - endQuery(); - } - - static void handlerInitSql() - { - U_TRACE_NO_PARAM(5, "Fortune::handlerInitSql()") - -# ifdef U_STATIC_ORM_DRIVER_PGSQL - U_INTERNAL_DUMP("UServer_Base::handler_db2 = %p", UServer_Base::handler_db2) - - if (UServer_Base::handler_db2 == U_NULLPTR) UServer_Base::handler_db2 = new UEventDB(); -# endif - } - - static void handlerFork() - { - U_TRACE_NO_PARAM(5, "Fortune::handlerFork()") - - pmessage = new UString(101U); - - pvfortune = new UVector(); - - Fortune* elem; - - for (uint32_t i = 0; i < 13; ++i) - { - elem = new Fortune(i+1); - - pvfortune->push(elem); - } - } - - static void handlerForkSql() - { - U_TRACE_NO_PARAM(5, "Fortune::handlerForkSql()") - - if (psql_fortune == U_NULLPTR) - { - psql_fortune = new UOrmSession(U_CONSTANT_TO_PARAM("fortune")); - - if (psql_fortune->isReady() == false) - { - U_WARNING("Fortune::handlerForkSql(): we cound't connect to db"); - - U_DELETE(psql_fortune) - - psql_fortune = U_NULLPTR; - - return; - } - - pstmt_fortune = new UOrmStatement(*psql_fortune, U_CONSTANT_TO_PARAM("SELECT id, message FROM Fortune")); - - handlerFork(); - - pstmt_fortune->into(uid, *pmessage); - -# ifdef U_STATIC_ORM_DRIVER_PGSQL - if (UOrmDriver::isPGSQL()) - { - UOrmDriverPgSql* pdrv = (UOrmDriverPgSql*)psql_fortune->getDriver(); - - conn = (PGconn*)pdrv->UOrmDriver::connection; - pstmt = (UPgSqlStatement*)pstmt_fortune->getStatement(); - - pstmt->prepareStatement(pdrv); - - UServer_Base::handler_db2->setConnection(conn); - } -# endif - } - } - -private: - U_DISALLOW_ASSIGN(Fortune) -}; -#endif diff --git a/frameworks/C++/ulib/src/fortune.usp b/frameworks/C++/ulib/src/fortune.usp deleted file mode 100644 index 038402a2585..00000000000 --- a/frameworks/C++/ulib/src/fortune.usp +++ /dev/null @@ -1,67 +0,0 @@ - - - - diff --git a/frameworks/C++/ulib/src/fortuneNoSql.h b/frameworks/C++/ulib/src/fortuneNoSql.h deleted file mode 100644 index 880304e011e..00000000000 --- a/frameworks/C++/ulib/src/fortuneNoSql.h +++ /dev/null @@ -1,115 +0,0 @@ -// fortuneNoSql.h - -#ifndef FORTUNE_NO_SQL_H -#define FORTUNE_NO_SQL_H 1 - -#include "fortune.h" - -#include -#include - -#ifdef USE_MONGODB -# include -#endif - -class U_EXPORT FortuneNoSql { -public: - -#ifdef USE_MONGODB - static UMongoDBClient* mc; -#endif - - static void handlerQueryMongoDB() - { - U_TRACE(5, "FortuneNoSql::handlerQueryMongoDB()") - - U_INTERNAL_ASSERT_POINTER(Fortune::pmessage) - -# ifdef USE_MONGODB - (void) mc->findAll(); - - for (uint32_t i = 0, n = mc->vitem.size(); i < n; ++i) - { - (void) U_JFIND(mc->vitem[i], "message", *Fortune::pmessage); - - Fortune::replace(i, i+1); - - Fortune::pmessage->clear(); - } -# endif - } - - static void handlerForkMongoDB() - { - U_TRACE_NO_PARAM(5, "FortuneNoSql::handlerForkMongoDB()") - -# ifdef USE_MONGODB - if (mc == U_NULLPTR) - { - U_NEW(UMongoDBClient, mc, UMongoDBClient); - - if (mc->connect(U_NULLPTR, 0) == false) - { - U_WARNING("FortuneNoSql::handlerForkMongoDB(): connection failed"); - - U_DELETE(mc) - - mc = U_NULLPTR; - - return; - } - - if (mc->selectCollection("hello_world", "fortune") == false) - { - U_WARNING("FortuneNoSql::handlerForkMongoDB(): selectCollection() failed"); - - U_DELETE(mc) - - mc = U_NULLPTR; - - return; - } - - Fortune::handlerFork(); - } -# endif - } - - static UREDISClient_Base* rc; - - static void handlerQueryREDIS() - { - U_TRACE(5, "FortuneNoSql::handlerQueryREDIS()") - - (void) rc->lrange(U_CONSTANT_TO_PARAM("fortunes 0 -1")); - - for (uint32_t i = 0, n = rc->vitem.size(); i < n; ++i) Fortune::replace(i, rc->vitem[i]); - } - - static void handlerForkREDIS() - { - U_TRACE_NO_PARAM(5, "Fortune::handlerForkREDIS()") - - if (rc == U_NULLPTR) - { - U_NEW(UREDISClient, rc, UREDISClient); - - if (rc->connect() == false) - { - U_WARNING("FortuneNoSql::handlerForkREDIS(): %V", rc->UClient_Base::getResponse().rep); - - U_DELETE(rc) - - rc = U_NULLPTR; - - return; - } - - Fortune::handlerFork(); - } - } - -private: - U_DISALLOW_ASSIGN(FortuneNoSql) -}; -#endif diff --git a/frameworks/C++/ulib/src/json.usp b/frameworks/C++/ulib/src/json.usp deleted file mode 100644 index 9afe75aefa0..00000000000 --- a/frameworks/C++/ulib/src/json.usp +++ /dev/null @@ -1,52 +0,0 @@ - - - - diff --git a/frameworks/C++/ulib/src/libFortune.cxx b/frameworks/C++/ulib/src/libFortune.cxx deleted file mode 100644 index 1348e76e96d..00000000000 --- a/frameworks/C++/ulib/src/libFortune.cxx +++ /dev/null @@ -1,14 +0,0 @@ -// fortune.cpp - -#include "fortune.h" - -char* Fortune::pwbuffer; -uint32_t Fortune::uid; -UString* Fortune::pmessage; -UOrmSession* Fortune::psql_fortune; -UOrmStatement* Fortune::pstmt_fortune; -UVector* Fortune::pvfortune; -#ifdef U_STATIC_ORM_DRIVER_PGSQL -PGconn* Fortune::conn; -UPgSqlStatement* Fortune::pstmt; -#endif diff --git a/frameworks/C++/ulib/src/libFortuneNoSql.cxx b/frameworks/C++/ulib/src/libFortuneNoSql.cxx deleted file mode 100644 index 7b05a9c15c7..00000000000 --- a/frameworks/C++/ulib/src/libFortuneNoSql.cxx +++ /dev/null @@ -1,8 +0,0 @@ -// fortuneNoSql.cpp - -#include "fortuneNoSql.h" - -#ifdef USE_MONGODB -UMongoDBClient* FortuneNoSql::mc; -#endif -UREDISClient_Base* FortuneNoSql::rc; diff --git a/frameworks/C++/ulib/src/libWorld.cxx b/frameworks/C++/ulib/src/libWorld.cxx deleted file mode 100644 index 214d809dc6b..00000000000 --- a/frameworks/C++/ulib/src/libWorld.cxx +++ /dev/null @@ -1,17 +0,0 @@ -// world.cpp - -#include "world.h" - -char World::wbuffer[18000]; -char* World::ptr; -char* World::pwbuffer; -World* World::pworld_query; -uint32_t World::rnum; -uint32_t World::rnumber[501]; -UOrmSession* World::psql_query; -UOrmStatement* World::pstmt_query; -#ifdef U_STATIC_ORM_DRIVER_PGSQL -char World::num2str[sizeof(unsigned int)]; -PGconn* World::conn; -UPgSqlStatement* World::pstmt; -#endif diff --git a/frameworks/C++/ulib/src/libWorldNoSql.cxx b/frameworks/C++/ulib/src/libWorldNoSql.cxx deleted file mode 100644 index 95b6895fd03..00000000000 --- a/frameworks/C++/ulib/src/libWorldNoSql.cxx +++ /dev/null @@ -1,16 +0,0 @@ -// worldNoSql.cpp - -#include "worldNoSql.h" - -#ifdef USE_MONGODB -bson_t* WorldNoSql::query; -UMongoDBClient* WorldNoSql::mc; -#endif -char WorldNoSql::rc_buffer[128]; -char WorldNoSql::es_buffer1[128]; -char WorldNoSql::es_buffer2[128]; -char* WorldNoSql::pbuffer1; -char* WorldNoSql::pbuffer2; -UString* WorldNoSql::str_rnumber; -UREDISClient_Base* WorldNoSql::rc; -UElasticSearchClient* WorldNoSql::es; diff --git a/frameworks/C++/ulib/src/mdb.usp b/frameworks/C++/ulib/src/mdb.usp deleted file mode 100644 index ffc16cd5f97..00000000000 --- a/frameworks/C++/ulib/src/mdb.usp +++ /dev/null @@ -1,14 +0,0 @@ - - - - diff --git a/frameworks/C++/ulib/src/mfortune.usp b/frameworks/C++/ulib/src/mfortune.usp deleted file mode 100644 index 7900caaa028..00000000000 --- a/frameworks/C++/ulib/src/mfortune.usp +++ /dev/null @@ -1,14 +0,0 @@ - - - - diff --git a/frameworks/C++/ulib/src/mquery.usp b/frameworks/C++/ulib/src/mquery.usp deleted file mode 100644 index 4c507a18912..00000000000 --- a/frameworks/C++/ulib/src/mquery.usp +++ /dev/null @@ -1,14 +0,0 @@ - - - - diff --git a/frameworks/C++/ulib/src/mupdate.usp b/frameworks/C++/ulib/src/mupdate.usp deleted file mode 100644 index 4fec5c328c1..00000000000 --- a/frameworks/C++/ulib/src/mupdate.usp +++ /dev/null @@ -1,14 +0,0 @@ - - - - diff --git a/frameworks/C++/ulib/src/plaintext.usp b/frameworks/C++/ulib/src/plaintext.usp deleted file mode 100644 index 40f909bc57c..00000000000 --- a/frameworks/C++/ulib/src/plaintext.usp +++ /dev/null @@ -1,30 +0,0 @@ - - - diff --git a/frameworks/C++/ulib/src/query.usp b/frameworks/C++/ulib/src/query.usp deleted file mode 100644 index 9c2004196e8..00000000000 --- a/frameworks/C++/ulib/src/query.usp +++ /dev/null @@ -1,62 +0,0 @@ - - - - diff --git a/frameworks/C++/ulib/src/rdb.usp b/frameworks/C++/ulib/src/rdb.usp deleted file mode 100644 index 564229833b1..00000000000 --- a/frameworks/C++/ulib/src/rdb.usp +++ /dev/null @@ -1,14 +0,0 @@ - - - - diff --git a/frameworks/C++/ulib/src/rfortune.usp b/frameworks/C++/ulib/src/rfortune.usp deleted file mode 100644 index 51f89828028..00000000000 --- a/frameworks/C++/ulib/src/rfortune.usp +++ /dev/null @@ -1,14 +0,0 @@ - - - - diff --git a/frameworks/C++/ulib/src/rquery.usp b/frameworks/C++/ulib/src/rquery.usp deleted file mode 100644 index 7173c2db981..00000000000 --- a/frameworks/C++/ulib/src/rquery.usp +++ /dev/null @@ -1,14 +0,0 @@ - - - - diff --git a/frameworks/C++/ulib/src/rupdate.usp b/frameworks/C++/ulib/src/rupdate.usp deleted file mode 100644 index de4a0e85549..00000000000 --- a/frameworks/C++/ulib/src/rupdate.usp +++ /dev/null @@ -1,14 +0,0 @@ - - - - diff --git a/frameworks/C++/ulib/src/update.usp b/frameworks/C++/ulib/src/update.usp deleted file mode 100644 index fc24a960a0c..00000000000 --- a/frameworks/C++/ulib/src/update.usp +++ /dev/null @@ -1,99 +0,0 @@ - - - - diff --git a/frameworks/C++/ulib/src/world.h b/frameworks/C++/ulib/src/world.h deleted file mode 100644 index a458e375a34..00000000000 --- a/frameworks/C++/ulib/src/world.h +++ /dev/null @@ -1,368 +0,0 @@ -// world.h - -#ifndef WORLD_H -#define WORLD_H 1 - -#include -#include -#include -#include -#include - -#ifdef U_STATIC_ORM_DRIVER_PGSQL -# include -# include -#endif - -class U_EXPORT World { -public: - uint32_t id, randomNumber; - - World() - { - U_TRACE_CTOR(5, World, "") - - // coverity[uninit_ctor] -# ifdef U_COVERITY_FALSE_POSITIVE - id = randomNumber = 0; -# endif - } - - World(uint32_t _id, uint32_t _randomNumber) : id(_id), randomNumber(_randomNumber) - { - U_TRACE_CTOR(5, World, "%u,%u", _id, _randomNumber) - } - - World(const World& w) : id(w.id), randomNumber(w.randomNumber) - { - U_TRACE_CTOR(5, World, "%p", &w) - - U_MEMORY_TEST_COPY(w) - } - - ~World() - { - U_TRACE_DTOR(5, World) - } - - // JSON - - void toJSON(UString& json) - { - U_TRACE(5, "World::toJSON(%V)", json.rep) - - json.toJSON(U_JSON_METHOD_HANDLER(id, unsigned int)); - json.toJSON(U_JSON_METHOD_HANDLER(randomNumber, unsigned int)); - } - - void fromJSON(UValue& json) - { - U_TRACE(5, "World::fromJSON(%p)", &json) - - json.fromJSON(U_JSON_METHOD_HANDLER(id, unsigned int)); - json.fromJSON(U_JSON_METHOD_HANDLER(randomNumber, unsigned int)); - } - - // ORM - - void bindParam(UOrmStatement* stmt) - { - U_TRACE(5, "World::bindParam(%p)", stmt) - - stmt->bindParam(U_ORM_TYPE_HANDLER(id, unsigned int)); - stmt->bindParam(U_ORM_TYPE_HANDLER(randomNumber, unsigned int)); - } - - void bindResult(UOrmStatement* stmt) - { - U_TRACE(5, "World::bindResult(%p)", stmt) - - stmt->bindResult(U_ORM_TYPE_HANDLER(id, unsigned int)); - stmt->bindResult(U_ORM_TYPE_HANDLER(randomNumber, unsigned int)); - } - - // SERVICE - - bool operator<(const World& other) const { return cmp_obj(&id, &other.id); } - - static int cmp_obj(const void* a, const void* b) - { - U_TRACE(5, "World::cmp_obj(%p,%p)", a, b) - -# ifdef U_STDCPP_ENABLE - /** - * The comparison function must follow a strict-weak-ordering - * - * 1) For all x, it is not the case that x < x (irreflexivity) - * 2) For all x, y, if x < y then it is not the case that y < x (asymmetry) - * 3) For all x, y, and z, if x < y and y < z then x < z (transitivity) - * 4) For all x, y, and z, if x is incomparable with y, and y is incomparable with z, then x is incomparable with z (transitivity of incomparability) - */ - - return (((const World*)a)->id < (((const World*)b)->id)); -# else - return (*(const World**)a)->id < ((*(const World**)b)->id); -# endif - } - - static char* ptr; - static char* pwbuffer; - static char wbuffer[18000]; - static uint32_t rnum, rnumber[501]; - - static World* pworld_query; - static UOrmSession* psql_query; - static UOrmStatement* pstmt_query; - -#ifdef U_STATIC_ORM_DRIVER_PGSQL - static PGconn* conn; - static UPgSqlStatement* pstmt; - static char num2str[sizeof(unsigned int)]; - - static void _sendQueryPrepared() - { - U_TRACE_NO_PARAM(5, "World::_sendQueryPrepared()") - - (void) U_SYSCALL(PQsendQueryPrepared, "%p,%S,%u,%p,%p,%p,%u", conn, pstmt->stmtName, 1, pstmt->paramValues, pstmt->paramLengths, pstmt->paramFormats, 1); - } - - static void sendQueryPrepared() - { - U_TRACE_NO_PARAM(5, "World::sendQueryPrepared()") - - U_INTERNAL_ASSERT_MAJOR(rnumber[0], 0) - - *(unsigned int*)num2str = htonl(rnumber[0]); - - _sendQueryPrepared(); - } - - static void sendQueryPrepared(uint32_t i) - { - U_TRACE(5, "World::sendQueryPrepared(%u)", i) - - U_INTERNAL_ASSERT_MAJOR(rnumber[i], 0) - - *(unsigned int*)num2str = htonl(rnumber[i]); - - _sendQueryPrepared(); - } -#endif - - static void initOneResult() - { - U_TRACE_NO_PARAM(5, "World::initOneResult()") - - U_INTERNAL_DUMP("wbuffer = %#.10S", wbuffer) - - if (u_get_unalignedp64(wbuffer+52) != U_MULTICHAR_CONSTANT64('\r','\n','{','"','i','d','"',':')) - { - u_put_unalignedp64(wbuffer, U_MULTICHAR_CONSTANT64('C','o','n','t','e','n','t','-')); - u_put_unalignedp64(wbuffer+8, U_MULTICHAR_CONSTANT64('L','e','n','g','t','h',':',' ')); - u_put_unalignedp32(wbuffer+16, U_MULTICHAR_CONSTANT32('3','1','\r','\n')); - u_put_unalignedp64(wbuffer+20, U_MULTICHAR_CONSTANT64('C','o','n','t','e','n','t','-')); - u_put_unalignedp64(wbuffer+28, U_MULTICHAR_CONSTANT64('T','y','p','e',':',' ','a','p')); - u_put_unalignedp64(wbuffer+36, U_MULTICHAR_CONSTANT64('p','l','i','c','a','t','i','o')); - u_put_unalignedp64(wbuffer+44, U_MULTICHAR_CONSTANT64('n','/','j','s','o','n','\r','\n')); - u_put_unalignedp64(wbuffer+52, U_MULTICHAR_CONSTANT64('\r','\n','{','"','i','d','"',':')); - - pwbuffer = u_num2str32(rnumber[0], wbuffer + U_CONSTANT_SIZE("Content-Length: 31\r\nContent-Type: application/json\r\n\r\n{\"id\":")); - - u_put_unalignedp64(pwbuffer, U_MULTICHAR_CONSTANT64(',','"','r','a','n','d','o','m')); - u_put_unalignedp64(pwbuffer+8, U_MULTICHAR_CONSTANT64('N','u','m','b','e','r','"',':')); - } - - U_INTERNAL_ASSERT_EQUALS(u_get_unalignedp64(wbuffer), U_MULTICHAR_CONSTANT64('C','o','n','t','e','n','t','-')) - } - - static void endOneResult() - { - U_TRACE_NO_PARAM(5, "World::endOneResult()") - - *ptr = '}'; - - uint32_t len = ptr-wbuffer+1, - body_len = len - U_CONSTANT_SIZE("Content-Length: 31\r\nContent-Type: application/json\r\n\r\n"); - - U_NUM2STR16(wbuffer+U_CONSTANT_SIZE("Content-Length: "), body_len); - - UClientImage_Base::wbuffer->setConstant(wbuffer, len); - } - - static void handlerOneResult(uint32_t random) - { - U_TRACE(5, "World::handlerOneResult(%u)", random) - - initOneResult(); - - ptr = u_num2str32(random, pwbuffer+16); - - endOneResult(); - } - - static void initResult() - { - U_TRACE_NO_PARAM(5, "World::initResult()") - - U_INTERNAL_DUMP("wbuffer = %#.10S", wbuffer) - - if (u_get_unalignedp64(wbuffer+56) != U_MULTICHAR_CONSTANT64('\n','[','{','"','i','d','"',':')) - { - u_put_unalignedp64(wbuffer, U_MULTICHAR_CONSTANT64('C','o','n','t','e','n','t','-')); - u_put_unalignedp64(wbuffer+8, U_MULTICHAR_CONSTANT64('L','e','n','g','t','h',':',' ')); - u_put_unalignedp64(wbuffer+16, U_MULTICHAR_CONSTANT64('1','3','3','3','1','\r','\n','C')); - u_put_unalignedp64(wbuffer+24, U_MULTICHAR_CONSTANT64('o','n','t','e','n','t','-','T')); - u_put_unalignedp64(wbuffer+32, U_MULTICHAR_CONSTANT64('y','p','e',':',' ','a','p','p')); - u_put_unalignedp64(wbuffer+40, U_MULTICHAR_CONSTANT64('l','i','c','a','t','i','o','n')); - u_put_unalignedp64(wbuffer+48, U_MULTICHAR_CONSTANT64('/','j','s','o','n','\r','\n','\r')); - u_put_unalignedp64(wbuffer+56, U_MULTICHAR_CONSTANT64('\n','[','{','"','i','d','"',':')); - - pwbuffer = u_num2str32(rnumber[0], wbuffer + U_CONSTANT_SIZE("Content-Length: 13331\r\nContent-Type: application/json\r\n\r\n[{\"id\":")); - - u_put_unalignedp64(pwbuffer, U_MULTICHAR_CONSTANT64(',','"','r','a','n','d','o','m')); - u_put_unalignedp64(pwbuffer+8, U_MULTICHAR_CONSTANT64('N','u','m','b','e','r','"',':')); - } - - U_INTERNAL_ASSERT_EQUALS(u_get_unalignedp64(wbuffer), U_MULTICHAR_CONSTANT64('C','o','n','t','e','n','t','-')) - - ptr = pwbuffer; - } - - static void endResult() - { - U_TRACE_NO_PARAM(5, "World::endResult()") - - *(ptr-1) = ']'; - - uint32_t len = ptr-wbuffer, - body_len = len - U_CONSTANT_SIZE("Content-Length: 13331\r\nContent-Type: application/json\r\n\r\n"); - - ptr = u_num2str32(body_len, wbuffer + U_CONSTANT_SIZE("Content-Length: ")); - - while (*ptr != '\r') *ptr++ = ' '; - - UClientImage_Base::wbuffer->setConstant(wbuffer, len); - } - - static void addResult(uint32_t i) - { - U_TRACE(5, "World::addResult(%u)", i) - - U_INTERNAL_ASSERT_MAJOR(i, 0) - - u_put_unalignedp32(ptr, U_MULTICHAR_CONSTANT32('{','"','i','d')); - u_put_unalignedp16(ptr+4, U_MULTICHAR_CONSTANT16('"',':')); - - ptr = u_num2str32(rnumber[i], ptr+6); - - u_put_unalignedp64(ptr, U_MULTICHAR_CONSTANT64(',','"','r','a','n','d','o','m')); - u_put_unalignedp64(ptr+8, U_MULTICHAR_CONSTANT64('N','u','m','b','e','r','"',':')); - } - - static void addRandom(uint32_t random) - { - U_TRACE(5, "World::addRandom(%u)", random) - - ptr = u_num2str32(random, ptr+16); - - u_put_unalignedp16(ptr, U_MULTICHAR_CONSTANT16('}',',')); - ptr += 2; - } - - static void handlerResult(uint32_t i, uint32_t random) - { - U_TRACE(5, "World::handlerResult(%u,%u)", i, random) - - if (i) addResult(i); - - addRandom(random); - } - - static void doUpdateNoSql(vPFu handlerUpdateNoSql) - { - U_TRACE(5, "World::doUpdateNoSql(%p)", handlerUpdateNoSql) - - initResult(); - - for (uint32_t i = 0, n = UHTTP::getFormFirstNumericValue(1, 500); i < n; ++i) - { - handlerUpdateNoSql(i); - - handlerResult(i, rnum); - } - - endResult(); - } - - static void handlerInitSql() - { - U_TRACE_NO_PARAM(5, "World::handlerInitSql()") - -# ifdef U_STATIC_ORM_DRIVER_PGSQL - U_INTERNAL_DUMP("UServer_Base::handler_db1 = %p", UServer_Base::handler_db1) - - if (UServer_Base::handler_db1 == U_NULLPTR) - { - U_NEW(UEventDB, UServer_Base::handler_db1, UEventDB); - } -# endif - } - - static void handlerFork() - { - U_TRACE_NO_PARAM(5, "World::handlerFork()") - - if (rnumber[0] == 0) for (uint32_t i = 0; i <= 500; ++i) rnumber[i] = u_get_num_random_range1(10000); - } - - static void handlerForkSql() - { - U_TRACE_NO_PARAM(5, "World::handlerForkSql()") - - if (psql_query == U_NULLPTR) - { - U_NEW(UOrmSession, psql_query, UOrmSession(U_CONSTANT_TO_PARAM("hello_world"))); - - if (psql_query->isReady() == false) - { - U_WARNING("World::handlerForkSql(): we cound't connect to db"); - - U_DELETE(psql_query) - - psql_query = U_NULLPTR; - - return; - } - - U_NEW(UOrmStatement, pstmt_query, UOrmStatement(*psql_query, U_CONSTANT_TO_PARAM("SELECT randomNumber, id FROM World WHERE id = ?"))); - - U_NEW(World, pworld_query, World); - - pstmt_query->use( pworld_query->id); - pstmt_query->into(pworld_query->randomNumber); - -# ifdef U_STATIC_ORM_DRIVER_PGSQL - if (UOrmDriver::isPGSQL()) - { - UOrmDriverPgSql* pdrv = (UOrmDriverPgSql*)psql_query->getDriver(); - - conn = (PGconn*)pdrv->UOrmDriver::connection; - pstmt = (UPgSqlStatement*)pstmt_query->getStatement(); - - (void) pstmt->setBindParam(pdrv); - - pstmt->paramValues[0] = num2str; - pstmt->paramLengths[0] = sizeof(unsigned int); - - UServer_Base::handler_db1->setConnection(conn); - } -# endif - - handlerFork(); - } - } - -private: - U_DISALLOW_ASSIGN(World) -}; -#endif diff --git a/frameworks/C++/ulib/src/worldNoSql.h b/frameworks/C++/ulib/src/worldNoSql.h deleted file mode 100644 index 58c4df17f54..00000000000 --- a/frameworks/C++/ulib/src/worldNoSql.h +++ /dev/null @@ -1,270 +0,0 @@ -// worldNoSql.h - -#ifndef WORLD_NO_SQL_H -#define WORLD_NO_SQL_H 1 - -#include "world.h" - -#include -#include - -#ifdef USE_MONGODB -# include -#endif - -class U_EXPORT WorldNoSql { -public: - - static UString* str_rnumber; - - static void doOneQuery(vPFu handlerQuery) - { - U_TRACE(5, "WorldNoSql::doOneQuery(%p)", handlerQuery) - - handlerQuery(World::rnumber[0]); - - uint32_t sz = str_rnumber->size(); - - World::initOneResult(); - - (void) memcpy(World::pwbuffer+16, str_rnumber->data(), sz); - - World::ptr = World::pwbuffer+16+sz; - - World::endOneResult(); - - str_rnumber->clear(); - } - - static void handlerResult(uint32_t i) - { - U_TRACE(5, "WorldNoSql::handlerResult(%u)", i) - - U_INTERNAL_ASSERT_POINTER(str_rnumber) - U_INTERNAL_ASSERT_POINTER(World::pwbuffer) - - if (i) World::addResult(i); - - uint32_t sz = str_rnumber->size(); - - (void) memcpy(World::ptr+16, str_rnumber->data(), sz); - World::ptr += 16+ sz; - - u_put_unalignedp16(World::ptr, U_MULTICHAR_CONSTANT16('}',',')); - World::ptr += 2; - - str_rnumber->clear(); - } - - static void doQuery(vPFu handlerQuery) - { - U_TRACE(5, "WorldNoSql::doQuery(%p)", handlerQuery) - - World::initResult(); - - for (uint32_t i = 0, n = UHTTP::getFormFirstNumericValue(1, 500); i < n; ++i) - { - handlerQuery(World::rnumber[i]); - - handlerResult(i); - } - - World::endResult(); - } - - static void handlerFork() - { - U_TRACE_NO_PARAM(5, "WorldNoSql::handlerFork()") - - if (str_rnumber == U_NULLPTR) U_NEW_STRING(str_rnumber, UString); - - World::handlerFork(); - - U_INTERNAL_ASSERT_POINTER(str_rnumber) - } - -#ifdef USE_MONGODB - static bson_t* query; - static UMongoDBClient* mc; -#endif - - static void handlerQueryMongoDB(uint32_t uid) - { - U_TRACE(5, "WorldNoSql::handlerQueryMongoDB(%u)", uid) - - U_INTERNAL_ASSERT_POINTER(str_rnumber) - -# ifdef USE_MONGODB - (void) mc->findOne(uid, query); - (void) U_JFIND(mc->vitem[0], "randomNumber", *str_rnumber); - - uint32_t pos = str_rnumber->find_first_of('.'); - - if (pos != U_NOT_FOUND) str_rnumber->size_adjust_constant(pos); -# endif - } - - static void handlerUpdateMongoDB(uint32_t i) - { - U_TRACE(5, "WorldNoSql::handlerUpdateMongoDB(%u)", i) - -# ifdef USE_MONGODB - (void) mc->findOne(World::rnumber[i], query); - (void) mc->update( World::rnumber[i], "randomNumber", World::rnum = u_get_num_random_range1(10000)); -# endif - } - - static void handlerForkMongoDB() - { - U_TRACE_NO_PARAM(5, "WorldNoSql::handlerForkMongoDB()") - -# ifdef USE_MONGODB - if (mc == U_NULLPTR) - { - U_NEW(UMongoDBClient, mc, UMongoDBClient); - - if (mc->connect(U_NULLPTR, 0) == false) - { - U_WARNING("WorldNoSql::handlerForkMongoDB(): connection failed"); - - U_DELETE(mc) - - mc = U_NULLPTR; - - return; - } - - if (mc->selectCollection("hello_world", "world") == false) - { - U_WARNING("WorldNoSql::handlerForkMongoDB(): selectCollection() failed"); - - U_DELETE(mc) - - mc = U_NULLPTR; - - return; - } - - query = (bson_t*) U_SYSCALL_NO_PARAM(bson_new); - - handlerFork(); - } -# endif - } - - static char rc_buffer[128]; - static UREDISClient_Base* rc; - - static void handlerQueryREDIS(uint32_t uid) - { - U_TRACE(5, "WorldNoSql::handlerQueryREDIS(%u)", uid) - - U_INTERNAL_ASSERT_POINTER(str_rnumber) - - char* ptr = rc_buffer+U_CONSTANT_SIZE("world:"); - - (void) rc->get(ptr, U_CONSTANT_SIZE("world:")+u_num2str32(uid, ptr)-ptr); - - *str_rnumber = rc->vitem[0]; - } - - static void handlerUpdateREDIS(uint32_t i) - { - U_TRACE(5, "WorldNoSql::handlerUpdateREDIS(%u)", i) - - char* start = rc_buffer+U_CONSTANT_SIZE("world:"); - char* ptr = u_num2str32(World::rnumber[i], start); - - (void) rc->get(start, ptr-start); - - *ptr = ' '; - ptr = u_num2str32(World::rnum = u_get_num_random_range1(10000), ptr+1); - - (void) rc->mset(start, ptr-start); - } - - static void handlerForkREDIS() - { - U_TRACE_NO_PARAM(5, "WorldNoSql::handlerForkREDIS()") - - if (rc == U_NULLPTR) - { - U_NEW(UREDISClient, rc, UREDISClient); - - if (rc->connect() == false) - { - U_WARNING("WorldNoSql::handlerForkREDIS(): %V", rc->UClient_Base::getResponse().rep); - - U_DELETE(rc) - - rc = U_NULLPTR; - - return; - } - - U_MEMCPY(rc_buffer, "world:", U_CONSTANT_SIZE("world:")); - - handlerFork(); - } - } - - static char* pbuffer1; - static char* pbuffer2; - static char es_buffer1[128]; - static char es_buffer2[128]; - static UElasticSearchClient* es; - -# define U_QLEN U_CONSTANT_SIZE("{\"query\":{\"match\":{\"_id\":\"") - - static void handlerQueryElasticSearch(uint32_t uid) - { - U_TRACE(5, "WorldNoSql::handlerQueryElasticSearch(%u)", uid) - - U_INTERNAL_ASSERT_POINTER(str_rnumber) - - (void) es->sendPOST(U_CONSTANT_TO_PARAM("/tfb/world/_search"), es_buffer1, U_QLEN+ - u__snprintf(es_buffer1+ U_QLEN, - sizeof(es_buffer1)-U_QLEN, U_CONSTANT_TO_PARAM("%u\"}}}"), uid)); - - (void) U_JFIND(es->getContent(), "randomNumber", *str_rnumber); - } - - static void handlerUpdateElasticSearch(uint32_t i) - { - U_TRACE(5, "WorldNoSql::handlerUpdateElasticSearch(%u)", i) - - uint32_t len1 = u__snprintf(pbuffer1, 100, U_CONSTANT_TO_PARAM("%u/_update"), World::rnumber[i]), - len2 = u__snprintf(pbuffer2, 100, U_CONSTANT_TO_PARAM("%u\"}}"), World::rnum = u_get_num_random_range1(10000)); - - (void) es->sendPOST(es_buffer1, len1+U_CONSTANT_SIZE("/tfb/world/"), es_buffer2, len2+U_CONSTANT_SIZE("{\"doc\":{\"_id\":\"")); - } - - static void handlerForkElasticSearch() - { - U_TRACE_NO_PARAM(5, "WorldNoSql::handlerForkElasticSearch()") - - if (es == U_NULLPTR) - { - U_NEW(UElasticSearchClient, es, UElasticSearchClient); - - if (es->connect() == false) - { - U_WARNING("WorldNoSql::handlerForkElasticSearch(): connection disabled or failed"); - - U_DELETE(es) - - es = U_NULLPTR; - - return; - } - - U_MEMCPY(es_buffer1, "{\"query\":{\"match\":{\"_id\":\"", U_QLEN); - - handlerFork(); - } - } - -private: - U_DISALLOW_ASSIGN(WorldNoSql) -}; -#endif diff --git a/frameworks/C++/ulib/ulib-json.dockerfile b/frameworks/C++/ulib/ulib-json.dockerfile deleted file mode 100644 index b7ed9f51c3b..00000000000 --- a/frameworks/C++/ulib/ulib-json.dockerfile +++ /dev/null @@ -1,82 +0,0 @@ -FROM ubuntu:18.04 - -COPY ./ ./ - -RUN apt-get update -yqq && \ - apt-get install -yqq software-properties-common build-essential curl locales wget unzip git \ - libmysqlclient-dev libpq-dev \ - libpcre3 libpcre3-dev \ - libssl-dev libcurl4-openssl-dev \ - zlib1g-dev \ - libreadline6-dev \ - libbz2-dev \ - libxslt-dev libgdbm-dev ncurses-dev \ - libffi-dev libtool bison libevent-dev \ - liborc-0.4-0 \ - libmcrypt-dev libicu-dev \ - re2c libnuma-dev \ - postgresql-server-dev-all libcap2-bin && \ - add-apt-repository ppa:ubuntu-toolchain-r/test -y && \ - apt-get update -yqq && \ - apt-get install -yqq gcc-8 g++-8 - -RUN locale-gen en_US.UTF-8 - -ENV LANG en_US.UTF-8 -ENV LANGUAGE en_US:en -ENV LC_ALL en_US.UTF-8 -ENV DEBIAN_FRONTEND noninteractive - -ENV CC=gcc-8 -ENV CXX=g++-8 -ENV AR=gcc-ar-8 -ENV RANLIB=gcc-ranlib-8 -ENV IROOT=/install -ENV ULIB_ROOT=$IROOT/ULib -ENV ULIB_VERSION=2.4.2 -ENV ULIB_DOCUMENT_ROOT=$ULIB_ROOT/ULIB_DOCUMENT_ROOT - -WORKDIR $IROOT - -RUN mkdir -p $ULIB_DOCUMENT_ROOT -RUN wget -q -O ULib-${ULIB_VERSION}.tar.gz https://github.com/stefanocasazza/ULib/archive/v${ULIB_VERSION}.tar.gz -RUN tar xf ULib-${ULIB_VERSION}.tar.gz - -WORKDIR $IROOT/ULib-$ULIB_VERSION - -# AVOID "configure: error: newly created file is older than distributed files! Check your system clock" -RUN cp /src/* src/ulib/net/server/plugin/usp -RUN find . -exec touch {} \; - -RUN echo "userver {" >> $ULIB_ROOT/benchmark.cfg -RUN echo "PORT 8080" >> $ULIB_ROOT/benchmark.cfg -RUN echo "PREFORK_CHILD $(( 3 * $(nproc) / 2 ))" >> $ULIB_ROOT/benchmark.cfg -RUN echo "TCP_LINGER_SET 0" >> $ULIB_ROOT/benchmark.cfg -RUN echo "LISTEN_BACKLOG 256" >> $ULIB_ROOT/benchmark.cfg -RUN echo "DOCUMENT_ROOT $ULIB_DOCUMENT_ROOT " >> $ULIB_ROOT/benchmark.cfg -RUN echo "}" >> $ULIB_ROOT/benchmark.cfg - -RUN USP_FLAGS="-DAS_cpoll_cppsp_DO" \ - ./configure --prefix=$ULIB_ROOT \ - --disable-static --disable-examples \ - --without-ssl --disable-HCRS --without-pcre --without-expat \ - --without-libz --without-libuuid --disable-HPRS --without-magic --without-libares \ - --enable-static-server-plugin=http - -RUN make install && \ - cd examples/userver && make install && \ - cd ../../src/ulib/net/server/plugin/usp && \ - make json.la && \ - cp .libs/json.so $ULIB_DOCUMENT_ROOT - -ENV PATH=${ULIB_ROOT}/bin:${PATH} - -ADD ./ /ulib -WORKDIR /ulib - -ENV UMEMPOOL="58,0,0,41,273,-15,-14,-20,36" - -EXPOSE 8080 - -CMD setcap cap_sys_nice,cap_sys_resource,cap_net_bind_service,cap_net_raw+eip $IROOT/ULib/bin/userver_tcp && \ - $IROOT/ULib/bin/userver_tcp -c $IROOT/ULib/benchmark.cfg diff --git a/frameworks/C++/ulib/ulib-json_fit.dockerfile b/frameworks/C++/ulib/ulib-json_fit.dockerfile deleted file mode 100644 index 9d4e97e204f..00000000000 --- a/frameworks/C++/ulib/ulib-json_fit.dockerfile +++ /dev/null @@ -1,82 +0,0 @@ -FROM ubuntu:18.04 - -COPY ./ ./ - -RUN apt-get update -yqq && \ - apt-get install -yqq software-properties-common build-essential curl locales wget unzip git \ - libmysqlclient-dev libpq-dev \ - libpcre3 libpcre3-dev \ - libssl-dev libcurl4-openssl-dev \ - zlib1g-dev \ - libreadline6-dev \ - libbz2-dev \ - libxslt-dev libgdbm-dev ncurses-dev \ - libffi-dev libtool bison libevent-dev \ - liborc-0.4-0 \ - libmcrypt-dev libicu-dev \ - re2c libnuma-dev \ - postgresql-server-dev-all libcap2-bin && \ - add-apt-repository ppa:ubuntu-toolchain-r/test -y && \ - apt-get update -yqq && \ - apt-get install -yqq gcc-8 g++-8 - -RUN locale-gen en_US.UTF-8 - -ENV LANG en_US.UTF-8 -ENV LANGUAGE en_US:en -ENV LC_ALL en_US.UTF-8 -ENV DEBIAN_FRONTEND noninteractive - -ENV CC=gcc-8 -ENV CXX=g++-8 -ENV AR=gcc-ar-8 -ENV RANLIB=gcc-ranlib-8 -ENV IROOT=/install -ENV ULIB_ROOT=$IROOT/ULib -ENV ULIB_VERSION=2.4.2 -ENV ULIB_DOCUMENT_ROOT=$ULIB_ROOT/ULIB_DOCUMENT_ROOT - -WORKDIR $IROOT - -RUN mkdir -p $ULIB_DOCUMENT_ROOT -RUN wget -q -O ULib-${ULIB_VERSION}.tar.gz https://github.com/stefanocasazza/ULib/archive/v${ULIB_VERSION}.tar.gz -RUN tar xf ULib-${ULIB_VERSION}.tar.gz - -WORKDIR $IROOT/ULib-$ULIB_VERSION - -# AVOID "configure: error: newly created file is older than distributed files! Check your system clock" -RUN cp /src/* src/ulib/net/server/plugin/usp -RUN find . -exec touch {} \; - -RUN echo "userver {" >> $ULIB_ROOT/benchmark.cfg -RUN echo "PORT 8080" >> $ULIB_ROOT/benchmark.cfg -RUN echo "PREFORK_CHILD $(nproc)" >> $ULIB_ROOT/benchmark.cfg -RUN echo "TCP_LINGER_SET 0" >> $ULIB_ROOT/benchmark.cfg -RUN echo "LISTEN_BACKLOG 256" >> $ULIB_ROOT/benchmark.cfg -RUN echo "DOCUMENT_ROOT $ULIB_DOCUMENT_ROOT " >> $ULIB_ROOT/benchmark.cfg -RUN echo "}" >> $ULIB_ROOT/benchmark.cfg - -RUN USP_FLAGS="-DAS_cpoll_cppsp_DO" \ - ./configure --prefix=$ULIB_ROOT \ - --disable-static --disable-examples \ - --without-ssl --disable-HCRS --without-pcre --without-expat \ - --without-libz --without-libuuid --disable-HPRS --without-magic --without-libares \ - --enable-static-server-plugin=http - -RUN make install && \ - cd examples/userver && make install && \ - cd ../../src/ulib/net/server/plugin/usp && \ - make json.la && \ - cp .libs/json.so $ULIB_DOCUMENT_ROOT - -ENV PATH=${ULIB_ROOT}/bin:${PATH} - -ADD ./ /ulib -WORKDIR /ulib - -ENV UMEMPOOL="58,0,0,41,273,-15,-14,-20,36" - -EXPOSE 8080 - -CMD setcap cap_sys_nice,cap_sys_resource,cap_net_bind_service,cap_net_raw+eip $IROOT/ULib/bin/userver_tcp && \ - $IROOT/ULib/bin/userver_tcp -c $IROOT/ULib/benchmark.cfg diff --git a/frameworks/C++/ulib/ulib-mongodb.dockerfile b/frameworks/C++/ulib/ulib-mongodb.dockerfile deleted file mode 100644 index 7c9e6d9d40a..00000000000 --- a/frameworks/C++/ulib/ulib-mongodb.dockerfile +++ /dev/null @@ -1,91 +0,0 @@ -FROM ubuntu:18.04 - -COPY ./ ./ - -RUN apt-get update -yqq && \ - apt-get install -yqq software-properties-common build-essential curl locales wget unzip git \ - libmysqlclient-dev libpq-dev \ - libpcre3 libpcre3-dev \ - libssl-dev libcurl4-openssl-dev \ - zlib1g-dev \ - libreadline6-dev \ - libbz2-dev \ - libxslt-dev libgdbm-dev ncurses-dev \ - libffi-dev libtool bison libevent-dev \ - liborc-0.4-0 \ - libmcrypt-dev libicu-dev \ - re2c libnuma-dev \ - postgresql-server-dev-all libcap2-bin && \ - add-apt-repository ppa:ubuntu-toolchain-r/test -y && \ - apt-get update -yqq && \ - apt-get install -yqq gcc-8 g++-8 - -RUN locale-gen en_US.UTF-8 - -ENV LANG en_US.UTF-8 -ENV LANGUAGE en_US:en -ENV LC_ALL en_US.UTF-8 -ENV DEBIAN_FRONTEND noninteractive - -ENV CC=gcc-8 -ENV CXX=g++-8 -ENV AR=gcc-ar-8 -ENV RANLIB=gcc-ranlib-8 -ENV IROOT=/install -ENV ULIB_ROOT=$IROOT/ULib -ENV ULIB_VERSION=2.4.2 -ENV ULIB_DOCUMENT_ROOT=$ULIB_ROOT/ULIB_DOCUMENT_ROOT - -WORKDIR $IROOT - -RUN wget -q https://github.com/mongodb/mongo-c-driver/releases/download/1.4.0/mongo-c-driver-1.4.0.tar.gz -RUN tar xf mongo-c-driver-1.4.0.tar.gz -RUN cd mongo-c-driver-1.4.0/ && \ - ./configure --prefix=${IROOT} --libdir=${IROOT} --disable-automatic-init-and-cleanup && \ - make && make install - -RUN mkdir -p $ULIB_DOCUMENT_ROOT -RUN wget -q -O ULib-${ULIB_VERSION}.tar.gz https://github.com/stefanocasazza/ULib/archive/v${ULIB_VERSION}.tar.gz -RUN tar xf ULib-${ULIB_VERSION}.tar.gz - -WORKDIR $IROOT/ULib-$ULIB_VERSION - -# AVOID "configure: error: newly created file is older than distributed files! Check your system clock" -RUN cp /src/* src/ulib/net/server/plugin/usp -RUN find . -exec touch {} \; - -RUN echo "userver {" >> $ULIB_ROOT/benchmark.cfg -RUN echo "PORT 8080" >> $ULIB_ROOT/benchmark.cfg -RUN echo "PREFORK_CHILD $(( 3 * $(nproc) / 2 ))" >> $ULIB_ROOT/benchmark.cfg -RUN echo "TCP_LINGER_SET -2" >> $ULIB_ROOT/benchmark.cfg -RUN echo "LISTEN_BACKLOG 256" >> $ULIB_ROOT/benchmark.cfg -RUN echo "DOCUMENT_ROOT $ULIB_DOCUMENT_ROOT " >> $ULIB_ROOT/benchmark.cfg -RUN echo "}" >> $ULIB_ROOT/benchmark.cfg - -RUN USP_FLAGS="-DAS_cpoll_cppsp_DO" \ - ./configure --prefix=$ULIB_ROOT \ - --disable-static --disable-examples \ - --without-ssl --disable-HCRS --without-pcre --without-expat \ - --without-libz --without-libuuid --disable-HPRS --without-magic --without-libares \ - --enable-static-server-plugin=http \ - --with-mongodb --with-mongodb-includes="-I$IROOT/include/libbson-1.0 -I$IROOT/include/libmongoc-1.0" --with-mongodb-ldflags="-L$IROOT" - -RUN make install && \ - cd examples/userver && make install && \ - cd ../../src/ulib/net/server/plugin/usp && \ - AM_LDFLAGS="-lFortune -lFortuneNoSql" make mfortune.la && \ - AM_LDFLAGS="-lWorld -lWorldNoSql" make mdb.la mquery.la mupdate.la && \ - cp .libs/mdb.so .libs/mquery.so .libs/mupdate.so .libs/mfortune.so $ULIB_DOCUMENT_ROOT - -ENV PATH=${ULIB_ROOT}/bin:${PATH} - -ADD ./ /ulib -WORKDIR /ulib - -ENV MONGODB_HOST=tfb-database -ENV UMEMPOOL="96,0,0,97,16417,-14,-20,-18,26" - -EXPOSE 8080 - -CMD setcap cap_sys_nice,cap_sys_resource,cap_net_bind_service,cap_net_raw+eip $IROOT/ULib/bin/userver_tcp && \ - $IROOT/ULib/bin/userver_tcp -c $IROOT/ULib/benchmark.cfg diff --git a/frameworks/C++/ulib/ulib-mysql.dockerfile b/frameworks/C++/ulib/ulib-mysql.dockerfile deleted file mode 100644 index b14a0aadb00..00000000000 --- a/frameworks/C++/ulib/ulib-mysql.dockerfile +++ /dev/null @@ -1,87 +0,0 @@ -FROM ubuntu:18.04 - -COPY ./ ./ - -RUN apt-get update -yqq && \ - apt-get install -yqq software-properties-common build-essential curl locales wget unzip git \ - libmysqlclient-dev libpq-dev \ - libpcre3 libpcre3-dev \ - libssl-dev libcurl4-openssl-dev \ - zlib1g-dev \ - libreadline6-dev \ - libbz2-dev \ - libxslt-dev libgdbm-dev ncurses-dev \ - libffi-dev libtool bison libevent-dev \ - liborc-0.4-0 \ - libmcrypt-dev libicu-dev \ - re2c libnuma-dev \ - postgresql-server-dev-all libcap2-bin && \ - add-apt-repository ppa:ubuntu-toolchain-r/test -y && \ - apt-get update -yqq && \ - apt-get install -yqq gcc-8 g++-8 - -RUN locale-gen en_US.UTF-8 - -ENV LANG en_US.UTF-8 -ENV LANGUAGE en_US:en -ENV LC_ALL en_US.UTF-8 -ENV DEBIAN_FRONTEND noninteractive - -ENV CC=gcc-8 -ENV CXX=g++-8 -ENV AR=gcc-ar-8 -ENV RANLIB=gcc-ranlib-8 -ENV IROOT=/install -ENV ULIB_ROOT=$IROOT/ULib -ENV ULIB_VERSION=2.4.2 -ENV ULIB_DOCUMENT_ROOT=$ULIB_ROOT/ULIB_DOCUMENT_ROOT - -WORKDIR $IROOT - -RUN mkdir -p $ULIB_DOCUMENT_ROOT -RUN wget -q -O ULib-${ULIB_VERSION}.tar.gz https://github.com/stefanocasazza/ULib/archive/v${ULIB_VERSION}.tar.gz -RUN tar xf ULib-${ULIB_VERSION}.tar.gz - -WORKDIR $IROOT/ULib-$ULIB_VERSION - -# AVOID "configure: error: newly created file is older than distributed files! Check your system clock" -RUN cp /src/* src/ulib/net/server/plugin/usp -RUN find . -exec touch {} \; - -RUN echo "userver {" >> $ULIB_ROOT/benchmark.cfg -RUN echo "PORT 8080" >> $ULIB_ROOT/benchmark.cfg -RUN echo "PREFORK_CHILD $(nproc)" >> $ULIB_ROOT/benchmark.cfg -RUN echo "TCP_LINGER_SET -2" >> $ULIB_ROOT/benchmark.cfg -RUN echo "LISTEN_BACKLOG 256" >> $ULIB_ROOT/benchmark.cfg -RUN echo "ORM_DRIVER mysql" >> $ULIB_ROOT/benchmark.cfg -RUN echo "DOCUMENT_ROOT $ULIB_DOCUMENT_ROOT " >> $ULIB_ROOT/benchmark.cfg -RUN echo "}" >> $ULIB_ROOT/benchmark.cfg - -RUN USP_FLAGS="-DAS_cpoll_cppsp_DO" \ - ./configure --prefix=$ULIB_ROOT \ - --with-mysql \ - --disable-static --disable-examples \ - --without-ssl --disable-HCRS --without-pcre --without-expat \ - --without-libz --without-libuuid --disable-HPRS --without-magic --without-libares \ - --enable-static-orm-driver='mysql' --enable-static-server-plugin=http - -RUN make install && \ - cd examples/userver && make install && \ - cd ../../src/ulib/net/server/plugin/usp && \ - AM_LDFLAGS="-lFortune" make fortune.la && \ - AM_LDFLAGS="-lWorld" make db.la query.la update.la cached_worlds.la && \ - cp .libs/db.so .libs/query.so .libs/update.so .libs/fortune.so .libs/cached_worlds.so $ULIB_DOCUMENT_ROOT - -ENV PATH=${ULIB_ROOT}/bin:${PATH} - -ADD ./ /ulib -WORKDIR /ulib - -ENV ORM_DRIVER="mysql" -ENV ORM_OPTION="host=tfb-database user=benchmarkdbuser password=benchmarkdbpass character-set=utf8 dbname=hello_world" -ENV UMEMPOOL="96,0,0,97,16417,-14,-20,-18,26" - -EXPOSE 8080 - -CMD setcap cap_sys_nice,cap_sys_resource,cap_net_bind_service,cap_net_raw+eip $IROOT/ULib/bin/userver_tcp && \ - $IROOT/ULib/bin/userver_tcp -c $IROOT/ULib/benchmark.cfg diff --git a/frameworks/C++/ulib/ulib-plaintext_fit.dockerfile b/frameworks/C++/ulib/ulib-plaintext_fit.dockerfile deleted file mode 100644 index 68394f88119..00000000000 --- a/frameworks/C++/ulib/ulib-plaintext_fit.dockerfile +++ /dev/null @@ -1,82 +0,0 @@ -FROM ubuntu:18.04 - -COPY ./ ./ - -RUN apt-get update -yqq && \ - apt-get install -yqq software-properties-common build-essential curl locales wget unzip git \ - libmysqlclient-dev libpq-dev \ - libpcre3 libpcre3-dev \ - libssl-dev libcurl4-openssl-dev \ - zlib1g-dev \ - libreadline6-dev \ - libbz2-dev \ - libxslt-dev libgdbm-dev ncurses-dev \ - libffi-dev libtool bison libevent-dev \ - liborc-0.4-0 \ - libmcrypt-dev libicu-dev \ - re2c libnuma-dev \ - postgresql-server-dev-all libcap2-bin && \ - add-apt-repository ppa:ubuntu-toolchain-r/test -y && \ - apt-get update -yqq && \ - apt-get install -yqq gcc-8 g++-8 - -RUN locale-gen en_US.UTF-8 - -ENV LANG en_US.UTF-8 -ENV LANGUAGE en_US:en -ENV LC_ALL en_US.UTF-8 -ENV DEBIAN_FRONTEND noninteractive - -ENV CC=gcc-8 -ENV CXX=g++-8 -ENV AR=gcc-ar-8 -ENV RANLIB=gcc-ranlib-8 -ENV IROOT=/install -ENV ULIB_ROOT=$IROOT/ULib -ENV ULIB_VERSION=2.4.2 -ENV ULIB_DOCUMENT_ROOT=$ULIB_ROOT/ULIB_DOCUMENT_ROOT - -WORKDIR $IROOT - -RUN mkdir -p $ULIB_DOCUMENT_ROOT -RUN wget -q -O ULib-${ULIB_VERSION}.tar.gz https://github.com/stefanocasazza/ULib/archive/v${ULIB_VERSION}.tar.gz -RUN tar xf ULib-${ULIB_VERSION}.tar.gz - -WORKDIR $IROOT/ULib-$ULIB_VERSION - -# AVOID "configure: error: newly created file is older than distributed files! Check your system clock" -RUN cp /src/* src/ulib/net/server/plugin/usp -RUN find . -exec touch {} \; - -RUN echo "userver {" >> $ULIB_ROOT/benchmark.cfg -RUN echo "PORT 8080" >> $ULIB_ROOT/benchmark.cfg -RUN echo "PREFORK_CHILD $(nproc)" >> $ULIB_ROOT/benchmark.cfg -RUN echo "TCP_LINGER_SET 0" >> $ULIB_ROOT/benchmark.cfg -RUN echo "LISTEN_BACKLOG 16384" >> $ULIB_ROOT/benchmark.cfg -RUN echo "DOCUMENT_ROOT $ULIB_DOCUMENT_ROOT " >> $ULIB_ROOT/benchmark.cfg -RUN echo "}" >> $ULIB_ROOT/benchmark.cfg - -RUN USP_FLAGS="-DAS_cpoll_cppsp_DO" \ - ./configure --prefix=$ULIB_ROOT \ - --disable-static --disable-examples \ - --without-ssl --without-pcre --without-expat \ - --without-libz --without-libuuid --without-magic --without-libares \ - --enable-static-server-plugin=http - -RUN make install && \ - cd examples/userver && make install && \ - cd ../../src/ulib/net/server/plugin/usp && \ - make plaintext.la && \ - cp .libs/plaintext.so $ULIB_DOCUMENT_ROOT - -ENV PATH=${ULIB_ROOT}/bin:${PATH} - -ADD ./ /ulib -WORKDIR /ulib - -ENV UMEMPOOL="58,0,0,41,16401,-14,-15,11,25" - -EXPOSE 8080 - -CMD setcap cap_sys_nice,cap_sys_resource,cap_net_bind_service,cap_net_raw+eip $IROOT/ULib/bin/userver_tcp && \ - $IROOT/ULib/bin/userver_tcp -c $IROOT/ULib/benchmark.cfg diff --git a/frameworks/C++/ulib/ulib-postgres.dockerfile b/frameworks/C++/ulib/ulib-postgres.dockerfile deleted file mode 100644 index 02fedb51354..00000000000 --- a/frameworks/C++/ulib/ulib-postgres.dockerfile +++ /dev/null @@ -1,87 +0,0 @@ -FROM ubuntu:18.04 - -COPY ./ ./ - -RUN apt-get update -yqq && \ - apt-get install -yqq software-properties-common build-essential curl locales wget unzip git \ - libmysqlclient-dev libpq-dev \ - libpcre3 libpcre3-dev \ - libssl-dev libcurl4-openssl-dev \ - zlib1g-dev \ - libreadline6-dev \ - libbz2-dev \ - libxslt-dev libgdbm-dev ncurses-dev \ - libffi-dev libtool bison libevent-dev \ - liborc-0.4-0 \ - libmcrypt-dev libicu-dev \ - re2c libnuma-dev \ - postgresql-server-dev-all libcap2-bin libldap-dev && \ - add-apt-repository ppa:ubuntu-toolchain-r/test -y && \ - apt-get update -yqq && \ - apt-get install -yqq gcc-8 g++-8 - -RUN locale-gen en_US.UTF-8 - -ENV LANG en_US.UTF-8 -ENV LANGUAGE en_US:en -ENV LC_ALL en_US.UTF-8 -ENV DEBIAN_FRONTEND noninteractive - -ENV CC=gcc-8 -ENV CXX=g++-8 -ENV AR=gcc-ar-8 -ENV RANLIB=gcc-ranlib-8 -ENV IROOT=/install -ENV ULIB_ROOT=$IROOT/ULib -ENV ULIB_VERSION=2.4.2 -ENV ULIB_DOCUMENT_ROOT=$ULIB_ROOT/ULIB_DOCUMENT_ROOT - -WORKDIR $IROOT - -RUN mkdir -p $ULIB_DOCUMENT_ROOT -RUN wget -q -O ULib-${ULIB_VERSION}.tar.gz https://github.com/stefanocasazza/ULib/archive/v${ULIB_VERSION}.tar.gz -RUN tar xf ULib-${ULIB_VERSION}.tar.gz - -WORKDIR $IROOT/ULib-$ULIB_VERSION - -# AVOID "configure: error: newly created file is older than distributed files! Check your system clock" -RUN cp /src/* src/ulib/net/server/plugin/usp -RUN find . -exec touch {} \; - -RUN echo "userver {" >> $ULIB_ROOT/benchmark.cfg -RUN echo "PORT 8080" >> $ULIB_ROOT/benchmark.cfg -RUN echo "PREFORK_CHILD $(( 2 * $(nproc)))" >> $ULIB_ROOT/benchmark.cfg -RUN echo "TCP_LINGER_SET -2" >> $ULIB_ROOT/benchmark.cfg -RUN echo "LISTEN_BACKLOG 256" >> $ULIB_ROOT/benchmark.cfg -RUN echo "ORM_DRIVER pgsql" >> $ULIB_ROOT/benchmark.cfg -RUN echo "DOCUMENT_ROOT $ULIB_DOCUMENT_ROOT " >> $ULIB_ROOT/benchmark.cfg -RUN echo "}" >> $ULIB_ROOT/benchmark.cfg - -RUN USP_FLAGS="-DAS_cpoll_cppsp_DO" \ - ./configure --prefix=$ULIB_ROOT \ - --disable-static --disable-examples \ - --with-pgsql \ - --without-ssl --disable-HCRS --without-pcre --without-expat \ - --without-libz --without-libuuid --disable-HPRS --without-magic --without-libares \ - --enable-static-orm-driver='pgsql' --enable-static-server-plugin=http - -RUN make install && \ - cd examples/userver && make install && \ - cd ../../src/ulib/net/server/plugin/usp && \ - AM_LDFLAGS="-lFortune" make fortune.la && \ - AM_LDFLAGS="-lWorld" make db.la query.la update.la cached_worlds.la && \ - cp .libs/db.so .libs/query.so .libs/update.so .libs/fortune.so .libs/cached_worlds.so $ULIB_DOCUMENT_ROOT - -ENV PATH=${ULIB_ROOT}/bin:${PATH} - -ADD ./ /ulib -WORKDIR /ulib - -ENV ORM_DRIVER="pgsql" -ENV UMEMPOOL="96,0,0,97,16417,-14,-20,-18,26" -ENV ORM_OPTION="host=tfb-database user=benchmarkdbuser password=benchmarkdbpass dbname=hello_world client_encoding=UTF8" - -EXPOSE 8080 - -CMD setcap cap_sys_nice,cap_sys_resource,cap_net_bind_service,cap_net_raw+eip $IROOT/ULib/bin/userver_tcp && \ - $IROOT/ULib/bin/userver_tcp -c $IROOT/ULib/benchmark.cfg diff --git a/frameworks/C++/ulib/ulib-postgres_fit.dockerfile b/frameworks/C++/ulib/ulib-postgres_fit.dockerfile deleted file mode 100644 index 9266d9baa3a..00000000000 --- a/frameworks/C++/ulib/ulib-postgres_fit.dockerfile +++ /dev/null @@ -1,87 +0,0 @@ -FROM ubuntu:18.04 - -COPY ./ ./ - -RUN apt-get update -yqq && \ - apt-get install -yqq software-properties-common build-essential curl locales wget unzip git \ - libmysqlclient-dev libpq-dev \ - libpcre3 libpcre3-dev \ - libssl-dev libcurl4-openssl-dev \ - zlib1g-dev \ - libreadline6-dev \ - libbz2-dev \ - libxslt-dev libgdbm-dev ncurses-dev \ - libffi-dev libtool bison libevent-dev \ - liborc-0.4-0 \ - libmcrypt-dev libicu-dev \ - re2c libnuma-dev \ - postgresql-server-dev-all libcap2-bin libldap-dev && \ - add-apt-repository ppa:ubuntu-toolchain-r/test -y && \ - apt-get update -yqq && \ - apt-get install -yqq gcc-8 g++-8 - -RUN locale-gen en_US.UTF-8 - -ENV LANG en_US.UTF-8 -ENV LANGUAGE en_US:en -ENV LC_ALL en_US.UTF-8 -ENV DEBIAN_FRONTEND noninteractive - -ENV CC=gcc-8 -ENV CXX=g++-8 -ENV AR=gcc-ar-8 -ENV RANLIB=gcc-ranlib-8 -ENV IROOT=/install -ENV ULIB_ROOT=$IROOT/ULib -ENV ULIB_VERSION=2.4.2 -ENV ULIB_DOCUMENT_ROOT=$ULIB_ROOT/ULIB_DOCUMENT_ROOT - -WORKDIR $IROOT - -RUN mkdir -p $ULIB_DOCUMENT_ROOT -RUN wget -q -O ULib-${ULIB_VERSION}.tar.gz https://github.com/stefanocasazza/ULib/archive/v${ULIB_VERSION}.tar.gz -RUN tar xf ULib-${ULIB_VERSION}.tar.gz - -WORKDIR $IROOT/ULib-$ULIB_VERSION - -# AVOID "configure: error: newly created file is older than distributed files! Check your system clock" -RUN cp /src/* src/ulib/net/server/plugin/usp -RUN find . -exec touch {} \; - -RUN echo "userver {" >> $ULIB_ROOT/benchmark.cfg -RUN echo "PORT 8080" >> $ULIB_ROOT/benchmark.cfg -RUN echo "PREFORK_CHILD $(nproc)" >> $ULIB_ROOT/benchmark.cfg -RUN echo "TCP_LINGER_SET -2" >> $ULIB_ROOT/benchmark.cfg -RUN echo "LISTEN_BACKLOG 256" >> $ULIB_ROOT/benchmark.cfg -RUN echo "ORM_DRIVER pgsql" >> $ULIB_ROOT/benchmark.cfg -RUN echo "DOCUMENT_ROOT $ULIB_DOCUMENT_ROOT " >> $ULIB_ROOT/benchmark.cfg -RUN echo "}" >> $ULIB_ROOT/benchmark.cfg - -RUN USP_FLAGS="-DAS_cpoll_cppsp_DO" \ - ./configure --prefix=$ULIB_ROOT \ - --disable-static --disable-examples \ - --with-pgsql \ - --without-ssl --disable-HCRS --without-pcre --without-expat \ - --without-libz --without-libuuid --disable-HPRS --without-magic --without-libares \ - --enable-static-orm-driver='pgsql' --enable-static-server-plugin=http - -RUN make install && \ - cd examples/userver && make install && \ - cd ../../src/ulib/net/server/plugin/usp && \ - AM_LDFLAGS="-lFortune" make fortune.la && \ - AM_LDFLAGS="-lWorld" make db.la query.la update.la cached_worlds.la && \ - cp .libs/db.so .libs/query.so .libs/update.so .libs/fortune.so .libs/cached_worlds.so $ULIB_DOCUMENT_ROOT - -ENV PATH=${ULIB_ROOT}/bin:${PATH} - -ADD ./ /ulib -WORKDIR /ulib - -ENV ORM_DRIVER="pgsql" -ENV UMEMPOOL="96,0,0,97,16417,-14,-20,-18,26" -ENV ORM_OPTION="host=tfb-database user=benchmarkdbuser password=benchmarkdbpass dbname=hello_world client_encoding=UTF8" - -EXPOSE 8080 - -CMD setcap cap_sys_nice,cap_sys_resource,cap_net_bind_service,cap_net_raw+eip $IROOT/ULib/bin/userver_tcp && \ - $IROOT/ULib/bin/userver_tcp -c $IROOT/ULib/benchmark.cfg diff --git a/frameworks/C++/ulib/ulib.dockerfile b/frameworks/C++/ulib/ulib.dockerfile deleted file mode 100644 index d9630d12886..00000000000 --- a/frameworks/C++/ulib/ulib.dockerfile +++ /dev/null @@ -1,82 +0,0 @@ -FROM ubuntu:18.04 - -COPY ./ ./ - -RUN apt-get update -yqq && \ - apt-get install -yqq software-properties-common build-essential curl locales wget unzip git \ - libmysqlclient-dev libpq-dev \ - libpcre3 libpcre3-dev \ - libssl-dev libcurl4-openssl-dev \ - zlib1g-dev \ - libreadline6-dev \ - libbz2-dev \ - libxslt-dev libgdbm-dev ncurses-dev \ - libffi-dev libtool bison libevent-dev \ - liborc-0.4-0 \ - libmcrypt-dev libicu-dev \ - re2c libnuma-dev \ - postgresql-server-dev-all libcap2-bin && \ - add-apt-repository ppa:ubuntu-toolchain-r/test -y && \ - apt-get update -yqq && \ - apt-get install -yqq gcc-8 g++-8 - -RUN locale-gen en_US.UTF-8 - -ENV LANG en_US.UTF-8 -ENV LANGUAGE en_US:en -ENV LC_ALL en_US.UTF-8 -ENV DEBIAN_FRONTEND noninteractive - -ENV CC=gcc-8 -ENV CXX=g++-8 -ENV AR=gcc-ar-8 -ENV RANLIB=gcc-ranlib-8 -ENV IROOT=/install -ENV ULIB_ROOT=$IROOT/ULib -ENV ULIB_VERSION=2.4.2 -ENV ULIB_DOCUMENT_ROOT=$ULIB_ROOT/ULIB_DOCUMENT_ROOT - -WORKDIR $IROOT - -RUN mkdir -p $ULIB_DOCUMENT_ROOT -RUN wget -q -O ULib-${ULIB_VERSION}.tar.gz https://github.com/stefanocasazza/ULib/archive/v${ULIB_VERSION}.tar.gz -RUN tar xf ULib-${ULIB_VERSION}.tar.gz - -WORKDIR $IROOT/ULib-$ULIB_VERSION - -# AVOID "configure: error: newly created file is older than distributed files! Check your system clock" -RUN cp /src/* src/ulib/net/server/plugin/usp -RUN find . -exec touch {} \; - -RUN echo "userver {" >> $ULIB_ROOT/benchmark.cfg -RUN echo "PORT 8080" >> $ULIB_ROOT/benchmark.cfg -RUN echo "PREFORK_CHILD $(( 3 * $(nproc) / 2 ))" >> $ULIB_ROOT/benchmark.cfg -RUN echo "TCP_LINGER_SET 0" >> $ULIB_ROOT/benchmark.cfg -RUN echo "LISTEN_BACKLOG 16384" >> $ULIB_ROOT/benchmark.cfg -RUN echo "DOCUMENT_ROOT $ULIB_DOCUMENT_ROOT " >> $ULIB_ROOT/benchmark.cfg -RUN echo "}" >> $ULIB_ROOT/benchmark.cfg - -RUN USP_FLAGS="-DAS_cpoll_cppsp_DO" \ - ./configure --prefix=$ULIB_ROOT \ - --disable-static --disable-examples \ - --without-ssl --without-pcre --without-expat \ - --without-libz --without-libuuid --without-magic --without-libares \ - --enable-static-server-plugin=http - -RUN make install && \ - cd examples/userver && make install && \ - cd ../../src/ulib/net/server/plugin/usp && \ - make plaintext.la && \ - cp .libs/plaintext.so $ULIB_DOCUMENT_ROOT - -ENV PATH=${ULIB_ROOT}/bin:${PATH} - -ADD ./ /ulib -WORKDIR /ulib - -ENV UMEMPOOL="58,0,0,41,16401,-14,-15,11,25" - -EXPOSE 8080 - -CMD setcap cap_sys_nice,cap_sys_resource,cap_net_bind_service,cap_net_raw+eip $IROOT/ULib/bin/userver_tcp && \ - $IROOT/ULib/bin/userver_tcp -c $IROOT/ULib/benchmark.cfg diff --git a/frameworks/C++/userver/README.md b/frameworks/C++/userver/README.md index d10de17e403..8b1d83c4d2a 100755 --- a/frameworks/C++/userver/README.md +++ b/frameworks/C++/userver/README.md @@ -2,14 +2,11 @@ This is the [userver](https://github.com/userver-framework/userver) portion of a [benchmarking test suite](https://github.com/TechEmpower/FrameworkBenchmarks) comparing a variety of web development platforms. -This benchmarks comes in two configurations: **userver** and **userver-bare**, where both configurations use exactly the same handlers code, but **userver-bare** replaces default http implementation of **userver** with custom one. -You see, **userver** being feature-rich framework widely used in production comes with a lot of useful functionality built-in (metrics, dynamic configuring, logging/tracing, congestion control etc...) none of which is of any use in benchmarks; although most of that can be disabled via configs, some parts remain, and these parts aren't free. -The aim of **userver-bare** is to explore practical limits of lower-level **userver** functionality when performance is an absolute must, while still being idiomatic userver code. - ### Test Type Implementation Source Code * [Plaintext](userver_benchmark/controllers/plaintext/handler.cpp) * [Json](userver_benchmark/controllers/json/handler.cpp) +* [Fortunes](userver_benchmark/controllers/fortunes/handler.cpp) * [Single Database Query](userver_benchmark/controllers/single_query/handler.cpp) * [Multiple Database Queries](userver_benchmark/controllers/multiple_queries/handler.cpp) * [Database Updates](userver_benchmark/controllers/updates/handler.cpp) @@ -24,6 +21,10 @@ http://localhost:8080/plaintext http://localhost:8080/json +### Fortunes + +http://localhost:8080/fortunes + ### Single Database Query http://localhost:8080/db diff --git a/frameworks/C++/userver/benchmark_config.json b/frameworks/C++/userver/benchmark_config.json index aba5e7d5933..8a455b99a30 100755 --- a/frameworks/C++/userver/benchmark_config.json +++ b/frameworks/C++/userver/benchmark_config.json @@ -25,30 +25,6 @@ "display_name": "userver", "notes": "", "versus": "None" - }, - "bare": { - "json_url": "/json", - "plaintext_url": "/plaintext", - "db_url": "/db", - "query_url": "/queries?queries=", - "update_url": "/updates?queries=", - "cached_query_url": "/cached-queries?count=", - "fortune_url": "/fortunes", - "port": 8081, - "approach": "Realistic", - "classification": "Micro", - "database": "postgres", - "framework": "userver", - "language": "C++", - "flavor": "None", - "orm": "Micro", - "platform": "None", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "userver[bare]", - "notes": "", - "versus": "None" } } ] diff --git a/frameworks/C++/userver/config.toml b/frameworks/C++/userver/config.toml index 316860f74a1..424fd5d6457 100644 --- a/frameworks/C++/userver/config.toml +++ b/frameworks/C++/userver/config.toml @@ -18,21 +18,3 @@ orm = "Micro" platform = "None" webserver = "None" versus = "None" - -[bare] -urls.plaintext = "/plaintext" -urls.json = "/json" -urls.db = "/db" -urls.query = "/queries?queries=" -urls.update = "/updates?queries=" -urls.cached_query = "/cached-queries?count=" -urls.fortune = "/fortunes" -approach = "Realistic" -classification = "Micro" -database = "Postgres" -database_os = "Linux" -os = "Linux" -orm = "Micro" -platform = "None" -webserver = "None" -versus = "None" diff --git a/frameworks/C++/userver/userver-bare.dockerfile b/frameworks/C++/userver/userver-bare.dockerfile deleted file mode 100644 index 4b1210c8fe2..00000000000 --- a/frameworks/C++/userver/userver-bare.dockerfile +++ /dev/null @@ -1,27 +0,0 @@ -FROM ghcr.io/userver-framework/ubuntu-userver-build-base:v1 AS builder - -RUN apt update && \ - apt install -y lsb-release wget software-properties-common gnupg && \ - wget https://apt.llvm.org/llvm.sh && chmod +x llvm.sh && ./llvm.sh 16 - -WORKDIR /src -RUN git clone https://github.com/userver-framework/userver.git && \ - cd userver && git checkout 781169b63bdbc012f7d98ed045bff75ff1b0b70d -COPY userver_benchmark/ ./ -RUN mkdir build && cd build && \ - cmake -DUSERVER_IS_THE_ROOT_PROJECT=0 -DUSERVER_FEATURE_CRYPTOPP_BLAKE2=0 \ - -DUSERVER_FEATURE_REDIS=0 -DUSERVER_FEATURE_CLICKHOUSE=0 -DUSERVER_FEATURE_MONGODB=0 -DUSERVER_FEATURE_RABBITMQ=0 -DUSERVER_FEATURE_GRPC=0 \ - -DUSERVER_FEATURE_UTEST=0 \ - -DUSERVER_FEATURE_POSTGRESQL=1 \ - -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS="-march=native" -DCMAKE_C_FLAGS="-march=native" \ - -DCMAKE_CXX_COMPILER=clang++-16 -DCMAKE_C_COMPILER=clang-16 -DUSERVER_USE_LD=lld-16 .. && \ - make -j $(nproc) - -FROM builder AS runner -WORKDIR /app -COPY userver_configs/* ./ -COPY --from=builder /src/build/userver_techempower ./ - -EXPOSE 8081 -CMD ./userver_techempower -c ./static_config.yaml - diff --git a/frameworks/C++/userver/userver.dockerfile b/frameworks/C++/userver/userver.dockerfile index 0c39abe0130..e115816b324 100644 --- a/frameworks/C++/userver/userver.dockerfile +++ b/frameworks/C++/userver/userver.dockerfile @@ -1,4 +1,4 @@ -FROM ghcr.io/userver-framework/ubuntu-userver-build-base:v1 AS builder +FROM ghcr.io/userver-framework/ubuntu-22.04-userver-pg AS builder RUN apt update && \ apt install -y lsb-release wget software-properties-common gnupg && \ @@ -6,15 +6,17 @@ RUN apt update && \ WORKDIR /src RUN git clone https://github.com/userver-framework/userver.git && \ - cd userver && git checkout 781169b63bdbc012f7d98ed045bff75ff1b0b70d + cd userver && git checkout bdd5e1e03921ff378b062f86a189c3cfa3d66332 + COPY userver_benchmark/ ./ RUN mkdir build && cd build && \ cmake -DUSERVER_IS_THE_ROOT_PROJECT=0 -DUSERVER_FEATURE_CRYPTOPP_BLAKE2=0 \ - -DUSERVER_FEATURE_REDIS=0 -DUSERVER_FEATURE_CLICKHOUSE=0 -DUSERVER_FEATURE_MONGODB=0 -DUSERVER_FEATURE_RABBITMQ=0 -DUSERVER_FEATURE_GRPC=0 \ -DUSERVER_FEATURE_UTEST=0 \ -DUSERVER_FEATURE_POSTGRESQL=1 \ + -DUSERVER_FEATURE_ERASE_LOG_WITH_LEVEL=warning \ -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS="-march=native" -DCMAKE_C_FLAGS="-march=native" \ - -DCMAKE_CXX_COMPILER=clang++-16 -DCMAKE_C_COMPILER=clang-16 -DUSERVER_USE_LD=lld-16 .. && \ + -DCMAKE_CXX_COMPILER=clang++-16 -DCMAKE_C_COMPILER=clang-16 -DUSERVER_USE_LD=lld-16 \ + -DUSERVER_LTO=0 .. && \ make -j $(nproc) FROM builder AS runner diff --git a/frameworks/C++/userver/userver_benchmark/CMakeLists.txt b/frameworks/C++/userver/userver_benchmark/CMakeLists.txt index 777bce060b7..507550f5755 100644 --- a/frameworks/C++/userver/userver_benchmark/CMakeLists.txt +++ b/frameworks/C++/userver/userver_benchmark/CMakeLists.txt @@ -9,10 +9,10 @@ file(GLOB_RECURSE SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/bare/*.cpp ) -include(userver/cmake/SetupEnvironment.cmake) include(GNUInstallDirs) add_subdirectory(userver) +userver_setup_environment() add_executable(${PROJECT_NAME} ${SOURCES} userver_techempower.cpp) -target_link_libraries(${PROJECT_NAME} PRIVATE userver-core userver-postgresql) +target_link_libraries(${PROJECT_NAME} PRIVATE userver-core userver-postgresql userver-llhttp) diff --git a/frameworks/C++/userver/userver_benchmark/bare/simple_connection.cpp b/frameworks/C++/userver/userver_benchmark/bare/simple_connection.cpp index eb09af89945..bb6a5a1880f 100644 --- a/frameworks/C++/userver/userver_benchmark/bare/simple_connection.cpp +++ b/frameworks/C++/userver/userver_benchmark/bare/simple_connection.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include "simple_server.hpp" @@ -11,83 +11,57 @@ #include #include #include +#include namespace userver_techempower::bare { namespace { -template -class SmallString final { - public: - SmallString() = default; - - void Append(const char* data, std::size_t length) { - const auto old_size = Size(); - data_.resize(old_size + length); - std::memcpy(Data() + old_size, data, length); - } - - void Append(std::string_view sw) { Append(sw.data(), sw.size()); } - - [[nodiscard]] std::string_view AsSw() const { return {Data(), Size()}; } - - [[nodiscard]] char* Data() { return data_.data(); } - [[nodiscard]] const char* Data() const { return data_.data(); } - - [[nodiscard]] std::size_t Size() const { return data_.size(); } - - void Clear() { data_.resize(0); } - - private: - boost::container::small_vector data_; -}; - struct HttpParser final { - http_parser parser{}; - http_parser_settings parser_settings{}; + llhttp_t parser{}; + llhttp_settings_t parser_settings{}; std::function on_request_cb{}; - SmallString<50> url; + userver::utils::SmallString<50> url; explicit HttpParser(std::function on_request_cb) : on_request_cb{std::move(on_request_cb)} { - http_parser_init(&parser, HTTP_REQUEST); - parser.data = this; - - http_parser_settings_init(&parser_settings); + llhttp_settings_init(&parser_settings); parser_settings.on_url = HttpOnUrl; parser_settings.on_message_begin = HttpOnMessageBegin; parser_settings.on_message_complete = HttpOnMessageComplete; + + llhttp_init(&parser, HTTP_REQUEST, &parser_settings); + parser.data = this; } - void Execute(const char* data, std::size_t length) { - http_parser_execute(&parser, &parser_settings, data, length); + auto Execute(const char* data, std::size_t length) { + return llhttp_execute(&parser, data, length); } - static int HttpOnUrl(http_parser* parser, const char* data, - std::size_t length) { + static int HttpOnUrl(llhttp_t* parser, const char* data, std::size_t length) { auto* self = static_cast(parser->data); - self->url.Append(data, length); + self->url.append(std::string_view{data, length}); return 0; } - static int HttpOnMessageBegin(http_parser* parser) { + static int HttpOnMessageBegin(llhttp_t* parser) { auto* self = static_cast(parser->data); - self->url.Clear(); + self->url.clear(); return 0; } - static int HttpOnMessageComplete(http_parser* parser) { + static int HttpOnMessageComplete(llhttp_t* parser) { auto* self = static_cast(parser->data); - self->on_request_cb(self->url.AsSw()); + self->on_request_cb(static_cast(self->url)); return 0; } }; class ResponseBuffers final { public: - using HeadersString = SmallString<200>; + using HeadersString = userver::utils::SmallString<200>; HeadersString& Next(userver::engine::io::Socket& socket, std::string&& body) { if (Size() == kMaxResponses) { @@ -104,19 +78,18 @@ class ResponseBuffers final { return; } - boost::container::small_vector - iovec(Size() * 2); + boost::container::small_vector io_vector( + Size() * 2); std::size_t index = 0; std::size_t total_size = 0; - for (const auto& response : responses_) { - iovec[index++] = {response.headers.Data(), response.headers.Size()}; - iovec[index++] = {response.body.data(), response.body.size()}; - total_size += response.headers.Size() + response.body.size(); + for (auto& response : responses_) { + io_vector[index++] = {response.headers.data(), response.headers.size()}; + io_vector[index++] = {response.body.data(), response.body.size()}; + total_size += response.headers.size() + response.body.size(); } - if (socket.SendAll(iovec.data(), iovec.size(), {}) != total_size) { + if (socket.SendAll(io_vector.data(), io_vector.size(), {}) != total_size) { throw std::runtime_error{"Socket closed by remote"}; } @@ -191,17 +164,17 @@ void SimpleConnection::Process() { const auto content_length_str = std::to_string(response.body.size()); auto& headers = buffers.Next(socket_, std::move(response.body)); - headers.Append(kCommonHeaders); - headers.Append("Content-Type: "); - headers.Append(response.content_type); + headers.append(kCommonHeaders); + headers.append("Content-Type: "); + headers.append(response.content_type); - headers.Append("\r\nContent-Length: "); - headers.Append(content_length_str); + headers.append("\r\nContent-Length: "); + headers.append(content_length_str); - headers.Append("\r\nDate: "); - headers.Append(GetCachedDate()); + headers.append("\r\nDate: "); + headers.append(GetCachedDate()); - headers.Append(kHeadersEnd); + headers.append(kHeadersEnd); }; HttpParser parser{handle_request}; @@ -218,8 +191,7 @@ void SimpleConnection::Process() { break; } - parser.Execute(buffer.data(), last_bytes_read); - if (parser.parser.http_errno != 0) { + if (parser.Execute(buffer.data(), last_bytes_read) != HPE_OK) { break; } diff --git a/frameworks/C++/userver/userver_benchmark/bare/simple_router.cpp b/frameworks/C++/userver/userver_benchmark/bare/simple_router.cpp index 61e634a95c3..dd7cf60636a 100644 --- a/frameworks/C++/userver/userver_benchmark/bare/simple_router.cpp +++ b/frameworks/C++/userver/userver_benchmark/bare/simple_router.cpp @@ -52,32 +52,32 @@ SimpleResponse SimpleRouter::RouteRequest(std::string_view url) const { } if (StartsWith(url, kJsonUrlPrefix)) { - return {ToString(json::Handler::GetResponse()), kContentTypeJson}; + return {json::Handler::GetResponse(), kContentTypeJson}; } if (StartsWith(url, kSingleQueryUrlPrefix)) { - return {ToString(single_query_.GetResponse()), kContentTypeJson}; + return {single_query_.GetResponse(), kContentTypeJson}; } if (StartsWith(url, kMultipleQueriesUrlPrefix)) { const auto queries = db_helpers::ParseParamFromQuery( url.substr(kMultipleQueriesUrlPrefix.size()), "queries"); - return {ToString(multiple_queries_.GetResponse(queries)), kContentTypeJson}; + return {multiple_queries_.GetResponse(queries), kContentTypeJson}; } if (StartsWith(url, kUpdatesUrlPrefix)) { const auto queries = db_helpers::ParseParamFromQuery( url.substr(kMultipleQueriesUrlPrefix.size()), "queries"); - return {ToString(updates_.GetResponse(queries)), kContentTypeJson}; + return {updates_.GetResponse(queries), kContentTypeJson}; } if (StartsWith(url, kCachedQueriesUrlPrefix)) { const auto count = db_helpers::ParseParamFromQuery( url.substr(kCachedQueriesUrlPrefix.size()), "count"); - return {ToString(cached_queries_.GetResponse(count)), kContentTypeJson}; + return {cached_queries_.GetResponse(count), kContentTypeJson}; } if (StartsWith(url, kFortunesUrlPrefix)) { diff --git a/frameworks/C++/userver/userver_benchmark/common/db_helpers.cpp b/frameworks/C++/userver/userver_benchmark/common/db_helpers.cpp index 899a2aaa87c..5403c01bd14 100644 --- a/frameworks/C++/userver/userver_benchmark/common/db_helpers.cpp +++ b/frameworks/C++/userver/userver_benchmark/common/db_helpers.cpp @@ -3,7 +3,6 @@ #include #include -#include #include namespace userver_techempower::db_helpers { @@ -30,10 +29,21 @@ int ParseFromQueryVal(std::string_view query_val) { userver::storages::postgres::Query CreateNonLoggingQuery( std::string statement) { return userver::storages::postgres::Query{ - statement, std::nullopt /* name */, + std::move(statement), std::nullopt /* name */, userver::storages::postgres::Query::LogMode::kNameOnly}; } +void WriteToStream(const WorldTableRow& row, + userver::formats::json::StringBuilder& sb) { + userver::formats::json::StringBuilder::ObjectGuard obj{sb}; + + sb.Key("id"); + WriteToStream(row.id, sb); + + sb.Key("randomNumber"); + WriteToStream(row.random_number, sb); +} + int GenerateRandomId() { return userver::utils::RandRange(1, kMaxWorldRows + 1); } @@ -42,13 +52,6 @@ int GenerateRandomValue() { return userver::utils::RandRange(1, kMaxWorldRows + 1); } -userver::formats::json::Value Serialize( - const WorldTableRow& value, - userver::formats::serialize::To) { - return userver::formats::json::MakeObject("id", value.id, "randomNumber", - value.random_number); -} - int ParseParamFromQuery(const userver::server::http::HttpRequest& request, const std::string& name) { const auto& arg_str = request.GetArg(name); diff --git a/frameworks/C++/userver/userver_benchmark/common/db_helpers.hpp b/frameworks/C++/userver/userver_benchmark/common/db_helpers.hpp index a4325c3b0fa..abed0a41cb4 100644 --- a/frameworks/C++/userver/userver_benchmark/common/db_helpers.hpp +++ b/frameworks/C++/userver/userver_benchmark/common/db_helpers.hpp @@ -1,9 +1,12 @@ #pragma once #include +#include #include +#include #include #include +#include #include namespace userver_techempower::db_helpers { @@ -18,6 +21,9 @@ const userver::storages::postgres::Query kSelectRowQuery = constexpr auto kClusterHostType = userver::storages::postgres::ClusterHostType::kMaster; +constexpr userver::storages::postgres::CommandControl kDefaultPgCC{ + std::chrono::seconds{7}, std::chrono::seconds{7}}; + constexpr std::string_view kDbComponentName = "hello-world-db"; struct WorldTableRow final { @@ -25,13 +31,12 @@ struct WorldTableRow final { int random_number; }; +void WriteToStream(const WorldTableRow& row, + userver::formats::json::StringBuilder& sb); + int GenerateRandomId(); int GenerateRandomValue(); -userver::formats::json::Value Serialize( - const WorldTableRow& value, - userver::formats::serialize::To); - int ParseParamFromQuery(const userver::server::http::HttpRequest& request, const std::string& name); diff --git a/frameworks/C++/userver/userver_benchmark/controllers/cached_queries/handler.cpp b/frameworks/C++/userver/userver_benchmark/controllers/cached_queries/handler.cpp index 00b35f94434..305b429b8b8 100644 --- a/frameworks/C++/userver/userver_benchmark/controllers/cached_queries/handler.cpp +++ b/frameworks/C++/userver/userver_benchmark/controllers/cached_queries/handler.cpp @@ -1,28 +1,30 @@ #include "handler.hpp" -#include - #include +#include +#include + namespace userver_techempower::cached_queries { Handler::Handler(const userver::components::ComponentConfig& config, const userver::components::ComponentContext& context) - : userver::server::handlers::HttpHandlerJsonBase{config, context}, + : userver::server::handlers::HttpHandlerBase{config, context}, cache_{context.FindComponent()}, query_arg_name_{"count"} {} -userver::formats::json::Value Handler::HandleRequestJsonThrow( +std::string Handler::HandleRequestThrow( const userver::server::http::HttpRequest& request, - const userver::formats::json::Value&, userver::server::request::RequestContext&) const { const auto queries = db_helpers::ParseParamFromQuery(request, query_arg_name_); + request.GetHttpResponse().SetHeader(userver::http::headers::kContentType, + "application/json"); return GetResponse(queries); } -userver::formats::json::Value Handler::GetResponse(int queries) const { +std::string Handler::GetResponse(int queries) const { boost::container::small_vector result( queries); @@ -31,7 +33,9 @@ userver::formats::json::Value Handler::GetResponse(int queries) const { std::generate(result.begin(), result.end(), [&cache] { return cache.at(db_helpers::GenerateRandomId()); }); - return userver::formats::json::ValueBuilder{result}.ExtractValue(); + userver::formats::json::StringBuilder sb{}; + WriteToStream(result, sb); + return sb.GetString(); } } // namespace userver_techempower::cached_queries diff --git a/frameworks/C++/userver/userver_benchmark/controllers/cached_queries/handler.hpp b/frameworks/C++/userver/userver_benchmark/controllers/cached_queries/handler.hpp index ca286985a3e..dbc187cbd15 100644 --- a/frameworks/C++/userver/userver_benchmark/controllers/cached_queries/handler.hpp +++ b/frameworks/C++/userver/userver_benchmark/controllers/cached_queries/handler.hpp @@ -1,24 +1,23 @@ #pragma once -#include +#include #include "world_cache_component.hpp" namespace userver_techempower::cached_queries { -class Handler final : public userver::server::handlers::HttpHandlerJsonBase { +class Handler final : public userver::server::handlers::HttpHandlerBase { public: static constexpr std::string_view kName = "cached-queries-handler"; Handler(const userver::components::ComponentConfig& config, const userver::components::ComponentContext& context); - userver::formats::json::Value HandleRequestJsonThrow( + std::string HandleRequestThrow( const userver::server::http::HttpRequest& request, - const userver::formats::json::Value&, userver::server::request::RequestContext&) const final; - userver::formats::json::Value GetResponse(int queries) const; + std::string GetResponse(int queries) const; private: const WorldCacheComponent& cache_; diff --git a/frameworks/C++/userver/userver_benchmark/controllers/fortunes/handler.cpp b/frameworks/C++/userver/userver_benchmark/controllers/fortunes/handler.cpp index 4c7619bc86d..acdc0346eb1 100644 --- a/frameworks/C++/userver/userver_benchmark/controllers/fortunes/handler.cpp +++ b/frameworks/C++/userver/userver_benchmark/controllers/fortunes/handler.cpp @@ -147,7 +147,7 @@ std::string Handler::HandleRequestThrow( std::string Handler::GetResponse() const { const auto pg_result = [this] { const auto lock = semaphore_.Acquire(); - return pg_->Execute(db_helpers::kClusterHostType, + return pg_->Execute(db_helpers::kClusterHostType, db_helpers::kDefaultPgCC, select_all_fortunes_query_); }(); diff --git a/frameworks/C++/userver/userver_benchmark/controllers/json/handler.cpp b/frameworks/C++/userver/userver_benchmark/controllers/json/handler.cpp index 390acc7c0cd..fd1c18a6bf4 100644 --- a/frameworks/C++/userver/userver_benchmark/controllers/json/handler.cpp +++ b/frameworks/C++/userver/userver_benchmark/controllers/json/handler.cpp @@ -1,16 +1,25 @@ #include "handler.hpp" +#include +#include + namespace userver_techempower::json { -userver::formats::json::Value Handler::HandleRequestJsonThrow( - const userver::server::http::HttpRequest&, - const userver::formats::json::Value&, +std::string Handler::HandleRequestThrow( + const userver::server::http::HttpRequest& request, userver::server::request::RequestContext&) const { + request.GetHttpResponse().SetHeader(userver::http::headers::kContentType, + "application/json"); return GetResponse(); } -userver::formats::json::Value Handler::GetResponse() { - return userver::formats::json::MakeObject("message", "Hello, World!"); +std::string Handler::GetResponse() { + const auto json = + userver::formats::json::MakeObject("message", "Hello, World!"); + + userver::formats::json::StringBuilder sb{}; + sb.WriteValue(json); + return sb.GetString(); } } // namespace userver_techempower::json diff --git a/frameworks/C++/userver/userver_benchmark/controllers/json/handler.hpp b/frameworks/C++/userver/userver_benchmark/controllers/json/handler.hpp index 7771a94863b..224d9c457fe 100644 --- a/frameworks/C++/userver/userver_benchmark/controllers/json/handler.hpp +++ b/frameworks/C++/userver/userver_benchmark/controllers/json/handler.hpp @@ -1,21 +1,20 @@ #pragma once -#include +#include namespace userver_techempower::json { -class Handler final : public userver::server::handlers::HttpHandlerJsonBase { +class Handler final : public userver::server::handlers::HttpHandlerBase { public: static constexpr std::string_view kName = "json-handler"; - using HttpHandlerJsonBase::HttpHandlerJsonBase; + using HttpHandlerBase::HttpHandlerBase; - userver::formats::json::Value HandleRequestJsonThrow( + std::string HandleRequestThrow( const userver::server::http::HttpRequest&, - const userver::formats::json::Value&, userver::server::request::RequestContext&) const final; - static userver::formats::json::Value GetResponse(); + static std::string GetResponse(); }; } // namespace userver_techempower::json diff --git a/frameworks/C++/userver/userver_benchmark/controllers/multiple_queries/handler.cpp b/frameworks/C++/userver/userver_benchmark/controllers/multiple_queries/handler.cpp index 19438c0ae6b..48ff33684e1 100644 --- a/frameworks/C++/userver/userver_benchmark/controllers/multiple_queries/handler.cpp +++ b/frameworks/C++/userver/userver_benchmark/controllers/multiple_queries/handler.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -16,7 +17,7 @@ constexpr std::size_t kBestConcurrencyWildGuess = 256; Handler::Handler(const userver::components::ComponentConfig& config, const userver::components::ComponentContext& context) - : userver::server::handlers::HttpHandlerJsonBase{config, context}, + : userver::server::handlers::HttpHandlerBase{config, context}, pg_{context .FindComponent( db_helpers::kDbComponentName) @@ -24,36 +25,41 @@ Handler::Handler(const userver::components::ComponentConfig& config, query_arg_name_{"queries"}, semaphore_{kBestConcurrencyWildGuess} {} -userver::formats::json::Value Handler::HandleRequestJsonThrow( +std::string Handler::HandleRequestThrow( const userver::server::http::HttpRequest& request, - const userver::formats::json::Value&, userver::server::request::RequestContext&) const { const auto queries = db_helpers::ParseParamFromQuery(request, query_arg_name_); + request.GetHttpResponse().SetHeader(userver::http::headers::kContentType, + "application/json"); return GetResponse(queries); } -userver::formats::json::Value Handler::GetResponse(int queries) const { - boost::container::small_vector result(queries); - for (auto& value : result) { - value.id = db_helpers::GenerateRandomId(); - } - - { +std::string Handler::GetResponse(int queries) const { + const auto db_result = [this, queries] { const auto lock = semaphore_.Acquire(); - auto trx = pg_->Begin(db_helpers::kClusterHostType, {}); - for (auto& value : result) { - value.random_number = trx.Execute(db_helpers::kSelectRowQuery, value.id) - .AsSingleRow( - userver::storages::postgres::kRowTag) - .random_number; + auto query_queue = pg_->CreateQueryQueue(db_helpers::kClusterHostType, + db_helpers::kDefaultPgCC.execute); + query_queue.Reserve(queries); + for (std::size_t i = 0; i < static_cast(queries); ++i) { + query_queue.Push(db_helpers::kDefaultPgCC, db_helpers::kSelectRowQuery, + db_helpers::GenerateRandomId()); } - trx.Commit(); + + return query_queue.Collect(db_helpers::kDefaultPgCC.execute); + }(); + + boost::container::small_vector result(queries); + for (std::size_t i = 0; i < static_cast(queries); ++i) { + result[i] = db_result[i].AsSingleRow( + userver::storages::postgres::kRowTag); } - return userver::formats::json::ValueBuilder{result}.ExtractValue(); + userver::formats::json::StringBuilder sb{}; + WriteToStream(result, sb); + return sb.GetString(); } } // namespace userver_techempower::multiple_queries diff --git a/frameworks/C++/userver/userver_benchmark/controllers/multiple_queries/handler.hpp b/frameworks/C++/userver/userver_benchmark/controllers/multiple_queries/handler.hpp index a96de194546..55d227cc5f6 100644 --- a/frameworks/C++/userver/userver_benchmark/controllers/multiple_queries/handler.hpp +++ b/frameworks/C++/userver/userver_benchmark/controllers/multiple_queries/handler.hpp @@ -2,24 +2,23 @@ #include "../../common/db_helpers.hpp" -#include +#include #include namespace userver_techempower::multiple_queries { -class Handler final : public userver::server::handlers::HttpHandlerJsonBase { +class Handler final : public userver::server::handlers::HttpHandlerBase { public: static constexpr std::string_view kName = "multiple-queries-handler"; Handler(const userver::components::ComponentConfig& config, const userver::components::ComponentContext& context); - userver::formats::json::Value HandleRequestJsonThrow( + std::string HandleRequestThrow( const userver::server::http::HttpRequest& request, - const userver::formats::json::Value&, userver::server::request::RequestContext&) const final; - userver::formats::json::Value GetResponse(int queries) const; + std::string GetResponse(int queries) const; private: const userver::storages::postgres::ClusterPtr pg_; diff --git a/frameworks/C++/userver/userver_benchmark/controllers/single_query/handler.cpp b/frameworks/C++/userver/userver_benchmark/controllers/single_query/handler.cpp index a6547041b83..3730af8c54a 100644 --- a/frameworks/C++/userver/userver_benchmark/controllers/single_query/handler.cpp +++ b/frameworks/C++/userver/userver_benchmark/controllers/single_query/handler.cpp @@ -1,6 +1,7 @@ #include "handler.hpp" #include +#include #include namespace userver_techempower::single_query { @@ -13,31 +14,34 @@ constexpr std::size_t kBestConcurrencyWildGuess = 256; Handler::Handler(const userver::components::ComponentConfig& config, const userver::components::ComponentContext& context) - : userver::server::handlers::HttpHandlerJsonBase{config, context}, + : userver::server::handlers::HttpHandlerBase{config, context}, pg_{context .FindComponent( db_helpers::kDbComponentName) .GetCluster()}, semaphore_{kBestConcurrencyWildGuess} {} -userver::formats::json::Value Handler::HandleRequestJsonThrow( - const userver::server::http::HttpRequest&, - const userver::formats::json::Value&, +std::string Handler::HandleRequestThrow( + const userver::server::http::HttpRequest& request, userver::server::request::RequestContext&) const { + request.GetHttpResponse().SetHeader(userver::http::headers::kContentType, + "application/json"); return GetResponse(); } -userver::formats::json::Value Handler::GetResponse() const { +std::string Handler::GetResponse() const { const auto row = [this] { const auto lock = semaphore_.Acquire(); return pg_ - ->Execute(db_helpers::kClusterHostType, db_helpers::kSelectRowQuery, - db_helpers::GenerateRandomId()) + ->Execute(db_helpers::kClusterHostType, db_helpers::kDefaultPgCC, + db_helpers::kSelectRowQuery, db_helpers::GenerateRandomId()) .AsSingleRow( userver::storages::postgres::kRowTag); }(); - return db_helpers::Serialize(row, {}); + userver::formats::json::StringBuilder sb{}; + WriteToStream(row, sb); + return sb.GetString(); } } // namespace userver_techempower::single_query diff --git a/frameworks/C++/userver/userver_benchmark/controllers/single_query/handler.hpp b/frameworks/C++/userver/userver_benchmark/controllers/single_query/handler.hpp index 1352d3c373a..1ae92801d3f 100644 --- a/frameworks/C++/userver/userver_benchmark/controllers/single_query/handler.hpp +++ b/frameworks/C++/userver/userver_benchmark/controllers/single_query/handler.hpp @@ -2,25 +2,24 @@ #include "../../common/db_helpers.hpp" -#include +#include #include namespace userver_techempower::single_query { -class Handler final : public userver::server::handlers::HttpHandlerJsonBase { +class Handler final : public userver::server::handlers::HttpHandlerBase { public: static constexpr std::string_view kName = "single-query-handler"; Handler(const userver::components::ComponentConfig& config, const userver::components::ComponentContext& context); - userver::formats::json::Value HandleRequestJsonThrow( + std::string HandleRequestThrow( const userver::server::http::HttpRequest&, - const userver::formats::json::Value&, userver::server::request::RequestContext&) const final; - userver::formats::json::Value GetResponse() const; + std::string GetResponse() const; private: const userver::storages::postgres::ClusterPtr pg_; diff --git a/frameworks/C++/userver/userver_benchmark/controllers/updates/handler.cpp b/frameworks/C++/userver/userver_benchmark/controllers/updates/handler.cpp index 4bf62bf645e..6b0e975e839 100644 --- a/frameworks/C++/userver/userver_benchmark/controllers/updates/handler.cpp +++ b/frameworks/C++/userver/userver_benchmark/controllers/updates/handler.cpp @@ -2,10 +2,20 @@ #include #include +#include #include #include +namespace userver::storages::postgres::io::traits { + +// Hijack userver's whitelist of allowed containers +template +struct IsCompatibleContainer> + : std::true_type {}; + +} // namespace userver::storages::postgres::io::traits + namespace userver_techempower::updates { namespace { @@ -26,59 +36,63 @@ constexpr std::size_t kBestConcurrencyWildGuess = 128; Handler::Handler(const userver::components::ComponentConfig& config, const userver::components::ComponentContext& context) - : userver::server::handlers::HttpHandlerJsonBase{config, context}, + : userver::server::handlers::HttpHandlerBase{config, context}, pg_{context.FindComponent("hello-world-db") .GetCluster()}, query_arg_name_{"queries"}, update_query_{db_helpers::CreateNonLoggingQuery(kUpdateQueryStr)}, semaphore_{kBestConcurrencyWildGuess} {} -userver::formats::json::Value Handler::HandleRequestJsonThrow( +std::string Handler::HandleRequestThrow( const userver::server::http::HttpRequest& request, - const userver::formats::json::Value&, userver::server::request::RequestContext&) const { const auto queries = db_helpers::ParseParamFromQuery(request, query_arg_name_); + request.GetHttpResponse().SetHeader(userver::http::headers::kContentType, + "application/json"); return GetResponse(queries); } -userver::formats::json::Value Handler::GetResponse(int queries) const { - // userver's PG doesn't accept boost::small_vector as an input, sadly - std::vector values(queries); - for (auto& value : values) { - value.id = db_helpers::GenerateRandomId(); +std::string Handler::GetResponse(int queries) const { + boost::container::small_vector ids(queries); + for (auto& id : ids) { + id = db_helpers::GenerateRandomId(); } // we have to sort ids to not deadlock in update - std::sort(values.begin(), values.end(), - [](const auto& lhs, const auto& rhs) { return lhs.id < rhs.id; }); + std::sort(ids.begin(), ids.end(), + [](const auto& lhs, const auto& rhs) { return lhs < rhs; }); - boost::container::small_vector result; + boost::container::small_vector values(queries); + for (auto& value : values) { + value = db_helpers::GenerateRandomValue(); + } - { + const auto db_results = [this, &ids, &values] { const auto lock = semaphore_.Acquire(); - auto trx = pg_->Begin(db_helpers::kClusterHostType, {}); - for (auto& value : values) { - value.random_number = trx.Execute(db_helpers::kSelectRowQuery, value.id) - .AsSingleRow( - userver::storages::postgres::kRowTag) - .random_number; + auto query_queue = pg_->CreateQueryQueue(db_helpers::kClusterHostType, + db_helpers::kDefaultPgCC.execute); + query_queue.Reserve(ids.size() + 1 /* for the update query */); + for (const auto id : ids) { + query_queue.Push(db_helpers::kDefaultPgCC, db_helpers::kSelectRowQuery, + id); } - // We copy values here (and hope compiler optimizes it into one memcpy call) - // to not serialize into json within transaction - result.assign(values.begin(), values.end()); + query_queue.Push(db_helpers::kDefaultPgCC, update_query_, ids, values); - for (auto& value : values) { - value.random_number = db_helpers::GenerateRandomValue(); - } + return query_queue.Collect(db_helpers::kDefaultPgCC.execute); + }(); - trx.ExecuteDecomposeBulk(update_query_, values, values.size()); - trx.Commit(); + boost::container::small_vector result(queries); + for (std::size_t i = 0; i < result.size(); ++i) { + result[i] = db_results[i].AsSingleRow( + userver::storages::postgres::kRowTag); } - return userver::formats::json::ValueBuilder{values}.ExtractValue(); + userver::formats::json::StringBuilder sb{}; + WriteToStream(result, sb); + return sb.GetString(); } } // namespace userver_techempower::updates diff --git a/frameworks/C++/userver/userver_benchmark/controllers/updates/handler.hpp b/frameworks/C++/userver/userver_benchmark/controllers/updates/handler.hpp index 15d6d0d29b0..d2a70884aad 100644 --- a/frameworks/C++/userver/userver_benchmark/controllers/updates/handler.hpp +++ b/frameworks/C++/userver/userver_benchmark/controllers/updates/handler.hpp @@ -2,25 +2,24 @@ #include "../../common/db_helpers.hpp" -#include +#include #include #include namespace userver_techempower::updates { -class Handler final : public userver::server::handlers::HttpHandlerJsonBase { +class Handler final : public userver::server::handlers::HttpHandlerBase { public: static constexpr std::string_view kName = "updates-handler"; Handler(const userver::components::ComponentConfig& config, const userver::components::ComponentContext& context); - userver::formats::json::Value HandleRequestJsonThrow( + std::string HandleRequestThrow( const userver::server::http::HttpRequest& request, - const userver::formats::json::Value&, userver::server::request::RequestContext&) const final; - userver::formats::json::Value GetResponse(int queries) const; + std::string GetResponse(int queries) const; private: const userver::storages::postgres::ClusterPtr pg_; diff --git a/frameworks/C++/userver/userver_benchmark/userver_techempower.cpp b/frameworks/C++/userver/userver_benchmark/userver_techempower.cpp index 4b7dda0e2ae..af0a2b64842 100644 --- a/frameworks/C++/userver/userver_benchmark/userver_techempower.cpp +++ b/frameworks/C++/userver/userver_benchmark/userver_techempower.cpp @@ -4,6 +4,7 @@ #include +#include #include #include #include @@ -65,7 +66,7 @@ int Main(int argc, char* argv[]) { .Append() // tracing tweaks .Append() - // bare + // bare (not used in the benchmark currently) .Append() .Append(); diff --git a/frameworks/C++/userver/userver_configs/static_config.yaml b/frameworks/C++/userver/userver_configs/static_config.yaml index b4fad14911f..ed793a694a7 100644 --- a/frameworks/C++/userver/userver_configs/static_config.yaml +++ b/frameworks/C++/userver/userver_configs/static_config.yaml @@ -1,8 +1,7 @@ # yaml components_manager: event_thread_pool: - threads: 5 - dedicated_timer_threads: 1 + threads: 8 coro_pool: initial_size: 10000 # Preallocate 10000 coroutines at startup. max_size: 300000 # Do not keep more than 300000 preallocated coroutines. @@ -12,7 +11,7 @@ components_manager: main-task-processor: # Make a task processor for CPU-bound couroutine tasks. thread_name: main-worker # OS will show the threads of this task processor with 'main-worker' prefix. - worker_threads: 23 + worker_threads: 48 guess-cpu-limit: true fs-task-processor: # Make a separate task processor for filesystem bound tasks. @@ -83,6 +82,7 @@ components_manager: max_queue_size: 512 connecting_limit: 15 ignore_unused_query_params: true + connlimit_mode: manual single-query-handler: path: /db diff --git a/frameworks/C/duda/README.md b/frameworks/C/duda/README.md deleted file mode 100644 index 7ced12ed71a..00000000000 --- a/frameworks/C/duda/README.md +++ /dev/null @@ -1,29 +0,0 @@ -# Duda I/O Benchmarking Test - -This is the web service used to benchmark Duda I/O web services framework. - -http://duda.io - -## Requirements - -Just the GNU C Compiler and a Linux system running Kernel version >= 2.6.32 - -## Tests available - -### 1. JSON - -URL: /json - -### 6. Plain text - -URL: /plaintext - -## About pending tests - -Most of tests that are related to database query are pending and will be available for the next Round. - -## Contact - -Eduardo Silva - - diff --git a/frameworks/C/duda/benchmark_config.json b/frameworks/C/duda/benchmark_config.json deleted file mode 100644 index e8885751e0a..00000000000 --- a/frameworks/C/duda/benchmark_config.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "framework": "duda", - "tests": [{ - "default": { - "json_url": "/json", - "plaintext_url": "/plaintext", - "port": 2001, - "approach": "Realistic", - "classification": "Platform", - "database": "None", - "framework": "None", - "language": "C", - "flavor": "None", - "orm": "Raw", - "platform": "duda", - "webserver": "Monkey", - "os": "Linux", - "database_os": "Linux", - "display_name": "Duda I/O", - "notes": "", - "versus": "duda" - } - }] -} diff --git a/frameworks/C/duda/config.toml b/frameworks/C/duda/config.toml deleted file mode 100644 index 58b23cba9a5..00000000000 --- a/frameworks/C/duda/config.toml +++ /dev/null @@ -1,15 +0,0 @@ -[framework] -name = "duda" - -[main] -urls.plaintext = "/plaintext" -urls.json = "/json" -approach = "Realistic" -classification = "Platform" -database = "None" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "duda" -webserver = "Monkey" -versus = "duda" diff --git a/frameworks/C/duda/duda.dockerfile b/frameworks/C/duda/duda.dockerfile deleted file mode 100644 index 9b969a75bbe..00000000000 --- a/frameworks/C/duda/duda.dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM python:2.7 - -COPY ./ ./ -# Get v0.31 (no official releases that work 2015-06-25) - -RUN git clone https://github.com/monkey/dudac.git -RUN cd dudac && git checkout 7c3d5b03b09fb4cb5f5e338fff72df2e25e95ef0 && \ - ./dudac -r && \ - ./dudac -s - -EXPOSE 2001 - -CMD ["./dudac/dudac", "-w", "webservice", "-p", "2001"] diff --git a/frameworks/C/duda/webservice/Makefile.in b/frameworks/C/duda/webservice/Makefile.in deleted file mode 100644 index 34e55a2c8b8..00000000000 --- a/frameworks/C/duda/webservice/Makefile.in +++ /dev/null @@ -1,7 +0,0 @@ -NAME = ws -CC = gcc -CFLAGS = -g -Wall -O2 -LDFLAGS = -DEFS = -INCDIR = -OBJECTS = main.o diff --git a/frameworks/C/duda/webservice/main.c b/frameworks/C/duda/webservice/main.c deleted file mode 100644 index 512f0ef8f6d..00000000000 --- a/frameworks/C/duda/webservice/main.c +++ /dev/null @@ -1,81 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -/* - * Duda I/O Benchmark Tests - * ======================== - * This web service is made for the performance contest made by - * TechEmpower, mode details here: - * - * http://www.techempower.com/benchmarks - * - * At the moment only Tests 1 & 6 are implemented. - */ - -#include "webservice.h" -#include "packages/json/json.h" - -/* Test Macros (Tn) */ -#define JSON_CONTENT_TYPE "Content-Type: application/json" -#define PLAIN_CONTENT_TYPE "Content-Type: text/plain" -#define T6_BODY "Hello, World!" - -DUDA_REGISTER("Duda I/O Benchmark Test", "WS Bench"); - -/* - * Test type 1: JSON serialization - * =============================== - * This test use the JSON API object to compose the JSON response - */ -void cb_json(duda_request_t *dr) -{ - char *body; - int body_len; - json_t *j_root; - - /* Instance the JSON object and compose the content */ - j_root = json->create_object(); - json->add_to_object(j_root, - "message", - json->create_string("Hello, World!")); - - /* Format output to string */ - body = json->print_unformatted_gc(dr, j_root); - body_len = strlen(body); - - /* Delete the JSON tree */ - json->delete(j_root); - - /* Compose the response */ - response->http_status(dr, 200); - response->http_header_n(dr, JSON_CONTENT_TYPE, sizeof(JSON_CONTENT_TYPE) - 1); - response->print(dr, body, body_len); - response->end(dr, NULL); -} - - -/* - * Test type 6: Plaintext - * ====================== - */ -void cb_plaintext(duda_request_t *dr) -{ - response->http_status(dr, 200); - response->http_header_n(dr, PLAIN_CONTENT_TYPE, sizeof(PLAIN_CONTENT_TYPE) - 1); - response->print(dr, T6_BODY, sizeof(T6_BODY) - 1); - response->end(dr, NULL); -} - -int duda_main() -{ - /* load packages */ - duda_load_package(json, "json"); - - /* let this web service own the virtual host */ - conf->service_root(); - - /* set callbacks */ - map->static_add("/json", "cb_json"); /* Test #1 */ - map->static_add("/plaintext", "cb_plaintext"); /* Test #6 */ - - return 0; -} diff --git a/frameworks/C/h2o/CMakeLists.txt b/frameworks/C/h2o/CMakeLists.txt index 2bc33436366..d5062f2b26d 100644 --- a/frameworks/C/h2o/CMakeLists.txt +++ b/frameworks/C/h2o/CMakeLists.txt @@ -1,5 +1,6 @@ cmake_minimum_required(VERSION 3.18.0) -project(h2o_app) +project(h2o-app) +find_library(BPF_LIB bpf REQUIRED) find_library(CRYPTO_LIB crypto REQUIRED) find_library(H2O_LIB h2o-evloop REQUIRED) find_library(MUSTACHE_C_LIB mustache_c REQUIRED) @@ -8,27 +9,56 @@ find_library(PQ_LIB pq REQUIRED) find_library(SSL_LIB ssl REQUIRED) find_library(YAJL_LIB yajl REQUIRED) find_library(Z_LIB z REQUIRED) +find_path(ASM_INCLUDE asm/types.h REQUIRED) +find_path(BPF_INCLUDE bpf/libbpf.h REQUIRED) find_path(H2O_INCLUDE h2o.h REQUIRED) find_path(MUSTACHE_C_INCLUDE mustache.h REQUIRED) find_path(NUMA_INCLUDE numaif.h REQUIRED) find_path(OPENSSL_INCLUDE openssl/ssl.h REQUIRED) find_path(PQ_INCLUDE postgresql/libpq-fe.h REQUIRED) find_path(YAJL_INCLUDE yajl/yajl_gen.h REQUIRED) -include_directories(src ${H2O_INCLUDE} ${MUSTACHE_C_INCLUDE} ${NUMA_INCLUDE} ${OPENSSL_INCLUDE}) -include_directories(${PQ_INCLUDE} ${YAJL_INCLUDE}) +find_program(BPFTOOL_BIN bpftool REQUIRED) +find_program(CLANG_BIN clang REQUIRED) +include_directories(src ${CMAKE_BINARY_DIR} ${BPF_INCLUDE} ${H2O_INCLUDE} ${MUSTACHE_C_INCLUDE}) +include_directories(${NUMA_INCLUDE} ${OPENSSL_INCLUDE} ${PQ_INCLUDE} ${YAJL_INCLUDE}) set(CMAKE_C_STANDARD 11) set(CMAKE_C_STANDARD_REQUIRED ON) add_compile_definitions(H2O_USE_LIBUV=0) -set(COMMON_OPTIONS -flto -pthread) -add_compile_options(-pedantic -Wall -Wextra ${COMMON_OPTIONS}) +set(COMMON_OPTIONS -flto=auto -pthread) +set(WARNING_OPTIONS -pedantic -Wall -Wextra) +add_compile_options(${COMMON_OPTIONS} ${WARNING_OPTIONS}) set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_FORTIFY_SOURCE=2") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O3") set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -O3") -file(GLOB_RECURSE SOURCES "src/*.c") -add_executable(${PROJECT_NAME} ${SOURCES}) +add_custom_command( + OUTPUT ${CMAKE_BINARY_DIR}/socket_load_balancer.h + COMMAND ${CLANG_BIN} + -c + -DNDEBUG + -g + -I ${ASM_INCLUDE} + -I ${BPF_INCLUDE} + -mcpu=v3 + -o ${CMAKE_BINARY_DIR}/socket_load_balancer.o + -O3 + -std=gnu11 + -target bpf + ${WARNING_OPTIONS} + ${CMAKE_CURRENT_SOURCE_DIR}/src/bpf/socket_load_balancer.c + COMMAND ${BPFTOOL_BIN} gen skeleton ${CMAKE_BINARY_DIR}/socket_load_balancer.o > + ${CMAKE_BINARY_DIR}/socket_load_balancer.h + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/src/bpf/socket_load_balancer.c + VERBATIM) +add_custom_target( + generated_headers + DEPENDS ${CMAKE_BINARY_DIR}/socket_load_balancer.h) +file(GLOB_RECURSE HANDLER_SOURCES "src/handlers/*.c") +file(GLOB SOURCES "src/*.c") +add_executable(${PROJECT_NAME} ${HANDLER_SOURCES} ${SOURCES}) +add_dependencies(${PROJECT_NAME} generated_headers) target_link_libraries(${PROJECT_NAME} ${COMMON_OPTIONS}) -target_link_libraries(${PROJECT_NAME} ${H2O_LIB} m ${MUSTACHE_C_LIB} ${NUMA_LIB} ${PQ_LIB}) -target_link_libraries(${PROJECT_NAME} ${SSL_LIB} ${CRYPTO_LIB} ${YAJL_LIB} ${Z_LIB}) +target_link_libraries(${PROJECT_NAME} ${BPF_LIB} ${H2O_LIB} m ${MUSTACHE_C_LIB} ${NUMA_LIB}) +target_link_libraries(${PROJECT_NAME} ${PQ_LIB} ${SSL_LIB} ${CRYPTO_LIB} ${YAJL_LIB} ${Z_LIB}) install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION bin) file(GLOB TEMPLATES "template/*") install(FILES ${TEMPLATES} DESTINATION share/${PROJECT_NAME}/template) diff --git a/frameworks/C/h2o/README.md b/frameworks/C/h2o/README.md index 1bb77b677c2..85fd65c2bfd 100644 --- a/frameworks/C/h2o/README.md +++ b/frameworks/C/h2o/README.md @@ -1,13 +1,22 @@ -# h2o +# h2o-app This is a framework implementation using the [H2O](https://h2o.examp1e.net) HTTP server. It builds directly on top of `libh2o` instead of running the standalone server. ## Requirements -[CMake](https://cmake.org), [H2O](https://h2o.examp1e.net), [libpq](https://www.postgresql.org), -[mustache-c](https://github.com/x86-64/mustache-c), [numactl](https://github.com/numactl/numactl), -[OpenSSL](https://www.openssl.org), [YAJL](https://lloyd.github.io/yajl) +[bpftool](https://bpftool.dev/), +[Clang](https://clang.llvm.org/), +[CMake](https://cmake.org/), +[GNU C Library](https://www.gnu.org/software/libc), +[H2O](https://h2o.examp1e.net/), +[libbpf](https://github.com/libbpf/libbpf), +[libpq](https://www.postgresql.org/), +[Linux](https://kernel.org/), +[mustache-c](https://github.com/x86-64/mustache-c), +[numactl](https://github.com/numactl/numactl), +[OpenSSL](https://www.openssl.org/), +[YAJL](https://lloyd.github.io/yajl) ## Test implementations @@ -30,4 +39,4 @@ options respectively. ## Contact -Anton Kirilov +Anton Kirilov diff --git a/frameworks/C/h2o/benchmark_config.json b/frameworks/C/h2o/benchmark_config.json index 1e222e90ce8..4fc6065316e 100644 --- a/frameworks/C/h2o/benchmark_config.json +++ b/frameworks/C/h2o/benchmark_config.json @@ -1,5 +1,6 @@ { "framework": "h2o", + "maintainers": ["volyrique"], "tests": [{ "default": { "json_url": "/json", diff --git a/frameworks/C/h2o/h2o.dockerfile b/frameworks/C/h2o/h2o.dockerfile index 8a04c410cac..d6713a3e688 100644 --- a/frameworks/C/h2o/h2o.dockerfile +++ b/frameworks/C/h2o/h2o.dockerfile @@ -1,73 +1,64 @@ -ARG UBUNTU_VERSION=22.04 +ARG UBUNTU_VERSION=25.10 -ARG H2O_APP_PREFIX=/opt/h2o_app +ARG H2O_APP_PREFIX=/opt/h2o-app -FROM "ubuntu:${UBUNTU_VERSION}" AS compile +FROM "buildpack-deps:${UBUNTU_VERSION}" AS compile +RUN echo "[timing] Installing system packages: $(date)" ARG DEBIAN_FRONTEND=noninteractive -RUN apt-get -yqq update && \ - apt-get -yqq install \ +RUN apt-get install \ + --no-install-recommends \ + -qqUy \ autoconf \ + automake \ bison \ + bpftool \ + clang \ cmake \ curl \ flex \ - g++ \ + gcc \ + libbpf-dev \ libbrotli-dev \ libcap-dev \ - libicu-dev \ libnuma-dev \ - libreadline-dev \ + libpq-dev \ libssl-dev \ libtool \ + liburing-dev \ libuv1-dev \ - libwslay-dev \ libyajl-dev \ libz-dev \ make \ - ninja-build \ - patch \ pkg-config \ + ruby \ systemtap-sdt-dev -ARG H2O_VERSION=13ba727ad12dfb2338165d2bcfb2136457e33c8a +RUN echo "[timing] Building H2O: $(date)" +ARG H2O_VERSION=3b9b6a53cac8bcc6a25fb28df81ad295fc5f9402 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_AR=/usr/bin/gcc-ar \ - -DCMAKE_C_FLAGS="-flto -march=native -mtune=native" \ - -DCMAKE_RANLIB=/usr/bin/gcc-ranlib \ - -G Ninja \ + -DCMAKE_C_FLAGS="-flto=auto -march=native -mtune=native" \ + -DWITH_MRUBY=on \ -S . && \ cmake --build build -j && \ - cmake --install build && \ - cp -a deps/picotls/include/picotls* deps/quicly/include/quicly* /usr/local/include + cmake --install build +RUN echo "[timing] Building mustache-c: $(date)" ARG MUSTACHE_C_REVISION=7fe52392879d0188c172d94bb4fde7c513d6b929 WORKDIR /tmp/mustache-c-build RUN curl -LSs "https://github.com/x86-64/mustache-c/archive/${MUSTACHE_C_REVISION}.tar.gz" | \ tar --strip-components=1 -xz && \ - CFLAGS="-flto -march=native -mtune=native -O3" ./autogen.sh && \ + CFLAGS="-flto=auto -march=native -mtune=native -O3 -Wno-implicit-function-declaration" \ + ./autogen.sh && \ make -j "$(nproc)" install -ARG POSTGRESQL_VERSION=c1ec02be1d79eac95160dea7ced32ace84664617 - -WORKDIR /tmp/postgresql-build -RUN curl -LSs "https://github.com/postgres/postgres/archive/${POSTGRESQL_VERSION}.tar.gz" | \ - tar --strip-components=1 -xz && \ - curl -LSs "https://www.postgresql.org/message-id/attachment/152078/v5-0001-Add-PQsendPipelineSync-to-libpq.patch" | \ - patch -Np1 && \ - CFLAGS="-flto -march=native -mtune=native -O3" ./configure \ - --includedir=/usr/local/include/postgresql \ - --prefix=/usr/local \ - --with-ssl=openssl && \ - make -j "$(nproc)" -C src/include install && \ - make -j "$(nproc)" -C src/interfaces/libpq install - +RUN echo "[timing] Building h2o-app: $(date)" ARG H2O_APP_PREFIX WORKDIR /tmp/build COPY CMakeLists.txt ../ @@ -77,36 +68,41 @@ RUN cmake \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_C_FLAGS="-march=native -mtune=native" \ -DCMAKE_INSTALL_PREFIX="${H2O_APP_PREFIX}" \ - -G Ninja \ -S .. && \ cmake --build . -j && \ cmake --install . +RUN echo "[timing] Finished compiling: $(date)" FROM "ubuntu:${UBUNTU_VERSION}" +RUN echo "[timing] Installing final system packages: $(date)" ARG DEBIAN_FRONTEND=noninteractive -RUN apt-get -yqq update && \ - apt-get -yqq install \ +RUN apt-get install \ + --no-install-recommends \ + -qqUy \ + libbpf1 \ libnuma1 \ + libpq5 \ + liburing2 \ libyajl2 +RUN echo "[timing] Copying h2o-app to its final location: $(date)" ARG H2O_APP_PREFIX COPY --from=compile "${H2O_APP_PREFIX}" "${H2O_APP_PREFIX}/" COPY --from=compile /usr/local/lib/libmustache_c.so "${H2O_APP_PREFIX}/lib/" -COPY --from=compile /usr/local/lib/libpq.so.5.17 "${H2O_APP_PREFIX}/lib/libpq.so.5" ENV LD_LIBRARY_PATH="${H2O_APP_PREFIX}/lib" EXPOSE 8080 ARG BENCHMARK_ENV ARG TFB_TEST_DATABASE ARG TFB_TEST_NAME +RUN echo "[timing] Running h2o-app: $(date)" CMD ["taskset", \ "-c", \ "0", \ - "/opt/h2o_app/bin/h2o_app", \ + "/opt/h2o-app/bin/h2o-app", \ "-a20", \ "-d", \ "dbname=hello_world host=tfb-database password=benchmarkdbpass sslmode=disable user=benchmarkdbuser", \ - "-e256", \ "-f", \ - "/opt/h2o_app/share/h2o_app/template", \ + "/opt/h2o-app/share/h2o-app/template", \ "-m1"] diff --git a/frameworks/C/h2o/src/bpf/socket_load_balancer.c b/frameworks/C/h2o/src/bpf/socket_load_balancer.c new file mode 100644 index 00000000000..ff342947617 --- /dev/null +++ b/frameworks/C/h2o/src/bpf/socket_load_balancer.c @@ -0,0 +1,58 @@ +/* + Copyright (c) 2025 Anton Valentinov Kirilov + + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + associated documentation files (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, publish, distribute, + sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT + OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +// TODO: Switch to the standard atomics () after +// the system header file mess gets sorted for eBPF. +#include +#include +#include +#include + +// We need a finite number of iterations to keep the eBPF verifier happy. +#define MAX_ITERATIONS 42 + +static size_t thread_idx; +size_t thread_num = 1; + +SEC("socket") int socket_load_balancer(void *skb) +{ + (void) skb; + + // TODO: Use __atomic_load_n() after LLVM starts supporting it for eBPF. + size_t idx = *(const volatile size_t *) &thread_idx; + int ret = thread_num; + + __atomic_thread_fence(__ATOMIC_RELAXED); + + for (size_t i = 0; i < MAX_ITERATIONS; i++) { + const size_t new_idx = (idx + 1) % thread_num; + + if (__atomic_compare_exchange_n(&thread_idx, + &idx, + new_idx, + false, + __ATOMIC_RELAXED, + __ATOMIC_RELAXED)) { + ret = idx; + break; + } + } + + return ret; +} diff --git a/frameworks/C/h2o/src/database.c b/frameworks/C/h2o/src/database.c index 59042b1dec3..fd5399d343c 100644 --- a/frameworks/C/h2o/src/database.c +++ b/frameworks/C/h2o/src/database.c @@ -56,8 +56,8 @@ typedef struct { typedef struct { list_t l; - const char *name; - const char *query; + char *name; + char *query; } prepared_statement_t; static h2o_socket_t *create_socket(int sd, h2o_loop_t *loop); @@ -75,7 +75,7 @@ static void on_database_write_ready(h2o_socket_t *sock, const char *err); static void on_process_queries(void *arg); static void poll_database_connection(h2o_socket_t *sock, const char *err); static void prepare_statements(db_conn_t *conn); -static void process_queries(db_conn_t *conn, bool removed); +static void process_queries(db_conn_pool_t *pool); static void remove_connection(db_conn_t *conn); static void start_database_connect(db_conn_pool_t *pool, db_conn_t *conn); @@ -186,7 +186,7 @@ static int flush_connection(h2o_socket_cb cb, db_conn_t *conn) if (send_status < 0) LIBRARY_ERROR("PQflush", PQerrorMessage(conn->conn)); - else if (send_status) + else if (send_status && !h2o_socket_is_writing(conn->sock)) h2o_socket_notify_write(conn->sock, cb); return send_status < 0; @@ -237,7 +237,10 @@ static void on_database_connect_read_ready(h2o_socket_t *sock, const char *err) h2o_timer_unlink(&conn->timer); h2o_socket_read_stop(conn->sock); h2o_socket_read_start(conn->sock, on_database_read_ready); - process_queries(conn, true); + *conn->pool->conn.tail = &conn->l; + conn->pool->conn.tail = &conn->l.next; + conn->l.next = NULL; + process_queries(conn->pool); return; default: LIBRARY_ERROR("PQresultStatus", PQresultErrorMessage(result)); @@ -370,7 +373,13 @@ static void on_database_read_ready(h2o_socket_t *sock, const char *err) for (PGnotify *notify = PQnotifies(conn->conn); notify; notify = PQnotifies(conn->conn)) PQfreemem(notify); - process_queries(conn, removed); + if (removed && conn->query_num) { + *conn->pool->conn.tail = &conn->l; + conn->pool->conn.tail = &conn->l.next; + conn->l.next = NULL; + } + + process_queries(conn->pool); } static void on_database_timeout(h2o_timer_t *timer) @@ -405,20 +414,83 @@ static void on_database_write_ready(h2o_socket_t *sock, const char *err) static void on_process_queries(void *arg) { + list_t *iter = NULL; db_conn_pool_t * const pool = arg; + size_t query_num = 0; - while (pool->queries.head && pool->conn) { - db_conn_t * const conn = H2O_STRUCT_FROM_MEMBER(db_conn_t, l, pool->conn); + while (pool->queries.head && pool->conn.head) { + db_conn_t * const conn = H2O_STRUCT_FROM_MEMBER(db_conn_t, l, pool->conn.head); + db_query_param_t * const param = H2O_STRUCT_FROM_MEMBER(db_query_param_t, + l, + conn->pool->queries.head); - pool->conn = conn->l.next; assert(conn->query_num); - process_queries(conn, true); + assert(pool->query_num < pool->config->max_query_num); + pool->conn.head = conn->l.next; + pool->queries.head = param->l.next; + + if (!pool->conn.head) { + assert(pool->conn.tail == &conn->l.next); + pool->conn.tail = &pool->conn.head; + } + + if (++pool->query_num == pool->config->max_query_num) { + assert(!pool->queries.head); + assert(pool->queries.tail == ¶m->l.next); + pool->queries.tail = &pool->queries.head; + } + + if (do_execute_query(conn, param)) { + param->on_error(param, DB_ERROR); + on_database_error(conn, DB_ERROR); + } + else { + query_num++; + + if (conn->query_num) { + *pool->conn.tail = &conn->l; + pool->conn.tail = &conn->l.next; + conn->l.next = NULL; + } + else { + conn->l.next = iter; + iter = &conn->l; + } + } } - if (pool->queries.head && pool->conn_num) - start_database_connect(pool, NULL); + if (iter) + do { + db_conn_t * const conn = H2O_STRUCT_FROM_MEMBER(db_conn_t, l, iter); + + iter = conn->l.next; + + if (flush_connection(on_database_write_ready, conn)) + on_database_error(conn, DB_ERROR); + } while (iter); + pool->conn.tail = &pool->conn.head; pool->process_queries = false; + query_num += pool->config->max_query_num - pool->query_num; + + for (iter = pool->conn.head; iter;) { + db_conn_t * const conn = H2O_STRUCT_FROM_MEMBER(db_conn_t, l, iter); + + iter = conn->l.next; + + if (flush_connection(on_database_write_ready, conn)) { + *pool->conn.tail = iter; + on_database_error(conn, DB_ERROR); + } + else + pool->conn.tail = &conn->l.next; + } + + const size_t conn_num = pool->config->max_db_conn_num - pool->conn_num; + + if (query_num > conn_num) + for (query_num -= conn_num; pool->conn_num && query_num; query_num--) + start_database_connect(pool, NULL); } static void poll_database_connection(h2o_socket_t *sock, const char *err) @@ -536,54 +608,44 @@ static void prepare_statements(db_conn_t *conn) } else { h2o_socket_read_start(conn->sock, on_database_read_ready); - process_queries(conn, true); + *conn->pool->conn.tail = &conn->l; + conn->pool->conn.tail = &conn->l.next; + conn->l.next = NULL; + process_queries(conn->pool); } } -static void process_queries(db_conn_t *conn, bool removed) +static void process_queries(db_conn_pool_t *pool) { - const bool flush = conn->query_num && conn->pool->queries.head; - - while (conn->query_num && conn->pool->queries.head) { - db_query_param_t * const param = H2O_STRUCT_FROM_MEMBER(db_query_param_t, - l, - conn->pool->queries.head); - - if (++conn->pool->query_num == conn->pool->config->max_query_num) { - assert(conn->pool->queries.tail == ¶m->l.next); - conn->pool->queries.tail = &conn->pool->queries.head; - } - - conn->pool->queries.head = param->l.next; - - if (do_execute_query(conn, param)) { - param->on_error(param, DB_ERROR); - on_database_error(conn, DB_ERROR); - return; - } - } - - if (flush && flush_connection(on_database_write_ready, conn)) - on_database_error(conn, DB_ERROR); - else if (conn->query_num && removed) { - conn->l.next = conn->pool->conn; - conn->pool->conn = &conn->l; + if (!pool->process_queries && pool->queries.head) { + task_message_t * const msg = h2o_mem_alloc(sizeof(*msg)); + + assert(pool->query_num < pool->config->max_query_num); + memset(msg, 0, sizeof(*msg)); + msg->arg = pool; + msg->super.type = TASK; + msg->task = on_process_queries; + pool->process_queries = true; + send_local_message(&msg->super, pool->local_messages); } - else if (!conn->query_num && !removed) - // This call should not be problematic, assuming a relatively low number of connections. - remove_connection(conn); } static void remove_connection(db_conn_t *conn) { - list_t *iter = conn->pool->conn; - list_t **prev = &conn->pool->conn; + list_t *iter = conn->pool->conn.head; + list_t **prev = &conn->pool->conn.head; for (; iter && iter != &conn->l; iter = iter->next) prev = &iter->next; - if (iter) + if (iter) { *prev = iter->next; + + if (!conn->pool->conn.head) { + assert(conn->pool->conn.tail == &iter->next); + conn->pool->conn.tail = &conn->pool->conn.head; + } + } } static void start_database_connect(db_conn_pool_t *pool, db_conn_t *conn) @@ -651,8 +713,8 @@ void add_prepared_statement(const char *name, const char *query, list_t **prepar memset(p, 0, sizeof(*p)); p->l.next = *prepared_statements; - p->name = name; - p->query = query; + p->name = h2o_strdup(NULL, name, SIZE_MAX).base; + p->query = h2o_strdup(NULL, query, SIZE_MAX).base; *prepared_statements = &p->l; } @@ -661,37 +723,15 @@ int execute_database_query(db_conn_pool_t *pool, db_query_param_t *param) int ret = 1; if (pool->query_num) { - if (pool->conn) { - // Delay sending the database queries to the server, so that if there is a rapid - // succession of calls to this function, all resultant queries would be inserted - // into a command pipeline with a smaller number of system calls. - if (!pool->process_queries) { - task_message_t * const msg = h2o_mem_alloc(sizeof(*msg)); - - memset(msg, 0, sizeof(*msg)); - msg->arg = pool; - msg->super.type = TASK; - msg->task = on_process_queries; - send_local_message(&msg->super, pool->local_messages); - pool->process_queries = true; - } - - ret = 0; - } - else { - if (pool->conn_num) - start_database_connect(pool, NULL); - - if (pool->conn_num < pool->config->max_db_conn_num && pool->query_num) - ret = 0; - } - - if (!ret) { - param->l.next = NULL; - *pool->queries.tail = ¶m->l; - pool->queries.tail = ¶m->l.next; - pool->query_num--; - } + // Delay sending the database queries to the server, so that if there is a rapid + // succession of calls to this function, all resultant queries would be inserted + // into a command pipeline with a smaller number of system calls. + param->l.next = NULL; + *pool->queries.tail = ¶m->l; + pool->queries.tail = ¶m->l.next; + pool->query_num--; + process_queries(pool); + ret = 0; } return ret; @@ -704,9 +744,9 @@ void free_database_connection_pool(db_conn_pool_t *pool) size_t num = 0; - if (pool->conn) + if (pool->conn.head) do { - db_conn_t * const conn = H2O_STRUCT_FROM_MEMBER(db_conn_t, l, pool->conn); + db_conn_t * const conn = H2O_STRUCT_FROM_MEMBER(db_conn_t, l, pool->conn.head); assert(!conn->queries.head); assert(conn->query_num == pool->config->max_pipeline_query_num); @@ -715,10 +755,10 @@ void free_database_connection_pool(db_conn_pool_t *pool) h2o_socket_read_stop(conn->sock); h2o_socket_close(conn->sock); PQfinish(conn->conn); - pool->conn = pool->conn->next; - free(conn); + pool->conn.head = conn->l.next; num++; - } while (pool->conn); + free(conn); + } while (pool->conn.head); assert(num + pool->conn_num == pool->config->max_db_conn_num); } @@ -732,6 +772,7 @@ void initialize_database_connection_pool(const char *conninfo, { memset(pool, 0, sizeof(*pool)); pool->config = config; + pool->conn.tail = &pool->conn.head; pool->conninfo = conninfo ? conninfo : ""; pool->local_messages = local_messages; pool->loop = loop; @@ -750,6 +791,8 @@ void remove_prepared_statements(list_t *prepared_statements) prepared_statements); prepared_statements = prepared_statements->next; + free(p->name); + free(p->query); free(p); } while (prepared_statements); } diff --git a/frameworks/C/h2o/src/database.h b/frameworks/C/h2o/src/database.h index b35d3805c3f..160e2ea9abc 100644 --- a/frameworks/C/h2o/src/database.h +++ b/frameworks/C/h2o/src/database.h @@ -49,10 +49,10 @@ typedef struct db_query_param_t { on_result_t on_result; void (*on_timeout)(struct db_query_param_t *); const char *command; - const char * const *paramValues; - const int *paramLengths; const int *paramFormats; + const int *paramLengths; const Oid *paramTypes; + const char * const *paramValues; size_t nParams; uint_fast32_t flags; int resultFormat; @@ -60,7 +60,7 @@ typedef struct db_query_param_t { typedef struct { const struct config_t *config; - list_t *conn; + queue_t conn; const char *conninfo; h2o_linklist_t *local_messages; h2o_loop_t *loop; diff --git a/frameworks/C/h2o/src/event_loop.c b/frameworks/C/h2o/src/event_loop.c index d5e138348de..6e95bea496e 100644 --- a/frameworks/C/h2o/src/event_loop.c +++ b/frameworks/C/h2o/src/event_loop.c @@ -32,22 +32,30 @@ #include #include #include +#include #include #include "error.h" #include "event_loop.h" #include "global_data.h" #include "thread.h" +#include "utility.h" +#define CONN_NUM_SAMPLE_PERIOD 2500 #define DEFAULT_TCP_FASTOPEN_QUEUE_LEN 4096 static void accept_connection(h2o_socket_t *listener, const char *err); static void accept_http_connection(h2o_socket_t *listener, const char *err); -static int get_listener_socket(const char *bind_address, uint16_t port); +static int get_listener_socket(bool is_main_thread, + int bpf_fd, + const char *bind_address, + uint16_t port); static void on_close_connection(void *data); static void process_messages(h2o_multithread_receiver_t *receiver, h2o_linklist_t *messages); static void shutdown_server(h2o_socket_t *listener, const char *err); -static void start_accept_polling(const config_t *config, +static void start_accept_polling(bool is_main_thread, + int bpf_fd, + const config_t *config, h2o_socket_cb accept_cb, bool is_https, event_loop_t *loop); @@ -72,6 +80,7 @@ static void accept_connection(h2o_socket_t *listener, const char *err) if (!sock) break; + ctx->event_loop.accepted_conn_num++; ctx->event_loop.conn_num++; sock->on_close.cb = on_close_connection; sock->on_close.data = &ctx->event_loop.conn_num; @@ -94,7 +103,10 @@ static void accept_http_connection(h2o_socket_t *listener, const char *err) ctx->event_loop.h2o_accept_ctx.ssl_ctx = ssl_ctx; } -static int get_listener_socket(const char *bind_address, uint16_t port) +static int get_listener_socket(bool is_main_thread, + int bpf_fd, + const char *bind_address, + uint16_t port) { int ret = -1; char buf[16]; @@ -144,6 +156,15 @@ static int get_listener_socket(const char *bind_address, uint16_t port) LOCAL_CHECK_ERRNO(setsockopt, s, IPPROTO_TCP, TCP_FASTOPEN, &option, sizeof(option)); LOCAL_CHECK_ERRNO(bind, s, iter->ai_addr, iter->ai_addrlen); LOCAL_CHECK_ERRNO(listen, s, INT_MAX); + + if (is_main_thread && bpf_fd >= 0) + LOCAL_CHECK_ERRNO(setsockopt, + s, + SOL_SOCKET, + SO_ATTACH_REUSEPORT_EBPF, + &bpf_fd, + sizeof(bpf_fd)); + ret = s; break; @@ -252,16 +273,17 @@ static void shutdown_server(h2o_socket_t *listener, const char *err) } } -static void start_accept_polling(const config_t *config, +static void start_accept_polling(bool is_main_thread, + int bpf_fd, + const config_t *config, h2o_socket_cb accept_cb, bool is_https, event_loop_t *loop) { - const int listener_sd = get_listener_socket(config->bind_address, + const int listener_sd = get_listener_socket(is_main_thread, + bpf_fd, + config->bind_address, is_https ? config->https_port : config->port); - // Let all the threads race to call accept() on the socket; since the latter is - // non-blocking, that will virtually act as load balancing, and SO_REUSEPORT - // will make it efficient. h2o_socket_t * const h2o_socket = h2o_evloop_socket_create(loop->h2o_ctx.loop, listener_sd, H2O_SOCKET_FLAG_DONT_READ); @@ -277,11 +299,36 @@ static void start_accept_polling(const config_t *config, void event_loop(struct thread_context_t *ctx) { + uint64_t last_sample = 0; + while (!ctx->shutdown || ctx->event_loop.conn_num) { h2o_evloop_run(ctx->event_loop.h2o_ctx.loop, INT32_MAX); process_messages(&ctx->global_thread_data->h2o_receiver, &ctx->event_loop.local_messages); + + const uint64_t now = h2o_now(ctx->event_loop.h2o_ctx.loop); + + if (now - last_sample > CONN_NUM_SAMPLE_PERIOD || last_sample > now) { + const size_t i = ctx->event_loop.conn_num_sample_idx; + + ctx->event_loop.conn_num_sample[i] = ctx->event_loop.conn_num; + ctx->event_loop.conn_num_sample_idx = + (i + 1) % ARRAY_SIZE(ctx->event_loop.conn_num_sample); + last_sample = now; + } } + + flockfile(stdout); + printf("Thread %ld statistics:\nAccepted connections: %zu\nConnection number samples: %zu", + syscall(SYS_gettid), + ctx->event_loop.accepted_conn_num, + *ctx->event_loop.conn_num_sample); + + for (size_t i = 1; i < ARRAY_SIZE(ctx->event_loop.conn_num_sample); i++) + printf(",%zu", ctx->event_loop.conn_num_sample[i]); + + putc_unlocked('\n', stdout); + funlockfile(stdout); } void free_event_loop(event_loop_t *event_loop, h2o_multithread_receiver_t *h2o_receiver) @@ -316,13 +363,18 @@ void initialize_event_loop(bool is_main_thread, if (global_data->ssl_ctx) { loop->h2o_accept_ctx.ssl_ctx = global_data->ssl_ctx; - start_accept_polling(config, accept_connection, true, loop); + start_accept_polling(is_main_thread, + global_data->bpf_fd, + config, + accept_connection, + true, + loop); // Assume that the majority of the connections use HTTPS, // so HTTP can take a few extra operations. accept_cb = accept_http_connection; } - start_accept_polling(config, accept_cb, false, loop); + start_accept_polling(is_main_thread, global_data->bpf_fd, config, accept_cb, false, loop); h2o_multithread_register_receiver(loop->h2o_ctx.queue, h2o_receiver, process_messages); diff --git a/frameworks/C/h2o/src/event_loop.h b/frameworks/C/h2o/src/event_loop.h index cff091154c7..41a1f3b920f 100644 --- a/frameworks/C/h2o/src/event_loop.h +++ b/frameworks/C/h2o/src/event_loop.h @@ -27,6 +27,8 @@ #include "global_data.h" +#define CONN_NUM_SAMPLES 512 + typedef enum { SHUTDOWN, TASK @@ -41,6 +43,9 @@ typedef struct { h2o_accept_ctx_t h2o_accept_ctx; h2o_context_t h2o_ctx; h2o_linklist_t local_messages; + size_t accepted_conn_num; + size_t conn_num_sample[CONN_NUM_SAMPLES]; + size_t conn_num_sample_idx; } event_loop_t; typedef struct { diff --git a/frameworks/C/h2o/src/global_data.h b/frameworks/C/h2o/src/global_data.h index 156efa8a6df..74e986cbcbf 100644 --- a/frameworks/C/h2o/src/global_data.h +++ b/frameworks/C/h2o/src/global_data.h @@ -30,6 +30,7 @@ #include "handlers/request_handler_data.h" struct global_thread_data_t; +struct socket_load_balancer; struct thread_context_t; typedef struct config_t { @@ -55,8 +56,10 @@ typedef struct { h2o_logger_t *file_logger; struct global_thread_data_t *global_thread_data; h2o_socket_t *signals; + struct socket_load_balancer *socket_load_balancer; SSL_CTX *ssl_ctx; size_t memory_alignment; + int bpf_fd; int signal_fd; h2o_buffer_prototype_t buffer_prototype; h2o_globalconf_t h2o_config; diff --git a/frameworks/C/h2o/src/handlers/world.c b/frameworks/C/h2o/src/handlers/world.c index 0a7aaf1d813..84088a25d42 100644 --- a/frameworks/C/h2o/src/handlers/world.c +++ b/frameworks/C/h2o/src/handlers/world.c @@ -57,17 +57,18 @@ // MAX_UPDATE_QUERY_LEN must be updated whenever UPDATE_QUERY_BEGIN, UPDATE_QUERY_ELEM, // UPDATE_QUERY_MIDDLE, UPDATE_QUERY_ELEM2, and UPDATE_QUERY_END are changed. #define UPDATE_QUERY_BEGIN "UPDATE " WORLD_TABLE_NAME " SET randomNumber = CASE id " -#define UPDATE_QUERY_ELEM "WHEN %" PRIu32 " THEN %" PRIu32 " " -#define UPDATE_QUERY_MIDDLE "ELSE randomNumber END WHERE id IN (%" PRIu32 -#define UPDATE_QUERY_ELEM2 ",%" PRIu32 +#define UPDATE_QUERY_ELEM "WHEN $%zu::integer THEN $%zu::integer " +#define UPDATE_QUERY_MIDDLE "ELSE randomNumber END WHERE id IN ($1::integer" +#define UPDATE_QUERY_ELEM2 ",$%zu::integer" #define UPDATE_QUERY_END ");" #define MAX_UPDATE_QUERY_LEN(n) \ (sizeof(UPDATE_QUERY_BEGIN) + sizeof(UPDATE_QUERY_MIDDLE) + \ sizeof(UPDATE_QUERY_END) - 1 - sizeof(UPDATE_QUERY_ELEM2) + \ (n) * (sizeof(UPDATE_QUERY_ELEM) - 1 + sizeof(UPDATE_QUERY_ELEM2) - 1 + \ - 3 * (sizeof(MKSTR(MAX_ID)) - 1) - 3 * (sizeof(PRIu32) - 1) - 3)) + 3 * sizeof(MKSTR(MAX_QUERIES)) - 3 * (sizeof("%zu") - 1))) +#define UPDATE_QUERY_NAME_PREFIX WORLD_TABLE_NAME "Update" #define USE_CACHE 2 #define WORLD_QUERY "SELECT * FROM " WORLD_TABLE_NAME " WHERE id = $1::integer;" @@ -236,9 +237,11 @@ static int do_multiple_queries(bool do_update, bool use_cache, h2o_req_t *req) const size_t num_query = get_query_number(req); - // MAX_QUERIES is a relatively small number, so assume no overflow in the following - // arithmetic operations. - assert(num_query <= MAX_QUERIES); + // MAX_QUERIES is a relatively small number, say less than or equal to UINT16_MAX, so assume no + // unsigned overflow in the following arithmetic operations. + static_assert(MAX_QUERIES <= UINT16_MAX, + "potential out-of-bounds memory accesses in the following code"); + assert(num_query && num_query <= MAX_QUERIES); size_t base_size = offsetof(multiple_query_ctx_t, res) + num_query * sizeof(query_result_t); @@ -246,16 +249,29 @@ static int do_multiple_queries(bool do_update, bool use_cache, h2o_req_t *req) base_size = base_size * _Alignof(query_param_t); const config_t * const config = ctx->global_thread_data->config; - const size_t num_query_in_progress = - MIN(num_query, config->max_db_conn_num * config->max_pipeline_query_num); + size_t num_query_in_progress = config->max_db_conn_num * config->max_pipeline_query_num; + + if (num_query_in_progress < config->max_db_conn_num || + num_query_in_progress < config->max_pipeline_query_num) + num_query_in_progress = num_query; + else + num_query_in_progress = MIN(num_query, num_query_in_progress); + + assert(num_query_in_progress); + size_t sz = base_size + num_query_in_progress * sizeof(query_param_t); if (do_update) { - const size_t reuse_size = (num_query_in_progress - 1) * sizeof(query_param_t); - const size_t update_query_len = MAX_UPDATE_QUERY_LEN(num_query); + size_t s = base_size + sizeof(query_param_t); + + s = (s + _Alignof(const char *) - 1) / _Alignof(const char *); + s = s * _Alignof(const char *) + 2 * num_query * sizeof(const char *); + s = (s + _Alignof(int) - 1) / _Alignof(int); + s = s * _Alignof(int) + 4 * num_query * sizeof(int); + s += sizeof(UPDATE_QUERY_NAME_PREFIX MKSTR(MAX_QUERIES)); - if (update_query_len > reuse_size) - sz += update_query_len - reuse_size; + if (s > sz) + sz = s; } multiple_query_ctx_t * const query_ctx = h2o_mem_alloc(sz); @@ -324,65 +340,57 @@ static int do_multiple_queries(bool do_update, bool use_cache, h2o_req_t *req) static void do_updates(multiple_query_ctx_t *query_ctx) { - char *iter = (char *) (query_ctx->query_param + 1); - size_t sz = MAX_UPDATE_QUERY_LEN(query_ctx->num_result); - - // Sort the results to avoid database deadlock. - qsort(query_ctx->res, query_ctx->num_result, sizeof(*query_ctx->res), compare_items); - query_ctx->query_param->param.command = iter; - query_ctx->query_param->param.nParams = 0; - query_ctx->query_param->param.on_result = on_update_result; - query_ctx->query_param->param.paramFormats = NULL; - query_ctx->query_param->param.paramLengths = NULL; - query_ctx->query_param->param.paramValues = NULL; - query_ctx->query_param->param.flags = 0; - - int c = snprintf(iter, sz, UPDATE_QUERY_BEGIN); - - if ((size_t) c >= sz) - goto error; - - iter += c; - sz -= c; + size_t offset = + offsetof(multiple_query_ctx_t, res) + query_ctx->num_result * sizeof(*query_ctx->res); - for (size_t i = 0; i < query_ctx->num_result; i++) { - query_ctx->res[i].random_number = 1 + get_random_number(MAX_ID, - &query_ctx->ctx->random_seed); - c = snprintf(iter, - sz, - UPDATE_QUERY_ELEM, - query_ctx->res[i].id, - query_ctx->res[i].random_number); + offset = ((offset + _Alignof(query_param_t) - 1) / _Alignof(query_param_t)); + offset = offset * _Alignof(query_param_t) + sizeof(query_param_t); + offset = (offset + _Alignof(const char *) - 1) / _Alignof(const char *); + offset *= _Alignof(const char *); - if ((size_t) c >= sz) - goto error; + const char ** const paramValues = (const char **) ((char *) query_ctx + offset); + const size_t nParams = query_ctx->num_result * 2; - iter += c; - sz -= c; - } + offset += nParams * sizeof(*paramValues); + offset = (offset + _Alignof(int) - 1) / _Alignof(int); + offset *= _Alignof(int); - c = snprintf(iter, sz, UPDATE_QUERY_MIDDLE, query_ctx->res->id); + int * const paramFormats = (int *) ((char *) query_ctx + offset); + int * const paramLengths = paramFormats + nParams; + char * const command = (char *) (paramLengths + nParams); + const size_t command_size = + sizeof(UPDATE_QUERY_NAME_PREFIX MKSTR(MAX_QUERIES)) - sizeof(UPDATE_QUERY_NAME_PREFIX) + 1; + const int c = snprintf(command + sizeof(UPDATE_QUERY_NAME_PREFIX) - 1, + command_size, + "%zu", + query_ctx->num_result); - if ((size_t) c >= sz) + if ((size_t) c >= command_size) goto error; - iter += c; - sz -= c; - - for (size_t i = 1; i < query_ctx->num_result; i++) { - c = snprintf(iter, sz, UPDATE_QUERY_ELEM2, query_ctx->res[i].id); - - if ((size_t) c >= sz) - goto error; - - iter += c; - sz -= c; - } - - c = snprintf(iter, sz, UPDATE_QUERY_END); + memcpy(command, UPDATE_QUERY_NAME_PREFIX, sizeof(UPDATE_QUERY_NAME_PREFIX) - 1); + // Sort the results to avoid database deadlock. + qsort(query_ctx->res, query_ctx->num_result, sizeof(*query_ctx->res), compare_items); - if ((size_t) c >= sz) - goto error; + for (size_t i = 0; i < query_ctx->num_result; i++) { + query_ctx->res[i].id = htonl(query_ctx->res[i].id); + query_ctx->res[i].random_number = + htonl(1 + get_random_number(MAX_ID, &query_ctx->ctx->random_seed)); + paramFormats[2 * i] = 1; + paramFormats[2 * i + 1] = 1; + paramLengths[2 * i] = sizeof(query_ctx->res[i].id); + paramLengths[2 * i + 1] = sizeof(query_ctx->res[i].random_number); + paramValues[2 * i] = (const char *) &query_ctx->res[i].id; + paramValues[2 * i + 1] = (const char *) &query_ctx->res[i].random_number; + } + + query_ctx->query_param->param.command = command; + query_ctx->query_param->param.flags = IS_PREPARED; + query_ctx->query_param->param.nParams = nParams; + query_ctx->query_param->param.on_result = on_update_result; + query_ctx->query_param->param.paramFormats = paramFormats; + query_ctx->query_param->param.paramLengths = paramLengths; + query_ctx->query_param->param.paramValues = paramValues; if (execute_database_query(&query_ctx->ctx->request_handler_data.hello_world_db, &query_ctx->query_param->param)) { @@ -408,7 +416,7 @@ static void fetch_from_cache(uint64_t now, h2o_cache_ref_t * const r = h2o_cache_fetch(data->world_cache, now, key, 0); if (r) { - const uint32_t * const table = (const uint32_t *) r->value.base; + const uint16_t * const table = (const uint16_t *) r->value.base; for (size_t i = 0; i < query_ctx->num_query; i++) { const uint32_t id = query_ctx->res[i].id; @@ -432,7 +440,7 @@ static void fetch_from_cache(uint64_t now, memset(ctx, 0, sizeof(*ctx)); ctx->data = data; ctx->loop = query_ctx->ctx->event_loop.h2o_ctx.loop; - ctx->table.len = (MAX_ID + 1) * sizeof(uint32_t); + ctx->table.len = (MAX_ID + 1) * sizeof(uint16_t); ctx->table.base = h2o_mem_alloc(ctx->table.len); memset(ctx->table.base, 0, ctx->table.len); ctx->param.command = POPULATE_CACHE_QUERY; @@ -597,10 +605,11 @@ static result_return_t on_populate_cache_result(db_query_param_t *param, PGresul param, param); query_result_t r = {.id = 0}; - uint32_t * const table = (uint32_t *) query_ctx->table.base; + uint16_t * const table = (uint16_t *) query_ctx->table.base; for (size_t i = 0; i < num_rows; i++) { process_result(result, i, &r); + assert(r.random_number <= UINT16_MAX); table[r.id] = r.random_number; } @@ -717,8 +726,14 @@ static result_return_t on_update_result(db_query_param_t *param, PGresult *resul query_ctx->gen = get_json_generator(&query_ctx->ctx->json_generator, &query_ctx->ctx->json_generator_num); - if (query_ctx->gen) + if (query_ctx->gen) { + for (size_t i = 0; i < query_ctx->num_result; i++) { + query_ctx->res[i].id = ntohl(query_ctx->res[i].id); + query_ctx->res[i].random_number = ntohl(query_ctx->res[i].random_number); + } + serialize_items(query_ctx->res, query_ctx->num_result, &query_ctx->gen, query_ctx->req); + } else send_error(INTERNAL_SERVER_ERROR, REQ_ERROR, query_ctx->req); } @@ -878,6 +893,57 @@ void initialize_world_handlers(h2o_hostconf_t *hostconf, h2o_access_log_filehandle_t *log_handle, request_handler_data_t *data) { + char name[sizeof(UPDATE_QUERY_NAME_PREFIX MKSTR(MAX_QUERIES))]; + char query[MAX_UPDATE_QUERY_LEN(MAX_QUERIES)]; + const size_t name_size = sizeof(name) - sizeof(UPDATE_QUERY_NAME_PREFIX) + 1; + + assert(sizeof(name) >= sizeof(UPDATE_QUERY_NAME_PREFIX)); + memcpy(name, UPDATE_QUERY_NAME_PREFIX, sizeof(UPDATE_QUERY_NAME_PREFIX) - 1); + assert(sizeof(query) >= sizeof(UPDATE_QUERY_BEGIN)); + memcpy(query, UPDATE_QUERY_BEGIN, sizeof(UPDATE_QUERY_BEGIN) - 1); + + for (size_t i = 0; i < MAX_QUERIES; i++) { + char *iter = query + sizeof(UPDATE_QUERY_BEGIN) - 1; + size_t sz = sizeof(query) - sizeof(UPDATE_QUERY_BEGIN) + 1; + int c = snprintf(name + sizeof(UPDATE_QUERY_NAME_PREFIX) - 1, name_size, "%zu", i + 1); + + if ((size_t) c >= name_size) + continue; + + for (size_t j = 0; j <= i; j++) { + c = snprintf(iter, + sz, + UPDATE_QUERY_ELEM, + 2 * j + 1, + 2 * j + 2); + + if ((size_t) c >= sz) + continue; + + iter += c; + sz -= c; + } + + assert(sz >= sizeof(UPDATE_QUERY_MIDDLE)); + memcpy(iter, UPDATE_QUERY_MIDDLE, sizeof(UPDATE_QUERY_MIDDLE) - 1); + iter += sizeof(UPDATE_QUERY_MIDDLE) - 1; + sz -= sizeof(UPDATE_QUERY_MIDDLE) - 1; + + for (size_t j = 1; j <= i; j++) { + c = snprintf(iter, sz, UPDATE_QUERY_ELEM2, 2 * j + 1); + + if ((size_t) c >= sz) + continue; + + iter += c; + sz -= c; + } + + assert(sz >= sizeof(UPDATE_QUERY_END)); + memcpy(iter, UPDATE_QUERY_END, sizeof(UPDATE_QUERY_END)); + add_prepared_statement(name, query, &data->prepared_statements); + } + add_prepared_statement(WORLD_TABLE_NAME, WORLD_QUERY, &data->prepared_statements); register_request_handler("/cached-worlds", cached_queries, hostconf, log_handle); register_request_handler("/db", single_query, hostconf, log_handle); diff --git a/frameworks/C/h2o/src/main.c b/frameworks/C/h2o/src/main.c index db598523cce..c068e9919a6 100644 --- a/frameworks/C/h2o/src/main.c +++ b/frameworks/C/h2o/src/main.c @@ -26,6 +26,8 @@ #include #include #include +#include +#include #include #include #include @@ -38,6 +40,7 @@ #include "global_data.h" #include "list.h" #include "request_handler.h" +#include "socket_load_balancer.h" #include "thread.h" #include "tls.h" #include "utility.h" @@ -81,6 +84,8 @@ static void free_global_data(global_data_t *global_data) if (global_data->file_logger) global_data->file_logger->dispose(global_data->file_logger); + close(global_data->bpf_fd); + socket_load_balancer__destroy(global_data->socket_load_balancer); cleanup_request_handlers(&global_data->request_handler_data); h2o_config_dispose(&global_data->h2o_config); @@ -93,6 +98,7 @@ static int initialize_global_data(const config_t *config, global_data_t *global_ sigset_t signals; memset(global_data, 0, sizeof(*global_data)); + global_data->bpf_fd = -1; global_data->buffer_prototype._initial_buf.capacity = H2O_SOCKET_INITIAL_INPUT_BUFFER_SIZE; global_data->memory_alignment = get_maximum_cache_line_size(); CHECK_ERRNO(sigemptyset, &signals); @@ -134,6 +140,20 @@ static int initialize_global_data(const config_t *config, global_data_t *global_ global_data->file_logger = h2o_access_log_register(pathconf, log_handle); } + global_data->socket_load_balancer = socket_load_balancer__open(); + + if (global_data->socket_load_balancer) { + global_data->socket_load_balancer->data->thread_num = config->thread_num; + + if (socket_load_balancer__load(global_data->socket_load_balancer)) { + socket_load_balancer__destroy(global_data->socket_load_balancer); + global_data->socket_load_balancer = NULL; + } + else + global_data->bpf_fd = + bpf_program__fd(global_data->socket_load_balancer->progs.socket_load_balancer); + } + global_data->global_thread_data = initialize_global_thread_data(config, global_data); if (global_data->global_thread_data) { @@ -176,10 +196,10 @@ static int parse_options(int argc, char *argv[], config_t *config) do { \ errno = 0; \ \ - const long long n = strtoll(optarg, NULL, 10); \ + const long n = strtol(optarg, NULL, 10); \ \ if (errno) { \ - print_library_error(__FILE__, __LINE__, "strtoll", errno); \ + print_library_error(__FILE__, __LINE__, "strtol", errno); \ return 1; \ } \ \ diff --git a/frameworks/CSharp/akazawayun.pro/AkazawaYun.Benchmark.sln b/frameworks/CSharp/akazawayun.pro/AkazawaYun.Benchmark.sln new file mode 100644 index 00000000000..66c1850c7f3 --- /dev/null +++ b/frameworks/CSharp/akazawayun.pro/AkazawaYun.Benchmark.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.14.36310.24 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AkazawaYun.Benchmark.WebApi", "src\AkazawaYun.Benchmark.WebApi\AkazawaYun.Benchmark.WebApi.csproj", "{BB5587FE-E4A0-851D-6025-F5FF0EC54525}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AkazawaYun.Benchmark.Platform", "src\AkazawaYun.Benchmark.Platform\AkazawaYun.Benchmark.Platform.csproj", "{E7CA7DF7-F4AB-47EC-BF2B-1148058CDF43}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {BB5587FE-E4A0-851D-6025-F5FF0EC54525}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BB5587FE-E4A0-851D-6025-F5FF0EC54525}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BB5587FE-E4A0-851D-6025-F5FF0EC54525}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BB5587FE-E4A0-851D-6025-F5FF0EC54525}.Release|Any CPU.Build.0 = Release|Any CPU + {E7CA7DF7-F4AB-47EC-BF2B-1148058CDF43}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E7CA7DF7-F4AB-47EC-BF2B-1148058CDF43}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E7CA7DF7-F4AB-47EC-BF2B-1148058CDF43}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E7CA7DF7-F4AB-47EC-BF2B-1148058CDF43}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {81EA49A3-BB25-4EC5-B861-02520931CF63} + EndGlobalSection +EndGlobal diff --git a/frameworks/CSharp/akazawayun.pro/README.md b/frameworks/CSharp/akazawayun.pro/README.md new file mode 100644 index 00000000000..0388851ec6a --- /dev/null +++ b/frameworks/CSharp/akazawayun.pro/README.md @@ -0,0 +1 @@ +AkazawaYun.PRO(https://akazawayun.cn/#akzLearning#%E5%BF%AB%E9%80%9F%E5%85%A5%E9%97%A8) diff --git a/frameworks/CSharp/akazawayun.pro/akazawayun.pro-platform.dockerfile b/frameworks/CSharp/akazawayun.pro/akazawayun.pro-platform.dockerfile new file mode 100644 index 00000000000..09f68ecd72d --- /dev/null +++ b/frameworks/CSharp/akazawayun.pro/akazawayun.pro-platform.dockerfile @@ -0,0 +1,13 @@ +# 生成 +FROM mcr.microsoft.com/dotnet/sdk:9.0 AS publish +WORKDIR /app +COPY src/AkazawaYun.Benchmark.Platform . +RUN dotnet publish -c Release -o /app/publish + +# 运行 +FROM mcr.microsoft.com/dotnet/sdk:9.0 AS runtime +WORKDIR /app +COPY --from=publish /app/publish . + +EXPOSE 8080 +ENTRYPOINT ["dotnet", "AkazawaYun.Benchmark.Platform.dll"] diff --git a/frameworks/CSharp/akazawayun.pro/akazawayun.pro.dockerfile b/frameworks/CSharp/akazawayun.pro/akazawayun.pro.dockerfile new file mode 100644 index 00000000000..439e8de4959 --- /dev/null +++ b/frameworks/CSharp/akazawayun.pro/akazawayun.pro.dockerfile @@ -0,0 +1,13 @@ +# 生成 +FROM mcr.microsoft.com/dotnet/sdk:9.0 AS publish +WORKDIR /app +COPY src/AkazawaYun.Benchmark.WebApi . +RUN dotnet publish -c Release -o /app/publish + +# 运行 +FROM mcr.microsoft.com/dotnet/sdk:9.0 AS runtime +WORKDIR /app +COPY --from=publish /app/publish . + +EXPOSE 8080 +ENTRYPOINT ["dotnet", "AkazawaYun.Benchmark.WebApi.dll"] diff --git a/frameworks/CSharp/akazawayun.pro/benchmark_config.json b/frameworks/CSharp/akazawayun.pro/benchmark_config.json new file mode 100644 index 00000000000..c9655a9f9c9 --- /dev/null +++ b/frameworks/CSharp/akazawayun.pro/benchmark_config.json @@ -0,0 +1,44 @@ +{ + "framework": "akazawayun.pro", + "tests": [ + { + "default": { + "display_name": "akazawayun.pro [webapi]", + "framework": "akazawayun.pro", + "webserver": "akazawayun.pro", + "plaintext_url": "/plaintext", + "json_url": "/json", + "db_url": "/db", + "query_url": "/queries?queries=", + "update_url": "/updates?queries=", + "port": 8080, + "classification": "Micro", + "approach": "Realistic", + "platform": ".NET", + "language": "C#", + "flavor": "CoreCLR", + "os": "Linux", + "database_os": "Linux", + "database": "MySQL", + "orm": "Micro", + "notes": "" + }, + "platform": { + "display_name": "akazawayun.pro [platform]", + "framework": "akazawayun.pro", + "webserver": "akazawayun.pro", + "plaintext_url": "/plaintext", + "json_url": "/json", + "port": 8080, + "classification": "Platform", + "approach": "Realistic", + "platform": ".NET", + "language": "C#", + "flavor": "CoreCLR", + "os": "Linux", + "database_os": "Linux", + "notes": "" + } + } + ] +} 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 new file mode 100644 index 00000000000..cdf987fdeb8 --- /dev/null +++ b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/AkazawaYun.Benchmark.Platform.csproj @@ -0,0 +1,21 @@ + + + + Exe + net9.0 + enable + enable + true + false + + + + true + true + + + + + + + diff --git a/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/Model.cs b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/Model.cs new file mode 100644 index 00000000000..574123c3697 --- /dev/null +++ b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/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.Platform/MyBenchmarkReceptor.cs b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/MyBenchmarkReceptor.cs new file mode 100644 index 00000000000..e79ab493524 --- /dev/null +++ b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/MyBenchmarkReceptor.cs @@ -0,0 +1,50 @@ +using AkazawaYun.PRO7; + +namespace AkazawaYun.Benchmark.Platform; + +class MyBenchmarkReceptor : akzWebReceptorBenchmark +{ + readonly JsonModel JsonModel; + + + public MyBenchmarkReceptor() + { + JsonModel = new() + { + message = "Hello, World!" + }; + } + + + public override ValueTask SendPlaintext(IHttpContext http) + { + return base.SendPlaintext(http); + } + public override async ValueTask SendJson(IHttpContext http) + { + await http.Slient.Send(DataJson_OnlyHeader); + akzJson.Text2Json(JsonModel, out ReadOnlyMemory json); + await http.Slient.Send(json); + } + 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.Platform/Program.cs b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/Program.cs new file mode 100644 index 00000000000..e2acab53351 --- /dev/null +++ b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.Platform/Program.cs @@ -0,0 +1,20 @@ +using AkazawaYun.PRO7; + +namespace AkazawaYun.Benchmark.Platform; + +class Program +{ + static readonly akzWebBuilder builder; + + static Program() + { + akzLog.War("AkazawaYun.PRO 平台压力测试特供版 ver2025.11.3, 只支持 /plaintext 和 /json"); + akzJson.Config(AotJsonContext.Default); + builder = akzWebBuilder.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.WebApi/AkazawaYun.Benchmark.WebApi.csproj b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.WebApi/AkazawaYun.Benchmark.WebApi.csproj new file mode 100644 index 00000000000..452b23e493c --- /dev/null +++ b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.WebApi/AkazawaYun.Benchmark.WebApi.csproj @@ -0,0 +1,22 @@ + + + + Exe + net9.0 + enable + enable + true + false + + + + true + true + + + + + + + + diff --git a/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.WebApi/Model.cs b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.WebApi/Model.cs new file mode 100644 index 00000000000..c191e3416d5 --- /dev/null +++ b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.WebApi/Model.cs @@ -0,0 +1,21 @@ +#pragma warning disable IDE1006,CS8981 +using AkazawaYun.AOT; +using System.Text.Json.Serialization; + +namespace AkazawaYun.Benchmark.WebApi; + + +[JsonSerializable(typeof(JsonModel))] +[JsonSerializable(typeof(world[]))] +public partial class AotJsonContext : JsonSerializerContext { } + + +public class JsonModel +{ + public string? message { get; set; } +} +public class world : IAotModel +{ + public int id { get; set; } + public int randomNumber { get; set; } +} diff --git a/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.WebApi/Mysql.cs b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.WebApi/Mysql.cs new file mode 100644 index 00000000000..049af6e21f3 --- /dev/null +++ b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.WebApi/Mysql.cs @@ -0,0 +1,10 @@ +using AkazawaYun.PRO7; +using MySql.Data.MySqlClient; +using System.Data.Common; + +namespace AkazawaYun.Benchmark.WebApi; + +class Mysql : akzDbFactory +{ + 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 new file mode 100644 index 00000000000..ab7234e6f72 --- /dev/null +++ b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.WebApi/Program.cs @@ -0,0 +1,112 @@ +#pragma warning disable IDE1006,IL2026 + +using AkazawaYun.AOT; +using AkazawaYun.PRO7; + +namespace AkazawaYun.Benchmark.WebApi; + +class Program : IPostFunctionWrapper +{ + static readonly akzWebBuilder builder; + static readonly akzDbFactory mysql; + const int port = 8080; + + static Program() + { + akzJson.Config(null, AotJsonContext.Default); + builder = akzWebBuilder.Shared.SetPort(port).SetDev() + .Add(() => null) + .Build() + .Config(lis => lis.LogLevel = 0) + .Config(itc => + { + itc.ClearInterceptor(); + itc.AddInterceptor(new akzWebInterceptorAsPost()); + }); + mysql = new akzDbBuilderII() + .SetServer("tfb-database") + //.SetServer("localhost:3306") + .SetUser("benchmarkdbuser") + //.SetUser("root") + .SetPwd("benchmarkdbpass") + //.SetPwd("123456") + .SetDatabase("hello_world") + .SetCharset() + .SetOtherset() + .Build(); + } + static async Task Main() + { + await builder.Launch(); + + akzLog.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]"); + + akzLog.Default = akzLog.Output.NoneButWar; + await Task.Delay(-1); + } + + + public static HttpRes plaintext() => HttpRes.HttpOK("Hello, World!", ".txt"); + public static JsonModel json() => new() + { + message = "Hello, World!" + }; + + //[WebFunctionAopTry] + public static async Task db() + { + await using IDb con = await mysql.Connect(); + world obj = await WorldService.GetRandomWorld(con); + return obj; + } + //[WebFunctionAopTry] + public static async Task queries(string queries) + { + int count = ParseCount(queries); + + await using IDb con = await mysql.Connect(); + world[] lst = await WorldService.GetWorlds(con, count); + return lst; + } + //[WebFunctionAopTry] + public static async Task updates(string queries) + { + int count = ParseCount(queries); + + await using IDb con = await mysql.Connect(); + world[] lst = await WorldService.GetWorlds(con, count); + + foreach (world obj in lst) + obj.randomNumber = Random.Shared.Next(1, 10001); + + await WorldService.SaveWorlds(con, lst); + + return lst; + } + + + static int ParseCount(string queries) + { + if (!int.TryParse(queries, out int count)) + return 1; + + count = Math.Clamp(count, 1, 500); + return count; + } + +} + +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 new file mode 100644 index 00000000000..8f996368ac5 --- /dev/null +++ b/frameworks/CSharp/akazawayun.pro/src/AkazawaYun.Benchmark.WebApi/WorldService.cs @@ -0,0 +1,45 @@ +using AkazawaYun.PRO7; + +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 + { + 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() + { + randomNumber = m.randomNumber, + }).Where(m => m.id == @id).Build(); + + + public static async Task GetRandomWorld(IDb con, IDictionary? shared = null) + { + int id = Random.Shared.Next(1, 10001); + shared ??= new DpSingleBuilder().Build(); + shared["id"] = id; + + world? obj = await con.Find(SqlSelect, shared).Toworld(); + return obj!; + } + public static async Task GetWorlds(IDb con, int count) + { + world[] lst = new world[count]; + var dp = new DpSingleBuilder().Build(); + for (int i = 0; i < count; i++) + { + world obj = await GetRandomWorld(con, dp); + lst[i] = obj; + } + return lst; + } + public static async Task SaveWorlds(IDb con, world[] lst) + { + await con.Execute(SqlUpdate, lst.ToDp()); + } +} diff --git a/frameworks/CSharp/appmpower/appmpower-ado-pg.dockerfile b/frameworks/CSharp/appmpower/appmpower-ado-pg.dockerfile deleted file mode 100644 index 2e7234ca98d..00000000000 --- a/frameworks/CSharp/appmpower/appmpower-ado-pg.dockerfile +++ /dev/null @@ -1,17 +0,0 @@ -FROM mcr.microsoft.com/dotnet/sdk:8.0.100 AS build -RUN apt-get update -RUN apt-get -yqq install clang zlib1g-dev libkrb5-dev libtinfo5 - -WORKDIR /app -COPY src . -RUN dotnet publish -c Release -o out /p:Driver=ado - -# Construct the actual image that will run -FROM mcr.microsoft.com/dotnet/aspnet:8.0.0 AS runtime - -WORKDIR /app -COPY --from=build /app/out ./ - -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 new file mode 100644 index 00000000000..ad6c396e22b --- /dev/null +++ b/frameworks/CSharp/appmpower/appmpower-odbc-my.dockerfile @@ -0,0 +1,56 @@ +FROM mcr.microsoft.com/dotnet/sdk:9.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:Database=mysql + +# Construct the actual image that will run +FROM mcr.microsoft.com/dotnet/aspnet:9.0 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 +#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 + +ENV PATH=/usr/local/unixODBC/bin:$PATH + +WORKDIR /etc/ +COPY odbcinst.ini . + +# 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 ./ + +RUN cp /usr/lib/libm* /app +#TODOGITHUB +RUN cp /usr/lib/x86_64-linux-gnu/libodbc* /app +#TODOLOCAL +#RUN cp /usr/lib/aarch64-linux-gnu/libodbc* /app + +EXPOSE 8080 + +ENTRYPOINT ["./appMpower"] \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/appmpower-odbc-pg.dockerfile b/frameworks/CSharp/appmpower/appmpower-odbc-pg.dockerfile index c06865cc0b2..1cf7855dd7f 100644 --- a/frameworks/CSharp/appmpower/appmpower-odbc-pg.dockerfile +++ b/frameworks/CSharp/appmpower/appmpower-odbc-pg.dockerfile @@ -1,16 +1,16 @@ -FROM mcr.microsoft.com/dotnet/sdk:8.0.100 AS build +FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build RUN apt-get update -RUN apt-get -yqq install clang zlib1g-dev libkrb5-dev libtinfo5 +RUN apt-get -yqq install clang zlib1g-dev WORKDIR /app COPY src . -RUN dotnet publish -c Release -o out /p:Driver=odbc +RUN dotnet publish -c Release -o out /p:Database=postgresql # Construct the actual image that will run -FROM mcr.microsoft.com/dotnet/aspnet:8.0.0 AS runtime +FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS runtime RUN apt-get update -RUN apt-get install -y unixodbc odbc-postgresql +RUN apt-get install -y unixodbc-dev unixodbc odbc-postgresql # unixodbc still needs to be installed even if compiled locally ENV PATH=/usr/local/unixODBC/bin:$PATH @@ -18,9 +18,20 @@ ENV PATH=/usr/local/unixODBC/bin:$PATH WORKDIR /etc/ COPY odbcinst.ini . +# 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 ./ +#TODOGITHUB +RUN cp /usr/lib/x86_64-linux-gnu/libodbc* /app +#TODOLOCAL +#RUN cp /usr/lib/aarch64-linux-gnu/libodbc* /app + EXPOSE 8080 ENTRYPOINT ["./appMpower"] \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/appmpower.dockerfile b/frameworks/CSharp/appmpower/appmpower.dockerfile index 7f77873dfaf..6621b6b6deb 100644 --- a/frameworks/CSharp/appmpower/appmpower.dockerfile +++ b/frameworks/CSharp/appmpower/appmpower.dockerfile @@ -1,14 +1,20 @@ -FROM mcr.microsoft.com/dotnet/sdk:8.0.100 AS build +FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build RUN apt-get update -RUN apt-get -yqq install clang zlib1g-dev libkrb5-dev libtinfo5 +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 # Construct the actual image that will run -FROM mcr.microsoft.com/dotnet/aspnet:8.0.0 AS runtime +FROM mcr.microsoft.com/dotnet/aspnet:9.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/out ./ diff --git a/frameworks/CSharp/appmpower/benchmark_config.json b/frameworks/CSharp/appmpower/benchmark_config.json index 6c22c0c65af..46dc7e7c00f 100644 --- a/frameworks/CSharp/appmpower/benchmark_config.json +++ b/frameworks/CSharp/appmpower/benchmark_config.json @@ -39,11 +39,11 @@ "webserver": "Kestrel", "os": "Linux", "database_os": "Linux", - "display_name": "appMpower [aot-no-reflection,odbc]", + "display_name": "appMpower [aot-no-reflection,pg,odbc]", "notes": "", "versus": "aspnetcore-minimal" }, - "ado-pg": { + "odbc-my": { "db_url": "/db", "query_url": "/queries?c=", "update_url": "/updates?c=", @@ -52,7 +52,7 @@ "port": 8080, "approach": "Realistic", "classification": "Platform", - "database": "Postgres", + "database": "MySQL", "framework": "appmpower", "language": "C#", "orm": "Raw", @@ -61,7 +61,7 @@ "webserver": "Kestrel", "os": "Linux", "database_os": "Linux", - "display_name": "appMpower [aot-no-reflection,ado]", + "display_name": "appMpower [aot-no-reflection,my,odbc]", "notes": "", "versus": "aspnetcore-minimal" } diff --git a/frameworks/CSharp/appmpower/config.toml b/frameworks/CSharp/appmpower/config.toml index d500b2df989..a3747682191 100644 --- a/frameworks/CSharp/appmpower/config.toml +++ b/frameworks/CSharp/appmpower/config.toml @@ -30,7 +30,7 @@ platform = ".NET" webserver = "Kestrel" versus = "aspnetcore-minimal" -[ado-pg] +[odbc-my] urls.db = "/db" urls.query = "/queries?c=" urls.update = "/updates?c=" @@ -38,7 +38,7 @@ urls.fortune = "/fortunes" urls.cached_query = "/cached-worlds?c=" approach = "Realistic" classification = "Micro" -database = "Postgres" +database = "MySQL" database_os = "Linux" os = "Linux" orm = "Raw" diff --git a/frameworks/CSharp/appmpower/odbcinst.ini b/frameworks/CSharp/appmpower/odbcinst.ini index c6260e38b93..544ba2067c1 100644 --- a/frameworks/CSharp/appmpower/odbcinst.ini +++ b/frameworks/CSharp/appmpower/odbcinst.ini @@ -5,6 +5,7 @@ Pooling=0 [ODBC Drivers] PostgreSQL = Installed +MariaDB = Installed ; ; odbcinst.ini @@ -15,7 +16,16 @@ Description=ODBC for PostgreSQL ; in version 08.x. Note that the library can also be installed under an other ; path than /usr/local/lib/ following your installation. ; This is the standard location used by apt-get install -y unixodbc +;ON SERVER Driver = /usr/lib/x86_64-linux-gnu/odbc/psqlodbcw.so +;TODOLOCAL: ON MAC +;Driver =/usr/lib/aarch64-linux-gnu/odbc/psqlodbcw.so + ;Driver =/usr/local/pgsqlodbc/lib/psqlodbcw.so Threading = 0 CPTimeout = 0 + +[MariaDB] +Description=MariaDB ODBC for MySQL +Driver = /usr/lib/libmaodbc.so +Threading = 0 \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/CachedWorldSerializer.cs b/frameworks/CSharp/appmpower/src/CachedWorldSerializer.cs deleted file mode 100644 index f7c78b6dd65..00000000000 --- a/frameworks/CSharp/appmpower/src/CachedWorldSerializer.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.Text.Json; - -namespace appMpower -{ - public class CachedWorldSerializer : Kestrel.IJsonSerializer - { - public void Serialize(Utf8JsonWriter utf8JsonWriter, CachedWorld world) - { - utf8JsonWriter.WriteStartObject(); - utf8JsonWriter.WriteNumber("id", world.Id); - utf8JsonWriter.WriteNumber("randomNumber", world.RandomNumber); - utf8JsonWriter.WriteEndObject(); - } - } -} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/Data/DbCommand.cs b/frameworks/CSharp/appmpower/src/Data/DbCommand.cs deleted file mode 100644 index 2086068c802..00000000000 --- a/frameworks/CSharp/appmpower/src/Data/DbCommand.cs +++ /dev/null @@ -1,225 +0,0 @@ -using System.Data; -using System.Threading.Tasks; - -namespace appMpower.Data -{ - public class DbCommand : IDbCommand - { - private IDbCommand _dbCommand; - private DbConnection _dbConnection; - - public DbCommand(DbConnection dbConnection) - { - _dbCommand = dbConnection.CreateCommand(); - _dbConnection = dbConnection; - } - - public DbCommand(string commandText, DbConnection dbConnection) - { - dbConnection.GetCommand(commandText, CommandType.Text, this); - } - - public DbCommand(string commandText, CommandType commandType, DbConnection dbConnection) - { - dbConnection.GetCommand(commandText, commandType, this); - } - - internal DbCommand(IDbCommand dbCommand, DbConnection dbConnection) - { - _dbCommand = dbCommand; - _dbConnection = dbConnection; - } - - internal IDbCommand Command - { - get - { - return _dbCommand; - } - set - { - _dbCommand = value; - } - } - - internal DbConnection DbConnection - { - get - { - return _dbConnection; - } - set - { - _dbConnection = value; - } - } - - public string CommandText - { - get - { - return _dbCommand.CommandText; - } - set - { - _dbCommand.CommandText = value; - } - } - - public int CommandTimeout - { - get - { - return _dbCommand.CommandTimeout; - } - set - { - _dbCommand.CommandTimeout = value; - } - } - public CommandType CommandType - { - get - { - return _dbCommand.CommandType; - } - set - { - _dbCommand.CommandType = value; - } - } - -#nullable enable - public IDbConnection? Connection - { - get - { - return _dbCommand.Connection; - } - set - { - _dbCommand.Connection = (IDbConnection?)value; - } - } -#nullable disable - - public IDataParameterCollection Parameters - { - get - { - return _dbCommand.Parameters; - } - } - -#nullable enable - public IDbTransaction? Transaction - { - get - { - return _dbCommand.Transaction; - } - set - { - _dbCommand.Transaction = (IDbTransaction?)value; - } - } -#nullable disable - - public UpdateRowSource UpdatedRowSource - { - get - { - return _dbCommand.UpdatedRowSource; - } - set - { - _dbCommand.UpdatedRowSource = value; - } - } - public void Cancel() - { - _dbCommand.Cancel(); - } - - public IDbDataParameter CreateParameter() - { - return _dbCommand.CreateParameter(); - } - - public IDbDataParameter CreateParameter(string name, object value) - { - return CreateParameter(name, DbType.String, value); - } - - public IDbDataParameter CreateParameter(string name, DbType dbType, object value) - { - IDbDataParameter dbDataParameter = null; - - if (this.Parameters.Contains(name)) - { - dbDataParameter = this.Parameters[name] as IDbDataParameter; - dbDataParameter.Value = value; - } - else - { - dbDataParameter = _dbCommand.CreateParameter(); - - dbDataParameter.ParameterName = name; - dbDataParameter.DbType = dbType; - dbDataParameter.Value = value; - this.Parameters.Add(dbDataParameter); - } - - return dbDataParameter; - } - - public int ExecuteNonQuery() - { - return _dbCommand.ExecuteNonQuery(); - } - - public IDataReader ExecuteReader() - { - return _dbCommand.ExecuteReader(); - } - - public async Task ExecuteNonQueryAsync() - { - return await (_dbCommand as System.Data.Common.DbCommand).ExecuteNonQueryAsync(); - } - - public async Task ExecuteReaderAsync(CommandBehavior behavior) - { - return await (_dbCommand as System.Data.Common.DbCommand).ExecuteReaderAsync(behavior); - } - - public IDataReader ExecuteReader(CommandBehavior behavior) - { - return _dbCommand.ExecuteReader(behavior); - } - -#nullable enable - public object? ExecuteScalar() - { - return _dbCommand.ExecuteScalar(); - } -#nullable disable - -#nullable enable - public async Task ExecuteScalarAsync() - { - return await ((System.Data.Common.DbCommand)_dbCommand).ExecuteScalarAsync(); - } -#nullable disable - - public void Prepare() - { - _dbCommand.Prepare(); - } - - public void Dispose() - { - _dbConnection.ReleaseCommand(this); - } - } -} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/Data/DbConnection.cs b/frameworks/CSharp/appmpower/src/Data/DbConnection.cs deleted file mode 100644 index 31dc5a783dc..00000000000 --- a/frameworks/CSharp/appmpower/src/Data/DbConnection.cs +++ /dev/null @@ -1,203 +0,0 @@ -using System.Collections.Concurrent; -using System.Data; -using System.Threading.Tasks; - -namespace appMpower.Data -{ - public class DbConnection : IDbConnection - { - private string _connectionString; - internal InternalConnection _internalConnection; - - public DbConnection() - { - _connectionString = DbProviderFactory.ConnectionString; - } - - public DbConnection(string connectionString) - { - _connectionString = connectionString; - } - - internal ConcurrentDictionary DbCommands - { - get - { - return _internalConnection.DbCommands; - } - set - { - _internalConnection.DbCommands = value; - } - } - - public short Number - { - get - { - return _internalConnection.Number; - } - set - { - _internalConnection.Number = value; - } - } - - public IDbConnection Connection - { - get - { - return _internalConnection.DbConnection; - } - set - { - _internalConnection.DbConnection = value; - } - } - - public string ConnectionString - { - get - { - return _internalConnection.DbConnection.ConnectionString; - } - set - { - _internalConnection.DbConnection.ConnectionString = value; - } - } - - public int ConnectionTimeout - { - get - { - return _internalConnection.DbConnection.ConnectionTimeout; - } - } - - public string Database - { - get - { - return _internalConnection.DbConnection.Database; - } - } - - public ConnectionState State - { - get - { - if (_internalConnection is null) return ConnectionState.Closed; - return _internalConnection.DbConnection.State; - } - } - - public IDbTransaction BeginTransaction() - { - return _internalConnection.DbConnection.BeginTransaction(); - } - - public IDbTransaction BeginTransaction(IsolationLevel il) - { - return _internalConnection.DbConnection.BeginTransaction(il); - } - - public void ChangeDatabase(string databaseName) - { - _internalConnection.DbConnection.ChangeDatabase(databaseName); - } - - public void Close() - { - _internalConnection.DbConnection.Close(); - } - - public async Task CloseAsync() - { - await (_internalConnection.DbConnection as System.Data.Common.DbConnection).CloseAsync(); - } - - public IDbCommand CreateCommand() - { - return _internalConnection.DbConnection.CreateCommand(); - } - - public void Open() - { - if (_internalConnection.DbConnection.State == ConnectionState.Closed) - { - _internalConnection.DbConnection.Open(); - } - } - - public void Dispose() - { -#if ADO - _internalConnection.DbConnection.Dispose(); - _internalConnection.Dispose(); -#else - DbConnections.Release(_internalConnection); -#endif - } - - public async Task OpenAsync() - { -#if ADO && SQLSERVER - _internalConnection = new(); - _internalConnection.DbConnection = new System.Data.SqlClient.SqlConnection(_connectionString); -#elif ADO && POSTGRESQL - _internalConnection = new(); - _internalConnection.DbConnection = new Npgsql.NpgsqlConnection(_connectionString); -#else - if (_internalConnection is null) - { - _internalConnection = await DbConnections.GetConnection(_connectionString); - } -#endif - - if (_internalConnection.DbConnection.State == ConnectionState.Closed) - { - await (_internalConnection.DbConnection as System.Data.Common.DbConnection).OpenAsync(); - } - } - - internal DbCommand GetCommand(string commandText, CommandType commandType, DbCommand dbCommand) - { -#if ADO - dbCommand.Command = _internalConnection.DbConnection.CreateCommand(); - dbCommand.Command.CommandText = commandText; - dbCommand.Command.CommandType = commandType; - dbCommand.DbConnection = this; -#else - DbCommand internalCommand; - - if (_internalConnection.DbCommands.TryRemove(commandText, out internalCommand)) - { - dbCommand.Command = internalCommand.Command; - dbCommand.DbConnection = internalCommand.DbConnection; - } - else - { - dbCommand.Command = _internalConnection.DbConnection.CreateCommand(); - dbCommand.Command.CommandText = commandText; - dbCommand.Command.CommandType = commandType; - dbCommand.DbConnection = this; - - //For non odbc drivers like Npgsql which do not support Prepare - dbCommand.Command.Prepare(); - - //Console.WriteLine("prepare pool connection: " + this._internalConnection.Number + " for command " + _internalConnection.DbCommands.Count); - } -#endif - - return dbCommand; - } - - public void ReleaseCommand(DbCommand dbCommand) - { -#if !ADO - _internalConnection.DbCommands.TryAdd(dbCommand.CommandText, dbCommand); -#endif - } - } -} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/Data/DbConnections.cs b/frameworks/CSharp/appmpower/src/Data/DbConnections.cs deleted file mode 100644 index d7658b41ebe..00000000000 --- a/frameworks/CSharp/appmpower/src/Data/DbConnections.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System.Collections.Concurrent; -using System.Threading.Tasks; - -namespace appMpower.Data -{ - public static class DbConnections - { - private static bool _connectionsCreated = false; - private static short _createdConnections = 0; - private static short _maxConnections = 250; - - private static ConcurrentStack _stack = new(); - private static ConcurrentQueue> _waitingQueue = new(); - - public static async Task GetConnection(string connectionString) - { - InternalConnection internalConnection = null; - - if (_connectionsCreated) - { - if (!_stack.TryPop(out internalConnection)) - { - internalConnection = await GetDbConnectionAsync(); - } - - return internalConnection; - } - else - { - internalConnection = new InternalConnection(); - internalConnection.DbConnection = new System.Data.Odbc.OdbcConnection(connectionString); - - _createdConnections++; - - if (_createdConnections == _maxConnections) _connectionsCreated = true; - - internalConnection.Number = _createdConnections; - internalConnection.DbCommands = new ConcurrentDictionary(); - //Console.WriteLine("opened connection number: " + dbConnection.Number); - - return internalConnection; - } - } - - public static Task GetDbConnectionAsync() - { - var taskCompletionSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); - - _waitingQueue.Enqueue(taskCompletionSource); - return taskCompletionSource.Task; - } - - public static void Release(InternalConnection internalConnection) - { - TaskCompletionSource taskCompletionSource; - - if (_waitingQueue.TryDequeue(out taskCompletionSource)) - { - taskCompletionSource.SetResult(internalConnection); - } - else - { - _stack.Push(internalConnection); - } - } - } -} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/Data/DbProviderFactory.cs b/frameworks/CSharp/appmpower/src/Data/DbProviderFactory.cs deleted file mode 100644 index 98a4aa67cb6..00000000000 --- a/frameworks/CSharp/appmpower/src/Data/DbProviderFactory.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.Data; - -namespace appMpower.Data -{ - public static class DbProviderFactory - { -#if MYSQL - public const string ConnectionString = "Driver={MariaDB};Server=tfb-database;Database=hello_world;Uid=benchmarkdbuser;Pwd=benchmarkdbpass;Pooling=false;OPTIONS=67108864;FLAG_FORWARD_CURSOR=1"; -#elif ADO - public const string ConnectionString = "Server=tfb-database;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;SSL Mode=0;Maximum Pool Size=18;NoResetOnClose=true;Enlist=false;Max Auto Prepare=4;Multiplexing=true;Write Coalescing Buffer Threshold Bytes=1000"; - //public const string ConnectionString = "Server=localhost;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;SSL Mode=Disable;Maximum Pool Size=18;NoResetOnClose=true;Enlist=false;Max Auto Prepare=4;Multiplexing=true;Write Coalescing Buffer Threshold Bytes=1000"; -#else - public const string ConnectionString = "Driver={PostgreSQL};Server=tfb-database;Database=hello_world;Uid=benchmarkdbuser;Pwd=benchmarkdbpass;UseServerSidePrepare=1;Pooling=false"; - //public const string ConnectionString = "Driver={PostgreSQL};Server=localhost;Database=hello_world;Uid=benchmarkdbuser;Pwd=benchmarkdbpass;UseServerSidePrepare=1;Pooling=false"; -#endif - } -} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/Data/InternalConnection.cs b/frameworks/CSharp/appmpower/src/Data/InternalConnection.cs deleted file mode 100644 index 25cecfeb4f8..00000000000 --- a/frameworks/CSharp/appmpower/src/Data/InternalConnection.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Collections.Concurrent; -using System.Data; - -namespace appMpower.Data -{ - public class InternalConnection : System.IDisposable - { - public short Number { get; set; } - public IDbConnection DbConnection { get; set; } - public ConcurrentDictionary DbCommands { get; set; } - - public void Dispose() - { - } - } -} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/Fortune.cs b/frameworks/CSharp/appmpower/src/Fortune.cs deleted file mode 100644 index 4d1b99661ca..00000000000 --- a/frameworks/CSharp/appmpower/src/Fortune.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; - -namespace appMpower -{ - 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); - } -} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/FortunesView.cs b/frameworks/CSharp/appmpower/src/FortunesView.cs deleted file mode 100644 index 8f56ddde4d5..00000000000 --- a/frameworks/CSharp/appmpower/src/FortunesView.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System.Collections.Generic; -using System.IO.Pipelines; -using System.Globalization; -using System.Text; -using System.Threading.Tasks; -using System.Web; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Primitives; -using PlatformBenchmarks; - -namespace appMpower -{ - public static class FortunesView - { - private readonly static KeyValuePair _headerServer = - new KeyValuePair("Server", "k"); - private readonly static KeyValuePair _headerContentType = - new KeyValuePair("Content-Type", "text/html; charset=UTF-8"); - - public static char[] _fortunesTableStart = "Fortunes
idmessage
".ToCharArray(); - public static char[] _fortunesRowStart = "".ToCharArray(); - public static char[] _fortunesTableEnd = "
idmessage
".ToCharArray(); - public static char[] _fortunesColumn = "".ToCharArray(); - public static char[] _fortunesRowEnd = "
".ToCharArray(); - - public static async Task Render(IHeaderDictionary headerDictionary, PipeWriter pipeWriter, List fortunes) - { - headerDictionary.Add(_headerServer); - headerDictionary.Add(_headerContentType); - - var writer = StringBuilderCache.Acquire(); - - writer.Append(_fortunesTableStart); - - foreach (var fortune in fortunes) - { - writer.Append(_fortunesRowStart).Append(fortune.Id.ToString(CultureInfo.InvariantCulture)).Append(_fortunesColumn).Append(HttpUtility.HtmlEncode(fortune.Message)).Append(_fortunesRowEnd); - } - - writer.Append(_fortunesTableEnd); - - headerDictionary.Add(new KeyValuePair("Content-Length", (writer.Length + 32).ToString())); - - await pipeWriter.WriteAsync(Encoding.UTF8.GetBytes(StringBuilderCache.GetStringAndRelease(writer))); - pipeWriter.Complete(); - } - } -} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/HttpApplication.cs b/frameworks/CSharp/appmpower/src/HttpApplication.cs deleted file mode 100644 index b7d8048692f..00000000000 --- a/frameworks/CSharp/appmpower/src/HttpApplication.cs +++ /dev/null @@ -1,116 +0,0 @@ -using System; -using System.Text; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Hosting.Server; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Features; -using appMpower.Kestrel; - -namespace appMpower -{ - public class HttpApplication : IHttpApplication - { - public static readonly byte[] _plainText = Encoding.UTF8.GetBytes("Hello, World!"); - private readonly static JsonMessageSerializer _jsonMessageSerializer = new JsonMessageSerializer(); - private readonly static WorldSerializer _worldSerializer = new WorldSerializer(); - private readonly static CachedWorldSerializer _cachedWorldSerializer = new CachedWorldSerializer(); - - public IFeatureCollection CreateContext(IFeatureCollection featureCollection) - { - return featureCollection; - } - - public async Task ProcessRequestAsync(IFeatureCollection featureCollection) - { - var request = featureCollection as IHttpRequestFeature; - var httpResponse = featureCollection as IHttpResponseFeature; - var httpResponseBody = featureCollection as IHttpResponseBodyFeature; - - PathString pathString = request.Path; - - if (pathString.HasValue) - { - int pathStringLength = pathString.Value.Length; - string pathStringStart = pathString.Value.Substring(1, 1); - - if (pathStringLength == 10 && pathStringStart == "p") - { - await PlainText.RenderAsync(httpResponse.Headers, httpResponseBody.Writer, _plainText); - return; - } - else if (pathStringLength == 5 && pathStringStart == "j") - { - Json.RenderOne(httpResponse.Headers, httpResponseBody.Writer, new JsonMessage { message = "Hello, World!" }, _jsonMessageSerializer); - return; - } - else if (pathStringLength == 3 && pathStringStart == "d") - { - Json.RenderOne(httpResponse.Headers, httpResponseBody.Writer, await RawDb.LoadSingleQueryRow(), _worldSerializer); - return; - } - else if (pathStringLength == 8 && pathStringStart == "q") - { - int count = 1; - - if (!Int32.TryParse(request.QueryString.Substring(request.QueryString.LastIndexOf("=") + 1), out count) || count < 1) - { - count = 1; - } - else if (count > 500) - { - count = 500; - } - -#if ADO - Json.RenderMany(httpResponse.Headers, httpResponseBody.Writer, await RawDb.LoadMultipleQueriesRows(count), _worldSerializer); -#else - Json.RenderMany(httpResponse.Headers, httpResponseBody.Writer, await RawDb.ReadMultipleRows(count), _worldSerializer); -#endif - - return; - } - else if (pathStringLength == 9 && pathStringStart == "f") - { - await FortunesView.Render(httpResponse.Headers, httpResponseBody.Writer, await RawDb.LoadFortunesRows()); - return; - } - else if (pathStringLength == 8 && pathStringStart == "u") - { - int count = 1; - - if (!Int32.TryParse(request.QueryString.Substring(request.QueryString.LastIndexOf("=") + 1), out count) || count < 1) - { - count = 1; - } - else if (count > 500) - { - count = 500; - } - - Json.RenderMany(httpResponse.Headers, httpResponseBody.Writer, await RawDb.LoadMultipleUpdatesRows(count), _worldSerializer); - return; - } - else if (pathStringLength == 14 && pathStringStart == "c") - { - int count = 1; - - if (!Int32.TryParse(request.QueryString.Substring(request.QueryString.LastIndexOf("=") + 1), out count) || count < 1) - { - count = 1; - } - else if (count > 500) - { - count = 500; - } - - Json.RenderMany(httpResponse.Headers, httpResponseBody.Writer, await RawDb.LoadCachedQueries(count), _cachedWorldSerializer); - return; - } - } - } - - public void DisposeContext(IFeatureCollection featureCollection, Exception exception) - { - } - } -} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/JsonMessage.cs b/frameworks/CSharp/appmpower/src/JsonMessage.cs deleted file mode 100644 index 24b78265baa..00000000000 --- a/frameworks/CSharp/appmpower/src/JsonMessage.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace appMpower -{ - public struct JsonMessage - { - public string message { get; set; } - } -} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/JsonMessageSerializer.cs b/frameworks/CSharp/appmpower/src/JsonMessageSerializer.cs deleted file mode 100644 index dca7f673368..00000000000 --- a/frameworks/CSharp/appmpower/src/JsonMessageSerializer.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Text.Json; - -namespace appMpower -{ - public class JsonMessageSerializer : Kestrel.IJsonSerializer - { - public void Serialize(Utf8JsonWriter utf8JsonWriter, JsonMessage jsonMessage) - { - utf8JsonWriter.WriteStartObject(); - utf8JsonWriter.WriteString("message", jsonMessage.message); - utf8JsonWriter.WriteEndObject(); - } - } -} diff --git a/frameworks/CSharp/appmpower/src/Kestrel/IJsonSerializer.cs b/frameworks/CSharp/appmpower/src/Kestrel/IJsonSerializer.cs deleted file mode 100644 index 4f28a4cc538..00000000000 --- a/frameworks/CSharp/appmpower/src/Kestrel/IJsonSerializer.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Text.Json; - -namespace appMpower.Kestrel -{ - public interface IJsonSerializer - { - public void Serialize(Utf8JsonWriter utf8JsonWriter, T t); - } -} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/Kestrel/Json.cs b/frameworks/CSharp/appmpower/src/Kestrel/Json.cs deleted file mode 100644 index c81028e2a9b..00000000000 --- a/frameworks/CSharp/appmpower/src/Kestrel/Json.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO.Pipelines; -using System.Text.Json; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Primitives; - -namespace appMpower.Kestrel -{ - public static class Json - { - private readonly static KeyValuePair _headerServer = - new KeyValuePair("Server", "k"); - private readonly static KeyValuePair _headerContentType = - new KeyValuePair("Content-Type", "application/json"); - - [ThreadStatic] - private static Utf8JsonWriter _utf8JsonWriter; - - public static JsonWriterOptions _jsonWriterOptions = new JsonWriterOptions - { - SkipValidation = true - }; - - public static void RenderOne(IHeaderDictionary headerDictionary, PipeWriter pipeWriter, T t, IJsonSerializer jsonSerializer) - { - headerDictionary.Add(_headerServer); - headerDictionary.Add(_headerContentType); - - Utf8JsonWriter utf8JsonWriter = _utf8JsonWriter ??= new Utf8JsonWriter(pipeWriter, new JsonWriterOptions { SkipValidation = true }); - utf8JsonWriter.Reset(pipeWriter); - - jsonSerializer.Serialize(utf8JsonWriter, t); - utf8JsonWriter.Flush(); - headerDictionary.Add(new KeyValuePair("Content-Length", utf8JsonWriter.BytesCommitted.ToString())); - } - - public static void RenderMany(IHeaderDictionary headerDictionary, PipeWriter pipeWriter, T[] tArray, IJsonSerializer jsonSerializer) - { - headerDictionary.Add(_headerServer); - headerDictionary.Add(_headerContentType); - - Utf8JsonWriter utf8JsonWriter = _utf8JsonWriter ??= new Utf8JsonWriter(pipeWriter, new JsonWriterOptions { SkipValidation = true }); - utf8JsonWriter.Reset(pipeWriter); - - utf8JsonWriter.WriteStartArray(); - - foreach (var t in tArray) - { - jsonSerializer.Serialize(utf8JsonWriter, t); - } - - utf8JsonWriter.WriteEndArray(); - utf8JsonWriter.Flush(); - headerDictionary.Add(new KeyValuePair("Content-Length", utf8JsonWriter.BytesCommitted.ToString())); - } - } -} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/Kestrel/PlainText.cs b/frameworks/CSharp/appmpower/src/Kestrel/PlainText.cs deleted file mode 100644 index cff1d028b23..00000000000 --- a/frameworks/CSharp/appmpower/src/Kestrel/PlainText.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -using System.Threading.Tasks; -using System.Collections.Generic; -using System.IO.Pipelines; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Primitives; - -namespace appMpower.Kestrel -{ - public static class PlainText - { - private readonly static KeyValuePair _headerServer = - new KeyValuePair("Server", new StringValues("k")); - private readonly static KeyValuePair _headerContentType = - new KeyValuePair("Content-Type", new StringValues("text/plain")); - - public static async Task RenderAsync(IHeaderDictionary headerDictionary, PipeWriter pipeWriter, ReadOnlyMemory utf8String) - { - headerDictionary.Add(_headerServer); - headerDictionary.Add(_headerContentType); - headerDictionary.Add(new KeyValuePair("Content-Length", utf8String.Length.ToString())); - - await pipeWriter.WriteAsync(utf8String); - pipeWriter.Complete(); - } - } -} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/Kestrel/ServiceProvider.cs b/frameworks/CSharp/appmpower/src/Kestrel/ServiceProvider.cs deleted file mode 100644 index 513174e68b9..00000000000 --- a/frameworks/CSharp/appmpower/src/Kestrel/ServiceProvider.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Logging.Abstractions; - -namespace appMpower.Kestrel -{ - public class ServiceProvider : ISupportRequiredService, IServiceProvider - { - public object GetRequiredService(Type serviceType) - { - return GetService(serviceType); - } - - public object GetService(Type serviceType) - { - if (serviceType == typeof(ILoggerFactory)) - { - return NullLoggerFactory.Instance; - } - - return null; - } - } -} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/Memory/CacheEntry.cs b/frameworks/CSharp/appmpower/src/Memory/CacheEntry.cs deleted file mode 100644 index 55ca29c4984..00000000000 --- a/frameworks/CSharp/appmpower/src/Memory/CacheEntry.cs +++ /dev/null @@ -1,257 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Collections.Generic; -using System.Runtime.CompilerServices; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.Extensions.Primitives; -using Microsoft.Extensions.Caching.Memory; - -namespace appMpower.Memory -{ - internal sealed partial class CacheEntry : ICacheEntry - { - private static readonly Action ExpirationCallback = ExpirationTokensExpired; - - private readonly MemoryCache _cache; - - private CacheEntryTokens _tokens; // might be null if user is not using the tokens or callbacks - private TimeSpan? _absoluteExpirationRelativeToNow; - private TimeSpan? _slidingExpiration; - private long? _size; - private CacheEntry _previous; // this field is not null only before the entry is added to the cache and tracking is enabled - private object _value; - private CacheEntryState _state; - - internal CacheEntry(object key, MemoryCache memoryCache) - { - Key = key ?? throw new ArgumentNullException(nameof(key)); - _cache = memoryCache ?? throw new ArgumentNullException(nameof(memoryCache)); - _previous = memoryCache.TrackLinkedCacheEntries ? CacheEntryHelper.EnterScope(this) : null; - _state = new CacheEntryState(CacheItemPriority.Normal); - } - - /// - /// Gets or sets an absolute expiration date for the cache entry. - /// - public DateTimeOffset? AbsoluteExpiration { get; set; } - - /// - /// Gets or sets an absolute expiration time, relative to now. - /// - public TimeSpan? AbsoluteExpirationRelativeToNow - { - get => _absoluteExpirationRelativeToNow; - set - { - // this method does not set AbsoluteExpiration as it would require calling Clock.UtcNow twice: - // once here and once in MemoryCache.SetEntry - - if (value <= TimeSpan.Zero) - { - throw new ArgumentOutOfRangeException( - nameof(AbsoluteExpirationRelativeToNow), - value, - "The relative expiration value must be positive."); - } - - _absoluteExpirationRelativeToNow = value; - } - } - - /// - /// Gets or sets how long a cache entry can be inactive (e.g. not accessed) before it will be removed. - /// This will not extend the entry lifetime beyond the absolute expiration (if set). - /// - public TimeSpan? SlidingExpiration - { - get => _slidingExpiration; - set - { - if (value <= TimeSpan.Zero) - { - throw new ArgumentOutOfRangeException( - nameof(SlidingExpiration), - value, - "The sliding expiration value must be positive."); - } - - _slidingExpiration = value; - } - } - - /// - /// Gets the instances which cause the cache entry to expire. - /// - public IList ExpirationTokens => GetOrCreateTokens().ExpirationTokens; - - /// - /// Gets or sets the callbacks will be fired after the cache entry is evicted from the cache. - /// - public IList PostEvictionCallbacks => GetOrCreateTokens().PostEvictionCallbacks; - - /// - /// Gets or sets the priority for keeping the cache entry in the cache during a - /// memory pressure triggered cleanup. The default is . - /// - public CacheItemPriority Priority { get => _state.Priority; set => _state.Priority = value; } - - /// - /// Gets or sets the size of the cache entry value. - /// - public long? Size - { - get => _size; - set - { - if (value < 0) - { - throw new ArgumentOutOfRangeException(nameof(value), value, $"{nameof(value)} must be non-negative."); - } - - _size = value; - } - } - - public object Key { get; private set; } - - public object Value - { - get => _value; - set - { - _value = value; - _state.IsValueSet = true; - } - } - - internal DateTimeOffset LastAccessed { get; set; } - - internal EvictionReason EvictionReason { get => _state.EvictionReason; private set => _state.EvictionReason = value; } - - public void Dispose() - { - if (!_state.IsDisposed) - { - _state.IsDisposed = true; - - if (_cache.TrackLinkedCacheEntries) - { - CacheEntryHelper.ExitScope(this, _previous); - } - - // Don't commit or propagate options if the CacheEntry Value was never set. - // We assume an exception occurred causing the caller to not set the Value successfully, - // so don't use this entry. - if (_state.IsValueSet) - { - _cache.SetEntry(this); - - if (_previous != null && CanPropagateOptions()) - { - PropagateOptions(_previous); - } - } - - _previous = null; // we don't want to root unnecessary objects - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] // added based on profiling - internal bool CheckExpired(in DateTimeOffset now) - => _state.IsExpired - || CheckForExpiredTime(now) - || (_tokens != null && _tokens.CheckForExpiredTokens(this)); - - internal void SetExpired(EvictionReason reason) - { - if (EvictionReason == EvictionReason.None) - { - EvictionReason = reason; - } - _state.IsExpired = true; - _tokens?.DetachTokens(); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] // added based on profiling - private bool CheckForExpiredTime(in DateTimeOffset now) - { - if (!AbsoluteExpiration.HasValue && !_slidingExpiration.HasValue) - { - return false; - } - - return FullCheck(now); - - bool FullCheck(in DateTimeOffset offset) - { - if (AbsoluteExpiration.HasValue && AbsoluteExpiration.Value <= offset) - { - SetExpired(EvictionReason.Expired); - return true; - } - - if (_slidingExpiration.HasValue - && (offset - LastAccessed) >= _slidingExpiration) - { - SetExpired(EvictionReason.Expired); - return true; - } - - return false; - } - } - - internal void AttachTokens() => _tokens?.AttachTokens(this); - - private static void ExpirationTokensExpired(object obj) - { - // start a new thread to avoid issues with callbacks called from RegisterChangeCallback - Task.Factory.StartNew(state => - { - var entry = (CacheEntry)state; - entry.SetExpired(EvictionReason.TokenExpired); - entry._cache.EntryExpired(entry); - }, obj, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); - } - - internal void InvokeEvictionCallbacks() => _tokens?.InvokeEvictionCallbacks(this); - - // this simple check very often allows us to avoid expensive call to PropagateOptions(CacheEntryHelper.Current) - [MethodImpl(MethodImplOptions.AggressiveInlining)] // added based on profiling - internal bool CanPropagateOptions() => (_tokens != null && _tokens.CanPropagateTokens()) || AbsoluteExpiration.HasValue; - - internal void PropagateOptions(CacheEntry parent) - { - if (parent == null) - { - return; - } - - // Copy expiration tokens and AbsoluteExpiration to the cache entries hierarchy. - // We do this regardless of it gets cached because the tokens are associated with the value we'll return. - _tokens?.PropagateTokens(parent); - - if (AbsoluteExpiration.HasValue) - { - if (!parent.AbsoluteExpiration.HasValue || AbsoluteExpiration < parent.AbsoluteExpiration) - { - parent.AbsoluteExpiration = AbsoluteExpiration; - } - } - } - - private CacheEntryTokens GetOrCreateTokens() - { - if (_tokens != null) - { - return _tokens; - } - - CacheEntryTokens result = new CacheEntryTokens(); - return Interlocked.CompareExchange(ref _tokens, result, null) ?? result; - } - } -} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/Memory/CacheEntryHelper.cs b/frameworks/CSharp/appmpower/src/Memory/CacheEntryHelper.cs deleted file mode 100644 index 71d07fe24c5..00000000000 --- a/frameworks/CSharp/appmpower/src/Memory/CacheEntryHelper.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Diagnostics; -using System.Threading; - -namespace appMpower.Memory -{ - internal static class CacheEntryHelper - { - private static readonly AsyncLocal _current = new AsyncLocal(); - - internal static CacheEntry Current - { - get => _current.Value; - private set => _current.Value = value; - } - - internal static CacheEntry EnterScope(CacheEntry current) - { - CacheEntry previous = Current; - Current = current; - return previous; - } - - internal static void ExitScope(CacheEntry current, CacheEntry previous) - { - Debug.Assert(Current == current, "Entries disposed in invalid order"); - Current = previous; - } - } -} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/Memory/CacheEntryState.cs b/frameworks/CSharp/appmpower/src/Memory/CacheEntryState.cs deleted file mode 100644 index 15d59ead9c1..00000000000 --- a/frameworks/CSharp/appmpower/src/Memory/CacheEntryState.cs +++ /dev/null @@ -1,62 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using Microsoft.Extensions.Caching.Memory; - -namespace appMpower.Memory -{ - internal sealed partial class CacheEntry - { - // this type exists just to reduce CacheEntry size by replacing many enum & boolean fields with one of a size of Int32 - private struct CacheEntryState - { - private byte _flags; - private byte _evictionReason; - private byte _priority; - - internal CacheEntryState(CacheItemPriority priority) : this() => _priority = (byte)priority; - - internal bool IsDisposed - { - get => ((Flags)_flags & Flags.IsDisposed) != 0; - set => SetFlag(Flags.IsDisposed, value); - } - - internal bool IsExpired - { - get => ((Flags)_flags & Flags.IsExpired) != 0; - set => SetFlag(Flags.IsExpired, value); - } - - internal bool IsValueSet - { - get => ((Flags)_flags & Flags.IsValueSet) != 0; - set => SetFlag(Flags.IsValueSet, value); - } - - internal EvictionReason EvictionReason - { - get => (EvictionReason)_evictionReason; - set => _evictionReason = (byte)value; - } - - internal CacheItemPriority Priority - { - get => (CacheItemPriority)_priority; - set => _priority = (byte)value; - } - - private void SetFlag(Flags option, bool value) => _flags = (byte)(value ? (_flags | (byte)option) : (_flags & ~(byte)option)); - - [Flags] - private enum Flags : byte - { - Default = 0, - IsValueSet = 1 << 0, - IsExpired = 1 << 1, - IsDisposed = 1 << 2, - } - } - } -} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/Memory/CacheEntryTokens.cs b/frameworks/CSharp/appmpower/src/Memory/CacheEntryTokens.cs deleted file mode 100644 index 247630639e7..00000000000 --- a/frameworks/CSharp/appmpower/src/Memory/CacheEntryTokens.cs +++ /dev/null @@ -1,140 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Primitives; -using Microsoft.Extensions.Caching.Memory; - -namespace appMpower.Memory -{ - internal sealed partial class CacheEntry - { - // this type exists just to reduce average CacheEntry size - // which typically is not using expiration tokens or callbacks - private sealed class CacheEntryTokens - { - private List _expirationTokens; - private List _expirationTokenRegistrations; - private List _postEvictionCallbacks; // this is not really related to tokens, but was moved here to shrink typical CacheEntry size - - internal List ExpirationTokens => _expirationTokens ??= new List(); - internal List PostEvictionCallbacks => _postEvictionCallbacks ??= new List(); - - internal void AttachTokens(CacheEntry cacheEntry) - { - if (_expirationTokens != null) - { - lock (this) - { - for (int i = 0; i < _expirationTokens.Count; i++) - { - IChangeToken expirationToken = _expirationTokens[i]; - if (expirationToken.ActiveChangeCallbacks) - { - _expirationTokenRegistrations ??= new List(1); - IDisposable registration = expirationToken.RegisterChangeCallback(ExpirationCallback, cacheEntry); - _expirationTokenRegistrations.Add(registration); - } - } - } - } - } - - internal bool CheckForExpiredTokens(CacheEntry cacheEntry) - { - if (_expirationTokens != null) - { - for (int i = 0; i < _expirationTokens.Count; i++) - { - IChangeToken expiredToken = _expirationTokens[i]; - if (expiredToken.HasChanged) - { - cacheEntry.SetExpired(EvictionReason.TokenExpired); - return true; - } - } - } - return false; - } - - internal bool CanPropagateTokens() => _expirationTokens != null; - - internal void PropagateTokens(CacheEntry parentEntry) - { - if (_expirationTokens != null) - { - lock (this) - { - lock (parentEntry.GetOrCreateTokens()) - { - foreach (IChangeToken expirationToken in _expirationTokens) - { - parentEntry.AddExpirationToken(expirationToken); - } - } - } - } - } - - internal void DetachTokens() - { - // _expirationTokenRegistrations is not checked for null, because AttachTokens might initialize it under lock - // instead we are checking for _expirationTokens, because if they are not null, then _expirationTokenRegistrations might also be not null - if (_expirationTokens != null) - { - lock (this) - { - List registrations = _expirationTokenRegistrations; - if (registrations != null) - { - _expirationTokenRegistrations = null; - for (int i = 0; i < registrations.Count; i++) - { - IDisposable registration = registrations[i]; - registration.Dispose(); - } - } - } - } - } - - internal void InvokeEvictionCallbacks(CacheEntry cacheEntry) - { - if (_postEvictionCallbacks != null) - { - Task.Factory.StartNew(state => InvokeCallbacks((CacheEntry)state), cacheEntry, - CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); - } - } - - private static void InvokeCallbacks(CacheEntry entry) - { - List callbackRegistrations = Interlocked.Exchange(ref entry._tokens._postEvictionCallbacks, null); - - if (callbackRegistrations == null) - { - return; - } - - for (int i = 0; i < callbackRegistrations.Count; i++) - { - PostEvictionCallbackRegistration registration = callbackRegistrations[i]; - - try - { - registration.EvictionCallback?.Invoke(entry.Key, entry.Value, entry.EvictionReason, registration.State); - } - catch (Exception e) - { - // This will be invoked on a background thread, don't let it throw. - entry._cache._logger.LogError(e, "EvictionCallback invoked failed"); - } - } - } - } - } -} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/Memory/MemoryCache.cs b/frameworks/CSharp/appmpower/src/Memory/MemoryCache.cs deleted file mode 100644 index df4f7063cf0..00000000000 --- a/frameworks/CSharp/appmpower/src/Memory/MemoryCache.cs +++ /dev/null @@ -1,520 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Runtime.CompilerServices; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.Extensions.Internal; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Logging.Abstractions; -using Microsoft.Extensions.Options; -using Microsoft.Extensions.Caching.Memory; - -namespace appMpower.Memory -{ - /// - /// An implementation of using a dictionary to - /// store its entries. - /// - public class MemoryCache : IMemoryCache - { - internal readonly ILogger _logger; - - private readonly MemoryCacheOptions _options; - private readonly ConcurrentDictionary _entries; - - private long _cacheSize; - private bool _disposed; - private DateTimeOffset _lastExpirationScan; - - /// - /// Creates a new instance. - /// - /// The options of the cache. - public MemoryCache(IOptions optionsAccessor) - : this(optionsAccessor, NullLoggerFactory.Instance) { } - - /// - /// Creates a new instance. - /// - /// The options of the cache. - /// The factory used to create loggers. - public MemoryCache(IOptions optionsAccessor, ILoggerFactory loggerFactory) - { - if (optionsAccessor == null) - { - throw new ArgumentNullException(nameof(optionsAccessor)); - } - - if (loggerFactory == null) - { - throw new ArgumentNullException(nameof(loggerFactory)); - } - - _options = optionsAccessor.Value; - //_logger = loggerFactory.CreateLogger(); - _logger = loggerFactory.CreateLogger("MemoryCache"); - - _entries = new ConcurrentDictionary(); - - if (_options.Clock == null) - { - _options.Clock = new SystemClock(); - } - - _lastExpirationScan = _options.Clock.UtcNow; - TrackLinkedCacheEntries = _options.TrackLinkedCacheEntries; // we store the setting now so it's consistent for entire MemoryCache lifetime - } - - /// - /// Cleans up the background collection events. - /// - ~MemoryCache() => Dispose(false); - - /// - /// Gets the count of the current entries for diagnostic purposes. - /// - public int Count => _entries.Count; - - // internal for testing - internal long Size { get => Interlocked.Read(ref _cacheSize); } - - internal bool TrackLinkedCacheEntries { get; } - - private ICollection> EntriesCollection => _entries; - - /// - public ICacheEntry CreateEntry(object key) - { - CheckDisposed(); - ValidateCacheKey(key); - - return new CacheEntry(key, this); - } - - internal void SetEntry(CacheEntry entry) - { - if (_disposed) - { - // No-op instead of throwing since this is called during CacheEntry.Dispose - return; - } - - if (_options.SizeLimit.HasValue && !entry.Size.HasValue) - { - //throw new InvalidOperationException(SR.Format(SR.CacheEntryHasEmptySize, nameof(entry.Size), nameof(_options.SizeLimit))); - throw new InvalidOperationException(); - } - - DateTimeOffset utcNow = _options.Clock.UtcNow; - - DateTimeOffset? absoluteExpiration = null; - if (entry.AbsoluteExpirationRelativeToNow.HasValue) - { - absoluteExpiration = utcNow + entry.AbsoluteExpirationRelativeToNow; - } - else if (entry.AbsoluteExpiration.HasValue) - { - absoluteExpiration = entry.AbsoluteExpiration; - } - - // Applying the option's absolute expiration only if it's not already smaller. - // This can be the case if a dependent cache entry has a smaller value, and - // it was set by cascading it to its parent. - if (absoluteExpiration.HasValue) - { - if (!entry.AbsoluteExpiration.HasValue || absoluteExpiration.Value < entry.AbsoluteExpiration.Value) - { - entry.AbsoluteExpiration = absoluteExpiration; - } - } - - // Initialize the last access timestamp at the time the entry is added - entry.LastAccessed = utcNow; - - if (_entries.TryGetValue(entry.Key, out CacheEntry priorEntry)) - { - priorEntry.SetExpired(EvictionReason.Replaced); - } - - bool exceedsCapacity = UpdateCacheSizeExceedsCapacity(entry); - - if (!entry.CheckExpired(utcNow) && !exceedsCapacity) - { - bool entryAdded = false; - - if (priorEntry == null) - { - // Try to add the new entry if no previous entries exist. - entryAdded = _entries.TryAdd(entry.Key, entry); - } - else - { - // Try to update with the new entry if a previous entries exist. - entryAdded = _entries.TryUpdate(entry.Key, entry, priorEntry); - - if (entryAdded) - { - if (_options.SizeLimit.HasValue) - { - // The prior entry was removed, decrease the by the prior entry's size - Interlocked.Add(ref _cacheSize, -priorEntry.Size.Value); - } - } - else - { - // The update will fail if the previous entry was removed after retrival. - // Adding the new entry will succeed only if no entry has been added since. - // This guarantees removing an old entry does not prevent adding a new entry. - entryAdded = _entries.TryAdd(entry.Key, entry); - } - } - - if (entryAdded) - { - entry.AttachTokens(); - } - else - { - if (_options.SizeLimit.HasValue) - { - // Entry could not be added, reset cache size - Interlocked.Add(ref _cacheSize, -entry.Size.Value); - } - entry.SetExpired(EvictionReason.Replaced); - entry.InvokeEvictionCallbacks(); - } - - if (priorEntry != null) - { - priorEntry.InvokeEvictionCallbacks(); - } - } - else - { - if (exceedsCapacity) - { - // The entry was not added due to overcapacity - entry.SetExpired(EvictionReason.Capacity); - - TriggerOvercapacityCompaction(); - } - else - { - if (_options.SizeLimit.HasValue) - { - // Entry could not be added due to being expired, reset cache size - Interlocked.Add(ref _cacheSize, -entry.Size.Value); - } - } - - entry.InvokeEvictionCallbacks(); - if (priorEntry != null) - { - RemoveEntry(priorEntry); - } - } - - StartScanForExpiredItemsIfNeeded(utcNow); - } - - /// - public bool TryGetValue(object key, out object result) - { - ValidateCacheKey(key); - CheckDisposed(); - - DateTimeOffset utcNow = _options.Clock.UtcNow; - - if (_entries.TryGetValue(key, out CacheEntry entry)) - { - // Check if expired due to expiration tokens, timers, etc. and if so, remove it. - // Allow a stale Replaced value to be returned due to concurrent calls to SetExpired during SetEntry. - if (!entry.CheckExpired(utcNow) || entry.EvictionReason == EvictionReason.Replaced) - { - entry.LastAccessed = utcNow; - result = entry.Value; - - if (TrackLinkedCacheEntries && entry.CanPropagateOptions()) - { - // When this entry is retrieved in the scope of creating another entry, - // that entry needs a copy of these expiration tokens. - entry.PropagateOptions(CacheEntryHelper.Current); - } - - StartScanForExpiredItemsIfNeeded(utcNow); - - return true; - } - else - { - // TODO: For efficiency queue this up for batch removal - RemoveEntry(entry); - } - } - - StartScanForExpiredItemsIfNeeded(utcNow); - - result = null; - return false; - } - - /// - public void Remove(object key) - { - ValidateCacheKey(key); - - CheckDisposed(); - if (_entries.TryRemove(key, out CacheEntry entry)) - { - if (_options.SizeLimit.HasValue) - { - Interlocked.Add(ref _cacheSize, -entry.Size.Value); - } - - entry.SetExpired(EvictionReason.Removed); - entry.InvokeEvictionCallbacks(); - } - - StartScanForExpiredItemsIfNeeded(_options.Clock.UtcNow); - } - - private void RemoveEntry(CacheEntry entry) - { - if (EntriesCollection.Remove(new KeyValuePair(entry.Key, entry))) - { - if (_options.SizeLimit.HasValue) - { - Interlocked.Add(ref _cacheSize, -entry.Size.Value); - } - entry.InvokeEvictionCallbacks(); - } - } - - internal void EntryExpired(CacheEntry entry) - { - // TODO: For efficiency consider processing these expirations in batches. - RemoveEntry(entry); - StartScanForExpiredItemsIfNeeded(_options.Clock.UtcNow); - } - - // Called by multiple actions to see how long it's been since we last checked for expired items. - // If sufficient time has elapsed then a scan is initiated on a background task. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void StartScanForExpiredItemsIfNeeded(DateTimeOffset utcNow) - { - if (_options.ExpirationScanFrequency < utcNow - _lastExpirationScan) - { - ScheduleTask(utcNow); - } - - void ScheduleTask(DateTimeOffset utcNow) - { - _lastExpirationScan = utcNow; - Task.Factory.StartNew(state => ScanForExpiredItems((MemoryCache)state), this, - CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); - } - } - - private static void ScanForExpiredItems(MemoryCache cache) - { - DateTimeOffset now = cache._lastExpirationScan = cache._options.Clock.UtcNow; - - foreach (KeyValuePair item in cache._entries) - { - CacheEntry entry = item.Value; - - if (entry.CheckExpired(now)) - { - cache.RemoveEntry(entry); - } - } - } - - private bool UpdateCacheSizeExceedsCapacity(CacheEntry entry) - { - if (!_options.SizeLimit.HasValue) - { - return false; - } - - long newSize = 0L; - for (int i = 0; i < 100; i++) - { - long sizeRead = Interlocked.Read(ref _cacheSize); - newSize = sizeRead + entry.Size.Value; - - if (newSize < 0 || newSize > _options.SizeLimit) - { - // Overflow occurred, return true without updating the cache size - return true; - } - - if (sizeRead == Interlocked.CompareExchange(ref _cacheSize, newSize, sizeRead)) - { - return false; - } - } - - return true; - } - - private void TriggerOvercapacityCompaction() - { - _logger.LogDebug("Overcapacity compaction triggered"); - - // Spawn background thread for compaction - ThreadPool.QueueUserWorkItem(s => OvercapacityCompaction((MemoryCache)s), this); - } - - private static void OvercapacityCompaction(MemoryCache cache) - { - long currentSize = Interlocked.Read(ref cache._cacheSize); - - cache._logger.LogDebug($"Overcapacity compaction executing. Current size {currentSize}"); - - double? lowWatermark = cache._options.SizeLimit * (1 - cache._options.CompactionPercentage); - if (currentSize > lowWatermark) - { - cache.Compact(currentSize - (long)lowWatermark, entry => entry.Size.Value); - } - - cache._logger.LogDebug($"Overcapacity compaction executed. New size {Interlocked.Read(ref cache._cacheSize)}"); - } - - /// Remove at least the given percentage (0.10 for 10%) of the total entries (or estimated memory?), according to the following policy: - /// 1. Remove all expired items. - /// 2. Bucket by CacheItemPriority. - /// 3. Least recently used objects. - /// ?. Items with the soonest absolute expiration. - /// ?. Items with the soonest sliding expiration. - /// ?. Larger objects - estimated by object graph size, inaccurate. - public void Compact(double percentage) - { - int removalCountTarget = (int)(_entries.Count * percentage); - Compact(removalCountTarget, _ => 1); - } - - private void Compact(long removalSizeTarget, Func computeEntrySize) - { - var entriesToRemove = new List(); - var lowPriEntries = new List(); - var normalPriEntries = new List(); - var highPriEntries = new List(); - long removedSize = 0; - - // Sort items by expired & priority status - DateTimeOffset now = _options.Clock.UtcNow; - foreach (KeyValuePair item in _entries) - { - CacheEntry entry = item.Value; - if (entry.CheckExpired(now)) - { - entriesToRemove.Add(entry); - removedSize += computeEntrySize(entry); - } - else - { - switch (entry.Priority) - { - case CacheItemPriority.Low: - lowPriEntries.Add(entry); - break; - case CacheItemPriority.Normal: - normalPriEntries.Add(entry); - break; - case CacheItemPriority.High: - highPriEntries.Add(entry); - break; - case CacheItemPriority.NeverRemove: - break; - default: - throw new NotSupportedException("Not implemented: " + entry.Priority); - } - } - } - - ExpirePriorityBucket(ref removedSize, removalSizeTarget, computeEntrySize, entriesToRemove, lowPriEntries); - ExpirePriorityBucket(ref removedSize, removalSizeTarget, computeEntrySize, entriesToRemove, normalPriEntries); - ExpirePriorityBucket(ref removedSize, removalSizeTarget, computeEntrySize, entriesToRemove, highPriEntries); - - foreach (CacheEntry entry in entriesToRemove) - { - RemoveEntry(entry); - } - - // Policy: - // 1. Least recently used objects. - // ?. Items with the soonest absolute expiration. - // ?. Items with the soonest sliding expiration. - // ?. Larger objects - estimated by object graph size, inaccurate. - static void ExpirePriorityBucket(ref long removedSize, long removalSizeTarget, Func computeEntrySize, List entriesToRemove, List priorityEntries) - { - // Do we meet our quota by just removing expired entries? - if (removalSizeTarget <= removedSize) - { - // No-op, we've met quota - return; - } - - // Expire enough entries to reach our goal - // TODO: Refine policy - - // LRU - priorityEntries.Sort((e1, e2) => e1.LastAccessed.CompareTo(e2.LastAccessed)); - foreach (CacheEntry entry in priorityEntries) - { - entry.SetExpired(EvictionReason.Capacity); - entriesToRemove.Add(entry); - removedSize += computeEntrySize(entry); - - if (removalSizeTarget <= removedSize) - { - break; - } - } - } - } - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool disposing) - { - if (!_disposed) - { - if (disposing) - { - GC.SuppressFinalize(this); - } - - _disposed = true; - } - } - - private void CheckDisposed() - { - if (_disposed) - { - Throw(); - } - - static void Throw() => throw new ObjectDisposedException(typeof(MemoryCache).FullName); - } - - private static void ValidateCacheKey(object key) - { - if (key == null) - { - Throw(); - } - - static void Throw() => throw new ArgumentNullException(nameof(key)); - } - } -} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/Memory/MemoryCacheOptions.cs b/frameworks/CSharp/appmpower/src/Memory/MemoryCacheOptions.cs deleted file mode 100644 index d714c96df42..00000000000 --- a/frameworks/CSharp/appmpower/src/Memory/MemoryCacheOptions.cs +++ /dev/null @@ -1,67 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using Microsoft.Extensions.Internal; -using Microsoft.Extensions.Options; - -namespace appMpower.Memory -{ - public class MemoryCacheOptions : IOptions - { - private long? _sizeLimit; - private double _compactionPercentage = 0.05; - - public ISystemClock Clock { get; set; } - - /// - /// Gets or sets the minimum length of time between successive scans for expired items. - /// - public TimeSpan ExpirationScanFrequency { get; set; } = TimeSpan.FromMinutes(1); - - /// - /// Gets or sets the maximum size of the cache. - /// - public long? SizeLimit - { - get => _sizeLimit; - set - { - if (value < 0) - { - throw new ArgumentOutOfRangeException(nameof(value), value, $"{nameof(value)} must be non-negative."); - } - - _sizeLimit = value; - } - } - - /// - /// Gets or sets the amount to compact the cache by when the maximum size is exceeded. - /// - public double CompactionPercentage - { - get => _compactionPercentage; - set - { - if (value < 0 || value > 1) - { - throw new ArgumentOutOfRangeException(nameof(value), value, $"{nameof(value)} must be between 0 and 1 inclusive."); - } - - _compactionPercentage = value; - } - } - - /// - /// Gets or sets whether to track linked entries. Disabled by default. - /// - /// Prior to .NET 7 this feature was always enabled. - public bool TrackLinkedCacheEntries { get; set; } - - MemoryCacheOptions IOptions.Value - { - get { return this; } - } - } -} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/Microsoft/BatchUpdateString.cs b/frameworks/CSharp/appmpower/src/Microsoft/BatchUpdateString.cs deleted file mode 100644 index 0f3e501c485..00000000000 --- a/frameworks/CSharp/appmpower/src/Microsoft/BatchUpdateString.cs +++ /dev/null @@ -1,84 +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.Linq; - -namespace PlatformBenchmarks -{ - internal class BatchUpdateString - { - private const int MaxBatch = 500; - - internal static readonly string[] Ids = Enumerable.Range(0, MaxBatch).Select(i => $"i{i}").ToArray(); - internal static readonly string[] Randoms = Enumerable.Range(0, MaxBatch).Select(i => $"r{i}").ToArray(); - internal static readonly string[] Jds = Enumerable.Range(0, MaxBatch).Select(i => $"j{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("(?::int,?::int),")); - sb.Append("(?::int,?::int) ORDER BY 1) AS temp(id, randomNumber) WHERE temp.id = world.id"); - //sb.Append("(?::int,?::int)) AS temp(id, randomNumber) WHERE temp.id = world.id"); - */ - -#if MYSQL - for (int i = 0; i < batchSize; i++) - { - sb.Append("UPDATE world SET randomNumber=? WHERE id=?;"); - } -#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("@j" + i + ","); - } - - sb.Append("@j" + lastIndex + ")"); -#else - sb.Append("UPDATE world SET randomNumber=CASE id "); - - for (int i = 0; i < batchSize; i++) - { - sb.Append("WHEN ? THEN ? "); - } - - sb.Append("ELSE randomnumber END WHERE id IN("); - - for (int i = 0; i < lastIndex; i++) - { - sb.Append("?,"); - } - - sb.Append("?)"); -#endif - - return _queries[batchSize] = StringBuilderCache.GetStringAndRelease(sb); - } - } -} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/Microsoft/CachKey.cs b/frameworks/CSharp/appmpower/src/Microsoft/CachKey.cs deleted file mode 100644 index 3bc21736c08..00000000000 --- a/frameworks/CSharp/appmpower/src/Microsoft/CachKey.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; - -namespace PlatformBenchmarks -{ - 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/appmpower/src/Microsoft/ConcurrentRandom.cs b/frameworks/CSharp/appmpower/src/Microsoft/ConcurrentRandom.cs deleted file mode 100644 index b5a74d48884..00000000000 --- a/frameworks/CSharp/appmpower/src/Microsoft/ConcurrentRandom.cs +++ /dev/null @@ -1,32 +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.Runtime.CompilerServices; -using System.Threading; - -namespace PlatformBenchmarks -{ - 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); - } - } -} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/Microsoft/StringBuilderCache.cs b/frameworks/CSharp/appmpower/src/Microsoft/StringBuilderCache.cs deleted file mode 100644 index 6f0b20b7278..00000000000 --- a/frameworks/CSharp/appmpower/src/Microsoft/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 PlatformBenchmarks -{ - 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/appmpower/src/Program.cs b/frameworks/CSharp/appmpower/src/Program.cs deleted file mode 100644 index 5647ac9b787..00000000000 --- a/frameworks/CSharp/appmpower/src/Program.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; -using System.Net; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Hosting.Server.Features; -using Microsoft.AspNetCore.Server.Kestrel.Core; -using Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets; -using Microsoft.Extensions.Logging.Abstractions; -using Microsoft.Extensions.Options; - -namespace appMpower -{ - class Program - { - static async Task Main(string[] args) - { - var socketTransportOptions = new SocketTransportOptions(); - var socketTransportFactory = new SocketTransportFactory(Options.Create(socketTransportOptions), NullLoggerFactory.Instance); - var kestrelServerOptions = new KestrelServerOptions(); - - kestrelServerOptions.Listen(IPAddress.Any, 8080); - kestrelServerOptions.AddServerHeader = false; - - using var kestrelServer = new KestrelServer(Options.Create(kestrelServerOptions), socketTransportFactory, NullLoggerFactory.Instance); - - await kestrelServer.StartAsync(new HttpApplication(), CancellationToken.None); - - Console.WriteLine("Listening on:"); - - foreach (var address in kestrelServer.Features.Get().Addresses) - { - Console.WriteLine(" - " + address); - } - - Console.WriteLine("Process CTRL+C to quit"); - var wh = new ManualResetEventSlim(); - Console.CancelKeyPress += (sender, e) => wh.Set(); - wh.Wait(); - } - } -} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/RawDb.cs b/frameworks/CSharp/appmpower/src/RawDb.cs deleted file mode 100644 index 8813ce6dfcc..00000000000 --- a/frameworks/CSharp/appmpower/src/RawDb.cs +++ /dev/null @@ -1,331 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Data; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.Extensions.Caching.Memory; -using appMpower.Data; -using PlatformBenchmarks; - -namespace appMpower -{ - 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]; - - private static readonly object[] _cacheKeys = Enumerable.Range(0, 10001).Select((i) => new CacheKey(i)).ToArray(); - - private static readonly appMpower.Memory.MemoryCache _cache = new appMpower.Memory.MemoryCache( - new appMpower.Memory.MemoryCacheOptions() - { - ExpirationScanFrequency = TimeSpan.FromMinutes(60) - }); - - public static async Task LoadSingleQueryRow() - { - using var pooledConnection = new DbConnection(DbProviderFactory.ConnectionString); - await pooledConnection.OpenAsync(); - - var (dbCommand, _) = CreateReadCommand(pooledConnection); - - using (dbCommand) - { - var world = await ReadSingleRow(dbCommand); - - return world; - } - } - - public static async Task LoadMultipleQueriesRows(int count) - { - var worlds = new World[count]; - - using var pooledConnection = new DbConnection(DbProviderFactory.ConnectionString); - await pooledConnection.OpenAsync(); - - var (dbCommand, dbDataParameter) = CreateReadCommand(pooledConnection); - - using (dbCommand) - { - for (int i = 0; i < count; i++) - { - worlds[i] = await ReadSingleRow(dbCommand); - dbDataParameter.Value = _random.Next(1, 10001); - } - } - - 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) - { - var dataReader = await dbCommand.ExecuteReaderAsync(CommandBehavior.SingleResult & CommandBehavior.SequentialAccess); - - while (dataReader.Read()) - { - fortunes.Add(new Fortune - ( - id: dataReader.GetInt32(0), -#if MYSQL - //MariaDB ODBC connector does not correctly support Japanese characters in combination with default ADO.NET; - //as a solution we custom read this string - message: ReadColumn(dataReader, 1) -#else - message: dataReader.GetString(1) -#endif - )); - } - - 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) - { - var worlds = new World[count]; - - using var pooledConnection = new DbConnection(DbProviderFactory.ConnectionString); - await pooledConnection.OpenAsync(); - - var (queryCommand, dbDataParameter) = CreateReadCommand(pooledConnection); - - using (queryCommand) - { - for (int i = 0; i < count; i++) - { - worlds[i] = await ReadSingleRow(queryCommand); - dbDataParameter.Value = _random.Next(1, 10001); - } - } - - using var updateCommand = new DbCommand(PlatformBenchmarks.BatchUpdateString.Query(count), pooledConnection); - - var ids = PlatformBenchmarks.BatchUpdateString.Ids; - var randoms = PlatformBenchmarks.BatchUpdateString.Randoms; - -#if !MYSQL - var jds = PlatformBenchmarks.BatchUpdateString.Jds; -#endif - - for (int i = 0; i < count; i++) - { - var randomNumber = _random.Next(1, 10001); - - updateCommand.CreateParameter(ids[i], DbType.Int32, worlds[i].Id); - updateCommand.CreateParameter(randoms[i], DbType.Int32, randomNumber); - - worlds[i].RandomNumber = randomNumber; - } - -#if !MYSQL - for (int i = 0; i < count; i++) - { - updateCommand.CreateParameter(jds[i], DbType.Int32, worlds[i].Id); - } -#endif - - await updateCommand.ExecuteNonQueryAsync(); - - return worlds; - } - - 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))); - } - - private static async Task ReadSingleRow(DbCommand dbCommand) - { - var dataReader = await dbCommand.ExecuteReaderAsync(CommandBehavior.SingleRow & CommandBehavior.SequentialAccess); - - dataReader.Read(); - - var world = new World - { - Id = dataReader.GetInt32(0), - RandomNumber = dataReader.GetInt32(1) - }; - - dataReader.Close(); - - return world; - } - - public static async Task ReadMultipleRows(int count) - { - int j = 0; - var ids = PlatformBenchmarks.BatchUpdateString.Ids; - var worlds = new World[count]; - string queryString; - - if (_queriesMultipleRows[count] != null) - { - queryString = _queriesMultipleRows[count]; - } - else - { - var stringBuilder = PlatformBenchmarks.StringBuilderCache.Acquire(); - - for (int i = 0; i < count; i++) - { - stringBuilder.Append("SELECT * FROM world WHERE id=?;"); - } - - queryString = _queriesMultipleRows[count] = PlatformBenchmarks.StringBuilderCache.GetStringAndRelease(stringBuilder); - } - - using var pooledConnection = new DbConnection(DbProviderFactory.ConnectionString); - await pooledConnection.OpenAsync(); - - using var dbCommand = new DbCommand(queryString, pooledConnection); - - for (int i = 0; i < count; i++) - { - dbCommand.CreateParameter(ids[i], DbType.Int32, _random.Next(1, 10001)); - } - - var dataReader = await dbCommand.ExecuteReaderAsync(CommandBehavior.Default & CommandBehavior.SequentialAccess); - - do - { - dataReader.Read(); - - worlds[j] = new World - { - Id = dataReader.GetInt32(0), - RandomNumber = dataReader.GetInt32(1) - }; - - j++; - } while (await dataReader.NextResultAsync()); - - 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); - } - - public static async Task PopulateCache() - { - using var pooledConnection = new DbConnection(DbProviderFactory.ConnectionString); - await pooledConnection.OpenAsync(); - - var (dbCommand, dbDataParameter) = CreateReadCommand(pooledConnection); - - using (dbCommand) - { - var cacheKeys = _cacheKeys; - var cache = _cache; - - for (var i = 1; i < 10001; i++) - { - dbDataParameter.Value = i; - cache.Set(cacheKeys[i], await ReadSingleRow(dbCommand)); - } - } - } - - public static Task LoadCachedQueries(int count) - { - var result = new CachedWorld[count]; - var cacheKeys = _cacheKeys; - var cache = _cache; - var random = _random; - - for (var i = 0; i < result.Length; i++) - { - var id = random.Next(1, 10001); - var key = cacheKeys[id]; - - if (cache.TryGetValue(key, out object cached)) - { - result[i] = (CachedWorld)cached; - } - else - { - //return LoadUncachedQueries(id, i, count, this, result); - return LoadUncachedQueries(id, i, count, result); - } - } - - return Task.FromResult(result); - } - - static async Task LoadUncachedQueries(int id, int i, int count, CachedWorld[] result) - { - using var pooledConnection = new DbConnection(DbProviderFactory.ConnectionString); - await pooledConnection.OpenAsync(); - - var (dbCommand, dbDataParameter) = CreateReadCommand(pooledConnection); - - using (dbCommand) - { - Func> create = async (entry) => - { - return await ReadSingleRow(dbCommand); - }; - - var cacheKeys = _cacheKeys; - var key = cacheKeys[id]; - - dbDataParameter.Value = id; - - for (; i < result.Length; i++) - { - result[i] = await _cache.GetOrCreateAsync(key, create); - - id = _random.Next(1, 10001); - dbDataParameter.Value = id; - key = cacheKeys[id]; - } - } - - return result; - } - } -} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/World.cs b/frameworks/CSharp/appmpower/src/World.cs deleted file mode 100644 index cfec08b1f9c..00000000000 --- a/frameworks/CSharp/appmpower/src/World.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace appMpower -{ - public struct World - { - public int Id { get; set; } - public int RandomNumber { get; set; } - } -} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/WorldSerializer.cs b/frameworks/CSharp/appmpower/src/WorldSerializer.cs deleted file mode 100644 index 6150c5560b7..00000000000 --- a/frameworks/CSharp/appmpower/src/WorldSerializer.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.Text.Json; - -namespace appMpower -{ - public class WorldSerializer : Kestrel.IJsonSerializer - { - public void Serialize(Utf8JsonWriter utf8JsonWriter, World world) - { - utf8JsonWriter.WriteStartObject(); - utf8JsonWriter.WriteNumber("id", world.Id); - utf8JsonWriter.WriteNumber("randomNumber", world.RandomNumber); - utf8JsonWriter.WriteEndObject(); - } - } -} diff --git a/frameworks/CSharp/appmpower/src/appMpower.Orm/Constants.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/Constants.cs new file mode 100644 index 00000000000..c1678a71a62 --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/Constants.cs @@ -0,0 +1,10 @@ +using appMpower.Orm.Data; + +namespace appMpower.Orm +{ + public static class Constants + { + public static Dbms Dbms = Dbms.PostgreSQL; + public static DbProvider DbProvider = DbProvider.ODBC; + } +} \ 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 new file mode 100644 index 00000000000..0dfe4581906 --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbCommand.cs @@ -0,0 +1,202 @@ +using System.Data; +using System.Data.Odbc; + +namespace appMpower.Orm.Data +{ + public class DbCommand : IDbCommand + { + private OdbcCommand _odbcCommand; + private DbConnection _dbConnection; + + public DbCommand(DbConnection dbConnection) + { + _odbcCommand = (OdbcCommand)dbConnection.CreateCommand(); + _dbConnection = dbConnection; + } + + public DbCommand(string commandText, DbConnection dbConnection) + { + _odbcCommand = dbConnection.GetCommand(commandText, CommandType.Text); + _dbConnection = dbConnection; + } + + public DbCommand(string commandText, CommandType commandType, DbConnection dbConnection) + { + _odbcCommand = dbConnection.GetCommand(commandText, commandType); + _dbConnection = dbConnection; + } + + internal IDbCommand Command + { + get + { + return _odbcCommand; + } + set + { + _odbcCommand = (OdbcCommand)value; + } + } + + public string CommandText + { + get + { + return _odbcCommand.CommandText; + } + set + { + _odbcCommand.CommandText = value; + } + } + + public int CommandTimeout + { + get + { + return _odbcCommand.CommandTimeout; + } + set + { + _odbcCommand.CommandTimeout = value; + } + } + public CommandType CommandType + { + get + { + return _odbcCommand.CommandType; + } + set + { + _odbcCommand.CommandType = value; + } + } + +#nullable enable + public IDbConnection? Connection + { + get + { + return _odbcCommand.Connection; + } + set + { + _odbcCommand.Connection = (OdbcConnection?)value; + } + } +#nullable disable + + public IDataParameterCollection Parameters + { + get + { + return _odbcCommand.Parameters; + } + } + +#nullable enable + public IDbTransaction? Transaction + { + get + { + return _odbcCommand.Transaction; + } + set + { + _odbcCommand.Transaction = (OdbcTransaction?)value; + } + } +#nullable disable + + public UpdateRowSource UpdatedRowSource + { + get + { + return _odbcCommand.UpdatedRowSource; + } + set + { + _odbcCommand.UpdatedRowSource = value; + } + } + public void Cancel() + { + _odbcCommand.Cancel(); + } + + public IDbDataParameter CreateParameter() + { + return _odbcCommand.CreateParameter(); + } + + public IDbDataParameter CreateParameter(string name, object value) + { + return CreateParameter(name, DbType.String, value); + } + + public IDbDataParameter CreateParameter(string name, DbType dbType, object value) + { + IDbDataParameter dbDataParameter; + + if (_odbcCommand.Parameters.Contains(name)) + { + dbDataParameter = _odbcCommand.Parameters[name]; + dbDataParameter.Value = value; + } + else + { + dbDataParameter = _odbcCommand.CreateParameter(); + + dbDataParameter.ParameterName = name; + dbDataParameter.DbType = dbType; + dbDataParameter.Value = value; + _odbcCommand.Parameters.Add(dbDataParameter); + } + + return dbDataParameter; + } + + public int ExecuteNonQuery() + { + return _odbcCommand.ExecuteNonQuery(); + } + + public IDataReader ExecuteReader() + { + return _odbcCommand.ExecuteReader(); + } + + public async Task ExecuteNonQueryAsync() + { + return await _odbcCommand.ExecuteNonQueryAsync(); + } + + public IDataReader ExecuteReader(CommandBehavior behavior) + { + return _odbcCommand.ExecuteReader(behavior); + } + + public async Task ExecuteReaderAsync(CommandBehavior behavior) + { + return await _odbcCommand.ExecuteReaderAsync(behavior); + } + +#nullable enable + public object? ExecuteScalar() + { + return _odbcCommand.ExecuteScalar(); + } +#nullable disable + + public void Prepare() + { + _odbcCommand.Prepare(); + } + + public void Dispose() + { + _dbConnection.Release(_odbcCommand); + } + } +} \ 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 new file mode 100644 index 00000000000..7175e1119b4 --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbConnection.cs @@ -0,0 +1,174 @@ +using System.Collections.Concurrent; +using System.Data; +using System.Data.Odbc; + +namespace appMpower.Orm.Data +{ + public class DbConnection : IDbConnection + { + private string _connectionString; + private bool _keyed = false; + private int _number; + private OdbcConnection _odbcConnection; + private ConcurrentStack _odbcCommands = new(); + private Dictionary _keyedOdbcCommands; + + public DbConnection() + { + } + + public DbConnection(string connectionString, bool keyed = false) + { + _keyed = keyed; + _connectionString = connectionString; + GetConnection(); + } + + public IDbConnection Connection + { + get + { + return _odbcConnection; + } + set + { + _odbcConnection = (OdbcConnection)value; + } + } + + public string ConnectionString + { + get + { + return _odbcConnection.ConnectionString; + } + set + { + _connectionString = value; + GetConnection(); + } + } + + private void GetConnection() + { + if (_keyed) + { + (_number, _odbcConnection, _keyedOdbcCommands) = + DbConnectionsKeyed.GetConnectionBase(_connectionString); + } + else + { + (_number, _odbcConnection, _odbcCommands) = + DbConnections.GetConnectionBase(_connectionString); + } + } + + public int ConnectionTimeout + { + get + { + return _odbcConnection.ConnectionTimeout; + } + } + + public string Database + { + get + { + return _odbcConnection.Database; + } + } + + public ConnectionState State + { + get + { + if (_odbcConnection is null) return ConnectionState.Closed; + return _odbcConnection.State; + } + } + + public IDbTransaction BeginTransaction() + { + return _odbcConnection.BeginTransaction(); + } + + public IDbTransaction BeginTransaction(IsolationLevel il) + { + return _odbcConnection.BeginTransaction(il); + } + + public void ChangeDatabase(string databaseName) + { + _odbcConnection.ChangeDatabase(databaseName); + } + + public void Close() + { + _odbcConnection.Close(); + } + + public IDbCommand CreateCommand() + { + return _odbcConnection.CreateCommand(); + } + + public void Open() + { + if (_odbcConnection.State == ConnectionState.Closed) + { + _odbcConnection.Open(); + } + } + + public async Task OpenAsync() + { + if (_odbcConnection.State == ConnectionState.Closed) + { + await _odbcConnection.OpenAsync(); + } + } + + public void Dispose() + { + if (_keyed) + { + DbConnectionsKeyed.Release((Number: _number, OdbcConnection: _odbcConnection, KeyedOdbcCommands: _keyedOdbcCommands)); + } + else + { + DbConnections.Release((Number: _number, OdbcConnection: _odbcConnection, OdbcCommands: _odbcCommands)); + } + } + + internal OdbcCommand GetCommand(string commandText, CommandType commandType) + { + OdbcCommand odbcCommand; + + if (_odbcCommands.TryPop(out odbcCommand)) + { + if (commandText != odbcCommand.CommandText) + { + odbcCommand.CommandText = commandText; + odbcCommand.Parameters.Clear(); + } + + return odbcCommand; + } + else if (_keyed && _keyedOdbcCommands.TryGetValue(commandText, out odbcCommand)) return odbcCommand; + + odbcCommand = _odbcConnection.CreateCommand(); + odbcCommand.CommandText = commandText; + odbcCommand.CommandType = commandType; + odbcCommand.Prepare(); + + return odbcCommand; + } + + internal void Release(OdbcCommand odbcCommand) + { + if (_keyed) _keyedOdbcCommands.TryAdd(odbcCommand.CommandText, odbcCommand); + else _odbcCommands.Push(odbcCommand); + } + } +} \ 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 new file mode 100644 index 00000000000..8897db571fc --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbConnections.cs @@ -0,0 +1,30 @@ +using System.Collections.Concurrent; +using System.Data.Odbc; + +namespace appMpower.Orm.Data +{ + internal static class DbConnections + { + private static short _createdConnections = 0; + + private static ConcurrentStack<(int Number, OdbcConnection OdbcConnection, ConcurrentStack OdbcCommands)> _connectionsStack = new(); + + internal static (int Number, OdbcConnection OdbcConnection, ConcurrentStack OdbcCommands) GetConnectionBase(string connectionString) + { + (int Number, OdbcConnection OdbcConnection, ConcurrentStack OdbcCommands) dbConnectionBase; + + if (!_connectionsStack.TryPop(out dbConnectionBase)) + { + _createdConnections++; + dbConnectionBase = (Number: _createdConnections, OdbcConnection: new OdbcConnection(connectionString), OdbcCommands: new ConcurrentStack()); + } + + return dbConnectionBase; + } + + internal static void Release((int Number, OdbcConnection OdbcConnection, ConcurrentStack OdbcCommands) dbConnectionBase) + { + _connectionsStack.Push(dbConnectionBase); + } + } +} \ 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 new file mode 100644 index 00000000000..0779d640192 --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbConnectionsKeyed.cs @@ -0,0 +1,30 @@ +using System.Collections.Concurrent; +using System.Data.Odbc; + +namespace appMpower.Orm.Data +{ + internal static class DbConnectionsKeyed + { + private static short _createdConnections = 0; + + private static ConcurrentStack<(int Number, OdbcConnection OdbcConnection, Dictionary)> _connectionsStack = new(); + + internal static (int Number, OdbcConnection OdbcConnection, Dictionary KeyedOdbcCommands) GetConnectionBase(string connectionString) + { + (int Number, OdbcConnection OdbcConnection, Dictionary KeyedOdbcCommands) dbConnectionBase; + + if (!_connectionsStack.TryPop(out dbConnectionBase)) + { + _createdConnections++; + dbConnectionBase = (Number: _createdConnections, OdbcConnection: new OdbcConnection(connectionString), KeyedOdbcCommands: new Dictionary()); + } + + return dbConnectionBase; + } + + internal static void Release((int Number, OdbcConnection OdbcConnection, Dictionary KeyedOdbcCommands) dbConnectionBase) + { + _connectionsStack.Push(dbConnectionBase); + } + } +} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbProvider.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbProvider.cs new file mode 100644 index 00000000000..bf60750b52d --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbProvider.cs @@ -0,0 +1,8 @@ +namespace appMpower.Orm.Data +{ + public enum DbProvider + { + ADO = 0, + ODBC = 1, + } +} \ 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 new file mode 100644 index 00000000000..1e72d164a25 --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/DbProviderFactory.cs @@ -0,0 +1,21 @@ +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/Data/Dbms.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/Dbms.cs new file mode 100644 index 00000000000..8c8bbeb67e6 --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/Data/Dbms.cs @@ -0,0 +1,9 @@ +namespace appMpower.Orm.Data +{ + public enum Dbms + { + MySQL = 0, + PostgreSQL = 1, + SQLServer = 2, + } +} \ 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 new file mode 100644 index 00000000000..5ea4ce43fa2 --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/DotnetMethods.cs @@ -0,0 +1,66 @@ +using System.Runtime.InteropServices; +using System.Text; +using System.Text.Json; +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 +public static class DotnetMethods +{ + private static JsonWriterOptions _jsonWriterOptions = new JsonWriterOptions + { + Indented = false, + SkipValidation = true + }; + + private readonly static WorldSerializer _worldSerializer = new WorldSerializer(); + private readonly static WorldsSerializer _worldsSerializer = new WorldsSerializer(); + + public static byte[] Db() + { + var world = RawDb.LoadSingleQueryRow().GetAwaiter().GetResult(); + + var memoryStream = new MemoryStream(); + using var utf8JsonWriter = new Utf8JsonWriter(memoryStream, _jsonWriterOptions); + + _worldSerializer.Serialize(utf8JsonWriter, world); + + return memoryStream.ToArray(); + } + + public static byte[] Query(int queries) + { + World[] worlds = RawDb.ReadMultipleRows(queries).GetAwaiter().GetResult(); + + var memoryStream = new MemoryStream(); + using var utf8JsonWriter = new Utf8JsonWriter(memoryStream, _jsonWriterOptions); + + _worldsSerializer.Serialize(utf8JsonWriter, worlds); + + return memoryStream.ToArray(); + } + + public static byte[] Updates(int count) + { + World[] worlds = RawDb.LoadMultipleUpdatesRows(count).GetAwaiter().GetResult(); + + var memoryStream = new MemoryStream(); + using var utf8JsonWriter = new Utf8JsonWriter(memoryStream, _jsonWriterOptions); + + _worldsSerializer.Serialize(utf8JsonWriter, worlds); + + return memoryStream.ToArray(); + } + + public static byte[] Fortunes() + { + List fortunes = RawDb.LoadFortunesRows().GetAwaiter().GetResult(); + string fortunesView = FortunesView.Render(fortunes); + byte[] byteArray = Encoding.UTF8.GetBytes(fortunesView); + + return byteArray.ToArray(); + } +} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower.Orm/FortunesView.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/FortunesView.cs new file mode 100644 index 00000000000..2c11f6473c6 --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/FortunesView.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; +using System.Globalization; +using System.Text; +using System.Threading.Tasks; +using System.Web; +using PlatformBenchmarks; +using appMpower.Orm.Objects; + +namespace appMpower.Orm +{ + public static class FortunesView + { + public static char[] _fortunesTableStart = "Fortunes".ToCharArray(); + public static char[] _fortunesRowStart = "".ToCharArray(); + public static char[] _fortunesTableEnd = "
idmessage
".ToCharArray(); + public static char[] _fortunesColumn = "".ToCharArray(); + public static char[] _fortunesRowEnd = "
".ToCharArray(); + + public static string Render(List fortunes) + { + var writer = StringBuilderCache.Acquire(); + + writer.Append(_fortunesTableStart); + + foreach (var fortune in fortunes) + { + writer.Append(_fortunesRowStart).Append(fortune.Id.ToString(CultureInfo.InvariantCulture)).Append(_fortunesColumn).Append(HttpUtility.HtmlEncode(fortune.Message)).Append(_fortunesRowEnd); + } + + writer.Append(_fortunesTableEnd); + + return StringBuilderCache.GetStringAndRelease(writer); + } + } +} \ 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 new file mode 100644 index 00000000000..a5887f50142 --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/Microsoft/BatchUpdateString.cs @@ -0,0 +1,66 @@ +// 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; + +namespace PlatformBenchmarks +{ + internal class BatchUpdateString + { + private const int MaxBatch = 500; + + internal static readonly string[] Ids = Enumerable.Range(0, MaxBatch).Select(i => $"i{i}").ToArray(); + internal static readonly string[] Randoms = Enumerable.Range(0, MaxBatch).Select(i => $"r{i}").ToArray(); + internal static readonly string[] Jds = Enumerable.Range(0, MaxBatch).Select(i => $"j{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("(?::int,?::int),")); + sb.Append("(?::int,?::int) ORDER BY 1) AS temp(id, randomNumber) WHERE temp.id = world.id"); + //sb.Append("(?::int,?::int)) AS temp(id, randomNumber) WHERE temp.id = world.id"); + */ + + if (Constants.Dbms == Dbms.MySQL) + { + for (int i = 0; i < batchSize; i++) + { + sb.Append("UPDATE world SET randomNumber=? WHERE id=?;"); + } + } + else + { + sb.Append("UPDATE world SET randomNumber=CASE id "); + + for (int i = 0; i < batchSize; i++) + { + sb.Append("WHEN ? THEN ? "); + } + + sb.Append("ELSE randomnumber END WHERE id IN("); + + for (int i = 0; i < lastIndex; i++) + { + sb.Append("?,"); + } + + sb.Append("?)"); + } + + return _queries[batchSize] = StringBuilderCache.GetStringAndRelease(sb); + } + } +} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower.Orm/Microsoft/ConcurrentRandom.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/Microsoft/ConcurrentRandom.cs new file mode 100644 index 00000000000..374c9f4e1bb --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/Microsoft/ConcurrentRandom.cs @@ -0,0 +1,30 @@ +// 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.CompilerServices; + +namespace PlatformBenchmarks +{ + 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); + } + } +} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower.Orm/Microsoft/StringBuilderCache.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/Microsoft/StringBuilderCache.cs new file mode 100644 index 00000000000..73b890db750 --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/Microsoft/StringBuilderCache.cs @@ -0,0 +1,54 @@ +// 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.Text; + +namespace PlatformBenchmarks; + +internal static class StringBuilderCache +{ + private const int DefaultCapacity = 1386; + private const int MaxBuilderSize = DefaultCapacity * 3; + [ThreadStatic] + private static StringBuilder t_cachedInstance; + + public static StringBuilder Acquire(int capacity = DefaultCapacity) + { + if (capacity <= MaxBuilderSize) + { + StringBuilder sb = t_cachedInstance; + + if (capacity < DefaultCapacity) + { + capacity = DefaultCapacity; + } + + if (sb != null) + { + 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; + } +} diff --git a/frameworks/CSharp/appmpower/src/appMpower.Orm/NativeMethods.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/NativeMethods.cs new file mode 100644 index 00000000000..6c20aded37a --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/NativeMethods.cs @@ -0,0 +1,203 @@ +using System.Runtime.InteropServices; +using System.Text; +using System.Text.Json; +using appMpower.Orm.Data; +using appMpower.Orm.Objects; +using appMpower.Orm.Serializers; + +namespace appMpower.Orm; + +public static class NativeMethods +{ + private static JsonWriterOptions _jsonWriterOptions = new JsonWriterOptions + { + Indented = false, + SkipValidation = true + }; + + private readonly static WorldSerializer _worldSerializer = new WorldSerializer(); + private readonly static WorldsSerializer _worldsSerializer = new WorldsSerializer(); + private readonly static FortunesSerializer _fortunesSerializer = new FortunesSerializer(); + 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(); + } + + [UnmanagedCallersOnly(EntryPoint = "DbProvider")] + public static void DbProvider(int dbProvider) + { + Constants.DbProvider = (DbProvider)dbProvider; + DbProviderFactory.SetConnectionString(); + } + + [UnmanagedCallersOnly(EntryPoint = "FreeHandlePointer")] + public static void FreeHandlePointer(IntPtr handlePointer) + { + GCHandle handle = GCHandle.FromIntPtr(handlePointer); + handle.Free(); + } + + [UnmanagedCallersOnly(EntryPoint = "Db")] + public static unsafe IntPtr Db(int* length, IntPtr* handlePointer) + { + var world = RawDb.LoadSingleQueryRow().GetAwaiter().GetResult(); + + var memoryStream = new MemoryStream(); + using var utf8JsonWriter = new Utf8JsonWriter(memoryStream, _jsonWriterOptions); + + _worldSerializer.Serialize(utf8JsonWriter, world); + + *length = (int)utf8JsonWriter.BytesCommitted; + byte[] byteArray = memoryStream.ToArray(); + + GCHandle handle = GCHandle.Alloc(byteArray, GCHandleType.Pinned); + // return the managed and byteArrayPointer pointer + IntPtr byteArrayPointer = handle.AddrOfPinnedObject(); + *handlePointer = GCHandle.ToIntPtr(handle); + + return byteArrayPointer; + /* + fixed(byte* b = memoryStream.ToArray()) + { + return b; + } + */ + } + + /* + [UnmanagedCallersOnly(EntryPoint = "Fortunes")] + public static unsafe IntPtr Fortunes(int* length, IntPtr* handlePointer) + { + List fortunes = RawDb.LoadFortunesRows().GetAwaiter().GetResult(); + string fortunesView = FortunesView.Render(fortunes); + byte[] byteArray = Encoding.UTF8.GetBytes(fortunesView); + + *length = byteArray.Length; + + GCHandle handle = GCHandle.Alloc(byteArray, GCHandleType.Pinned); + IntPtr byteArrayPointer = handle.AddrOfPinnedObject(); + *handlePointer = GCHandle.ToIntPtr(handle); + + 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(); + + var memoryStream = new MemoryStream(); + using var utf8JsonWriter = new Utf8JsonWriter(memoryStream, _jsonWriterOptions); + + _worldsSerializer.Serialize(utf8JsonWriter, worlds); + + *length = (int)utf8JsonWriter.BytesCommitted; + byte[] byteArray = memoryStream.ToArray(); + + GCHandle handle = GCHandle.Alloc(byteArray, GCHandleType.Pinned); + IntPtr byteArrayPointer = handle.AddrOfPinnedObject(); + *handlePointer = GCHandle.ToIntPtr(handle); + + return byteArrayPointer; + } + + [UnmanagedCallersOnly(EntryPoint = "Updates")] + public static unsafe IntPtr Updates(int count, int* length, IntPtr* handlePointer) + { + World[] worlds = RawDb.LoadMultipleUpdatesRows(count).GetAwaiter().GetResult(); + + var memoryStream = new MemoryStream(); + using var utf8JsonWriter = new Utf8JsonWriter(memoryStream, _jsonWriterOptions); + + _worldsSerializer.Serialize(utf8JsonWriter, worlds); + + *length = (int)utf8JsonWriter.BytesCommitted; + byte[] byteArray = memoryStream.ToArray(); + + GCHandle handle = GCHandle.Alloc(byteArray, GCHandleType.Pinned); + IntPtr byteArrayPointer = handle.AddrOfPinnedObject(); + *handlePointer = GCHandle.ToIntPtr(handle); + + return byteArrayPointer; + } + + [UnmanagedCallersOnly(EntryPoint = "DbById")] + public static unsafe IntPtr DbById(int id, int* length, IntPtr* handlePointer) + { + var world = RawDb.LoadSingleQueryRowById(id).GetAwaiter().GetResult(); + + var memoryStream = new MemoryStream(); + using var utf8JsonWriter = new Utf8JsonWriter(memoryStream, _jsonWriterOptions); + + _worldSerializer.Serialize(utf8JsonWriter, world); + + *length = (int)utf8JsonWriter.BytesCommitted; + byte[] byteArray = memoryStream.ToArray(); + + GCHandle handle = GCHandle.Alloc(byteArray, GCHandleType.Pinned); + IntPtr byteArrayPointer = handle.AddrOfPinnedObject(); + *handlePointer = GCHandle.ToIntPtr(handle); + + return byteArrayPointer; + } +} diff --git a/frameworks/CSharp/appmpower/src/CachedWorld.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/Objects/CachedWorld.cs similarity index 88% rename from frameworks/CSharp/appmpower/src/CachedWorld.cs rename to frameworks/CSharp/appmpower/src/appMpower.Orm/Objects/CachedWorld.cs index 857b8283c73..7ef3f074167 100644 --- a/frameworks/CSharp/appmpower/src/CachedWorld.cs +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/Objects/CachedWorld.cs @@ -1,4 +1,4 @@ -namespace appMpower +namespace appMpower.Orm.Objects { public struct CachedWorld { diff --git a/frameworks/CSharp/appmpower/src/appMpower.Orm/Objects/Fortune.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/Objects/Fortune.cs new file mode 100644 index 00000000000..c6eb823c9fa --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/Objects/Fortune.cs @@ -0,0 +1,20 @@ +namespace appMpower.Orm.Objects +{ + 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); + } +} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower.Orm/Objects/World.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/Objects/World.cs new file mode 100644 index 00000000000..4e10e128998 --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/Objects/World.cs @@ -0,0 +1,8 @@ +namespace appMpower.Orm.Objects +{ + public struct World + { + public int Id { get; set; } + public int RandomNumber { get; set; } + } +} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower.Orm/RawDb.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/RawDb.cs new file mode 100644 index 00000000000..fec986f8755 --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/RawDb.cs @@ -0,0 +1,250 @@ +using System.Data; +using appMpower.Orm.Data; +using appMpower.Orm.Objects; +using PlatformBenchmarks; + +namespace appMpower.Orm +{ + public static class RawDb + { + private const int MaxBatch = 500; + + private static Random _random = new Random(); + + private static string[] _queriesMultipleRows = new string[MaxBatch + 1]; + + public static async Task LoadSingleQueryRow() + { + using var pooledConnection = new DbConnection(DbProviderFactory.ConnectionString); + await pooledConnection.OpenAsync(); + + var (dbCommand, _) = CreateReadCommand(pooledConnection); + + using (dbCommand) + { + World world = await ReadSingleRow(dbCommand); + + return world; + } + } + + public static async Task LoadSingleQueryRowById(int id) + { + using var pooledConnection = new DbConnection(DbProviderFactory.ConnectionString); + await pooledConnection.OpenAsync(); + + var (dbCommand, _) = CreateReadCommandById(pooledConnection, id); + + using (dbCommand) + { + World world = await ReadSingleRow(dbCommand); + + return world; + } + } + + public static async Task LoadMultipleQueriesRows(int count) + { + var worlds = new World[count]; + + using var pooledConnection = new DbConnection(DbProviderFactory.ConnectionString); + await pooledConnection.OpenAsync(); + + var (dbCommand, dbDataParameter) = CreateReadCommand(pooledConnection); + + using (dbCommand) + { + for (int i = 0; i < count; i++) + { + worlds[i] = await ReadSingleRow(dbCommand); + dbDataParameter.Value = _random.Next(1, 10001); + } + } + + 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) + { + var worlds = new World[count]; + + using var pooledConnection = new DbConnection(DbProviderFactory.ConnectionString, true); + await pooledConnection.OpenAsync(); + + var (queryCommand, dbDataParameter) = CreateReadCommand(pooledConnection); + + using (queryCommand) + { + for (int i = 0; i < count; i++) + { + worlds[i] = await ReadSingleRow(queryCommand); + dbDataParameter.Value = _random.Next(1, 10001); + } + } + + using var updateCommand = new DbCommand(BatchUpdateString.Query(count), pooledConnection); + + var ids = BatchUpdateString.Ids; + var randoms = BatchUpdateString.Randoms; + + for (int i = 0; i < count; i++) + { + var randomNumber = _random.Next(1, 10001); + + updateCommand.CreateParameter(ids[i], DbType.Int32, worlds[i].Id); + updateCommand.CreateParameter(randoms[i], DbType.Int32, randomNumber); + + worlds[i].RandomNumber = randomNumber; + } + + if (Constants.Dbms != Dbms.MySQL) + { + var jds = BatchUpdateString.Jds; + + for (int i = 0; i < count; i++) + { + updateCommand.CreateParameter(jds[i], DbType.Int32, worlds[i].Id); + } + } + + updateCommand.ExecuteNonQuery(); + + return worlds; + } + + internal static (DbCommand dbCommand, IDbDataParameter dbDataParameter) CreateReadCommand(DbConnection pooledConnection) + { + DbCommand dbCommand = new DbCommand("SELECT * FROM world WHERE id=?", pooledConnection); + + 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); + + return (dbCommand, dbCommand.CreateParameter("Id", DbType.Int32, id)); + } + + internal static async Task ReadSingleRow(DbCommand dbCommand) + { + var dataReader = await dbCommand.ExecuteReaderAsync(CommandBehavior.SingleRow & CommandBehavior.SequentialAccess); + + dataReader.Read(); + + var world = new World + { + Id = dataReader.GetInt32(0), + RandomNumber = dataReader.GetInt32(1) + }; + + dataReader.Close(); + + return world; + } + + public static async Task ReadMultipleRows(int count) + { + int j = 0; + var ids = BatchUpdateString.Ids; + var worlds = new World[count]; + string queryString; + + if (_queriesMultipleRows[count] != null) + { + queryString = _queriesMultipleRows[count]; + } + else + { + var stringBuilder = StringBuilderCache.Acquire(); + + for (int i = 0; i < count; i++) + { + stringBuilder.Append("SELECT * FROM world WHERE id=?;"); + } + + queryString = _queriesMultipleRows[count] = StringBuilderCache.GetStringAndRelease(stringBuilder); + } + + using var pooledConnection = new DbConnection(DbProviderFactory.ConnectionString); + await pooledConnection.OpenAsync(); + + using var dbCommand = new DbCommand(queryString, pooledConnection); + + for (int i = 0; i < count; i++) + { + dbCommand.CreateParameter(ids[i], DbType.Int32, _random.Next(1, 10001)); + } + + var dataReader = await dbCommand.ExecuteReaderAsync(CommandBehavior.Default & CommandBehavior.SequentialAccess); + + do + { + dataReader.Read(); + + worlds[j] = new World + { + Id = dataReader.GetInt32(0), + RandomNumber = dataReader.GetInt32(1) + }; + + j++; + } while (await dataReader.NextResultAsync()); + + 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 new file mode 100644 index 00000000000..d1697c0c0cc --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/Serializers/FortunesSerializer.cs @@ -0,0 +1,24 @@ +using System.Text.Json; +using appMpower.Orm.Objects; + +namespace appMpower.Orm.Serializers +{ + public class FortunesSerializer : IJsonSerializer> + { + public void Serialize(Utf8JsonWriter utf8JsonWriter, List fortunes) + { + utf8JsonWriter.WriteStartArray(); + + foreach (Fortune fortune in fortunes) + { + utf8JsonWriter.WriteStartObject(); + utf8JsonWriter.WriteNumber("id", fortune.Id); + utf8JsonWriter.WriteString("message", fortune.Message); + utf8JsonWriter.WriteEndObject(); + } + + utf8JsonWriter.WriteEndArray(); + utf8JsonWriter.Flush(); + } + } +} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower.Orm/Serializers/IJsonSerializer.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/Serializers/IJsonSerializer.cs new file mode 100644 index 00000000000..8986ee387ee --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/Serializers/IJsonSerializer.cs @@ -0,0 +1,9 @@ +using System.Text.Json; + +namespace appMpower.Orm.Serializers +{ + public interface IJsonSerializer + { + public void Serialize(Utf8JsonWriter utf8JsonWriter, T t); + } +} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower.Orm/Serializers/WorldSerializer.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/Serializers/WorldSerializer.cs new file mode 100644 index 00000000000..1e078da5957 --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/Serializers/WorldSerializer.cs @@ -0,0 +1,17 @@ +using System.Text.Json; +using appMpower.Orm.Objects; + +namespace appMpower.Orm.Serializers +{ + public class WorldSerializer : IJsonSerializer + { + public void Serialize(Utf8JsonWriter utf8JsonWriter, World world) + { + utf8JsonWriter.WriteStartObject(); + utf8JsonWriter.WriteNumber("id", world.Id); + utf8JsonWriter.WriteNumber("randomNumber", world.RandomNumber); + utf8JsonWriter.WriteEndObject(); + utf8JsonWriter.Flush(); + } + } +} diff --git a/frameworks/CSharp/appmpower/src/appMpower.Orm/Serializers/WorldsSerizalizer.cs b/frameworks/CSharp/appmpower/src/appMpower.Orm/Serializers/WorldsSerizalizer.cs new file mode 100644 index 00000000000..223af9bd702 --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/Serializers/WorldsSerizalizer.cs @@ -0,0 +1,24 @@ +using System.Text.Json; +using appMpower.Orm.Objects; + +namespace appMpower.Orm.Serializers +{ + public class WorldsSerializer : IJsonSerializer + { + public void Serialize(Utf8JsonWriter utf8JsonWriter, World[] worlds) + { + utf8JsonWriter.WriteStartArray(); + + foreach (World world in worlds) + { + utf8JsonWriter.WriteStartObject(); + utf8JsonWriter.WriteNumber("id", world.Id); + utf8JsonWriter.WriteNumber("randomNumber", world.RandomNumber); + utf8JsonWriter.WriteEndObject(); + } + + utf8JsonWriter.WriteEndArray(); + utf8JsonWriter.Flush(); + } + } +} diff --git a/frameworks/CSharp/appmpower/src/appMpower.Orm/appMpower.Orm.csproj b/frameworks/CSharp/appmpower/src/appMpower.Orm/appMpower.Orm.csproj new file mode 100644 index 00000000000..23a9b6c47cb --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower.Orm/appMpower.Orm.csproj @@ -0,0 +1,47 @@ + + + + net9.0 + enable + + true + true + true + + + linux-x64 + + + + + true + false + Size + none + false + + true + true + true + false + + true + + true + + true + + true + false + false + + + + + + + + + + + diff --git a/frameworks/CSharp/appmpower/src/appMpower.csproj b/frameworks/CSharp/appmpower/src/appMpower.csproj deleted file mode 100644 index 14258de5d67..00000000000 --- a/frameworks/CSharp/appmpower/src/appMpower.csproj +++ /dev/null @@ -1,55 +0,0 @@ - - - - net8.0 - Exe - true - - - - - true - true - true - false - Speed - none - false - - - true - true - true - false - - - true - - true - - - - - true - - - true - false - false - - - - - - - - - - $(DefineConstants);POSTGRESQL - $(DefineConstants);ODBC - $(DefineConstants);ADO - - - \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower/JsonMessage.cs b/frameworks/CSharp/appmpower/src/appMpower/JsonMessage.cs new file mode 100644 index 00000000000..ab1685ab8ad --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower/JsonMessage.cs @@ -0,0 +1,7 @@ +namespace appMpower +{ + public struct JsonMessage + { + public string Message { get; set; } + } +} \ 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 new file mode 100644 index 00000000000..93a91a7529a --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower/Middleware/CachingMiddelware.cs @@ -0,0 +1,132 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Primitives; + +namespace appMpower; + +public class CachingMiddleware +{ + private static readonly Dictionary _cache = new(); + private static readonly Random _random = new(); + + private static readonly byte[] _startBytes = Encoding.UTF8.GetBytes("["); + private static readonly byte[] _endBytes = Encoding.UTF8.GetBytes("]"); + private static readonly byte[] _comma = Encoding.UTF8.GetBytes(","); + + + private readonly static KeyValuePair _headerServer = + new KeyValuePair("Server", new StringValues("k")); + private readonly static KeyValuePair _headerContentType = + new KeyValuePair("Content-Type", new StringValues("application/json")); + + private readonly RequestDelegate _next; + + public CachingMiddleware(RequestDelegate next) + { + _next = next; + } + + public unsafe Task Invoke(HttpContext httpContext) + { + if (httpContext.Request.Path.StartsWithSegments("/cached-worlds", StringComparison.Ordinal)) + { + int payloadLength; + IntPtr handlePointer; + IntPtr bytePointer; + byte[] json; + + if (_cache.Count == 0) + { + 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); + } + + NativeMethods.FreeHandlePointer(handlePointer); + _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 response = httpContext.Response; + response.Headers.Add(_headerServer); + response.Headers.Add(_headerContentType); + + int queriesLength = 0; + int[] keys = new int[queries]; + + for (int i = 0; i < queries; i++) + { + 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); + } + + NativeMethods.FreeHandlePointer(handlePointer); + _cache.Add(keys[i], json); + } + + queriesLength += json.Length; + } + + 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; + + if (i < queries - 1) + { + Buffer.BlockCopy(_comma, 0, result, position, _comma.Length); + position += _comma.Length; + } + } + + Buffer.BlockCopy(_endBytes, 0, result, position, _endBytes.Length); + + response.Headers.Add( + new KeyValuePair("Content-Length", result.Length.ToString())); + + return response.Body.WriteAsync(result, 0, result.Length); + } + + return _next(httpContext); + } +} + +public static class CachingMiddlewareExtensions +{ + public static IApplicationBuilder UseCaching(this IApplicationBuilder builder) + { + return builder.UseMiddleware(); + } +} diff --git a/frameworks/CSharp/appmpower/src/appMpower/Middleware/FortunesMiddleware.cs b/frameworks/CSharp/appmpower/src/appMpower/Middleware/FortunesMiddleware.cs new file mode 100644 index 00000000000..6e16aaec5fb --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower/Middleware/FortunesMiddleware.cs @@ -0,0 +1,178 @@ +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; + +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")); + private readonly static KeyValuePair _headerContentType = + new KeyValuePair("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; + } + + public unsafe 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 + }; + + 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; + } + + NativeMethods.FreeHandlePointer(handlePointer); + + 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++) + { + bool isMatch = true; + + for (int j = 0; j < delimiter.Length; j++) + { + if (array[i + j] != delimiter[j]) + { + isMatch = false; + break; + } + } + + if (isMatch) + { + return i; + } + } + + return -1; + } + + private static Fortune ConvertBytesToObject(ReadOnlySpan data) + { + int offset = 0; + + // 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(); + } +} diff --git a/frameworks/CSharp/appmpower/src/appMpower/Middleware/JsonMiddleware.cs b/frameworks/CSharp/appmpower/src/appMpower/Middleware/JsonMiddleware.cs new file mode 100644 index 00000000000..2e90051ff2f --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower/Middleware/JsonMiddleware.cs @@ -0,0 +1,64 @@ +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; + +namespace appMpower; + +public class JsonMiddleware +{ + private readonly static JsonWriterOptions _jsonWriterOptions = new JsonWriterOptions + { + Indented = false, + SkipValidation = true + }; + + private readonly static JsonMessageSerializer _jsonMessageSerializer = new JsonMessageSerializer(); + + private readonly static KeyValuePair _headerServer = + new KeyValuePair("Server", new StringValues("k")); + private readonly static KeyValuePair _headerContentType = + new KeyValuePair("Content-Type", new StringValues("application/json")); + + private readonly RequestDelegate _nextStage; + + public JsonMiddleware(RequestDelegate nextStage) + { + _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); + + _jsonMessageSerializer.Serialize(utf8JsonWriter, new JsonMessage { Message = "Hello, World!" }); + + response.Headers.Add( + new KeyValuePair("Content-Length", utf8JsonWriter.BytesPending.ToString())); + + utf8JsonWriter.Flush(); + + return Task.CompletedTask; + } + + return _nextStage(httpContext); + } +} + +public static class JsonMiddlewareExtensions +{ + public static IApplicationBuilder UseJson(this IApplicationBuilder builder) + { + return builder.UseMiddleware(); + } +} \ 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 new file mode 100644 index 00000000000..f2e6829f79c --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower/Middleware/MultipleQueriesMiddleware.cs @@ -0,0 +1,68 @@ +using System; +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; + +public class MultipleQueriesMiddleware +{ + private readonly static KeyValuePair _headerServer = + new KeyValuePair("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(); + } +} diff --git a/frameworks/CSharp/appmpower/src/appMpower/Middleware/MultipleUpdatesMiddleware.cs b/frameworks/CSharp/appmpower/src/appMpower/Middleware/MultipleUpdatesMiddleware.cs new file mode 100644 index 00000000000..672f0d14e0f --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower/Middleware/MultipleUpdatesMiddleware.cs @@ -0,0 +1,68 @@ +using System; +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; + +public class MultipleUpdatesMiddelware +{ + private readonly static KeyValuePair _headerServer = + new KeyValuePair("Server", new StringValues("k")); + private readonly static KeyValuePair _headerContentType = + new KeyValuePair("Content-Type", new StringValues("application/json")); + + private readonly RequestDelegate _next; + + public MultipleUpdatesMiddelware(RequestDelegate next) + { + _next = next; + } + + 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); + + int payloadLength; + IntPtr handlePointer; + + IntPtr bytePointer = NativeMethods.Updates(count, 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 MultipleUpdatesMiddelwareExtensions +{ + public static IApplicationBuilder UseMultipleUpdates(this IApplicationBuilder builder) + { + return builder.UseMiddleware(); + } +} diff --git a/frameworks/CSharp/appmpower/src/appMpower/Middleware/PlaintextMiddleware.cs b/frameworks/CSharp/appmpower/src/appMpower/Middleware/PlaintextMiddleware.cs new file mode 100644 index 00000000000..cf7ad20e54a --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower/Middleware/PlaintextMiddleware.cs @@ -0,0 +1,50 @@ +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 +{ + private readonly static KeyValuePair _headerServer = + new KeyValuePair("Server", new StringValues("k")); + private readonly static KeyValuePair _headerContentType = + new KeyValuePair("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) + { + return builder.UseMiddleware(); + } +} diff --git a/frameworks/CSharp/appmpower/src/appMpower/Middleware/SingleQueryMiddleware.cs b/frameworks/CSharp/appmpower/src/appMpower/Middleware/SingleQueryMiddleware.cs new file mode 100644 index 00000000000..747a55c5a63 --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower/Middleware/SingleQueryMiddleware.cs @@ -0,0 +1,63 @@ +using System; +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; + +public class SingleQueryMiddleware +{ + private readonly static KeyValuePair _headerServer = + new KeyValuePair("Server", new StringValues("k")); + private readonly static KeyValuePair _headerContentType = + new KeyValuePair("Content-Type", new StringValues("application/json")); + + private readonly RequestDelegate _nextStage; + + public SingleQueryMiddleware(RequestDelegate nextStage) + { + _nextStage = nextStage; + } + + 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); + + int payloadLength; + IntPtr handlePointer; + + IntPtr bytePointer = NativeMethods.Db(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 _nextStage(httpContext); + } +} + +public static class SingleQueryMiddlewareExtensions +{ + public static IApplicationBuilder UseSingleQuery(this IApplicationBuilder builder) + { + return builder.UseMiddleware(); + } +} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower/NativeMethods.cs b/frameworks/CSharp/appmpower/src/appMpower/NativeMethods.cs new file mode 100644 index 00000000000..89b8a0764e3 --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower/NativeMethods.cs @@ -0,0 +1,46 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +public static partial class NativeMethods +{ +#if DEBUG + private const string LibName = "appMpower.Orm.dylib"; +#else + private const string LibName = "appMpower.Orm.so"; +#endif + + [LibraryImport(LibName, EntryPoint = "Dbms", StringMarshalling = StringMarshalling.Utf16)] + [UnmanagedCallConv(CallConvs = new[] { typeof(CallConvCdecl) })] + public static partial void Dbms(int dbms); + + [LibraryImport(LibName, EntryPoint = "DbProvider", StringMarshalling = StringMarshalling.Utf16)] + [UnmanagedCallConv(CallConvs = new[] { typeof(CallConvCdecl) })] + public static partial void DbProvider(int dbProvider); + + [LibraryImport(LibName, EntryPoint = "FreeHandlePointer")] + [UnmanagedCallConv(CallConvs = new[] { typeof(CallConvCdecl) })] + public static partial void FreeHandlePointer(IntPtr handlePointer); + + [LibraryImport(LibName, EntryPoint = "Db", StringMarshalling = StringMarshalling.Utf16)] + [UnmanagedCallConv(CallConvs = new[] { typeof(CallConvCdecl) })] + public static partial IntPtr Db(out int length, out IntPtr handlePointer); + + [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)] + [UnmanagedCallConv(CallConvs = new[] { typeof(CallConvCdecl) })] + public static partial IntPtr Query(int queries, out int length, out IntPtr handlePointer); + + [LibraryImport(LibName, EntryPoint = "Updates", StringMarshalling = StringMarshalling.Utf16)] + [UnmanagedCallConv(CallConvs = new[] { typeof(CallConvCdecl) })] + public static partial IntPtr Updates(int queries, out int length, out IntPtr handlePointer); + + [LibraryImport(LibName, StringMarshalling = StringMarshalling.Utf16)] + [UnmanagedCallConv(CallConvs = new[] { typeof(CallConvCdecl) })] + public static partial IntPtr DbById(int id, out int length, out IntPtr handlePointer); + +} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower/Objects/Fortune.cs b/frameworks/CSharp/appmpower/src/appMpower/Objects/Fortune.cs new file mode 100644 index 00000000000..187a3c06980 --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower/Objects/Fortune.cs @@ -0,0 +1,22 @@ +using System; + +namespace appMpower.Objects +{ + public struct Fortune : IComparable, IComparable + { + public Fortune(int id, string message) + { + Id = id; + Message = message; + } + + public int Id { get; set; } + + public string Message { get; set; } + + 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); + } +} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower/Program.cs b/frameworks/CSharp/appmpower/src/appMpower/Program.cs new file mode 100644 index 00000000000..f2f36aa627d --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower/Program.cs @@ -0,0 +1,44 @@ +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; } +} diff --git a/frameworks/CSharp/appmpower/src/appMpower/Serializers/IJsonSerializer.cs b/frameworks/CSharp/appmpower/src/appMpower/Serializers/IJsonSerializer.cs new file mode 100644 index 00000000000..eb59ff827ed --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower/Serializers/IJsonSerializer.cs @@ -0,0 +1,9 @@ +using System.Text.Json; + +namespace appMpower.Serializers +{ + public interface IJsonSerializer + { + public void Serialize(Utf8JsonWriter utf8JsonWriter, T t); + } +} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower/Serializers/JsonMessageSerializer.cs b/frameworks/CSharp/appmpower/src/appMpower/Serializers/JsonMessageSerializer.cs new file mode 100644 index 00000000000..c06636f1a31 --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower/Serializers/JsonMessageSerializer.cs @@ -0,0 +1,14 @@ +using System.Text.Json; + +namespace appMpower.Serializers +{ + public class JsonMessageSerializer : IJsonSerializer + { + public void Serialize(Utf8JsonWriter utf8JsonWriter, JsonMessage jsonMessage) + { + utf8JsonWriter.WriteStartObject(); + utf8JsonWriter.WriteString("message", jsonMessage.Message); + utf8JsonWriter.WriteEndObject(); + } + } +} diff --git a/frameworks/CSharp/appmpower/src/appMpower/Slices/Fortunes.cshtml b/frameworks/CSharp/appmpower/src/appMpower/Slices/Fortunes.cshtml new file mode 100644 index 00000000000..ebf2c38d5ec --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower/Slices/Fortunes.cshtml @@ -0,0 +1,2 @@ +@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 new file mode 100644 index 00000000000..98a692ef65a --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower/Slices/_ViewImports.cshtml @@ -0,0 +1,10 @@ +@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 new file mode 100644 index 00000000000..4b571cf8286 --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower/Startup.cs @@ -0,0 +1,56 @@ +using System.Text.Encodings.Web; +using System.Text.Unicode; +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; + +namespace appMpower; + +public class Startup +{ + private readonly IConfiguration _configuration; + + public Startup(IConfiguration configuration) + { + _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('—'); + services.AddWebEncoders(options => + { + options.TextEncoderSettings = settings; + }); + } + + public void Configure(IApplicationBuilder app) + { + app.UsePlainText(); + app.UseJson(); + app.UseSingleQuery(); + app.UseCaching(); + app.UseFortunes(); + app.UseMultipleQueries(); + app.UseMultipleUpdates(); + } +} \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower/appMpower.csproj b/frameworks/CSharp/appmpower/src/appMpower/appMpower.csproj new file mode 100644 index 00000000000..5db0aac55f8 --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower/appMpower.csproj @@ -0,0 +1,37 @@ + + + + net9.0 + Exe + true + + + + + + + + + + + + + + + + + + $(DefineConstants);ODBC + $(DefineConstants);POSTGRESQL + $(DefineConstants);MYSQL + + + \ No newline at end of file diff --git a/frameworks/CSharp/appmpower/src/appMpower/appsettings.json b/frameworks/CSharp/appmpower/src/appMpower/appsettings.json new file mode 100644 index 00000000000..0b1badf0626 --- /dev/null +++ b/frameworks/CSharp/appmpower/src/appMpower/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "None", + "Microsoft": "None", + "Microsoft.Hosting.Lifetime": "None" + } + } +} diff --git a/frameworks/CSharp/appmpower/src/nuget.config b/frameworks/CSharp/appmpower/src/appMpower/nuget.config similarity index 100% rename from frameworks/CSharp/appmpower/src/nuget.config rename to frameworks/CSharp/appmpower/src/appMpower/nuget.config diff --git a/frameworks/CSharp/appmpower/src/src.sln b/frameworks/CSharp/appmpower/src/src.sln new file mode 100644 index 00000000000..bedda48f506 --- /dev/null +++ b/frameworks/CSharp/appmpower/src/src.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "appMpower.Orm", "appMpower.Orm\appMpower.Orm.csproj", "{1EC05247-7299-4F69-887B-3B746DF5F878}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "appMpower", "appMpower\appMpower.csproj", "{EB5D3496-53B9-49A7-A3AD-754078142F81}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1EC05247-7299-4F69-887B-3B746DF5F878}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1EC05247-7299-4F69-887B-3B746DF5F878}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1EC05247-7299-4F69-887B-3B746DF5F878}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1EC05247-7299-4F69-887B-3B746DF5F878}.Release|Any CPU.Build.0 = Release|Any CPU + {EB5D3496-53B9-49A7-A3AD-754078142F81}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EB5D3496-53B9-49A7-A3AD-754078142F81}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EB5D3496-53B9-49A7-A3AD-754078142F81}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EB5D3496-53B9-49A7-A3AD-754078142F81}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/frameworks/CSharp/aspnetcore-mono/Benchmarks/Benchmarks.csproj b/frameworks/CSharp/aspnetcore-mono/Benchmarks/Benchmarks.csproj index 3ccea1c3707..1a1e7ee6d9a 100644 --- a/frameworks/CSharp/aspnetcore-mono/Benchmarks/Benchmarks.csproj +++ b/frameworks/CSharp/aspnetcore-mono/Benchmarks/Benchmarks.csproj @@ -25,6 +25,7 @@ + diff --git a/frameworks/CSharp/aspnetcore-mono/PlatformBenchmarks/PlatformBenchmarks.csproj b/frameworks/CSharp/aspnetcore-mono/PlatformBenchmarks/PlatformBenchmarks.csproj index db72cd753ec..325b9acb8cc 100644 --- a/frameworks/CSharp/aspnetcore-mono/PlatformBenchmarks/PlatformBenchmarks.csproj +++ b/frameworks/CSharp/aspnetcore-mono/PlatformBenchmarks/PlatformBenchmarks.csproj @@ -23,7 +23,7 @@ - + diff --git a/frameworks/CSharp/aspnetcore-mono/benchmark_config.json b/frameworks/CSharp/aspnetcore-mono/benchmark_config.json index e52c7d74b55..74fd85c0b83 100644 --- a/frameworks/CSharp/aspnetcore-mono/benchmark_config.json +++ b/frameworks/CSharp/aspnetcore-mono/benchmark_config.json @@ -40,6 +40,7 @@ "database_os": "Linux", "display_name": "ASP.NET Core [Platform, Mono, Pg]", "notes": "", + "tags": ["broken"], "versus": "aspcore-ado-pg" }, "mw": { @@ -123,4 +124,4 @@ "versus": "aspcore-mono-pg" } }] -} \ No newline at end of file +} diff --git a/frameworks/CSharp/aspnetcore/README.md b/frameworks/CSharp/aspnetcore/README.md index 2e0ddeab3b4..00092de375d 100644 --- a/frameworks/CSharp/aspnetcore/README.md +++ b/frameworks/CSharp/aspnetcore/README.md @@ -6,5 +6,5 @@ See [.NET Core](http://dot.net) and [ASP.NET Core](https://github.com/dotnet/asp **Language** -* C# 8.0 +* C# 13.0 diff --git a/frameworks/CSharp/aspnetcore/appsettings.postgresql.json b/frameworks/CSharp/aspnetcore/appsettings.postgresql.json index abc42e6ce8a..423af4d19b0 100644 --- a/frameworks/CSharp/aspnetcore/appsettings.postgresql.json +++ b/frameworks/CSharp/aspnetcore/appsettings.postgresql.json @@ -1,4 +1,4 @@ { - "ConnectionString": "Server=tfb-database;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;SSL Mode=Disable;Maximum Pool Size=18;NoResetOnClose=true;Enlist=false;Max Auto Prepare=4;Multiplexing=true;Write Coalescing Buffer Threshold Bytes=1000", + "ConnectionString": "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", "Database": "postgresql" } diff --git a/frameworks/CSharp/aspnetcore/aspnetcore-aot.dockerfile b/frameworks/CSharp/aspnetcore/aspnetcore-aot.dockerfile new file mode 100644 index 00000000000..a7396e3b919 --- /dev/null +++ b/frameworks/CSharp/aspnetcore/aspnetcore-aot.dockerfile @@ -0,0 +1,17 @@ +FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build +RUN apt-get update +RUN apt-get -yqq install clang zlib1g-dev +WORKDIR /app +COPY src/Platform . +RUN dotnet publish -c Release -o out /p:DatabaseProvider=Npgsql /p:PublishAot=true /p:OptimizationPreference=Speed /p:GarbageCollectionAdaptationMode=0 + +FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS runtime +ENV URLS=http://+:8080 + +WORKDIR /app +COPY --from=build /app/out ./ +COPY appsettings.postgresql.json ./appsettings.json + +EXPOSE 8080 + +ENTRYPOINT ["./Platform"] diff --git a/frameworks/CSharp/aspnetcore/aspnetcore-minimal.dockerfile b/frameworks/CSharp/aspnetcore/aspnetcore-minimal.dockerfile index 0a6f94bd171..24893c9717a 100644 --- a/frameworks/CSharp/aspnetcore/aspnetcore-minimal.dockerfile +++ b/frameworks/CSharp/aspnetcore/aspnetcore-minimal.dockerfile @@ -1,10 +1,13 @@ -FROM mcr.microsoft.com/dotnet/sdk:8.0.100-rc.2 AS build +FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build WORKDIR /app COPY src/Minimal . RUN dotnet publish -c Release -o out -FROM mcr.microsoft.com/dotnet/aspnet:8.0.0-rc.2 AS runtime +FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS runtime ENV URLS http://+:8080 +ENV DOTNET_GCDynamicAdaptationMode=0 +ENV DOTNET_ReadyToRun=0 +ENV DOTNET_HillClimbing_Disable=1 WORKDIR /app COPY --from=build /app/out ./ diff --git a/frameworks/CSharp/aspnetcore/aspnetcore-mvc.dockerfile b/frameworks/CSharp/aspnetcore/aspnetcore-mvc.dockerfile index ae592c1e2ed..6922a53bf2a 100644 --- a/frameworks/CSharp/aspnetcore/aspnetcore-mvc.dockerfile +++ b/frameworks/CSharp/aspnetcore/aspnetcore-mvc.dockerfile @@ -1,10 +1,13 @@ -FROM mcr.microsoft.com/dotnet/sdk:8.0.100-rc.2 AS build +FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build WORKDIR /app COPY src/Mvc . RUN dotnet publish -c Release -o out -FROM mcr.microsoft.com/dotnet/aspnet:8.0.0-rc.2 AS runtime +FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS runtime ENV URLS http://+:8080 +ENV DOTNET_GCDynamicAdaptationMode=0 +ENV DOTNET_ReadyToRun=0 +ENV DOTNET_HillClimbing_Disable=1 WORKDIR /app COPY --from=build /app/out ./ diff --git a/frameworks/CSharp/aspnetcore/aspnetcore-mysql.dockerfile b/frameworks/CSharp/aspnetcore/aspnetcore-mysql.dockerfile index 628eb43c57b..ecc0a8331c3 100644 --- a/frameworks/CSharp/aspnetcore/aspnetcore-mysql.dockerfile +++ b/frameworks/CSharp/aspnetcore/aspnetcore-mysql.dockerfile @@ -1,10 +1,13 @@ -FROM mcr.microsoft.com/dotnet/sdk:8.0.100-rc.2 AS build +FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build WORKDIR /app COPY src/Platform . RUN dotnet publish -c Release -o out /p:DatabaseProvider=MySqlConnector -FROM mcr.microsoft.com/dotnet/aspnet:8.0.0-rc.2 AS runtime +FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS runtime ENV URLS http://+:8080 +ENV DOTNET_GCDynamicAdaptationMode=0 +ENV DOTNET_ReadyToRun=0 +ENV DOTNET_HillClimbing_Disable=1 WORKDIR /app COPY --from=build /app/out ./ diff --git a/frameworks/CSharp/aspnetcore/aspnetcore.dockerfile b/frameworks/CSharp/aspnetcore/aspnetcore.dockerfile index 90409f3b188..64510ffe786 100644 --- a/frameworks/CSharp/aspnetcore/aspnetcore.dockerfile +++ b/frameworks/CSharp/aspnetcore/aspnetcore.dockerfile @@ -1,11 +1,13 @@ -FROM mcr.microsoft.com/dotnet/sdk:8.0.100-rc.2 AS build +FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build WORKDIR /app COPY src/Platform . RUN dotnet publish -c Release -o out /p:DatabaseProvider=Npgsql -FROM mcr.microsoft.com/dotnet/aspnet:8.0.0-rc.2 AS runtime -ENV URLS http://+:8080 -ENV DOTNET_SYSTEM_NET_SOCKETS_INLINE_COMPLETIONS 1 +FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS runtime +ENV URLS=http://+:8080 +ENV DOTNET_GCDynamicAdaptationMode=0 +ENV DOTNET_ReadyToRun=0 +ENV DOTNET_HillClimbing_Disable=1 WORKDIR /app COPY --from=build /app/out ./ diff --git a/frameworks/CSharp/aspnetcore/benchmark_config.json b/frameworks/CSharp/aspnetcore/benchmark_config.json index c8452e6ddf0..eb56fddfb57 100644 --- a/frameworks/CSharp/aspnetcore/benchmark_config.json +++ b/frameworks/CSharp/aspnetcore/benchmark_config.json @@ -1,5 +1,6 @@ { "framework": "aspnetcore", + "maintainers": ["DamianEdwards", "sebastienros"], "tests": [ { "default": { @@ -14,7 +15,7 @@ "approach": "Realistic", "classification": "Platform", "database": "Postgres", - "framework": "ASP.NET Core", + "framework": "ASP.NET Core [Platform]", "language": "C#", "orm": "Raw", "platform": ".NET", @@ -22,7 +23,30 @@ "webserver": "Kestrel", "os": "Linux", "database_os": "Linux", - "display_name": "ASP.NET Core [Platform, Pg]", + "display_name": "ASP.NET Core [Platform]", + "notes": "" + }, + "aot": { + "plaintext_url": "/plaintext", + "json_url": "/json", + "db_url": "/db", + "query_url": "/queries/", + "fortune_url": "/fortunes", + "update_url": "/updates/", + "cached_query_url": "/cached-worlds/", + "port": 8080, + "approach": "Realistic", + "classification": "Platform", + "database": "Postgres", + "framework": "ASP.NET Core [Platform]", + "language": "C#", + "orm": "Raw", + "platform": ".NET", + "flavor": "NativeAOT", + "webserver": "Kestrel", + "os": "Linux", + "database_os": "Linux", + "display_name": "ASP.NET Core [Platform, AOT]", "notes": "" }, "minimal": { @@ -44,7 +68,7 @@ "webserver": "Kestrel", "os": "Linux", "database_os": "Linux", - "display_name": "ASP.NET Core [Minimal APIs, Pg, Dapper]", + "display_name": "ASP.NET Core [Minimal APIs]", "notes": "", "versus": "aspnetcore" }, @@ -66,7 +90,7 @@ "webserver": "Kestrel", "os": "Linux", "database_os": "Linux", - "display_name": "ASP.NET Core [MVC, Pg, EF]", + "display_name": "ASP.NET Core [MVC]", "notes": "", "versus": "aspnetcore" }, @@ -80,7 +104,7 @@ "approach": "Realistic", "classification": "Platform", "database": "MySQL", - "framework": "ASP.NET Core", + "framework": "ASP.NET Core [Platform]", "language": "C#", "orm": "Raw", "platform": ".NET", @@ -88,8 +112,9 @@ "webserver": "Kestrel", "os": "Linux", "database_os": "Linux", - "display_name": "ASP.NET Core [Platform, My]", - "notes": "" + "display_name": "ASP.NET Core [Platform, MySQL]", + "notes": "", + "versus": "aspnetcore" } } ] diff --git a/frameworks/CSharp/aspnetcore/config.toml b/frameworks/CSharp/aspnetcore/config.toml index 46fdecb59c6..9ba1398034c 100644 --- a/frameworks/CSharp/aspnetcore/config.toml +++ b/frameworks/CSharp/aspnetcore/config.toml @@ -19,6 +19,23 @@ platform = ".NET" webserver = "Kestrel" versus = "None" +[aot] +urls.plaintext = "/plaintext" +urls.json = "/json" +urls.db = "/db" +urls.query = "/queries/" +urls.update = "/updates/" +urls.cached_query = "/cached-worlds/" +approach = "Realistic" +classification = "Platform" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = ".NET" +webserver = "Kestrel" +versus = "None" + [minimal] urls.plaintext = "/plaintext" urls.json = "/json" diff --git a/frameworks/CSharp/aspnetcore/src/Minimal/Minimal.csproj b/frameworks/CSharp/aspnetcore/src/Minimal/Minimal.csproj index d0262bd6d69..12f3446d8b7 100644 --- a/frameworks/CSharp/aspnetcore/src/Minimal/Minimal.csproj +++ b/frameworks/CSharp/aspnetcore/src/Minimal/Minimal.csproj @@ -1,7 +1,7 @@  - net8.0 + net9.0 enable enable latest @@ -9,9 +9,9 @@ - - - + + + diff --git a/frameworks/CSharp/aspnetcore/src/Minimal/Program.cs b/frameworks/CSharp/aspnetcore/src/Minimal/Program.cs index 9ac63edcca2..7aaac6db1ac 100644 --- a/frameworks/CSharp/aspnetcore/src/Minimal/Program.cs +++ b/frameworks/CSharp/aspnetcore/src/Minimal/Program.cs @@ -1,13 +1,11 @@ // 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.Text.Encodings.Web; -using System.Text.Unicode; -using Microsoft.AspNetCore.Http.HttpResults; -using RazorSlices; using Minimal; using Minimal.Database; using Minimal.Models; +using System.Text.Encodings.Web; +using System.Text.Unicode; var builder = WebApplication.CreateBuilder(args); @@ -36,14 +34,14 @@ app.MapGet("/db", async (Db db) => await db.LoadSingleQueryRow()); -var createFortunesTemplate = RazorSlice.ResolveSliceFactory>("/Templates/Fortunes.cshtml"); var htmlEncoder = CreateHtmlEncoder(); app.MapGet("/fortunes", async (HttpContext context, Db db) => { var fortunes = await db.LoadFortunesRows(); - var template = (RazorSliceHttpResult>)createFortunesTemplate(fortunes); - template.HtmlEncoder = htmlEncoder; - return template; + var result = Results.Extensions.RazorSlice>(fortunes); + result.HtmlEncoder = htmlEncoder; + + return result; }); app.MapGet("/queries/{count?}", async (Db db, string? count) => await db.LoadMultipleQueriesRows(count)); diff --git a/frameworks/CSharp/aspnetcore/src/Minimal/Templates/Fortunes.cshtml b/frameworks/CSharp/aspnetcore/src/Minimal/Slices/Fortunes.cshtml similarity index 100% rename from frameworks/CSharp/aspnetcore/src/Minimal/Templates/Fortunes.cshtml rename to frameworks/CSharp/aspnetcore/src/Minimal/Slices/Fortunes.cshtml diff --git a/frameworks/CSharp/aspnetcore/src/Minimal/Templates/_ViewImports.cshtml b/frameworks/CSharp/aspnetcore/src/Minimal/Slices/_ViewImports.cshtml similarity index 100% rename from frameworks/CSharp/aspnetcore/src/Minimal/Templates/_ViewImports.cshtml rename to frameworks/CSharp/aspnetcore/src/Minimal/Slices/_ViewImports.cshtml diff --git a/frameworks/CSharp/aspnetcore/src/Mvc/Mvc.csproj b/frameworks/CSharp/aspnetcore/src/Mvc/Mvc.csproj index 8da7f631b80..68c70002683 100644 --- a/frameworks/CSharp/aspnetcore/src/Mvc/Mvc.csproj +++ b/frameworks/CSharp/aspnetcore/src/Mvc/Mvc.csproj @@ -1,7 +1,7 @@  - net8.0 + net9.0 enable enable latest @@ -9,8 +9,8 @@ - - + + diff --git a/frameworks/CSharp/aspnetcore/src/Platform/BenchmarkApplication.Caching.cs b/frameworks/CSharp/aspnetcore/src/Platform/BenchmarkApplication.Caching.cs index eb5fff0199e..a99586c96e2 100644 --- a/frameworks/CSharp/aspnetcore/src/Platform/BenchmarkApplication.Caching.cs +++ b/frameworks/CSharp/aspnetcore/src/Platform/BenchmarkApplication.Caching.cs @@ -6,7 +6,7 @@ namespace PlatformBenchmarks; -public partial class BenchmarkApplication +public sealed partial class BenchmarkApplication { private static async Task Caching(PipeWriter pipeWriter, int count) { diff --git a/frameworks/CSharp/aspnetcore/src/Platform/BenchmarkApplication.Fortunes.cs b/frameworks/CSharp/aspnetcore/src/Platform/BenchmarkApplication.Fortunes.cs index 5550be2c495..0279754a128 100644 --- a/frameworks/CSharp/aspnetcore/src/Platform/BenchmarkApplication.Fortunes.cs +++ b/frameworks/CSharp/aspnetcore/src/Platform/BenchmarkApplication.Fortunes.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.IO.Pipelines; using System.Runtime.CompilerServices; using System.Threading.Tasks; @@ -8,7 +9,7 @@ namespace PlatformBenchmarks; -public partial class BenchmarkApplication +public sealed partial class BenchmarkApplication { private async Task FortunesRaw(PipeWriter pipeWriter) { @@ -18,7 +19,7 @@ await RawDb.LoadFortunesRows(), FortunesTemplateFactory); } - private ValueTask OutputFortunes(PipeWriter pipeWriter, TModel model, SliceFactory templateFactory) + private ValueTask OutputFortunes(PipeWriter pipeWriter, TModel model, Func> templateFactory) { // Render headers var preamble = """ @@ -38,7 +39,7 @@ private ValueTask OutputFortunes(PipeWriter pipeWriter, TModel model, Sl // Kestrel PipeWriter span size is 4K, headers above already written to first span & template output is ~1350 bytes, // so 2K chunk size should result in only a single span and chunk being used. var chunkedWriter = GetChunkedWriter(pipeWriter, chunkSizeHint: 2048); - var renderTask = template.RenderAsync(chunkedWriter, null, HtmlEncoder); + var renderTask = template.RenderAsync(chunkedWriter, HtmlEncoder); if (renderTask.IsCompletedSuccessfully) { @@ -50,16 +51,16 @@ private ValueTask OutputFortunes(PipeWriter pipeWriter, TModel model, Sl return AwaitTemplateRenderTask(renderTask, chunkedWriter, template); } - private static async ValueTask AwaitTemplateRenderTask(ValueTask renderTask, ChunkedBufferWriter chunkedWriter, RazorSlice template) + private static async ValueTask AwaitTemplateRenderTask(ValueTask renderTask, ChunkedPipeWriter chunkedWriter, RazorSlice template) { await renderTask; EndTemplateRendering(chunkedWriter, template); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void EndTemplateRendering(ChunkedBufferWriter chunkedWriter, RazorSlice template) + private static void EndTemplateRendering(ChunkedPipeWriter chunkedWriter, RazorSlice template) { - chunkedWriter.End(); + chunkedWriter.Complete(); ReturnChunkedWriter(chunkedWriter); template.Dispose(); } diff --git a/frameworks/CSharp/aspnetcore/src/Platform/BenchmarkApplication.HttpConnection.cs b/frameworks/CSharp/aspnetcore/src/Platform/BenchmarkApplication.HttpConnection.cs index cbd375cb61b..892ecc48457 100644 --- a/frameworks/CSharp/aspnetcore/src/Platform/BenchmarkApplication.HttpConnection.cs +++ b/frameworks/CSharp/aspnetcore/src/Platform/BenchmarkApplication.HttpConnection.cs @@ -12,7 +12,7 @@ namespace PlatformBenchmarks; -public partial class BenchmarkApplication : IHttpConnection +public sealed partial class BenchmarkApplication : IHttpConnection { private State _state; @@ -193,15 +193,15 @@ private static BufferWriter GetWriter(PipeWriter pipeWriter, int => new(new(pipeWriter), sizeHint); [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static ChunkedBufferWriter GetChunkedWriter(PipeWriter pipeWriter, int chunkSizeHint) + private static ChunkedPipeWriter GetChunkedWriter(PipeWriter pipeWriter, int chunkSizeHint) { var writer = ChunkedWriterPool.Get(); - writer.SetOutput(new WriterAdapter(pipeWriter), chunkSizeHint); + writer.SetOutput(pipeWriter, chunkSizeHint); return writer; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void ReturnChunkedWriter(ChunkedBufferWriter writer) => ChunkedWriterPool.Return(writer); + private static void ReturnChunkedWriter(ChunkedPipeWriter writer) => ChunkedWriterPool.Return(writer); private struct WriterAdapter : IBufferWriter { diff --git a/frameworks/CSharp/aspnetcore/src/Platform/BenchmarkApplication.Json.cs b/frameworks/CSharp/aspnetcore/src/Platform/BenchmarkApplication.Json.cs index 5babe2b61eb..dbfea6b0454 100644 --- a/frameworks/CSharp/aspnetcore/src/Platform/BenchmarkApplication.Json.cs +++ b/frameworks/CSharp/aspnetcore/src/Platform/BenchmarkApplication.Json.cs @@ -9,7 +9,7 @@ namespace PlatformBenchmarks; -public partial class BenchmarkApplication +public sealed partial class BenchmarkApplication { private readonly static uint _jsonPayloadSize = (uint)JsonSerializer.SerializeToUtf8Bytes( new JsonMessage { message = "Hello, World!" }, diff --git a/frameworks/CSharp/aspnetcore/src/Platform/BenchmarkApplication.MultipleQueries.cs b/frameworks/CSharp/aspnetcore/src/Platform/BenchmarkApplication.MultipleQueries.cs index 0541e20de1f..82ea5a4a8a2 100644 --- a/frameworks/CSharp/aspnetcore/src/Platform/BenchmarkApplication.MultipleQueries.cs +++ b/frameworks/CSharp/aspnetcore/src/Platform/BenchmarkApplication.MultipleQueries.cs @@ -8,7 +8,7 @@ namespace PlatformBenchmarks; -public partial class BenchmarkApplication +public sealed partial class BenchmarkApplication { private static async Task MultipleQueries(PipeWriter pipeWriter, int count) { diff --git a/frameworks/CSharp/aspnetcore/src/Platform/BenchmarkApplication.Plaintext.cs b/frameworks/CSharp/aspnetcore/src/Platform/BenchmarkApplication.Plaintext.cs index 6e4c4eec1c8..57c90e64e92 100644 --- a/frameworks/CSharp/aspnetcore/src/Platform/BenchmarkApplication.Plaintext.cs +++ b/frameworks/CSharp/aspnetcore/src/Platform/BenchmarkApplication.Plaintext.cs @@ -7,7 +7,7 @@ namespace PlatformBenchmarks; -public partial class BenchmarkApplication +public sealed partial class BenchmarkApplication { private static ReadOnlySpan _plaintextPreamble => "HTTP/1.1 200 OK\r\n"u8 + diff --git a/frameworks/CSharp/aspnetcore/src/Platform/BenchmarkApplication.SingleQuery.cs b/frameworks/CSharp/aspnetcore/src/Platform/BenchmarkApplication.SingleQuery.cs index 350eb43ad13..dd8add86fab 100644 --- a/frameworks/CSharp/aspnetcore/src/Platform/BenchmarkApplication.SingleQuery.cs +++ b/frameworks/CSharp/aspnetcore/src/Platform/BenchmarkApplication.SingleQuery.cs @@ -7,7 +7,7 @@ namespace PlatformBenchmarks; -public partial class BenchmarkApplication +public sealed partial class BenchmarkApplication { private static async Task SingleQuery(PipeWriter pipeWriter) { diff --git a/frameworks/CSharp/aspnetcore/src/Platform/BenchmarkApplication.Updates.cs b/frameworks/CSharp/aspnetcore/src/Platform/BenchmarkApplication.Updates.cs index 6962aa0cf2c..66bfdba1858 100644 --- a/frameworks/CSharp/aspnetcore/src/Platform/BenchmarkApplication.Updates.cs +++ b/frameworks/CSharp/aspnetcore/src/Platform/BenchmarkApplication.Updates.cs @@ -7,7 +7,7 @@ namespace PlatformBenchmarks; -public partial class BenchmarkApplication +public sealed partial class BenchmarkApplication { private static async Task Updates(PipeWriter pipeWriter, int count) { diff --git a/frameworks/CSharp/aspnetcore/src/Platform/BenchmarkApplication.cs b/frameworks/CSharp/aspnetcore/src/Platform/BenchmarkApplication.cs index 1d7810c2ebc..2db511586a3 100644 --- a/frameworks/CSharp/aspnetcore/src/Platform/BenchmarkApplication.cs +++ b/frameworks/CSharp/aspnetcore/src/Platform/BenchmarkApplication.cs @@ -10,6 +10,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http; using Microsoft.Extensions.ObjectPool; +using Platform.Templates; using RazorSlices; namespace PlatformBenchmarks @@ -40,14 +41,14 @@ public sealed partial class BenchmarkApplication public static RawDb RawDb { get; set; } - private static readonly DefaultObjectPool> ChunkedWriterPool + private static readonly DefaultObjectPool ChunkedWriterPool = new(new ChunkedWriterObjectPolicy()); - private sealed class ChunkedWriterObjectPolicy : IPooledObjectPolicy> + private sealed class ChunkedWriterObjectPolicy : IPooledObjectPolicy { - public ChunkedBufferWriter Create() => new(); + public ChunkedPipeWriter Create() => new(); - public bool Return(ChunkedBufferWriter writer) + public bool Return(ChunkedPipeWriter writer) { writer.Reset(); return true; @@ -55,9 +56,9 @@ public bool Return(ChunkedBufferWriter writer) } #if NPGSQL - private readonly static SliceFactory> FortunesTemplateFactory = RazorSlice.ResolveSliceFactory>("/Templates/FortunesUtf8.cshtml"); + private readonly static Func, RazorSlice>> FortunesTemplateFactory = FortunesUtf8.Create; #else - private readonly static SliceFactory> FortunesTemplateFactory = RazorSlice.ResolveSliceFactory>("/Templates/FortunesUtf16.cshtml"); + private readonly static Func, RazorSlice>> FortunesTemplateFactory = FortunesUtf16.Create; #endif [ThreadStatic] diff --git a/frameworks/CSharp/aspnetcore/src/Platform/ChunkedBufferWriter.cs b/frameworks/CSharp/aspnetcore/src/Platform/ChunkedBufferWriter.cs deleted file mode 100644 index 700519edb58..00000000000 --- a/frameworks/CSharp/aspnetcore/src/Platform/ChunkedBufferWriter.cs +++ /dev/null @@ -1,241 +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.Buffers; -using System.Buffers.Text; -using System.Diagnostics; -using System.Numerics; -using System.Runtime.CompilerServices; - -namespace PlatformBenchmarks; - -internal sealed class ChunkedBufferWriter : IBufferWriter where TWriter : IBufferWriter -{ - private const int DefaultChunkSizeHint = 2048; - private static readonly StandardFormat DefaultHexFormat = GetHexFormat(DefaultChunkSizeHint); - private static ReadOnlySpan ChunkTerminator => "\r\n"u8; - - private TWriter _output; - private int _chunkSizeHint; - private StandardFormat _hexFormat = DefaultHexFormat; - private Memory _currentFullChunk; - private Memory _currentChunk; - private int _buffered; - private bool _ended = false; - - public Memory Memory => _currentChunk; - - public TWriter Output => _output; - - public int Buffered => _buffered; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void SetOutput(TWriter output, int chunkSizeHint = DefaultChunkSizeHint) - { - _buffered = 0; - _chunkSizeHint = chunkSizeHint; - _output = output; - - StartNewChunk(chunkSizeHint, isFirst: true); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Reset() - { - _buffered = 0; - _output = default; - _ended = false; - _hexFormat = DefaultHexFormat; - _currentFullChunk = default; - _currentChunk = default; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Advance(int count) - { - ThrowIfEnded(); - - _buffered += count; - _currentChunk = _currentChunk[count..]; - } - - public Memory GetMemory(int sizeHint = 0) - { - ThrowIfEnded(); - - if (_currentChunk.Length <= sizeHint) - { - EnsureMore(sizeHint); - } - return _currentChunk; - } - - public Span GetSpan(int sizeHint = 0) => GetMemory(sizeHint).Span; - - public void End() - { - ThrowIfEnded(); - - CommitCurrentChunk(isFinal: true); - - _ended = true; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static StandardFormat GetHexFormat(int maxValue) - { - var hexDigitCount = CountHexDigits(maxValue); - - return new StandardFormat('X', (byte)hexDigitCount); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static int CountHexDigits(int n) => n <= 16 ? 1 : (BitOperations.Log2((uint)n) >> 2) + 1; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void StartNewChunk(int sizeHint, bool isFirst = false) - { - ThrowIfEnded(); - - // Header is like: - // 520\r\n - - var oldFullChunkHexLength = -1; - if (!isFirst) - { - oldFullChunkHexLength = CountHexDigits(_currentFullChunk.Length); - } - _currentFullChunk = _output.GetMemory(Math.Max(_chunkSizeHint, sizeHint)); - var newFullChunkHexLength = CountHexDigits(_currentFullChunk.Length); - - var currentFullChunkSpan = _currentFullChunk.Span; - - // Write space for HEX digits - currentFullChunkSpan[..newFullChunkHexLength].Fill(48); // 48 == '0' - - // Write header terminator - var terminator = "\r\n"u8; - terminator.CopyTo(currentFullChunkSpan[newFullChunkHexLength..]); - var chunkHeaderLength = newFullChunkHexLength + terminator.Length; - _currentChunk = _currentFullChunk[chunkHeaderLength..]; - - if ((!isFirst && oldFullChunkHexLength != newFullChunkHexLength) || (isFirst && DefaultChunkSizeHint != _chunkSizeHint)) - { - // Update HEX format if changed - _hexFormat = GetHexFormat(_currentFullChunk.Length); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void CommitCurrentChunk(bool isFinal = false, int sizeHint = 0) - { - ThrowIfEnded(); - - var contentLength = _buffered; - - if (contentLength > 0) - { - // Update the chunk header - var chunkLengthHexDigitsLength = CountHexDigits(contentLength); - var span = _currentFullChunk.Span; - if (!Utf8Formatter.TryFormat(contentLength, span, out var bytesWritten, _hexFormat)) - { - throw new NotSupportedException("Chunk size too large"); - } - Debug.Assert(chunkLengthHexDigitsLength == bytesWritten, "HEX formatting math problem."); - var headerLength = chunkLengthHexDigitsLength + 2; - - // Total chunk length: content length as HEX string + \r\n + content + \r\n - var spanOffset = headerLength + contentLength; - var chunkTotalLength = spanOffset + ChunkTerminator.Length; - - Debug.Assert(span.Length >= chunkTotalLength, "Bad chunk size calculation."); - - // Write out the chunk terminator - ChunkTerminator.CopyTo(span[spanOffset..]); - spanOffset = chunkTotalLength; - - if (!isFinal) - { - _output.Advance(chunkTotalLength); - StartNewChunk(sizeHint); - } - else - { - // Write out final chunk (zero-length chunk) - var terminator = "0\r\n\r\n"u8; - if ((spanOffset + terminator.Length) <= span.Length) - { - // There's space for the final chunk in the current span - terminator.CopyTo(span[spanOffset..]); - _output.Advance(chunkTotalLength + terminator.Length); - } - else - { - // Final chunk doesn't fit in current span so just write it directly after advancing the writer - _output.Advance(chunkTotalLength); - _output.Write(terminator); - } - } - - _buffered = 0; - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Write(ReadOnlySpan source) - { - ThrowIfEnded(); - - if (_currentChunk.Length >= (source.Length + ChunkTerminator.Length)) - { - source.CopyTo(_currentChunk.Span); - Advance(source.Length); - } - else - { - WriteMultiBuffer(source); - } - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private void EnsureMore(int count = 0) - { - if (count > (_currentChunk.Length - _buffered - ChunkTerminator.Length)) - { - if (_buffered > 0) - { - CommitCurrentChunk(isFinal: false, count); - } - else - { - StartNewChunk(count); - } - } - } - - private void WriteMultiBuffer(ReadOnlySpan source) - { - while (source.Length > 0) - { - if ((_currentChunk.Length - ChunkTerminator.Length) == 0) - { - EnsureMore(); - } - - var writable = Math.Min(source.Length, _currentChunk.Length - ChunkTerminator.Length); - source[..writable].CopyTo(_currentChunk.Span); - source = source[writable..]; - Advance(writable); - } - } - - private void ThrowIfEnded() - { - if (_ended) - { - throw new InvalidOperationException("Cannot use the writer after calling End()."); - } - } -} \ No newline at end of file diff --git a/frameworks/CSharp/aspnetcore/src/Platform/ChunkedPipeWriter.cs b/frameworks/CSharp/aspnetcore/src/Platform/ChunkedPipeWriter.cs new file mode 100644 index 00000000000..5a1dd80c678 --- /dev/null +++ b/frameworks/CSharp/aspnetcore/src/Platform/ChunkedPipeWriter.cs @@ -0,0 +1,268 @@ +// 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.Buffers; +using System.Buffers.Text; +using System.Diagnostics; +using System.IO.Pipelines; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Threading; +using System.Threading.Tasks; + +namespace PlatformBenchmarks; + +internal sealed class ChunkedPipeWriter : PipeWriter +{ + private const int DefaultChunkSizeHint = 2048; + private static readonly StandardFormat DefaultHexFormat = GetHexFormat(DefaultChunkSizeHint); + private static ReadOnlySpan ChunkTerminator => "\r\n"u8; + + private PipeWriter _output; + private int _chunkSizeHint; + private StandardFormat _hexFormat = DefaultHexFormat; + private Memory _currentFullChunk; + private Memory _currentChunk; + private int _buffered; + private long _unflushedBytes; + private bool _ended = false; + + public Memory Memory => _currentChunk; + + public PipeWriter Output => _output; + + public int Buffered => _buffered; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetOutput(PipeWriter output, int chunkSizeHint = DefaultChunkSizeHint) + { + _buffered = 0; + _unflushedBytes = 0; + _chunkSizeHint = chunkSizeHint; + _output = output; + + StartNewChunk(chunkSizeHint, isFirst: true); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Reset() + { + _buffered = 0; + _unflushedBytes = 0; + _output = default; + _ended = false; + _hexFormat = DefaultHexFormat; + _currentFullChunk = default; + _currentChunk = default; + } + + public override bool CanGetUnflushedBytes => true; + + public override long UnflushedBytes => _unflushedBytes; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override void Advance(int count) + { + ThrowIfEnded(); + + _buffered += count; + _unflushedBytes += count; + _currentChunk = _currentChunk[count..]; + } + + public override Memory GetMemory(int sizeHint = 0) + { + ThrowIfEnded(); + + if (_currentChunk.Length <= sizeHint) + { + EnsureMore(sizeHint); + } + return _currentChunk; + } + + public override Span GetSpan(int sizeHint = 0) => GetMemory(sizeHint).Span; + + public override void CancelPendingFlush() + { + _output.CancelPendingFlush(); + } + + public override void Complete(Exception exception = null) + { + ThrowIfEnded(); + + CommitCurrentChunk(isFinal: true); + + _ended = true; + } + + public override ValueTask FlushAsync(CancellationToken cancellationToken = default) + { + CommitCurrentChunk(isFinal: false); + + var flushTask = _output.FlushAsync(cancellationToken); + + _unflushedBytes = 0; + + return flushTask; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static StandardFormat GetHexFormat(int maxValue) + { + var hexDigitCount = CountHexDigits(maxValue); + + return new StandardFormat('X', (byte)hexDigitCount); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int CountHexDigits(int n) => n <= 16 ? 1 : (BitOperations.Log2((uint)n) >> 2) + 1; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void StartNewChunk(int sizeHint, bool isFirst = false) + { + ThrowIfEnded(); + + // Header is like: + // 520\r\n + + var oldFullChunkHexLength = -1; + if (!isFirst) + { + oldFullChunkHexLength = CountHexDigits(_currentFullChunk.Length); + } + _currentFullChunk = _output.GetMemory(Math.Max(_chunkSizeHint, sizeHint)); + var newFullChunkHexLength = CountHexDigits(_currentFullChunk.Length); + + var currentFullChunkSpan = _currentFullChunk.Span; + + // Write space for HEX digits + currentFullChunkSpan[..newFullChunkHexLength].Fill(48); // 48 == '0' + + // Write header terminator + var terminator = "\r\n"u8; + terminator.CopyTo(currentFullChunkSpan[newFullChunkHexLength..]); + var chunkHeaderLength = newFullChunkHexLength + terminator.Length; + _currentChunk = _currentFullChunk[chunkHeaderLength..]; + + if ((!isFirst && oldFullChunkHexLength != newFullChunkHexLength) || (isFirst && DefaultChunkSizeHint != _chunkSizeHint)) + { + // Update HEX format if changed + _hexFormat = GetHexFormat(_currentFullChunk.Length); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void CommitCurrentChunk(bool isFinal = false, int sizeHint = 0) + { + ThrowIfEnded(); + + var contentLength = _buffered; + + if (contentLength > 0) + { + // Update the chunk header + var chunkLengthHexDigitsLength = CountHexDigits(contentLength); + var span = _currentFullChunk.Span; + if (!Utf8Formatter.TryFormat(contentLength, span, out var bytesWritten, _hexFormat)) + { + throw new NotSupportedException("Chunk size too large"); + } + Debug.Assert(chunkLengthHexDigitsLength == bytesWritten, "HEX formatting math problem."); + var headerLength = chunkLengthHexDigitsLength + 2; + + // Total chunk length: content length as HEX string + \r\n + content + \r\n + var spanOffset = headerLength + contentLength; + var chunkTotalLength = spanOffset + ChunkTerminator.Length; + + Debug.Assert(span.Length >= chunkTotalLength, "Bad chunk size calculation."); + + // Write out the chunk terminator + ChunkTerminator.CopyTo(span[spanOffset..]); + spanOffset = chunkTotalLength; + + if (!isFinal) + { + _output.Advance(chunkTotalLength); + StartNewChunk(sizeHint); + } + else + { + // Write out final chunk (zero-length chunk) + var terminator = "0\r\n\r\n"u8; + if ((spanOffset + terminator.Length) <= span.Length) + { + // There's space for the final chunk in the current span + terminator.CopyTo(span[spanOffset..]); + _output.Advance(chunkTotalLength + terminator.Length); + } + else + { + // Final chunk doesn't fit in current span so just write it directly after advancing the writer + _output.Advance(chunkTotalLength); + _output.Write(terminator); + } + } + + _buffered = 0; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Write(ReadOnlySpan source) + { + ThrowIfEnded(); + + if (_currentChunk.Length >= (source.Length + ChunkTerminator.Length)) + { + source.CopyTo(_currentChunk.Span); + Advance(source.Length); + } + else + { + WriteMultiBuffer(source); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private void EnsureMore(int count = 0) + { + if (count > (_currentChunk.Length - _buffered - ChunkTerminator.Length)) + { + if (_buffered > 0) + { + CommitCurrentChunk(isFinal: false, count); + } + else + { + StartNewChunk(count); + } + } + } + + private void WriteMultiBuffer(ReadOnlySpan source) + { + while (source.Length > 0) + { + if ((_currentChunk.Length - ChunkTerminator.Length) == 0) + { + EnsureMore(); + } + + var writable = Math.Min(source.Length, _currentChunk.Length - ChunkTerminator.Length); + source[..writable].CopyTo(_currentChunk.Span); + source = source[writable..]; + Advance(writable); + } + } + + private void ThrowIfEnded() + { + if (_ended) + { + throw new InvalidOperationException("Cannot use the writer after calling End()."); + } + } +} \ No newline at end of file diff --git a/frameworks/CSharp/aspnetcore/src/Platform/Platform.csproj b/frameworks/CSharp/aspnetcore/src/Platform/Platform.csproj index c826ee1320b..7db51dc3ec7 100644 --- a/frameworks/CSharp/aspnetcore/src/Platform/Platform.csproj +++ b/frameworks/CSharp/aspnetcore/src/Platform/Platform.csproj @@ -1,7 +1,7 @@  - net8.0 + net9.0 true true preview @@ -18,10 +18,14 @@ - - - - + + + + + + + + diff --git a/frameworks/CSharp/aspnetcore/src/Platform/Program.cs b/frameworks/CSharp/aspnetcore/src/Platform/Program.cs index 9b22d3f5b40..28fc5d757dd 100644 --- a/frameworks/CSharp/aspnetcore/src/Platform/Program.cs +++ b/frameworks/CSharp/aspnetcore/src/Platform/Program.cs @@ -52,7 +52,6 @@ public static IWebHost BuildWebHost(string[] args) #if DEBUG .AddUserSecrets() #endif - .AddEnvironmentVariables() .AddEnvironmentVariables() .AddCommandLine(args) .Build(); diff --git a/frameworks/CSharp/beetlex/Benchmarks.sln b/frameworks/CSharp/beetlex/Benchmarks.sln index 07298d57325..3922903f0b2 100644 --- a/frameworks/CSharp/beetlex/Benchmarks.sln +++ b/frameworks/CSharp/beetlex/Benchmarks.sln @@ -1,11 +1,11 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.28010.2036 +# Visual Studio Version 17 +VisualStudioVersion = 17.9.34728.123 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Benchmarks", "Benchmarks\Benchmarks.csproj", "{12CA0190-5EA2-460F-ABC4-FAD454148EBF}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlatformBenchmarks", "PlatformBenchmarks\PlatformBenchmarks.csproj", "{8ACF83AD-E861-4642-BEF3-A6211F99389D}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PlatformBenchmarks", "PlatformBenchmarks\PlatformBenchmarks.csproj", "{8ACF83AD-E861-4642-BEF3-A6211F99389D}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/frameworks/CSharp/beetlex/Benchmarks/Benchmarks.csproj b/frameworks/CSharp/beetlex/Benchmarks/Benchmarks.csproj index 01cb00297fd..2ae062718ff 100644 --- a/frameworks/CSharp/beetlex/Benchmarks/Benchmarks.csproj +++ b/frameworks/CSharp/beetlex/Benchmarks/Benchmarks.csproj @@ -2,13 +2,12 @@ Exe - net5.0 + net8.0 true - - + diff --git a/frameworks/CSharp/beetlex/Benchmarks/Program.cs b/frameworks/CSharp/beetlex/Benchmarks/Program.cs index 05ba5ed2db8..30f02f76908 100644 --- a/frameworks/CSharp/beetlex/Benchmarks/Program.cs +++ b/frameworks/CSharp/beetlex/Benchmarks/Program.cs @@ -6,9 +6,9 @@ using System.Threading; using System.Text; using BeetleX.Buffers; -using SpanJson; using System.Collections.Generic; using BeetleX.EventArgs; +using System.Text.Json; namespace Benchmarks { @@ -109,8 +109,8 @@ public async virtual Task StartAsync(CancellationToken cancellationToken) mComplete.TrySetResult(new object()); }; mApiServer.Open(); - RawDb._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"; - //RawDb._connectionString = "Server=192.168.2.19;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;Maximum Pool Size=256;NoResetOnClose=true;Enlist=false;Max Auto Prepare=3"; + RawDb._connectionString = "Server=tfb-database;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;SSL Mode=Disable;Maximum Pool Size=64;NoResetOnClose=true;Enlist=false;Max Auto Prepare=4;Multiplexing=true;Write Coalescing Buffer Threshold Bytes=1000"; + //RawDb._connectionString = "Server=localhost;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;Maximum Pool Size=256;NoResetOnClose=true;Enlist=false;Max Auto Prepare=3"; await mComplete.Task; } @@ -140,7 +140,8 @@ public SpanJsonResult(object data) public override void Write(PipeStream stream, HttpResponse response) { - JsonSerializer.NonGeneric.Utf8.SerializeAsync(Data, stream); + + JsonSerializer.Serialize(stream, Data); ; } diff --git a/frameworks/CSharp/beetlex/PlatformBenchmarks/DBRaw.cs b/frameworks/CSharp/beetlex/PlatformBenchmarks/DBRaw.cs index c1ef0fa4722..6aae831fcbb 100644 --- a/frameworks/CSharp/beetlex/PlatformBenchmarks/DBRaw.cs +++ b/frameworks/CSharp/beetlex/PlatformBenchmarks/DBRaw.cs @@ -7,113 +7,47 @@ using System.Runtime.Versioning; using System.Text; using System.Threading.Tasks; -using System.Runtime.InteropServices.ComTypes; -using BeetleX.EventArgs; + using Microsoft.Extensions.Caching.Memory; using Npgsql; +using System.Runtime.CompilerServices; + namespace PlatformBenchmarks { - public class RawDb + public sealed class RawDb { - private readonly ConcurrentRandom _random; + private readonly MemoryCache _cache + = new(new MemoryCacheOptions { ExpirationScanFrequency = TimeSpan.FromMinutes(60) }); - private readonly DbProviderFactory _dbProviderFactory; - - private readonly static MemoryCache _cache = new MemoryCache( - new MemoryCacheOptions() - { - ExpirationScanFrequency = TimeSpan.FromMinutes(60) - }); - - private static readonly object[] _cacheKeys = Enumerable.Range(0, 10001).Select((i) => new CacheKey(i)).ToArray(); - - public static string _connectionString = null; + private static DbProviderFactory _dbProviderFactory => Npgsql.NpgsqlFactory.Instance; + private readonly string _connectionString; - public RawDb(ConcurrentRandom random, DbProviderFactory dbProviderFactory) + public RawDb(ConcurrentRandom random, string connectionString) { _random = random; - _dbProviderFactory = dbProviderFactory; - OnCreateCommand(); - } - private void OnCreateCommand() - { - SingleCommand = new Npgsql.NpgsqlCommand(); - SingleCommand.CommandText = "SELECT id, randomnumber FROM world WHERE id = @Id"; - mID = new Npgsql.NpgsqlParameter("@Id", _random.Next(1, 10001)); - SingleCommand.Parameters.Add(mID); - FortuneCommand = new Npgsql.NpgsqlCommand(); - FortuneCommand.CommandText = "SELECT id, message FROM fortune"; - } - - private DbCommand SingleCommand; - - private DbCommand FortuneCommand; - - private Npgsql.NpgsqlParameter mID; - - private static int ListDefaultSize = 8; - - private World[] mWorldBuffer = null; - - private World[] GetWorldBuffer() - { - if (mWorldBuffer == null) - mWorldBuffer = new World[512]; - return mWorldBuffer; - } - - private Fortune[] mFortunesBuffer = null; - - private Fortune[] GetFortuneBuffer() - { - if (mFortunesBuffer == null) - mFortunesBuffer = new Fortune[512]; - return mFortunesBuffer; + _connectionString = connectionString; } public async Task LoadSingleQueryRow() { - using (var db = _dbProviderFactory.CreateConnection()) - { - db.ConnectionString = _connectionString; - await db.OpenAsync(); - SingleCommand.Connection = db; - mID.TypedValue = _random.Next(1, 10001); - return await ReadSingleRow(db, SingleCommand); - - } - } - - async Task ReadSingleRow(DbConnection connection, DbCommand cmd) - { - using (var rdr = await cmd.ExecuteReaderAsync(CommandBehavior.SingleRow)) - + using (var connection = (NpgsqlConnection)_dbProviderFactory.CreateConnection()) { - await rdr.ReadAsync(); - return new World + connection.ConnectionString = _connectionString; + await connection.OpenAsync(); + var (cmd, _) = CreateReadCommand(connection); + using (var command = cmd) { - Id = rdr.GetInt32(0), - RandomNumber = rdr.GetInt32(1) - }; - } - } - public async Task> LoadMultipleQueriesRows(int count) - { - using (var db = _dbProviderFactory.CreateConnection()) - { - db.ConnectionString = _connectionString; - await db.OpenAsync(); - return await LoadMultipleRows(count, db); + return await ReadSingleRow(cmd); + } } } - - public Task LoadCachedQueries(int count) + public Task LoadCachedQueries(int count) { - var result = new World[count]; + var result = new CachedWorld[count]; var cacheKeys = _cacheKeys; var cache = _cache; var random = _random; @@ -121,42 +55,40 @@ public Task LoadCachedQueries(int count) { var id = random.Next(1, 10001); var key = cacheKeys[id]; - var data = cache.Get(key); - - if (data != null) + if (cache.TryGetValue(key, out var cached)) { - result[i] = data; + result[i] = (CachedWorld)cached; } else { - return LoadUncachedQueries(id, i, count, this, result); + return LoadUncachedQueries(_connectionString, id, i, count, this, result); } } return Task.FromResult(result); - static async Task LoadUncachedQueries(int id, int i, int count, RawDb rawdb, World[] result) + static async Task LoadUncachedQueries(string conn, int id, int i, int count, RawDb rawdb, CachedWorld[] result) { - using (var db = new NpgsqlConnection(_connectionString)) + using (var connection = (NpgsqlConnection)_dbProviderFactory.CreateConnection()) { - await db.OpenAsync(); - Func> create = async (entry) => - { - return await rawdb.ReadSingleRow(db, rawdb.SingleCommand); - }; + connection.ConnectionString = conn; + await connection.OpenAsync(); + var (cmd, idParameter) = rawdb.CreateReadCommand(connection); + using var command = cmd; + async Task create(ICacheEntry _) => await ReadSingleRow(cmd); + var cacheKeys = _cacheKeys; var key = cacheKeys[id]; - rawdb.SingleCommand.Connection = db; - rawdb.mID.TypedValue = id; + idParameter.TypedValue = id; + for (; i < result.Length; i++) { - var data = await _cache.GetOrCreateAsync(key, create); - result[i] = data; + result[i] = await rawdb._cache.GetOrCreateAsync(key, create); + id = rawdb._random.Next(1, 10001); - rawdb.SingleCommand.Connection = db; - rawdb.mID.TypedValue = id; + idParameter.TypedValue = id; key = cacheKeys[id]; } } @@ -164,216 +96,212 @@ static async Task LoadUncachedQueries(int id, int i, int count, RawDb r } } - - private async Task> LoadMultipleRows(int count, DbConnection db) + public async Task PopulateCache() { - SingleCommand.Connection = db; - SingleCommand.Parameters[0].Value = _random.Next(1, 10001); - var result = GetWorldBuffer(); - for (int i = 0; i < count; i++) + using (var connection = (NpgsqlConnection)_dbProviderFactory.CreateConnection()) { - result[i] = await ReadSingleRow(db, SingleCommand); - SingleCommand.Parameters[0].Value = _random.Next(1, 10001); + connection.ConnectionString = _connectionString; + await connection.OpenAsync(); + var (cmd, idParameter) = CreateReadCommand(connection); + using var command = cmd; + + var cacheKeys = _cacheKeys; + var cache = _cache; + for (var i = 1; i < 10001; i++) + { + idParameter.TypedValue = i; + cache.Set(cacheKeys[i], await ReadSingleRow(cmd)); + } } - return new ArraySegment(result, 0, count); + Console.WriteLine("Caching Populated"); } - public async Task> LoadFortunesRows() + public async Task LoadMultipleQueriesRows(int count) { - int count = 0; - var result = GetFortuneBuffer(); - using (var db = new NpgsqlConnection(_connectionString)) + var results = new World[count]; + + using (var connection = (NpgsqlConnection)_dbProviderFactory.CreateConnection()) { - await db.OpenAsync(); - FortuneCommand.Connection = db; - using (var rdr = await FortuneCommand.ExecuteReaderAsync()) + connection.ConnectionString = _connectionString; + await connection.OpenAsync(); + + using var batch = new NpgsqlBatch(connection) { - while (await rdr.ReadAsync()) + // Inserts a PG Sync message between each statement in the batch, required for compliance with + // TechEmpower general test requirement 7 + // https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview + EnableErrorBarriers = true + }; + + for (var i = 0; i < count; i++) + { + batch.BatchCommands.Add(new() { - result[count] = (new Fortune - { - Id = rdr.GetInt32(0), - Message = rdr.GetString(1) - }); - count++; - } + CommandText = "SELECT id, randomnumber FROM world WHERE id = $1", + Parameters = { new NpgsqlParameter { TypedValue = _random.Next(1, 10001) } } + }); + } + + using var reader = await batch.ExecuteReaderAsync(); + + for (var i = 0; i < count; i++) + { + await reader.ReadAsync(); + results[i] = new World { Id = reader.GetInt32(0), RandomNumber = reader.GetInt32(1) }; + await reader.NextResultAsync(); } } - result[count] = (new Fortune { Message = "Additional fortune added at request time." }); - count++; - Array.Sort(result, 0, count); - return new ArraySegment(result, 0, count); + return results; } + public async Task LoadMultipleUpdatesRows(int count) { - using (var db = new NpgsqlConnection(_connectionString)) + var results = new World[count]; + + using (var connection = (NpgsqlConnection)_dbProviderFactory.CreateConnection()) { - await db.OpenAsync(); - var updateCmd = UpdateCommandsCached.PopCommand(count); - try + connection.ConnectionString = _connectionString; + await connection.OpenAsync(); + var (queryCmd, queryParameter) = CreateReadCommand(connection); + using (queryCmd) { - var command = updateCmd.Command; - command.Connection = db; - SingleCommand.Connection = db; - mID.TypedValue = _random.Next(1, int.MaxValue) % 10000 + 1; - var results = new World[count]; - for (int i = 0; i < count; i++) + for (var i = 0; i < results.Length; i++) { - results[i] = await ReadSingleRow(db, SingleCommand); - mID.TypedValue = _random.Next(1, int.MaxValue) % 10000 + 1; + results[i] = await ReadSingleRow(queryCmd); + queryParameter.TypedValue = _random.Next(1, 10001); } + } - for (int i = 0; i < count; i++) + using (var updateCmd = new NpgsqlCommand(BatchUpdateString.Query(count), connection)) + { + for (var i = 0; i < results.Length; i++) { - var randomNumber = _random.Next(1, int.MaxValue) % 10000 + 1; - updateCmd.Parameters[i * 2].TypedValue = results[i].Id; - updateCmd.Parameters[i * 2 + 1].TypedValue = randomNumber; - //updateCmd.Parameters[i * 2].Value = results[i].Id; - //updateCmd.Parameters[i * 2 + 1].Value = randomNumber; + var randomNumber = _random.Next(1, 10001); + + updateCmd.Parameters.Add(new NpgsqlParameter { TypedValue = results[i].Id }); + updateCmd.Parameters.Add(new NpgsqlParameter { TypedValue = randomNumber }); + results[i].RandomNumber = randomNumber; } - await command.ExecuteNonQueryAsync(); - return results; - } - catch (Exception e_) - { - throw e_; - } - finally - { - UpdateCommandsCached.PushCommand(count, updateCmd); + await updateCmd.ExecuteNonQueryAsync(); } } - } - } + return results; + } - public sealed class CacheKey : IEquatable - { - private readonly int _value; + public async Task> LoadFortunesRows() + { + // Benchmark requirements explicitly prohibit pre-initializing the list size + var result = new List(); - public CacheKey(int value) - => _value = value; + using (var connection = (NpgsqlConnection)_dbProviderFactory.CreateConnection()) + { + connection.ConnectionString = _connectionString; + await connection.OpenAsync(); - public bool Equals(CacheKey key) - => key._value == _value; + using (var cmd = new NpgsqlCommand("SELECT id, message FROM fortune", connection)) + { - public override bool Equals(object obj) - => ReferenceEquals(obj, this); + using (var rdr = await cmd.ExecuteReaderAsync()) + { - public override int GetHashCode() - => _value; + while (await rdr.ReadAsync()) + { + result.Add(new Fortune + { + Id = rdr.GetInt32(0), + Message = rdr.GetString(1) + }); + } + } + } + } + result.Add(new Fortune { Message = "Additional fortune added at request time." }); + result.Sort(); - public override string ToString() - => _value.ToString(); - } + return result; + } - internal class UpdateCommandsCached - { - private static System.Collections.Concurrent.ConcurrentStack[] mCacheTable - = new System.Collections.Concurrent.ConcurrentStack[1024]; - public static string[] IDParamereNames = new string[1024]; + 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.Next(1, 10001) }; - public static string[] RandomParamereNames = new string[1024]; + cmd.Parameters.Add(parameter); - static UpdateCommandsCached() - { - for (int i = 0; i < 1024; i++) - { - IDParamereNames[i] = $"@Id_{i}"; - RandomParamereNames[i] = $"@Random_{i}"; - mCacheTable[i] = new System.Collections.Concurrent.ConcurrentStack(); - } + return (cmd, parameter); } - private static CommandCacheItem CreatCommand(int count) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static async Task ReadSingleRow(NpgsqlCommand cmd) { - CommandCacheItem item = new CommandCacheItem(); - NpgsqlCommand cmd = new Npgsql.NpgsqlCommand(); - cmd.CommandText = BatchUpdateString.Query(count); - for (int i = 0; i < count; i++) - { - var id = new NpgsqlParameter(); - id.ParameterName = IDParamereNames[i]; - cmd.Parameters.Add(id); - item.Parameters.Add(id); - - var random = new NpgsqlParameter(); - random.ParameterName = RandomParamereNames[i]; - cmd.Parameters.Add(random); - item.Parameters.Add(random); - } - item.Command = cmd; - return item; + using var rdr = await cmd.ExecuteReaderAsync(System.Data.CommandBehavior.SingleRow); + await rdr.ReadAsync(); + return new World + { + Id = rdr.GetInt32(0), + RandomNumber = rdr.GetInt32(1) + }; } - public static void PushCommand(int count, CommandCacheItem cmd) - { - mCacheTable[count].Push(cmd); - } + private static readonly object[] _cacheKeys = Enumerable.Range(0, 10001).Select((i) => new CacheKey(i)).ToArray(); - public static CommandCacheItem PopCommand(int count) + public sealed class CacheKey : IEquatable { - if (mCacheTable[count].TryPop(out CommandCacheItem cmd)) - return cmd; - return CreatCommand(count); - } + private readonly int _value; - private static bool mInited = false; + public CacheKey(int value) + => _value = value; - public static void Init() - { - if (mInited) - return; - lock (typeof(UpdateCommandsCached)) - { - if (mInited) - return; - for (int i = 1; i <= 500; i++) - { - for (int k = 0; k < 10; k++) - { - var cmd = CreatCommand(i); - mCacheTable[i].Push(cmd); - } - } - mInited = true; - HttpServer.ApiServer.Log(LogType.Info, null, $"Init update commands cached"); - return; - } - } - } + public bool Equals(CacheKey key) + => key._value == _value; - class CommandCacheItem - { - public Npgsql.NpgsqlCommand Command { get; set; } + public override bool Equals(object obj) + => ReferenceEquals(obj, this); + + public override int GetHashCode() + => _value; - public List> Parameters { get; private set; } = new List>(1024); + public override string ToString() + => _value.ToString(); + } } - internal class BatchUpdateString + internal sealed class BatchUpdateString { private const int MaxBatch = 500; + internal static readonly string[] ParamNames = Enumerable.Range(0, MaxBatch * 2).Select(i => $"@p{i}").ToArray(); + private static string[] _queries = new string[MaxBatch + 1]; public static string Query(int batchSize) + => _queries[batchSize] is null + ? CreateBatch(batchSize) + : _queries[batchSize]; + + private static string CreateBatch(int batchSize) { - if (_queries[batchSize] != null) + var sb = StringBuilderCache.Acquire(); + + + sb.Append("UPDATE world SET randomNumber = temp.randomNumber FROM (VALUES "); + var c = 1; + for (var i = 0; i < batchSize; i++) { - return _queries[batchSize]; + if (i > 0) + sb.Append(", "); + sb.Append($"(${c++}, ${c++})"); } + sb.Append(" ORDER BY 1) AS temp(id, randomNumber) WHERE temp.id = world.id"); + - 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); } } diff --git a/frameworks/CSharp/beetlex/PlatformBenchmarks/GMTDate.cs b/frameworks/CSharp/beetlex/PlatformBenchmarks/GMTDate.cs index ac9266097ba..bfd6b79223a 100644 --- a/frameworks/CSharp/beetlex/PlatformBenchmarks/GMTDate.cs +++ b/frameworks/CSharp/beetlex/PlatformBenchmarks/GMTDate.cs @@ -1,4 +1,5 @@ -using BeetleX.Buffers; + +using BeetleX.Light.Memory; using System; using System.Collections.Generic; using System.Text; @@ -48,7 +49,7 @@ public static GMTDate Default } } - public ArraySegment DATE + public Memory DATE { get; set; @@ -94,18 +95,20 @@ private void Init() }, null, 1000, 1000); } - private ArraySegment GetData() + private Memory GetData() { return GetData(DateTime.Now); } - public void Write(PipeStream stream) + + + public void Write(IStreamWriter stream) { - var data = DATE; - stream.Write(data.Array, 0, data.Count); + + stream.Write(DATE.Span); } - private ArraySegment GetData(DateTime date) + private Memory GetData(DateTime date) { date = date.ToUniversalTime(); int offset13 = 0; @@ -189,7 +192,7 @@ private ArraySegment GetData(DateTime date) buffer[offset13] = _n; offset13++; - return new ArraySegment(GTM_BUFFER, 0, offset13); + return new Memory(GTM_BUFFER, 0, offset13); } } diff --git a/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.Caching.cs b/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.Caching.cs index 13d89c6fc97..2794fcbdd82 100644 --- a/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.Caching.cs +++ b/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.Caching.cs @@ -1,18 +1,18 @@ -using BeetleX; -using BeetleX.Buffers; -using SpanJson; +using BeetleX.Light.Memory; using System; using System.Collections.Generic; +using System.IO; using System.Text; +using System.Text.Json; using System.Threading.Tasks; namespace PlatformBenchmarks { public partial class HttpHandler { - - public async Task caching(string queryString, PipeStream stream, HttpToken token, ISession session) + + public async Task caching(string queryString, IStreamWriter stream) { int count = 1; if (!string.IsNullOrEmpty(queryString)) @@ -30,20 +30,39 @@ public async Task caching(string queryString, PipeStream stream, HttpToken token count = 500; if (count < 1) count = 1; + ContentLengthMemory content = new ContentLengthMemory(); try { - var data = await token.Db.LoadCachedQueries(count); + var data = await DB.LoadCachedQueries(count); stream.Write(_jsonResultPreamble.Data, 0, _jsonResultPreamble.Length); - token.ContentLength = stream.Allocate(HttpHandler._LengthSize); + content.Data = GetContentLengthMemory(stream); GMTDate.Default.Write(stream); - token.ContentPostion = stream.CacheLength; - await JsonSerializer.NonGeneric.Utf8.SerializeAsync(data, stream); + stream.WriteSequenceNetStream.StartWriteLength(); + + var jsonWriter = GetJsonWriter(stream); + using (var unflush = stream.UnFlush()) + { + jsonWriter.WriteStartArray(); + foreach (var item in data) + { + jsonWriter.WriteStartObject(); + jsonWriter.WriteNumber("Id", item.Id); + jsonWriter.WriteNumber("RandomNumber", item.RandomNumber); + jsonWriter.WriteEndObject(); + } + jsonWriter.WriteEndArray(); + jsonWriter.Flush(); + + } } catch (Exception e_) { - stream.Write(e_.Message); + Context.GetLoger(BeetleX.Light.Logs.LogLevel.Error)?.WriteException(Context, "PlatformBenchmarks", "caching", e_); + stream.WriteString(e_.Message); } - OnCompleted(stream, session, token); + var len = stream.WriteSequenceNetStream.EndWriteLength(); + content.Full(len); + } } } diff --git a/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.cs b/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.cs index 8e5b65d9c79..117d19fee9a 100644 --- a/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.cs +++ b/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.cs @@ -1,15 +1,21 @@ -using BeetleX; -using BeetleX.Buffers; -using BeetleX.EventArgs; -using SpanJson; +using BeetleX.Light; +using BeetleX.Light.Memory; using System; +using System.Buffers; using System.Collections.Generic; +using System.IO; +using System.IO.Pipelines; using System.Text; +using System.Text.Json; using System.Threading.Tasks; namespace PlatformBenchmarks { - public partial class HttpHandler : ServerHandlerBase + + + + + public partial class HttpHandler : SesionBase { private static readonly AsciiString _line = new AsciiString("\r\n"); @@ -41,38 +47,22 @@ public partial class HttpHandler : ServerHandlerBase private static readonly AsciiString _path_Fortunes = "/fortunes"; - private static readonly AsciiString _result_plaintext = "Hello, World!"; private static readonly AsciiString _cached_worlds = "/cached-worlds"; - private readonly static uint _jsonPayloadSize = (uint)System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(new JsonMessage { message = "Hello, World!" }, SerializerOptions).Length; - - + private readonly static uint _jsonPayloadSize = (uint)System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(new JsonMessage { message = "Hello, World!" }).Length; - private readonly static AsciiString _jsonPreamble = - _httpsuccess - + _headerContentTypeJson - + _headerServer - + _headerContentLength + _jsonPayloadSize.ToString() + _line; - - private readonly static AsciiString _plaintextPreamble = - _httpsuccess - + _headerContentTypeText - + _headerServer - + _headerContentLength + _result_plaintext.Length.ToString() + _line; private readonly static AsciiString _jsonResultPreamble = _httpsuccess + _headerContentTypeJson - + _headerServer - + _headerContentLength; + + _headerServer; private readonly static AsciiString _HtmlResultPreamble = _httpsuccess + _headerContentTypeHtml - + _headerServer - + _headerContentLength; + + _headerServer; @@ -83,24 +73,49 @@ public partial class HttpHandler : ServerHandlerBase private static byte _question = 63; - public HttpHandler() + struct ContentLengthMemory { - RequestDispatchs = new BeetleX.Dispatchs.DispatchCenter(OnRequest, Math.Min(Environment.ProcessorCount, 16)); + public Memory Data { get; set; } + + public void Full(int length) + { + _headerContentLength.Data.CopyTo(Data); + var span = Data.Slice(_headerContentLength.Length).Span; + var len = span.Write(length.ToString(), Encoding.ASCII); + for (int i = len; i < span.Length - 2; i++) + { + span[i] = 32; + } + span[^2] = 13; + span[^1] = 10; + } } - private BeetleX.Dispatchs.DispatchCenter RequestDispatchs; + protected Memory GetContentLengthMemory(IStreamWriter writer) + { + var result = writer.WriteSequenceNetStream.GetWriteMemory(28); + writer.WriteSequenceNetStream.WriteAdvance(28); + return result; + } + public NetContext Context { get; set; } - public override void Connected(IServer server, ConnectedEventArgs e) + public HttpHandler() { - base.Connected(server, e); - e.Session.Socket.NoDelay = true; - var token = new HttpToken(); - token.ThreadDispatcher = RequestDispatchs.Next(); - token.Session = e.Session; - token.Db = new RawDb(new ConcurrentRandom(), Npgsql.NpgsqlFactory.Instance); - e.Session.Tag = token; + + } + + private Queue _Requests = new Queue(); + + public static RawDb DB; + + private RequestData _ReadRequest = null; + public override void Connected(NetContext context) + { + base.Connected(context); + this.Context = context; + } private int AnalysisUrl(ReadOnlySpan url) @@ -114,195 +129,216 @@ private int AnalysisUrl(ReadOnlySpan url) } - private void OnRequest(HttpToken token) - { - if (token.Requests.TryDequeue(out RequestData result)) - { - OnStartRequest(result, token.Session, token, token.Session.Stream.ToPipeStream()); - } - } - - public override void SessionReceive(IServer server, SessionReceiveEventArgs e) + public override void Receive(NetContext context, object message) { - base.SessionReceive(server, e); - PipeStream pipeStream = e.Session.Stream.ToPipeStream(); - HttpToken token = (HttpToken)e.Session.Tag; - var result = pipeStream.IndexOfLine(); - while (result.End != null) + var stream = context.Reader.ReadSequenceNetStream; + var reader = stream.GetReadOnlySequence(); + var len = reader.IndexOf(_line); + while (len != null) { - if (result.Length == 2) + var lendata = len.Value; + stream.ReadAdvance(lendata.Length); + if (lendata.Length == 2) { - pipeStream.ReadFree(result.Length); - OnStartRequest(token.CurrentRequest, e.Session, token, pipeStream); + _Requests.Enqueue(_ReadRequest); + _ReadRequest = null; } else { - if (token.CurrentRequest == null) + if (_ReadRequest == null) { - var request = new RequestData(); - byte[] buffer = null; - buffer = new byte[result.Length]; - pipeStream.Read(buffer, 0, result.Length); - request.Data = new ArraySegment(buffer, 0, result.Length); - AnalysisAction(request); - if (request.Action == ActionType.Plaintext) - { - token.CurrentRequest = request; - } - else - { - token.CurrentRequest = request; - pipeStream.ReadFree((int)pipeStream.Length); - OnStartRequest(request, e.Session, token, pipeStream); - return; - } + _ReadRequest = new RequestData(); + } + if (_ReadRequest.Action == null) + { + AnalysisAction(lendata, out var type, out var querystring); + _ReadRequest.Action = type; + _ReadRequest.QueryString = querystring; + } else { - pipeStream.ReadFree(result.Length); + } } - if (pipeStream.Length > 0) - result = pipeStream.IndexOfLine(); - else - break; + reader = stream.GetReadOnlySequence(); + len = reader.IndexOf(_line); + } + if (_Requests.Count > 0) + { + OnStartRequest(context.Writer); } } - private void AnalysisAction(RequestData requestData) + //public override void SessionReceive(IServer server, SessionReceiveEventArgs e) + //{ + // base.SessionReceive(server, e); + // PipeStream pipeStream = e.Session.Stream.ToPipeStream(); + // HttpToken token = (HttpToken)e.Session.Tag; + // var result = pipeStream.IndexOfLine(); + // while (result.End != null) + // { + // if (result.Length == 2) + // { + // pipeStream.ReadFree(result.Length); + // OnStartRequest(token.CurrentRequest, e.Session, token, pipeStream); + // } + // else + // { + // if (token.CurrentRequest == null) + // { + // var request = new RequestData(); + // byte[] buffer = null; + // buffer = new byte[result.Length]; + // pipeStream.Read(buffer, 0, result.Length); + // request.Data = new ArraySegment(buffer, 0, result.Length); + // AnalysisAction(request); + // if (request.Action == ActionType.Plaintext) + // { + // token.CurrentRequest = request; + // } + // else + // { + // token.CurrentRequest = request; + // pipeStream.ReadFree((int)pipeStream.Length); + // OnStartRequest(request, e.Session, token, pipeStream); + // return; + // } + // } + // else + // { + // pipeStream.ReadFree(result.Length); + // } + // } + // if (pipeStream.Length > 0) + // result = pipeStream.IndexOfLine(); + // else + // break; + // } + //} + + private void AnalysisAction(ReadOnlySequence line, out ActionType type, out string queryString) { - var line = _line.AsSpan(); - int len = requestData.Data.Count; - var receiveData = requestData.GetSpan(); - ReadOnlySpan http = line; - ReadOnlySpan method = line; - ReadOnlySpan url = line; - int offset2 = 0; - int count = 0; - for (int i = 0; i < len; i++) - { - if (receiveData[i] == line[0]) - { - http = receiveData.Slice(offset2, i - offset2); - break; - } - else - { - if (receiveData[i] == _Space) - { - if (count != 0) - { - url = receiveData.Slice(offset2, i - offset2); - offset2 = i + 1; - } - else - { - method = receiveData.Slice(offset2, i - offset2); - offset2 = i + 1; - count++; - } - } - } - } - int queryIndex = AnalysisUrl(url); - ReadOnlySpan baseUrl = default; - ReadOnlySpan queryString = default; - if (queryIndex > 0) + type = ActionType.Plaintext; + queryString = default; + var spanIndex = line.PositionOf((byte)32); + var postion = line.GetPosition(1, spanIndex.Value); + line = line.Slice(postion); + spanIndex = line.PositionOf((byte)32); + var url = line.Slice(0, spanIndex.Value); + int baseurlLen = 0; + spanIndex = url.PositionOf((byte)63); + if (spanIndex != null) { - baseUrl = url.Slice(0, queryIndex); - queryString = url.Slice(queryIndex + 1, url.Length - queryIndex - 1); - requestData.QueryString = Encoding.ASCII.GetString(queryString); + baseurlLen = (int)url.Slice(0, spanIndex.Value).Length; + queryString = url.Slice(baseurlLen + 1).ReadString(Encoding.ASCII); } else { - baseUrl = url; + baseurlLen = (int)url.Length; } - if (baseUrl.Length == _path_Plaintext.Length && baseUrl.StartsWith(_path_Plaintext)) + + Span baseUrl = stackalloc byte[baseurlLen]; + url.Slice(0, baseurlLen).CopyTo(baseUrl); + + if (baseUrl.Length == _path_Plaintext.Length && baseUrl[1] == 'p') { - requestData.Action = ActionType.Plaintext; + type = ActionType.Plaintext; } - else if (baseUrl.Length == _path_Json.Length && baseUrl.StartsWith(_path_Json)) + else if (baseUrl.Length == _path_Json.Length && baseUrl[1] == 'j') { - requestData.Action = ActionType.Json; + type = ActionType.Json; } else if (baseUrl.Length == _path_Db.Length && baseUrl.StartsWith(_path_Db)) { - requestData.Action = ActionType.Db; + type = ActionType.Db; } else if (baseUrl.Length == _path_Queries.Length && baseUrl.StartsWith(_path_Queries)) { - requestData.Action = ActionType.Queries; + type = ActionType.Queries; } else if (baseUrl.Length == _cached_worlds.Length && baseUrl.StartsWith(_cached_worlds)) { - requestData.Action = ActionType.Caching; + type = ActionType.Caching; } else if (baseUrl.Length == _path_Updates.Length && baseUrl.StartsWith(_path_Updates)) { - requestData.Action = ActionType.Updates; + type = ActionType.Updates; } else if (baseUrl.Length == _path_Fortunes.Length && baseUrl.StartsWith(_path_Fortunes)) { - requestData.Action = ActionType.Fortunes; + type = ActionType.Fortunes; } else { - requestData.Action = ActionType.Other; + type = ActionType.Other; } } - public virtual async Task OnStartRequest(RequestData data, ISession session, HttpToken token, PipeStream stream) + public async Task OnStartRequest(IStreamWriter stream) { - ActionType type = data.Action; - if (type == ActionType.Plaintext) - { - await Plaintext(stream, token, session); - } - else if (type == ActionType.Json) - { - await Json(stream, token, session); - } - else if (type == ActionType.Db) - { - await db(stream, token, session); - } - else if (type == ActionType.Queries) + bool haveData = false; + while (_Requests.Count > 0) { - await queries(data.QueryString, stream, token, session); - } - else if (type == ActionType.Caching) - { - await caching(data.QueryString, stream, token, session); - } - else if (type == ActionType.Updates) - { - await updates(data.QueryString, stream, token, session); - } - else if (type == ActionType.Fortunes) - { - await fortunes(stream, token, session); + haveData = true; + var data = _Requests.Dequeue(); + ActionType type = data.Action.Value; + if (type == ActionType.Plaintext) + { + Plaintext(stream); + } + else if (type == ActionType.Json) + { + Json(stream); + } + else if (type == ActionType.Db) + { + await db(stream); + } + else if (type == ActionType.Queries) + { + await queries(data.QueryString, stream); + } + else if (type == ActionType.Caching) + { + await caching(data.QueryString, stream); + } + else if (type == ActionType.Updates) + { + await updates(data.QueryString, stream); + } + else if (type == ActionType.Fortunes) + { + await fortunes(stream); + } + else + { + await Default(stream); + } } - else + if (haveData) { - await Default(stream, token, session); + stream.Flush(); } - } - private void OnCompleted(PipeStream stream, ISession session, HttpToken token) + + + private Utf8JsonWriter GetJsonWriter(IStreamWriter stream) { - var type = token.CurrentRequest.Action; - if (type != ActionType.Plaintext && type != ActionType.Json) - { - token.FullLength((stream.CacheLength - token.ContentPostion).ToString()); - } - if (token.Requests.IsEmpty && stream.Length == 0) - session.Stream.Flush(); - token.CurrentRequest = null; + Utf8JsonWriter utf8JsonWriter = _utf8JsonWriter ??= new Utf8JsonWriter((Stream)stream.WriteSequenceNetStream, new JsonWriterOptions { SkipValidation = true }); + utf8JsonWriter.Reset((Stream)stream.WriteSequenceNetStream); + return utf8JsonWriter; } + [ThreadStatic] + private static Utf8JsonWriter _utf8JsonWriter; + public static JsonWriterOptions _jsonWriterOptions = new JsonWriterOptions + { + SkipValidation = true + }; } } diff --git a/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.db.cs b/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.db.cs index a6f6c8f2291..1604195625e 100644 --- a/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.db.cs +++ b/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.db.cs @@ -1,8 +1,7 @@ -using BeetleX; -using BeetleX.Buffers; -using SpanJson; +using BeetleX.Light.Memory; using System; using System.Collections.Generic; +using System.IO; using System.Text; using System.Threading.Tasks; @@ -12,23 +11,36 @@ public partial class HttpHandler { - public async ValueTask db(PipeStream stream, HttpToken token, ISession session) + public async Task db(IStreamWriter stream) { + ContentLengthMemory content = new ContentLengthMemory(); + try { - var data = await token.Db.LoadSingleQueryRow(); - stream.Write(_jsonResultPreamble.Data, 0, _jsonResultPreamble.Length); - token.ContentLength = stream.Allocate(HttpHandler._LengthSize); + var data = await DB.LoadSingleQueryRow(); + stream.Write(_jsonResultPreamble.AsSpan()); + content.Data = GetContentLengthMemory(stream); GMTDate.Default.Write(stream); - token.ContentPostion = stream.CacheLength; - System.Text.Json.JsonSerializer.Serialize(GetUtf8JsonWriter(stream, token), data, SerializerOptions); + stream.WriteSequenceNetStream.StartWriteLength(); + var jsonWriter = GetJsonWriter(stream); + using (var unflush = stream.UnFlush()) + { + jsonWriter.WriteStartObject(); + jsonWriter.WriteNumber("Id", data.Id); + jsonWriter.WriteNumber("RandomNumber", data.RandomNumber); + jsonWriter.WriteEndObject(); + System.Text.Json.JsonSerializer.Serialize((Stream)stream.WriteSequenceNetStream, data); + } + } catch (Exception e_) { - HttpServer.ApiServer.Log(BeetleX.EventArgs.LogType.Error, null, $"db error {e_.Message}@{e_.StackTrace}"); - stream.Write(e_.Message); + Context.GetLoger(BeetleX.Light.Logs.LogLevel.Error)?.WriteException(Context, "PlatformBenchmarks", "db", e_); + stream.WriteString(e_.Message); } - OnCompleted(stream, session, token); + var len = stream.WriteSequenceNetStream.EndWriteLength(); + content.Full(len); + } } } diff --git a/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.default.cs b/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.default.cs index acbaff5b164..2300e16a4b2 100644 --- a/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.default.cs +++ b/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.default.cs @@ -1,6 +1,7 @@ -using BeetleX; -using BeetleX.Buffers; + +using BeetleX.Light.Memory; using System; +using System.Buffers; using System.Collections.Generic; using System.Linq; using System.Text; @@ -15,16 +16,19 @@ public partial class HttpHandler + _headerContentTypeJson.ToString() + _headerServer.ToString(); - public Task Default(PipeStream stream, HttpToken token, ISession session) - { + public ValueTask Default(IStreamWriter stream) + { + stream.Write(_defaultPreamble.Data, 0, _defaultPreamble.Length); - token.ContentLength = stream.Allocate(HttpHandler._LengthSize); + ContentLengthMemory contentLength = new ContentLengthMemory(); + contentLength.Data = GetContentLengthMemory(stream); GMTDate.Default.Write(stream); - token.ContentPostion = stream.CacheLength; - stream.Write(" beetlex server
"); - stream.Write("path not found!"); - OnCompleted(stream, session, token); - return Task.CompletedTask; + stream.WriteSequenceNetStream.StartWriteLength(); + stream.WriteString(" beetlex server
"); + stream.WriteString("path not found!"); + var length = stream.WriteSequenceNetStream.EndWriteLength(); + contentLength.Full(length); + return ValueTask.CompletedTask; } } } diff --git a/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.fortunes.cs b/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.fortunes.cs index 55250710b35..7bb2fc40acb 100644 --- a/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.fortunes.cs +++ b/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.fortunes.cs @@ -1,5 +1,5 @@ -using BeetleX; -using BeetleX.Buffers; + +using BeetleX.Light.Memory; using System; using System.Collections.Generic; using System.Globalization; @@ -13,87 +13,56 @@ namespace PlatformBenchmarks public partial class HttpHandler { - private readonly static AsciiString _fortunesTableStart = "Fortunes"; - private readonly static AsciiString _fortunesRowStart = ""; - private readonly static AsciiString _fortunesTableEnd = "
idmessage
"; - private readonly static AsciiString _fortunesColumn = ""; - private readonly static AsciiString _fortunesRowEnd = "
"; - - protected HtmlEncoder HtmlEncoder { get; } = CreateHtmlEncoder(); - - private static HtmlEncoder CreateHtmlEncoder() + 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 + settings.AllowCharacter('\u2014'); // allow EM DASH through return HtmlEncoder.Create(settings); } - public async Task fortunes(PipeStream stream, HttpToken token, ISession session) + private static ReadOnlySpan _fortunesTableStart => "Fortunes"u8; + private static ReadOnlySpan _fortunesRowStart => ""u8; + private static ReadOnlySpan _fortunesTableEnd => "
idmessage
"u8; + private static ReadOnlySpan _fortunesColumn => ""u8; + private static ReadOnlySpan _fortunesRowEnd => "
"u8; + + + public async Task fortunes(IStreamWriter stream) { + ContentLengthMemory content = new ContentLengthMemory(); try { - var data = await token.Db.LoadFortunesRows(); + var data = await DB.LoadFortunesRows(); - stream.Write(_HtmlResultPreamble.Data, 0, _HtmlResultPreamble.Length); - token.ContentLength = stream.Allocate(HttpHandler._LengthSize); + stream.Write(_HtmlResultPreamble); + content.Data = GetContentLengthMemory(stream); GMTDate.Default.Write(stream); - token.ContentPostion = stream.CacheLength; - var html = token.GetHtmlBufferWriter(); - html.Reset(); - html.Write(_fortunesTableStart.Data, 0, _fortunesTableStart.Length); + stream.WriteSequenceNetStream.StartWriteLength(); + stream.Write(_fortunesTableStart); foreach (var item in data) { - html.Write(_fortunesRowStart.Data, 0, _fortunesRowStart.Length); - WriteNumeric(html, (uint)item.Id); - html.Write(_fortunesColumn.Data, 0, _fortunesColumn.Length); - html.Write(HtmlEncoder.Encode(item.Message)); - html.Write(_fortunesRowEnd.Data, 0, _fortunesRowEnd.Length); + stream.Write(_fortunesRowStart); + stream.WriteString(item.Id.ToString(CultureInfo.InvariantCulture)); + stream.Write(_fortunesColumn); + stream.WriteString(htmlEncoder.Encode(item.Message)); + stream.Write(_fortunesRowEnd); } - html.Write(_fortunesTableEnd.Data, 0, _fortunesTableEnd.Length); - stream.Write(html.Data, 0, html.Length); - + stream.Write(_fortunesTableEnd); } catch (Exception e_) { - HttpServer.ApiServer.Log(BeetleX.EventArgs.LogType.Error, null, $"fortunes error {e_.Message}@{e_.StackTrace}"); - stream.Write(e_.Message); + Context.GetLoger(BeetleX.Light.Logs.LogLevel.Error)?.WriteException(Context, "PlatformBenchmarks", "fortunes", e_); + stream.WriteString(e_.Message); } - OnCompleted(stream, session, token); - } - - internal void WriteNumeric(HtmlBufferWriter writer, uint number) - { - const byte AsciiDigitStart = (byte)'0'; - - if (number < 10) - { - writer.Write((byte)(number + AsciiDigitStart)); - - } - else if (number < 100) - { - var tens = (byte)((number * 205u) >> 11); // div10, valid to 1028 - var span = new byte[2]; - span[0] = (byte)(tens + AsciiDigitStart); - span[1] = (byte)(number - (tens * 10) + AsciiDigitStart); - writer.Write(span, 0, 2); + var len = stream.WriteSequenceNetStream.EndWriteLength(); + content.Full(len); - } - else if (number < 1000) - { - var digit0 = (byte)((number * 41u) >> 12); // div100, valid to 1098 - var digits01 = (byte)((number * 205u) >> 11); // div10, valid to 1028 - var span = new byte[3]; - span[0] = (byte)(digit0 + AsciiDigitStart); - span[1] = (byte)(digits01 - (digit0 * 10) + AsciiDigitStart); - span[2] = (byte)(number - (digits01 * 10) + AsciiDigitStart); - writer.Write(span, 0, 3); - } } - internal void WriteNumeric(PipeStream stream, uint number) + internal void WriteNumeric(IStreamWriter stream, uint number) { const byte AsciiDigitStart = (byte)'0'; diff --git a/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.json.cs b/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.json.cs index 1577248fa81..4a379e98931 100644 --- a/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.json.cs +++ b/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.json.cs @@ -1,8 +1,10 @@ using BeetleX; -using BeetleX.Buffers; -using SpanJson; + +using BeetleX.Light.Memory; + using System; using System.Collections.Generic; +using System.IO; using System.Text; using System.Text.Json; using System.Threading.Tasks; @@ -11,29 +13,25 @@ namespace PlatformBenchmarks { public partial class HttpHandler { - - private static readonly JsonSerializerOptions SerializerOptions = new JsonSerializerOptions(); - - private static Utf8JsonWriter GetUtf8JsonWriter(PipeStream stream, HttpToken token) + private static ReadOnlySpan _jsonPreamble => + "HTTP/1.1 200 OK\r\n"u8 + + "Server: B\r\n"u8 + + "Content-Type: application/json\r\n"u8 + + "Content-Length: 27\r\n"u8; + public void Json(IStreamWriter stream) { - var buffer = stream.CreateBufferWriter(); - if (token.Utf8JsonWriter == null) + stream.Write(_jsonPreamble); + GMTDate.Default.Write(stream); + var jsonWriter = GetJsonWriter(stream); + using (var unflush = stream.UnFlush()) { - token.Utf8JsonWriter = new Utf8JsonWriter(buffer, new JsonWriterOptions { SkipValidation = true }); + jsonWriter.WriteStartObject(); + jsonWriter.WriteString("message", "Hello, World!"); + jsonWriter.WriteEndObject(); + jsonWriter.Flush(); } - var writer = token.Utf8JsonWriter; - writer.Reset(buffer); - return writer; - } - public ValueTask Json(PipeStream stream, HttpToken token, ISession session) - { - stream.Write(_jsonPreamble.Data, 0, _jsonPreamble.Length); - GMTDate.Default.Write(stream); - System.Text.Json.JsonSerializer.Serialize(GetUtf8JsonWriter(stream, token), new JsonMessage { message = "Hello, World!" }, SerializerOptions); - OnCompleted(stream, session, token); - return ValueTask.CompletedTask; } } } diff --git a/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.plaintext.cs b/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.plaintext.cs index 83741829b84..fe50d21011d 100644 --- a/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.plaintext.cs +++ b/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.plaintext.cs @@ -1,7 +1,8 @@ -using BeetleX; -using BeetleX.Buffers; + +using BeetleX.Light.Memory; using System; using System.Collections.Generic; +using System.Data; using System.Text; using System.Threading.Tasks; @@ -9,15 +10,27 @@ namespace PlatformBenchmarks { public partial class HttpHandler { - - public ValueTask Plaintext(PipeStream stream, HttpToken token, ISession session) + private static ReadOnlySpan _plaintextPreamble => + "HTTP/1.1 200 OK\r\n"u8 + + "Server: B\r\n"u8 + + "Content-Type: text/plain\r\n"u8 + + "Content-Length: 13\r\n"u8; + + private static ReadOnlySpan _plainTextBody => "Hello, World!"u8; + public void Plaintext(IStreamWriter stream) { - stream.Write(_plaintextPreamble.Data, 0, _plaintextPreamble.Length); - GMTDate.Default.Write(stream); - stream.Write(_result_plaintext.Data, 0, _result_plaintext.Length); - OnCompleted(stream, session, token); - return ValueTask.CompletedTask; + Span data = stream.WriteSequenceNetStream.GetWriteSpan(256); + var timedata = GMTDate.Default.DATE; + _plaintextPreamble.CopyTo(data); + data = data.Slice(_plaintextPreamble.Length); + timedata.Span.CopyTo(data); + data = data.Slice(timedata.Length); + _plainTextBody.CopyTo(data); + //stream.Write(_plaintextPreamble.AsSpan()); + //GMTDate.Default.Write(stream); + //stream.Write(_result_plaintext.Data.AsSpan()); + stream.WriteSequenceNetStream.WriteAdvance(_plaintextPreamble.Length + timedata.Length + _plainTextBody.Length); } } } diff --git a/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.queries.cs b/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.queries.cs index 8027191667c..4e7039176dd 100644 --- a/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.queries.cs +++ b/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.queries.cs @@ -1,24 +1,24 @@ -using BeetleX; -using BeetleX.Buffers; -using SpanJson; +using BeetleX.Light.Memory; using System; using System.Collections.Generic; +using System.IO; using System.Text; +using System.Text.Json; using System.Threading.Tasks; namespace PlatformBenchmarks { public partial class HttpHandler { - public async ValueTask queries(string queryString, PipeStream stream, HttpToken token, ISession session) + public async ValueTask queries(string queryString, IStreamWriter stream) { int count = 1; - if(!string.IsNullOrEmpty(queryString)) + if (!string.IsNullOrEmpty(queryString)) { var values = queryString.Split('='); - if(values.Length>1) + if (values.Length > 1) { - if(int.TryParse(values[1],out int size)) + if (int.TryParse(values[1], out int size)) { count = size; } @@ -28,20 +28,39 @@ public async ValueTask queries(string queryString, PipeStream stream, HttpToken count = 500; if (count < 1) count = 1; + ContentLengthMemory content = new ContentLengthMemory(); try { - var data = await token.Db.LoadMultipleQueriesRows(count); + var data = await DB.LoadMultipleQueriesRows(count); stream.Write(_jsonResultPreamble.Data, 0, _jsonResultPreamble.Length); - token.ContentLength = stream.Allocate(HttpHandler._LengthSize); + content.Data = GetContentLengthMemory(stream); GMTDate.Default.Write(stream); - token.ContentPostion = stream.CacheLength; - System.Text.Json.JsonSerializer.Serialize(GetUtf8JsonWriter(stream, token), data, SerializerOptions); + + stream.WriteSequenceNetStream.StartWriteLength(); + + var jsonWriter = GetJsonWriter(stream); + using (var unflush = stream.UnFlush()) + { + jsonWriter.WriteStartArray(); + foreach (var item in data) + { + jsonWriter.WriteStartObject(); + jsonWriter.WriteNumber("Id", item.Id); + jsonWriter.WriteNumber("RandomNumber", item.RandomNumber); + jsonWriter.WriteEndObject(); + } + jsonWriter.WriteEndArray(); + jsonWriter.Flush(); + + } } catch (Exception e_) { - stream.Write(e_.Message); + Context.GetLoger(BeetleX.Light.Logs.LogLevel.Error)?.WriteException(Context, "PlatformBenchmarks", "queries", e_); + stream.WriteString(e_.Message); } - OnCompleted(stream, session, token); + var len = stream.WriteSequenceNetStream.EndWriteLength(); + content.Full(len); } } } diff --git a/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.updates.cs b/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.updates.cs index 8f3e6d84815..99d938f32a5 100644 --- a/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.updates.cs +++ b/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpHandler.updates.cs @@ -1,16 +1,17 @@ -using BeetleX; -using BeetleX.Buffers; -using SpanJson; + +using BeetleX.Light.Memory; using System; using System.Collections.Generic; +using System.IO; using System.Text; +using System.Text.Json; using System.Threading.Tasks; namespace PlatformBenchmarks { public partial class HttpHandler { - public async ValueTask updates(string queryString, PipeStream stream, HttpToken token, ISession session) + public async ValueTask updates(string queryString, IStreamWriter stream) { int count = 1; if (!string.IsNullOrEmpty(queryString)) @@ -28,22 +29,24 @@ public async ValueTask updates(string queryString, PipeStream stream, HttpToken count = 500; if (count < 1) count = 1; + ContentLengthMemory content = new ContentLengthMemory(); try { - var data = await token.Db.LoadMultipleUpdatesRows(count); + var data = await DB.LoadMultipleUpdatesRows(count); stream.Write(_jsonResultPreamble.Data, 0, _jsonResultPreamble.Length); - token.ContentLength = stream.Allocate(HttpHandler._LengthSize); + content.Data = GetContentLengthMemory(stream); GMTDate.Default.Write(stream); - token.ContentPostion = stream.CacheLength; - System.Text.Json.JsonSerializer.Serialize(GetUtf8JsonWriter(stream, token), data, SerializerOptions); + stream.WriteSequenceNetStream.StartWriteLength(); + JsonSerializer.Serialize((Stream)stream.WriteSequenceNetStream, data); } catch (Exception e_) { - HttpServer.ApiServer.Log(BeetleX.EventArgs.LogType.Error, null, $"updates error {e_.Message}@{e_.StackTrace}"); - stream.Write(e_.Message); + Context.GetLoger(BeetleX.Light.Logs.LogLevel.Error)?.WriteException(Context, "PlatformBenchmarks", "updates", e_); + stream.WriteString(e_.Message); } - OnCompleted(stream, session, token); + var len = stream.WriteSequenceNetStream.EndWriteLength(); + content.Full(len); } } } diff --git a/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpServer.cs b/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpServer.cs index 422da242a7a..b6cb8e3a1a0 100644 --- a/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpServer.cs +++ b/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpServer.cs @@ -1,5 +1,5 @@ -using BeetleX; -using BeetleX.EventArgs; +using BeetleX.Light; +using BeetleX.Light.Logs; using Microsoft.Extensions.Hosting; using System; using System.Collections.Generic; @@ -11,38 +11,36 @@ namespace PlatformBenchmarks { public class HttpServer : IHostedService { - public static IServer ApiServer; + private static NetServer _apiServer; - public virtual Task StartAsync(CancellationToken cancellationToken) + public static string _connectionString; + + public virtual async Task StartAsync(CancellationToken cancellationToken) { - ArraySegment date = GMTDate.Default.DATE; - ServerOptions serverOptions = new ServerOptions(); - serverOptions.LogLevel = LogType.Error; - serverOptions.DefaultListen.Port = 8080; - serverOptions.Statistical = false; - serverOptions.BufferPoolMaxMemory = 1000; - serverOptions.BufferPoolSize = 1024 * 24; - ApiServer = SocketFactory.CreateTcpServer(serverOptions); - ApiServer.Open(); - if (!Program.UpDB) - { - RawDb._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"; - // RawDb._connectionString = "Server=192.168.2.19;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;Maximum Pool Size=256;NoResetOnClose=true;Enlist=false;Max Auto Prepare=3"; - } - else + _connectionString = "Server=tfb-database;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;SSL Mode=Disable;Maximum Pool Size=16;NoResetOnClose=true;Enlist=false;Max Auto Prepare=4;Multiplexing=true;Write Coalescing Buffer Threshold Bytes=1000"; + //_connectionString = "Server=localhost;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;SSL Mode=Disable;Maximum Pool Size=16;NoResetOnClose=true;Enlist=false;Max Auto Prepare=4;Multiplexing=true;Write Coalescing Buffer Threshold Bytes=1000"; + ThreadPool.SetMinThreads(Environment.ProcessorCount * 2, Environment.ProcessorCount * 2); + Constants.MemorySegmentMinSize = 1024 * 16; + Constants.MemorySegmentMaxSize = 1024 * 16; + Constants.InitMemoryBlock(); + var date = GMTDate.Default.DATE; + HttpHandler.DB = new RawDb(new ConcurrentRandom(), HttpServer._connectionString); + await HttpHandler.DB.PopulateCache(); + _apiServer = new NetServer(); + _apiServer.Options.LogLevel = BeetleX.Light.Logs.LogLevel.Error; + _apiServer.Options.AddLogOutputHandler(); + _apiServer.Options.SetDefaultListen(o => { + o.Port = 8080; + }); + _apiServer.Start(); - RawDb._connectionString = "Server=tfb-database;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;Maximum Pool Size=64;NoResetOnClose=true;Enlist=false;Max Auto Prepare=3;Multiplexing=true;Write Coalescing Delay Us=500;Write Coalescing Buffer Threshold Bytes=1000"; - // RawDb._connectionString = "Server=192.168.2.19;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;Maximum Pool Size=64;NoResetOnClose=true;Enlist=false;Max Auto Prepare=3"; - } - // ApiServer.Log(LogType.Info, null, $"Debug mode [{Program.Debug}]"); - return Task.CompletedTask; } public virtual Task StopAsync(CancellationToken cancellationToken) { - ApiServer.Dispose(); + return Task.CompletedTask; } } diff --git a/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpToken.cs b/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpToken.cs index 3d85f8426e5..09d845f6b7e 100644 --- a/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpToken.cs +++ b/frameworks/CSharp/beetlex/PlatformBenchmarks/HttpToken.cs @@ -1,76 +1,76 @@ -using BeetleX; -using BeetleX.Buffers; -using BeetleX.Dispatchs; -using System; -using System.Collections.Concurrent; -using System.Text; -using System.Text.Json; +//using BeetleX; +//using BeetleX.Buffers; +//using BeetleX.Dispatchs; +//using System; +//using System.Collections.Concurrent; +//using System.Text; +//using System.Text.Json; -namespace PlatformBenchmarks -{ - public class HttpToken - { - private byte[] mLengthBuffer = new byte[10]; +//namespace PlatformBenchmarks +//{ +// public class HttpToken +// { +// private byte[] mLengthBuffer = new byte[10]; - public RawDb Db { get; set; } +// public RawDb Db { get; set; } - public HttpToken() - { +// public HttpToken() +// { - } +// } - public SingleThreadDispatcher ThreadDispatcher { get; set; } +// public SingleThreadDispatcher ThreadDispatcher { get; set; } - public ConcurrentQueue Requests { get; set; } = new ConcurrentQueue(); +// public ConcurrentQueue Requests { get; set; } = new ConcurrentQueue(); - public Utf8JsonWriter Utf8JsonWriter { get; set; } +// public Utf8JsonWriter Utf8JsonWriter { get; set; } - public ISession Session { get; set; } +// public ISession Session { get; set; } - public RequestData CurrentRequest { get; set; } +// public RequestData CurrentRequest { get; set; } - private HtmlBufferWriter mHtmlBufferWriter = null; +// private HtmlBufferWriter mHtmlBufferWriter = null; - public HtmlBufferWriter GetHtmlBufferWriter() - { - if (mHtmlBufferWriter == null) - mHtmlBufferWriter = new HtmlBufferWriter(2048); - return mHtmlBufferWriter; - } +// public HtmlBufferWriter GetHtmlBufferWriter() +// { +// if (mHtmlBufferWriter == null) +// mHtmlBufferWriter = new HtmlBufferWriter(2048); +// return mHtmlBufferWriter; +// } - public byte[] GetLengthBuffer(string length) - { - Encoding.ASCII.GetBytes(length, 0, length.Length, mLengthBuffer, 0); - for (int i = length.Length; i < mLengthBuffer.Length; i++) - { - mLengthBuffer[i] = 32; - } - mLengthBuffer[6] = (byte)'\r'; - mLengthBuffer[7] = (byte)'\n'; - return mLengthBuffer; - } +// public byte[] GetLengthBuffer(string length) +// { +// Encoding.ASCII.GetBytes(length, 0, length.Length, mLengthBuffer, 0); +// for (int i = length.Length; i < mLengthBuffer.Length; i++) +// { +// mLengthBuffer[i] = 32; +// } +// mLengthBuffer[6] = (byte)'\r'; +// mLengthBuffer[7] = (byte)'\n'; +// return mLengthBuffer; +// } - public int ContentPostion { get; set; } +// public int ContentPostion { get; set; } - public MemoryBlockCollection ContentLength { get; set; } +// public MemoryBlockCollection ContentLength { get; set; } - public void FullLength(string length) - { - var item = GetLengthBuffer(length); - ContentLength.Full(item); - } +// public void FullLength(string length) +// { +// var item = GetLengthBuffer(length); +// ContentLength.Full(item); +// } - private int mProcessStatus = 0; +// private int mProcessStatus = 0; - public void CompletedProcess() - { - System.Threading.Interlocked.Exchange(ref mProcessStatus, 0); - } +// public void CompletedProcess() +// { +// System.Threading.Interlocked.Exchange(ref mProcessStatus, 0); +// } - public bool EnterProcess() - { - return System.Threading.Interlocked.CompareExchange(ref mProcessStatus, 1, 0) == 0; - } +// public bool EnterProcess() +// { +// return System.Threading.Interlocked.CompareExchange(ref mProcessStatus, 1, 0) == 0; +// } - } -} +// } +//} diff --git a/frameworks/CSharp/beetlex/PlatformBenchmarks/NetApplication.cs b/frameworks/CSharp/beetlex/PlatformBenchmarks/NetApplication.cs new file mode 100644 index 00000000000..da5b14f5b96 --- /dev/null +++ b/frameworks/CSharp/beetlex/PlatformBenchmarks/NetApplication.cs @@ -0,0 +1,19 @@ +using BeetleX.Light; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Sockets; +using System.Text; +using System.Threading.Tasks; + +namespace PlatformBenchmarks +{ + public class HttpNetApplication : ApplicationBase + { + public override bool Connecting(Socket socket, ListenHandler handler) + { + socket.NoDelay = true; + return true; + } + } +} diff --git a/frameworks/CSharp/beetlex/PlatformBenchmarks/PlatformBenchmarks.csproj b/frameworks/CSharp/beetlex/PlatformBenchmarks/PlatformBenchmarks.csproj index d3c07772725..7518d6b0de0 100644 --- a/frameworks/CSharp/beetlex/PlatformBenchmarks/PlatformBenchmarks.csproj +++ b/frameworks/CSharp/beetlex/PlatformBenchmarks/PlatformBenchmarks.csproj @@ -2,17 +2,17 @@ Exe - net5.0 + net8.0 true - - - - - + + + + + diff --git a/frameworks/CSharp/beetlex/PlatformBenchmarks/Program.cs b/frameworks/CSharp/beetlex/PlatformBenchmarks/Program.cs index 774acc842ee..ab262ef92a3 100644 --- a/frameworks/CSharp/beetlex/PlatformBenchmarks/Program.cs +++ b/frameworks/CSharp/beetlex/PlatformBenchmarks/Program.cs @@ -1,6 +1,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using System; +using System.IO; namespace PlatformBenchmarks { @@ -14,7 +15,11 @@ class Program public static void Main(string[] args) { //Debug = (args != null && args.Length > 0 && args[0] == "debug"); + var data = GMTDate.Default.DATE; UpDB = (args != null && args.Length > 0 && args[0] == "updb"); + //HttpServer server = new HttpServer(); + //server.StartAsync(default); + //Console.ReadLine(); new HostBuilder().ConfigureServices(delegate (HostBuilderContext hostContext, IServiceCollection services) { services.AddHostedService(); diff --git a/frameworks/CSharp/beetlex/PlatformBenchmarks/RequestData.cs b/frameworks/CSharp/beetlex/PlatformBenchmarks/RequestData.cs index ab5b8080aee..f4d45c9174e 100644 --- a/frameworks/CSharp/beetlex/PlatformBenchmarks/RequestData.cs +++ b/frameworks/CSharp/beetlex/PlatformBenchmarks/RequestData.cs @@ -1,4 +1,5 @@ using System; +using System.Buffers; using System.Collections.Generic; using System.Linq; using System.Text; @@ -6,24 +7,12 @@ namespace PlatformBenchmarks { - public class RequestData : IDisposable + public class RequestData { - public ArraySegment Data { get; set; } - - public ReadOnlySpan GetSpan() - { - return new ReadOnlySpan(Data.Array, Data.Offset, Data.Count); - } - - public void Dispose() - { - - //System.Buffers.ArrayPool.Shared.Return(Data.Array); - } public string QueryString { get; set; } - public ActionType Action { get; set; } + public ActionType? Action { get; set; } } diff --git a/frameworks/CSharp/beetlex/beetlex-core-updb.dockerfile b/frameworks/CSharp/beetlex/beetlex-core-updb.dockerfile deleted file mode 100644 index b813173db92..00000000000 --- a/frameworks/CSharp/beetlex/beetlex-core-updb.dockerfile +++ /dev/null @@ -1,12 +0,0 @@ -FROM mcr.microsoft.com/dotnet/sdk:5.0-alpine AS build -WORKDIR /app -COPY PlatformBenchmarks . -RUN dotnet publish -c Release -o out - -FROM mcr.microsoft.com/dotnet/aspnet:5.0 AS runtime -WORKDIR /app -COPY --from=build /app/out ./ - -EXPOSE 8080 - -ENTRYPOINT ["dotnet", "PlatformBenchmarks.dll","updb"] diff --git a/frameworks/CSharp/beetlex/beetlex-core.dockerfile b/frameworks/CSharp/beetlex/beetlex-core.dockerfile index 84f4b69a3ff..cd9b870469a 100644 --- a/frameworks/CSharp/beetlex/beetlex-core.dockerfile +++ b/frameworks/CSharp/beetlex/beetlex-core.dockerfile @@ -1,9 +1,9 @@ -FROM mcr.microsoft.com/dotnet/sdk:5.0-alpine AS build +FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build WORKDIR /app COPY PlatformBenchmarks . RUN dotnet publish -c Release -o out -FROM mcr.microsoft.com/dotnet/aspnet:5.0 AS runtime +FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime WORKDIR /app COPY --from=build /app/out ./ diff --git a/frameworks/CSharp/beetlex/beetlex.dockerfile b/frameworks/CSharp/beetlex/beetlex.dockerfile index 8540e376359..78deeac145e 100644 --- a/frameworks/CSharp/beetlex/beetlex.dockerfile +++ b/frameworks/CSharp/beetlex/beetlex.dockerfile @@ -1,9 +1,9 @@ -FROM mcr.microsoft.com/dotnet/sdk:5.0-alpine AS build +FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build WORKDIR /app COPY Benchmarks . RUN dotnet publish -c Release -o out -FROM mcr.microsoft.com/dotnet/aspnet:5.0 AS runtime +FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime WORKDIR /app COPY --from=build /app/out ./ diff --git a/frameworks/CSharp/beetlex/benchmark_config.json b/frameworks/CSharp/beetlex/benchmark_config.json index b5e85bfbf49..67f3a560196 100644 --- a/frameworks/CSharp/beetlex/benchmark_config.json +++ b/frameworks/CSharp/beetlex/benchmark_config.json @@ -48,25 +48,6 @@ "display_name": "beetlex-core", "notes": "", "versus": "aspcore" - }, - "core-updb": { - "update_url": "/updates?queries=", - "fortune_url": "/fortunes", - "port": 8080, - "approach": "Realistic", - "classification": "Platform", - "database": "Postgres", - "framework": "beetlex", - "language": "C#", - "orm": "Raw", - "platform": ".NET", - "flavor": "CoreCLR", - "webserver": "beetlex", - "os": "Linux", - "database_os": "Linux", - "display_name": "beetlex-core-updb", - "notes": "", - "versus": "aspcore" } } ] diff --git a/frameworks/CSharp/beetlex/config.toml b/frameworks/CSharp/beetlex/config.toml index 3e389ec3a67..ec807d12eb2 100644 --- a/frameworks/CSharp/beetlex/config.toml +++ b/frameworks/CSharp/beetlex/config.toml @@ -36,15 +36,3 @@ platform = ".NET" webserver = "beetlex" versus = "aspcore" -[core-updb] -urls.update = "/updates?queries=" -urls.fortune = "/fortunes" -approach = "Realistic" -classification = "Platform" -database = "Postgres" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = ".NET" -webserver = "beetlex" -versus = "aspcore" diff --git a/frameworks/CSharp/celerio/README.md b/frameworks/CSharp/celerio/README.md new file mode 100644 index 00000000000..438fe9ac12f --- /dev/null +++ b/frameworks/CSharp/celerio/README.md @@ -0,0 +1,23 @@ +# Celerio Benchmarks + +Celerio is a modern C# framework designed for high-performance web applications based on Source Generation **only**. +This benchmark tests Celerio using the standard TechEmpower FrameworkBenchmarks suite. + +## Links + +- [GitHub](https://github.com/Oxule/Celerio) +- [NuGet](https://www.nuget.org/packages/Celerio) + +## Infrastructure Software Versions + +- C# 12 +- .NET 8 + +## Benchmarks Included + +- **Plaintext** +- **JSON** + +## Author + +* [Oxule](https://github.com/Oxule) diff --git a/frameworks/CSharp/celerio/benchmark_config.json b/frameworks/CSharp/celerio/benchmark_config.json new file mode 100644 index 00000000000..9cd233d5d6a --- /dev/null +++ b/frameworks/CSharp/celerio/benchmark_config.json @@ -0,0 +1,26 @@ +{ + "framework": "celerio", + "tests": [ + { + "default": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "None", + "framework": "Celerio", + "language": "CSharp", + "flavor": "None", + "orm": "None", + "platform": ".NET", + "webserver": "Celerio", + "os": "Linux", + "database_os": "Linux", + "display_name": "Celerio", + "notes": "", + "versus": "aspcore-mvc" + } + } + ] +} diff --git a/frameworks/CSharp/celerio/celerio.dockerfile b/frameworks/CSharp/celerio/celerio.dockerfile new file mode 100644 index 00000000000..3558ec99b4b --- /dev/null +++ b/frameworks/CSharp/celerio/celerio.dockerfile @@ -0,0 +1,24 @@ +FROM mcr.microsoft.com/dotnet/runtime:8.0 AS base +USER $APP_UID +WORKDIR /app + +FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build +ARG BUILD_CONFIGURATION=Release +WORKDIR /src +COPY ["src/src.csproj", "src/"] +RUN dotnet restore "src/src.csproj" +COPY . . +WORKDIR "/src/src" +RUN dotnet build "./src.csproj" -c $BUILD_CONFIGURATION -o /app/build + +FROM build AS publish +ARG BUILD_CONFIGURATION=Release +RUN dotnet publish "./src.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false + +FROM base AS final +WORKDIR /app +COPY --from=publish /app/publish . + +EXPOSE 8080 + +ENTRYPOINT ["dotnet", "src.dll"] diff --git a/frameworks/CSharp/celerio/config.toml b/frameworks/CSharp/celerio/config.toml new file mode 100644 index 00000000000..e942fe23094 --- /dev/null +++ b/frameworks/CSharp/celerio/config.toml @@ -0,0 +1,15 @@ +[framework] +name = "celerio" + +[main] +urls.plaintext = "/plaintext" +urls.json = "/json" +approach = "Realistic" +classification = "Micro" +database = "None" +database_os = "Linux" +os = "Linux" +orm = "None" +platform = ".NET" +webserver = "Celerio" +versus = "aspcore-mvc" \ No newline at end of file diff --git a/frameworks/CSharp/celerio/src/.dockerignore b/frameworks/CSharp/celerio/src/.dockerignore new file mode 100644 index 00000000000..cd967fc3a29 --- /dev/null +++ b/frameworks/CSharp/celerio/src/.dockerignore @@ -0,0 +1,25 @@ +**/.dockerignore +**/.env +**/.git +**/.gitignore +**/.project +**/.settings +**/.toolstarget +**/.vs +**/.vscode +**/.idea +**/*.*proj.user +**/*.dbmdl +**/*.jfm +**/azds.yaml +**/bin +**/charts +**/docker-compose* +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/obj +**/secrets.dev.yaml +**/values.dev.yaml +LICENSE +README.md \ No newline at end of file diff --git a/frameworks/CSharp/celerio/src/Endpoints.cs b/frameworks/CSharp/celerio/src/Endpoints.cs new file mode 100644 index 00000000000..eb90fb38413 --- /dev/null +++ b/frameworks/CSharp/celerio/src/Endpoints.cs @@ -0,0 +1,25 @@ +namespace src; + +using Celerio; +using static Celerio.Result; + +public static class Endpoints +{ + [Get("/plaintext")] + public static Result Plaintext() + { + return Ok().Text("Hello, World!"); + } + + [Serializable] + public class SampleResponse + { + public string message { get; set; } = "Hello, World!"; + } + + [Get("/json")] + public static Result Json() + { + return Ok().Json(new SampleResponse()); + } +} \ No newline at end of file diff --git a/frameworks/CSharp/celerio/src/Program.cs b/frameworks/CSharp/celerio/src/Program.cs new file mode 100644 index 00000000000..c442387575e --- /dev/null +++ b/frameworks/CSharp/celerio/src/Program.cs @@ -0,0 +1,6 @@ +using System.Net; +using Celerio.Generated; + +var server = new Server(IPAddress.Any, 8080); +server.Start(); +await Task.Delay(Timeout.Infinite); \ No newline at end of file diff --git a/frameworks/CSharp/celerio/src/src.csproj b/frameworks/CSharp/celerio/src/src.csproj new file mode 100644 index 00000000000..d262c58dd1f --- /dev/null +++ b/frameworks/CSharp/celerio/src/src.csproj @@ -0,0 +1,18 @@ + + + + Exe + net8.0 + preview + enable + enable + + true + Linux + + + + + + + diff --git a/frameworks/CSharp/embedio/Benchmarks/Benchmarks.csproj b/frameworks/CSharp/embedio/Benchmarks/Benchmarks.csproj index 19e73c8b7c4..0015577d97e 100644 --- a/frameworks/CSharp/embedio/Benchmarks/Benchmarks.csproj +++ b/frameworks/CSharp/embedio/Benchmarks/Benchmarks.csproj @@ -1,23 +1,23 @@  - + - - net5.0 - 9.0 - + + net9.0 + 13.0 + EmbedIO Benchmarks Test suite to be executed with TechEmpower FrameworkBenchmarks. - - Benchmarks.Program + + Benchmarks.Program Exe - + true false - + - + - + - - \ No newline at end of file + + diff --git a/frameworks/CSharp/embedio/Benchmarks/Program.cs b/frameworks/CSharp/embedio/Benchmarks/Program.cs index db1f8734c3e..f554daee530 100644 --- a/frameworks/CSharp/embedio/Benchmarks/Program.cs +++ b/frameworks/CSharp/embedio/Benchmarks/Program.cs @@ -1,10 +1,12 @@ -using EmbedIO; -using Swan.Logging; -using System; +using System; using System.Text; using System.Threading; using System.Threading.Tasks; +using EmbedIO; + +using Swan.Logging; + namespace Benchmarks { @@ -21,7 +23,7 @@ public class JsonResult public static class Program { - private static readonly ManualResetEvent _WaitEvent = new ManualResetEvent(false); + private static readonly ManualResetEvent WaitEvent = new(false); public static async Task Main(string[] args) { @@ -60,12 +62,12 @@ public static async Task Main(string[] args) { AppDomain.CurrentDomain.ProcessExit += (_, __) => { - _WaitEvent.Set(); + WaitEvent.Set(); }; await server.RunAsync(); - _WaitEvent.WaitOne(); + WaitEvent.WaitOne(); return 0; } diff --git a/frameworks/CSharp/embedio/README.md b/frameworks/CSharp/embedio/README.md index f04d7d2ecd9..afa7412870f 100644 --- a/frameworks/CSharp/embedio/README.md +++ b/frameworks/CSharp/embedio/README.md @@ -6,17 +6,17 @@ See the [project website](https://github.com/unosquare/embedio) for more informa **Language** -* C# 9.0 +* C# 13.0 **Platforms** -* .NET 5 +* .NET 9 **Web Servers** * [EmbedIO](https://github.com/unosquare/embedio) -## Paths & Source for Tests +## Paths \& Source for Tests * [Plaintext](Benchmarks/Program.cs): "/plaintext" * [JSON](Benchmarks/Program.cs): "/json" diff --git a/frameworks/CSharp/embedio/embedio.dockerfile b/frameworks/CSharp/embedio/embedio.dockerfile index 675c16d8841..35e05ff1fc4 100644 --- a/frameworks/CSharp/embedio/embedio.dockerfile +++ b/frameworks/CSharp/embedio/embedio.dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/dotnet/sdk:5.0-alpine AS build +FROM mcr.microsoft.com/dotnet/sdk:9.0-alpine AS build WORKDIR /source # copy csproj and restore as distinct layers @@ -7,10 +7,10 @@ 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 +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:5.0-alpine +FROM mcr.microsoft.com/dotnet/runtime-deps:9.0-alpine WORKDIR /app COPY --from=build /app . diff --git a/frameworks/CSharp/fastendpoints/Benchmarks/Benchmarks.csproj b/frameworks/CSharp/fastendpoints/Benchmarks/Benchmarks.csproj index d93151d2ee7..bbfe65a1034 100644 --- a/frameworks/CSharp/fastendpoints/Benchmarks/Benchmarks.csproj +++ b/frameworks/CSharp/fastendpoints/Benchmarks/Benchmarks.csproj @@ -1,7 +1,7 @@ - net7.0 + net9.0 enable enable CA2016;IDE1006 diff --git a/frameworks/CSharp/fastendpoints/Benchmarks/Endpoints/JsonEndpoint.cs b/frameworks/CSharp/fastendpoints/Benchmarks/Endpoints/JsonEndpoint.cs index 20598ad3181..1fb401af540 100644 --- a/frameworks/CSharp/fastendpoints/Benchmarks/Endpoints/JsonEndpoint.cs +++ b/frameworks/CSharp/fastendpoints/Benchmarks/Endpoints/JsonEndpoint.cs @@ -1,6 +1,6 @@ namespace Benchmarks.Endpoints; -public sealed class JsonEndpoint : Endpoint +sealed class JsonEndpoint : Ep.NoReq.Res { public override void Configure() { @@ -8,9 +8,10 @@ public override void Configure() AllowAnonymous(); } - public override Task HandleAsync(EmptyRequest _, CancellationToken __) + public override Task HandleAsync(CancellationToken ct) { HttpContext.Response.ContentLength = 27; + return SendAsync(new { message = "Hello, World!" }); } } \ No newline at end of file diff --git a/frameworks/CSharp/fastendpoints/Benchmarks/Endpoints/PlainTextEndpoint.cs b/frameworks/CSharp/fastendpoints/Benchmarks/Endpoints/PlainTextEndpoint.cs index 23a8eb36546..af7e31d2386 100644 --- a/frameworks/CSharp/fastendpoints/Benchmarks/Endpoints/PlainTextEndpoint.cs +++ b/frameworks/CSharp/fastendpoints/Benchmarks/Endpoints/PlainTextEndpoint.cs @@ -1,8 +1,8 @@ namespace Benchmarks.Endpoints; -public sealed class PlainTextEndpoint : Endpoint +sealed class PlainTextEndpoint : Ep.NoReq.Res { - private static readonly byte[] payload = System.Text.Encoding.UTF8.GetBytes("Hello, World!"); + static readonly byte[] _payload = "Hello, World!"u8.ToArray(); public override void Configure() { @@ -10,11 +10,12 @@ public override void Configure() AllowAnonymous(); } - public override Task HandleAsync(EmptyRequest _, CancellationToken __) + public override Task HandleAsync(CancellationToken ct) { HttpContext.Response.StatusCode = StatusCodes.Status200OK; HttpContext.Response.ContentType = "text/plain"; - HttpContext.Response.ContentLength = payload.Length; - return HttpContext.Response.Body.WriteAsync(payload, 0, payload.Length); + HttpContext.Response.ContentLength = _payload.Length; + + return HttpContext.Response.Body.WriteAsync(_payload, 0, _payload.Length); } } \ No newline at end of file diff --git a/frameworks/CSharp/fastendpoints/Benchmarks/Program.cs b/frameworks/CSharp/fastendpoints/Benchmarks/Program.cs index 0cafb905e95..5b5aacbb6e8 100644 --- a/frameworks/CSharp/fastendpoints/Benchmarks/Program.cs +++ b/frameworks/CSharp/fastendpoints/Benchmarks/Program.cs @@ -1,9 +1,9 @@ global using FastEndpoints; -var builder = WebApplication.CreateBuilder(); -builder.Logging.ClearProviders(); -builder.Services.AddFastEndpoints(); +var bld = WebApplication.CreateBuilder(); +bld.Logging.ClearProviders(); +bld.Services.AddFastEndpoints(); -var app = builder.Build(); +var app = bld.Build(); app.UseFastEndpoints(); -app.Run("http://0.0.0.0:8080"); +app.Run("http://0.0.0.0:8080"); \ No newline at end of file diff --git a/frameworks/CSharp/fastendpoints/README.md b/frameworks/CSharp/fastendpoints/README.md index 8e0f978fdf5..768b79ba75e 100644 --- a/frameworks/CSharp/fastendpoints/README.md +++ b/frameworks/CSharp/fastendpoints/README.md @@ -5,11 +5,11 @@ This includes tests for plaintext and json serialization. **Language** -* C# 10.0 +* C# 13.0 **Platforms** -* .NET Core (Windows and Linux) +* .NET 9 (Windows and Linux) **Web Servers** @@ -18,7 +18,7 @@ This includes tests for plaintext and json serialization. **Web Stack** * [FastEndpoints](https://fast-endpoints.com/) -* ASP.Net 6 +* ASP.NET 9 ## Paths & Source for Tests diff --git a/frameworks/CSharp/fastendpoints/fastendpoints.dockerfile b/frameworks/CSharp/fastendpoints/fastendpoints.dockerfile index e7e53b5d27b..cd6de83683d 100644 --- a/frameworks/CSharp/fastendpoints/fastendpoints.dockerfile +++ b/frameworks/CSharp/fastendpoints/fastendpoints.dockerfile @@ -1,16 +1,16 @@ -FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build +FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build WORKDIR /app COPY Benchmarks . RUN dotnet publish -c Release -o out -FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS runtime +FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS runtime +ENV DOTNET_GCDynamicAdaptationMode=0 +ENV DOTNET_ReadyToRun=0 +ENV DOTNET_HillClimbing_Disable=1 + WORKDIR /app COPY --from=build /app/out ./ -ENV DOTNET_TieredPGO 1 -ENV DOTNET_TC_QuickJitForLoops 1 -ENV DOTNET_ReadyToRun 0 - EXPOSE 8080 ENTRYPOINT ["dotnet", "Benchmarks.dll"] \ No newline at end of file diff --git a/frameworks/CSharp/genhttp/Benchmarks/Benchmarks.csproj b/frameworks/CSharp/genhttp/Benchmarks/Benchmarks.csproj index f6ba3053312..ae302d86dbb 100644 --- a/frameworks/CSharp/genhttp/Benchmarks/Benchmarks.csproj +++ b/frameworks/CSharp/genhttp/Benchmarks/Benchmarks.csproj @@ -1,40 +1,40 @@  - - - - net7.0 - 10.0 - - GenHTTP Benchmarks - Test suite to be executed with TechEmpower FrameworkBenchmarks. - - Benchmarks.Program - Exe - - true - true - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + + + + net10.0 + 14.0 + true + Exe + + GenHTTP Benchmarks + Test suite to be executed with TechEmpower FrameworkBenchmarks. + + $(DefineConstants);$(GENHTTP_ENGINE_NAME) + + true + true + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frameworks/CSharp/genhttp/Benchmarks/Model/DatabaseContext.cs b/frameworks/CSharp/genhttp/Benchmarks/Model/DatabaseContext.cs index 2bc6ca7ed0d..f27f1d8e245 100644 --- a/frameworks/CSharp/genhttp/Benchmarks/Model/DatabaseContext.cs +++ b/frameworks/CSharp/genhttp/Benchmarks/Model/DatabaseContext.cs @@ -1,52 +1,43 @@ using Microsoft.EntityFrameworkCore; -namespace Benchmarks.Model +namespace Benchmarks.Model; + +public sealed class DatabaseContext : DbContext { + private static DbContextOptions _options; - public sealed class DatabaseContext : DbContext - { - private static DbContextOptions _Options; + private static DbContextOptions _noTrackingOptions; - private static DbContextOptions _NoTrackingOptions; + #region Factory - #region Factory + public static DatabaseContext Create() => new(_options ??= GetOptions(true)); - public static DatabaseContext Create() - { - return new DatabaseContext(_Options ??= GetOptions(true)); - } - - public static DatabaseContext CreateNoTracking() - { - return new DatabaseContext(_NoTrackingOptions ??= GetOptions(false)); - } + public static DatabaseContext CreateNoTracking() => new(_noTrackingOptions ??= GetOptions(false)); - private static DbContextOptions GetOptions(bool tracking) - { - var optionsBuilder = new DbContextOptionsBuilder(); - - optionsBuilder.UseNpgsql("Server=tfb-database;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;Maximum Pool Size=256;NoResetOnClose=true;Enlist=false;Max Auto Prepare=4"); + private static DbContextOptions GetOptions(bool tracking) + { + var optionsBuilder = new DbContextOptionsBuilder(); - if (!tracking) - { - optionsBuilder.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking); - } + optionsBuilder.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"); - return optionsBuilder.Options; + if (!tracking) + { + optionsBuilder.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking); } - private DatabaseContext(DbContextOptions options) : base(options) { } + return optionsBuilder.Options; + } - #endregion + private DatabaseContext(DbContextOptions options) : base(options) { } - #region Entities + #endregion - public DbSet World { get; set; } + #region Entities - public DbSet Fortune { get; set; } + public DbSet World { get; set; } - #endregion + public DbSet Fortune { get; set; } - } + #endregion } diff --git a/frameworks/CSharp/genhttp/Benchmarks/Model/Fortune.cs b/frameworks/CSharp/genhttp/Benchmarks/Model/Fortune.cs index c3ca5d1d6a7..919f997e01b 100644 --- a/frameworks/CSharp/genhttp/Benchmarks/Model/Fortune.cs +++ b/frameworks/CSharp/genhttp/Benchmarks/Model/Fortune.cs @@ -1,25 +1,17 @@ -using System; -using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -namespace Benchmarks.Model -{ - - [Table("fortune")] - public class Fortune : IComparable, IComparable - { - - [Column("id")] - public int ID { get; set; } +namespace Benchmarks.Model; - [Column("message")] - [StringLength(2048)] - public string Message { get; set; } - - public int CompareTo(object obj) => CompareTo((Fortune)obj); +[Table("fortune")] +public class Fortune +{ - public int CompareTo(Fortune other) => string.CompareOrdinal(Message, other.Message); + [Column("id")] + public int Id { get; set; } - } + [Column("message")] + [StringLength(2048)] + public string Message { get; set; } } diff --git a/frameworks/CSharp/genhttp/Benchmarks/Model/World.cs b/frameworks/CSharp/genhttp/Benchmarks/Model/World.cs index ec19183f331..45da4ab828d 100644 --- a/frameworks/CSharp/genhttp/Benchmarks/Model/World.cs +++ b/frameworks/CSharp/genhttp/Benchmarks/Model/World.cs @@ -1,18 +1,15 @@ using System.ComponentModel.DataAnnotations.Schema; -namespace Benchmarks.Model -{ - - [Table("world")] - public class World - { +namespace Benchmarks.Model; - [Column("id")] - public int Id { get; set; } +[Table("world")] +public class World +{ - [Column("randomnumber")] - public int RandomNumber { get; set; } + [Column("id")] + public int Id { get; set; } - } + [Column("randomnumber")] + public int RandomNumber { get; set; } -} +} \ No newline at end of file diff --git a/frameworks/CSharp/genhttp/Benchmarks/Program.cs b/frameworks/CSharp/genhttp/Benchmarks/Program.cs index efd8a162ac9..91323662c2d 100644 --- a/frameworks/CSharp/genhttp/Benchmarks/Program.cs +++ b/frameworks/CSharp/genhttp/Benchmarks/Program.cs @@ -1,35 +1,26 @@ -using GenHTTP.Engine; +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; -using Benchmarks.Tests; -using Benchmarks.Utilities; - -namespace Benchmarks -{ - - public static class Program - { - - public static int Main(string[] args) - { - var tests = Layout.Create() - .Add("plaintext", Content.From(Resource.FromString("Hello, World!"))) - .Add("fortunes", new FortuneHandlerBuilder()) - .AddService("json") - .AddService("db") - .AddService("queries") - .AddService("updates") - .AddService("cached-worlds") - .Add(ServerHeader.Create()); - - return Host.Create() - .Handler(tests) - .Run(); - } - - } - -} +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/Resources/Fortunes.html b/frameworks/CSharp/genhttp/Benchmarks/Resources/Fortunes.html deleted file mode 100644 index b7e0d81eb8a..00000000000 --- a/frameworks/CSharp/genhttp/Benchmarks/Resources/Fortunes.html +++ /dev/null @@ -1,7 +0,0 @@ - - - @foreach (var cookie in Model.Cookies) - { - - } -
idmessage
@cookie.ID@HttpUtility.HtmlEncode(cookie.Message)
\ No newline at end of file diff --git a/frameworks/CSharp/genhttp/Benchmarks/Resources/Template.html b/frameworks/CSharp/genhttp/Benchmarks/Resources/Template.html index 7b521ecb334..90bf1592593 100644 --- a/frameworks/CSharp/genhttp/Benchmarks/Resources/Template.html +++ b/frameworks/CSharp/genhttp/Benchmarks/Resources/Template.html @@ -1,9 +1,22 @@  - @Model.Meta.Title + Fortunes - @Model.Content + + + + + + + {for cookie in cookies: + + + + + } +
idmessage
{ cookie.id }{ cookie.message }
+ - \ No newline at end of file + diff --git a/frameworks/CSharp/genhttp/Benchmarks/Tests/CacheResource.cs b/frameworks/CSharp/genhttp/Benchmarks/Tests/CacheResource.cs index c5c91258a94..e0e4bc50d91 100644 --- a/frameworks/CSharp/genhttp/Benchmarks/Tests/CacheResource.cs +++ b/frameworks/CSharp/genhttp/Benchmarks/Tests/CacheResource.cs @@ -1,84 +1,84 @@ -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 Benchmarks.Model; - -using GenHTTP.Modules.Webservices; +namespace Benchmarks.Tests; -namespace Benchmarks.Tests +public sealed class CacheResource { + private static readonly Random Random = new(); - public sealed class CacheResource + private static readonly MemoryCache Cache = new(new MemoryCacheOptions { - private static readonly Random _Random = new Random(); - - private static readonly MemoryCache _Cache = new MemoryCache(new MemoryCacheOptions() { ExpirationScanFrequency = TimeSpan.FromMinutes(60) }); - - 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; + ExpirationScanFrequency = TimeSpan.FromMinutes(60) + }); - public bool Equals(CacheKey key) => key._value == _value; + private static readonly object[] CacheKeys = Enumerable.Range(0, 10001).Select(i => new CacheKey(i)).ToArray(); - public override bool Equals(object obj) => ReferenceEquals(obj, this); + [ResourceMethod(":queries")] + public ValueTask> GetWorldsFromPath(string queries) => GetWorlds(queries); - public override int GetHashCode() => _value; + [ResourceMethod] + public async ValueTask> GetWorlds(string queries) + { + var count = 1; - public override string ToString() => _value.ToString(); + int.TryParse(queries, out count); + if (count < 1) + { + count = 1; } + else if (count > 500) + { + count = 500; + } + + var result = new List(count); - [ResourceMethod(":queries")] - public ValueTask> GetWorldsFromPath(string queries) => GetWorlds(queries); + await using var context = DatabaseContext.CreateNoTracking(); - [ResourceMethod] - public async ValueTask> GetWorlds(string queries) + for (var i = 0; i < count; i++) { - var count = 1; + var id = Random.Next(1, 10001); - int.TryParse(queries, out count); + var key = CacheKeys[id]; - if (count < 1) count = 1; - else if (count > 500) count = 500; + var data = Cache.Get(key); - var result = new List(count); + if (data != null) + { + result.Add(data); + } + else + { + var resolved = await context.World.FirstOrDefaultAsync(w => w.Id == id).ConfigureAwait(false); - using var context = DatabaseContext.CreateNoTracking(); + Cache.Set(key, resolved); - for (var i = 0; i < count; i++) - { - var id = _Random.Next(1, 10001); + result.Add(resolved); + } + } - var key = _CacheKeys[id]; + return result; + } - var data = _Cache.Get(key); + public sealed class CacheKey : IEquatable + { + private readonly int _value; - if (data != null) - { - result.Add(data); - } - else - { - var resolved = await context.World.FirstOrDefaultAsync(w => w.Id == id).ConfigureAwait(false); + public CacheKey(int value) + { + _value = value; + } - _Cache.Set(key, resolved); + public bool Equals(CacheKey key) => key._value == _value; - result.Add(resolved); - } - } + public override bool Equals(object obj) => ReferenceEquals(obj, this); - return result; - } + public override int GetHashCode() => _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 64256d0a215..ac33808fdfd 100644 --- a/frameworks/CSharp/genhttp/Benchmarks/Tests/DbResource.cs +++ b/frameworks/CSharp/genhttp/Benchmarks/Tests/DbResource.cs @@ -1,29 +1,21 @@ -using System; -using System.Threading.Tasks; - -using Microsoft.EntityFrameworkCore; - +using Benchmarks.Model; using GenHTTP.Modules.Webservices; +using Microsoft.EntityFrameworkCore; -using Benchmarks.Model; +namespace Benchmarks.Tests; -namespace Benchmarks.Tests +public sealed class DbResource { + private static readonly Random Random = new(); - public sealed class DbResource + [ResourceMethod] + public async ValueTask GetRandomWorld() { - private static readonly Random _Random = new(); - - [ResourceMethod] - public async ValueTask GetRandomWorld() - { - var id = _Random.Next(1, 10001); - - using var context = DatabaseContext.CreateNoTracking(); + var id = Random.Next(1, 10001); - return await context.World.FirstOrDefaultAsync(w => w.Id == id).ConfigureAwait(false); - } + await using var context = DatabaseContext.CreateNoTracking(); + return await context.World.FirstOrDefaultAsync(w => w.Id == id).ConfigureAwait(false); } } diff --git a/frameworks/CSharp/genhttp/Benchmarks/Tests/FortuneHandler.cs b/frameworks/CSharp/genhttp/Benchmarks/Tests/FortuneHandler.cs index d53b3f1328b..c7a488f5e78 100644 --- a/frameworks/CSharp/genhttp/Benchmarks/Tests/FortuneHandler.cs +++ b/frameworks/CSharp/genhttp/Benchmarks/Tests/FortuneHandler.cs @@ -1,116 +1,85 @@ -using System.Collections.Generic; -using System.Threading.Tasks; -using System.Linq; -using System.Web; -using System.IO; - -using Microsoft.EntityFrameworkCore; - +using System.Web; +using Benchmarks.Model; +using Cottle; using GenHTTP.Api.Content; -using GenHTTP.Api.Content.Templating; using GenHTTP.Api.Protocol; using GenHTTP.Modules.IO; -using GenHTTP.Modules.Razor; - -using Benchmarks.Model; +using GenHTTP.Modules.Pages; +using GenHTTP.Modules.Pages.Rendering; -namespace Benchmarks.Tests -{ +using Microsoft.EntityFrameworkCore; - #region Factory +namespace Benchmarks.Tests; - public class FortuneHandlerBuilder : IHandlerBuilder - { +public class FortuneHandler : IHandler +{ - public IHandler Build(IHandler parent) - { - return new FortuneHandler(parent); - } + #region Get-/Setters - } + private TemplateRenderer Template { get; } #endregion - #region Supporting data structures + #region Initialization - public sealed class FortuneModel : BasicModel + public FortuneHandler() { + var resource = Resource.FromAssembly("Template.html").Build(); - public List Cookies { get; } - - public FortuneModel(IRequest request, IHandler handler, List cookies) : base(request, handler) - { - Cookies = cookies; - } - + Template = Renderer.From(resource); } #endregion - public class FortuneHandler : IHandler, IPageRenderer - { - - #region Get-/Setters - - public IHandler Parent { get; } + #region Functionality - private IHandler Page { get; } + public ValueTask PrepareAsync() => new(); - private IRenderer Template { get; } - - #endregion - - #region Initialization - - public FortuneHandler(IHandler parent) + public async ValueTask HandleAsync(IRequest request) + { + var data = new Dictionary { - Parent = parent; + ["cookies"] = Value.FromEnumerable(await GetFortunes()) + }; - Page = ModRazor.Page(Resource.FromAssembly("Fortunes.html"), (r, h) => GetFortunes(r, h)) - .Title("Fortunes") - .AddAssemblyReference() - .AddUsing("System.Web") - .Build(this); + return request.GetPage(await Template.RenderAsync(data)).Build(); + } - Template = ModRazor.Template(Resource.FromAssembly("Template.html")).Build(); - } + private static async ValueTask> GetFortunes() + { + await using var context = DatabaseContext.CreateNoTracking(); - #endregion + var fortunes = await context.Fortune.ToListAsync().ConfigureAwait(false); - #region Functionality + var result = new List(fortunes.Count + 1); - public async ValueTask PrepareAsync() + foreach (var fortune in fortunes) { - await Page.PrepareAsync(); - await Template.PrepareAsync(); + result.Add(Value.FromDictionary(new Dictionary() + { + ["id"] = fortune.Id, + ["message"] = HttpUtility.HtmlEncode(fortune.Message) + })); } - public ValueTask CalculateChecksumAsync() => new(17); - - public IEnumerable GetContent(IRequest request) => Enumerable.Empty(); - - public ValueTask RenderAsync(TemplateModel model) => Template.RenderAsync(model); - - public ValueTask RenderAsync(TemplateModel model, Stream target) => Template.RenderAsync(model, target); - - public ValueTask HandleAsync(IRequest request) => Page.HandleAsync(request); - - private static async ValueTask GetFortunes(IRequest request, IHandler handler) + result.Add(Value.FromDictionary(new Dictionary() { - using var context = DatabaseContext.CreateNoTracking(); - - var fortunes = await context.Fortune.ToListAsync().ConfigureAwait(false); - - fortunes.Add(new Fortune() { Message = "Additional fortune added at request time." }); - - fortunes.Sort(); + ["id"] = 0, + ["message"] = "Additional fortune added at request time." + })); - return new FortuneModel(request, handler, fortunes); - } + result.Sort((one, two) => + { + var firstMessage = one.Fields["message"].AsString; + var secondMessage = two.Fields["message"].AsString; - #endregion + return string.Compare(firstMessage, secondMessage, StringComparison.Ordinal); + }); + return result; } + #endregion + } diff --git a/frameworks/CSharp/genhttp/Benchmarks/Tests/JsonHandler.cs b/frameworks/CSharp/genhttp/Benchmarks/Tests/JsonHandler.cs new file mode 100644 index 00000000000..7fb89b926d7 --- /dev/null +++ b/frameworks/CSharp/genhttp/Benchmarks/Tests/JsonHandler.cs @@ -0,0 +1,35 @@ +using Benchmarks.Utilities; + +using GenHTTP.Api.Content; +using GenHTTP.Api.Protocol; + +namespace Benchmarks.Tests; + +public sealed class JsonResult +{ + + public string Message { get; set; } +} + +public sealed class JsonHandler : IHandler +{ + private static readonly FlexibleContentType ContentType = new(GenHTTP.Api.Protocol.ContentType.ApplicationJson, "utf-8"); + + public ValueTask PrepareAsync() => new(); + + public ValueTask HandleAsync(IRequest request) + { + var result = new JsonResult() + { + Message = "Hello, World!" + }; + + var response = request.Respond() + .Content(new FixedLengthJsonContent(result)) + .Type(ContentType) + .Build(); + + return new(response); + } + +} diff --git a/frameworks/CSharp/genhttp/Benchmarks/Tests/JsonResource.cs b/frameworks/CSharp/genhttp/Benchmarks/Tests/JsonResource.cs deleted file mode 100644 index 8158b3acd0d..00000000000 --- a/frameworks/CSharp/genhttp/Benchmarks/Tests/JsonResource.cs +++ /dev/null @@ -1,21 +0,0 @@ -using GenHTTP.Modules.Webservices; - -namespace Benchmarks.Tests -{ - - public sealed class JsonResult - { - - public string Message { get; set; } - - } - - public sealed class JsonResource - { - - [ResourceMethod] - public JsonResult GetMessage() => new() { Message = "Hello, World!" }; - - } - -} diff --git a/frameworks/CSharp/genhttp/Benchmarks/Tests/QueryResource.cs b/frameworks/CSharp/genhttp/Benchmarks/Tests/QueryResource.cs index 52a4b4994e1..592d9083242 100644 --- a/frameworks/CSharp/genhttp/Benchmarks/Tests/QueryResource.cs +++ b/frameworks/CSharp/genhttp/Benchmarks/Tests/QueryResource.cs @@ -1,47 +1,44 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; - +using Benchmarks.Model; +using GenHTTP.Modules.Webservices; using Microsoft.EntityFrameworkCore; -using Benchmarks.Model; - -using GenHTTP.Modules.Webservices; +namespace Benchmarks.Tests; -namespace Benchmarks.Tests +public sealed class QueryResource { + private static readonly Random Random = new(); + + [ResourceMethod(":queries")] + public ValueTask> GetWorldsFromPath(string queries) => GetWorlds(queries); - public sealed class QueryResource + [ResourceMethod] + public async ValueTask> GetWorlds(string queries) { - private static readonly Random _Random = new Random(); + var count = 1; - [ResourceMethod(":queries")] - public ValueTask> GetWorldsFromPath(string queries) => GetWorlds(queries); + int.TryParse(queries, out count); - [ResourceMethod] - public async ValueTask> GetWorlds(string queries) + if (count < 1) { - var count = 1; - - int.TryParse(queries, out count); - - if (count < 1) count = 1; - else if (count > 500) count = 500; - - var result = new List(count); + count = 1; + } + else if (count > 500) + { + count = 500; + } - using var context = DatabaseContext.CreateNoTracking(); + var result = new List(count); - for (int _ = 0; _ < count; _++) - { - var id = _Random.Next(1, 10001); + using var context = DatabaseContext.CreateNoTracking(); - result.Add(await context.World.FirstOrDefaultAsync(w => w.Id == id).ConfigureAwait(false)); - } + for (var _ = 0; _ < count; _++) + { + var id = Random.Next(1, 10001); - return result; + result.Add(await context.World.FirstOrDefaultAsync(w => w.Id == id).ConfigureAwait(false)); } + return result; } -} +} \ No newline at end of file diff --git a/frameworks/CSharp/genhttp/Benchmarks/Tests/UpdateResource.cs b/frameworks/CSharp/genhttp/Benchmarks/Tests/UpdateResource.cs index dcb697333a0..9b2ce8e270c 100644 --- a/frameworks/CSharp/genhttp/Benchmarks/Tests/UpdateResource.cs +++ b/frameworks/CSharp/genhttp/Benchmarks/Tests/UpdateResource.cs @@ -1,66 +1,64 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - +using Benchmarks.Model; +using GenHTTP.Modules.Webservices; using Microsoft.EntityFrameworkCore; -using Benchmarks.Model; +namespace Benchmarks.Tests; -using GenHTTP.Modules.Webservices; - -namespace Benchmarks.Tests +public sealed class UpdateResource { + private static readonly Random Random = new(); + + [ResourceMethod(":queries")] + public ValueTask> UpdateWorldsFromPath(string queries) => UpdateWorlds(queries); - public sealed class UpdateResource + [ResourceMethod] + public async ValueTask> UpdateWorlds(string queries) { - private static Random _Random = new Random(); + var count = 1; - [ResourceMethod(":queries")] - public ValueTask> UpdateWorldsFromPath(string queries) => UpdateWorlds(queries); + int.TryParse(queries, out count); - [ResourceMethod] - public async ValueTask> UpdateWorlds(string queries) + if (count < 1) { - var count = 1; - - int.TryParse(queries, out count); - - if (count < 1) count = 1; - else if (count > 500) count = 500; + count = 1; + } + else if (count > 500) + { + count = 500; + } - var result = new List(count); + var result = new List(count); - var ids = Enumerable.Range(1, 10000).Select(x => _Random.Next(1, 10001)).Distinct().Take(count).ToArray(); + var ids = Enumerable.Range(1, 10000).Select(x => Random.Next(1, 10001)).Distinct().Take(count).ToArray(); - using (var context = DatabaseContext.Create()) + using (var context = DatabaseContext.Create()) + { + foreach (var id in ids) { - foreach (var id in ids) - { - var record = await context.World.FirstOrDefaultAsync(w => w.Id == id).ConfigureAwait(false); + var record = await context.World.FirstOrDefaultAsync(w => w.Id == id).ConfigureAwait(false); - var old = record.RandomNumber; + var old = record.RandomNumber; - var current = old; + var current = old; - for (int i = 0; i < 5; i++) - { - current = _Random.Next(1, 10001); + for (var i = 0; i < 5; i++) + { + current = Random.Next(1, 10001); - if (current != old) break; + if (current != old) + { + break; } + } - record.RandomNumber = current; + record.RandomNumber = current; - result.Add(record); + result.Add(record); - await context.SaveChangesAsync(); - } + await context.SaveChangesAsync(); } - - return result; } + return result; } - -} +} \ No newline at end of file diff --git a/frameworks/CSharp/genhttp/Benchmarks/Utilities/FixedLengthJsonContent.cs b/frameworks/CSharp/genhttp/Benchmarks/Utilities/FixedLengthJsonContent.cs new file mode 100644 index 00000000000..7ef372c65f0 --- /dev/null +++ b/frameworks/CSharp/genhttp/Benchmarks/Utilities/FixedLengthJsonContent.cs @@ -0,0 +1,31 @@ +using System.Text.Json; + +using GenHTTP.Api.Protocol; + +using Benchmarks.Tests; + +namespace Benchmarks.Utilities; + +public sealed class FixedLengthJsonContent : IResponseContent +{ + private readonly MemoryStream _buffer = new(); + + public ulong? Length => (ulong)_buffer.Length; + + public FixedLengthJsonContent(JsonResult result) + { + JsonSerializer.SerializeAsync(_buffer, result); + } + + public ValueTask CalculateChecksumAsync() => throw new NotImplementedException(); + + public ValueTask WriteAsync(Stream target, uint bufferSize) + { + _buffer.Seek(0, SeekOrigin.Begin); + + _buffer.CopyTo(target); + + return ValueTask.CompletedTask; + } + +} diff --git a/frameworks/CSharp/genhttp/Benchmarks/Utilities/ServerHeader.cs b/frameworks/CSharp/genhttp/Benchmarks/Utilities/ServerHeader.cs index 7fff879379e..5b0a8b090d9 100644 --- a/frameworks/CSharp/genhttp/Benchmarks/Utilities/ServerHeader.cs +++ b/frameworks/CSharp/genhttp/Benchmarks/Utilities/ServerHeader.cs @@ -1,11 +1,7 @@ -namespace Benchmarks.Utilities -{ - - public static class ServerHeader - { +namespace Benchmarks.Utilities; - public static ServerHeaderConcernBuilder Create() => new ServerHeaderConcernBuilder(); - - } +public static class ServerHeader +{ + public static ServerHeaderConcernBuilder Create() => new(); } diff --git a/frameworks/CSharp/genhttp/Benchmarks/Utilities/ServerHeaderConcern.cs b/frameworks/CSharp/genhttp/Benchmarks/Utilities/ServerHeaderConcern.cs index d4020d4fd7e..3536a8c8988 100644 --- a/frameworks/CSharp/genhttp/Benchmarks/Utilities/ServerHeaderConcern.cs +++ b/frameworks/CSharp/genhttp/Benchmarks/Utilities/ServerHeaderConcern.cs @@ -1,54 +1,42 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; - -using GenHTTP.Api.Content; +using GenHTTP.Api.Content; using GenHTTP.Api.Protocol; -namespace Benchmarks.Utilities -{ - - public sealed class ServerHeaderConcern : IConcern - { +namespace Benchmarks.Utilities; - #region Get-/Setters +public sealed class ServerHeaderConcern : IConcern +{ - public IHandler Content { get; } + #region Initialization - public IHandler Parent { get; } + public ServerHeaderConcern(IHandler content) + { + Content = content; + } - #endregion + #endregion - #region Initialization + #region Get-/Setters - public ServerHeaderConcern(IHandler parent, Func contentFactory) - { - Parent = parent; - Content = contentFactory(this); - } + public IHandler Content { get; } - #endregion + #endregion - #region Functionality + #region Functionality - public IEnumerable GetContent(IRequest request) => Content.GetContent(request); + public ValueTask PrepareAsync() => Content.PrepareAsync(); - public ValueTask PrepareAsync() => Content.PrepareAsync(); + public async ValueTask HandleAsync(IRequest request) + { + var response = await Content.HandleAsync(request); - public async ValueTask HandleAsync(IRequest request) + if (response != null) { - var response = await Content.HandleAsync(request); - - if (response != null) - { - response.Headers.Add("Server", "TFB"); - } - - return response; + response.Headers.Add("Server", "TFB"); } - #endregion - + return response; } + #endregion + } diff --git a/frameworks/CSharp/genhttp/Benchmarks/Utilities/ServerHeaderConcernBuilder.cs b/frameworks/CSharp/genhttp/Benchmarks/Utilities/ServerHeaderConcernBuilder.cs index b935ac66553..1f96404b09a 100644 --- a/frameworks/CSharp/genhttp/Benchmarks/Utilities/ServerHeaderConcernBuilder.cs +++ b/frameworks/CSharp/genhttp/Benchmarks/Utilities/ServerHeaderConcernBuilder.cs @@ -1,18 +1,10 @@ -using System; +using GenHTTP.Api.Content; -using GenHTTP.Api.Content; +namespace Benchmarks.Utilities; -namespace Benchmarks.Utilities +public sealed class ServerHeaderConcernBuilder : IConcernBuilder { - public sealed class ServerHeaderConcernBuilder : IConcernBuilder - { - - public IConcern Build(IHandler parent, Func contentFactory) - { - return new ServerHeaderConcern(parent, contentFactory); - } - - } + public IConcern Build(IHandler content) => new ServerHeaderConcern(content); } diff --git a/frameworks/CSharp/genhttp/README.md b/frameworks/CSharp/genhttp/README.md index fcdb7ce9100..9c5c5d1199a 100644 --- a/frameworks/CSharp/genhttp/README.md +++ b/frameworks/CSharp/genhttp/README.md @@ -6,11 +6,11 @@ See the [GenHTTP website](https://genhttp.org) for more information. **Language** -* C# 8.0 +* C# 13.0 **Platforms** -* .NET Core +* .NET 8/9 **Web Servers** diff --git a/frameworks/CSharp/genhttp/benchmark_config.json b/frameworks/CSharp/genhttp/benchmark_config.json index 3d8304e5dc6..2943457c204 100644 --- a/frameworks/CSharp/genhttp/benchmark_config.json +++ b/frameworks/CSharp/genhttp/benchmark_config.json @@ -1,5 +1,6 @@ { - "framework": "genhttp", + "framework": "genhttp", + "maintainers": ["Kaliumhexacyanoferrat"], "tests": [{ "default": { "plaintext_url": "/plaintext", @@ -20,8 +21,32 @@ "webserver": "GenHTTP", "os": "Linux", "database_os": "Linux", - "display_name": "GenHTTP", + "display_name": "genhttp [internal]", "notes": "" } - }] + }, + { + "kestrel": { + "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": "Kestrel", + "os": "Linux", + "database_os": "Linux", + "display_name": "genhttp [kestrel]", + "notes": "" + } + }] } diff --git a/frameworks/CSharp/genhttp/config.toml b/frameworks/CSharp/genhttp/config.toml index a70294262d8..538213c05b4 100644 --- a/frameworks/CSharp/genhttp/config.toml +++ b/frameworks/CSharp/genhttp/config.toml @@ -18,3 +18,21 @@ orm = "Raw" platform = ".NET" webserver = "GenHTTP" versus = "None" + +[kestrel] +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 = "Kestrel" +versus = "None" diff --git a/frameworks/CSharp/genhttp/genhttp-kestrel.dockerfile b/frameworks/CSharp/genhttp/genhttp-kestrel.dockerfile new file mode 100644 index 00000000000..e345a538f34 --- /dev/null +++ b/frameworks/CSharp/genhttp/genhttp-kestrel.dockerfile @@ -0,0 +1,33 @@ +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 + +# 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 \ + COMPlus_EnableDiagnostics=0 \ + COMPlus_DbgEnableMiniDump=0 \ + COMPlus_DbgEnableMiniDumpCollection=0 \ + COMPlus_DbgMiniDumpType=0 \ + DOTNET_TieredPGO=0 \ + DOTNET_TC_QuickJitForLoops=1 \ + DOTNET_TC_QuickJit=1 + +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 5cfddc0ccff..9414123202e 100644 --- a/frameworks/CSharp/genhttp/genhttp.dockerfile +++ b/frameworks/CSharp/genhttp/genhttp.dockerfile @@ -1,19 +1,33 @@ -FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build -WORKDIR /app -COPY Benchmarks . -RUN dotnet publish -c Release -o out +FROM mcr.microsoft.com/dotnet/sdk:10.0-alpine AS build +WORKDIR /source + +ENV GENHTTP_ENGINE_NAME=INTERNAL +ENV GENHTTP_ENGINE_PACKAGE=GenHTTP.Core + +# copy csproj and restore as distinct layers +COPY Benchmarks/*.csproj . +RUN dotnet restore -r linux-musl-x64 -FROM mcr.microsoft.com/dotnet/runtime:7.0 AS runtime -ENV DOTNET_SYSTEM_NET_SOCKETS_INLINE_COMPLETIONS 1 +# copy and publish app and libraries +COPY Benchmarks/ . +RUN dotnet publish -c release -o /app -r linux-musl-x64 --no-restore --self-contained -# Full PGO -ENV DOTNET_TieredPGO 1 -ENV DOTNET_TC_QuickJitForLoops 1 -ENV DOTNET_ReadyToRun 0 +# final stage/image +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 WORKDIR /app -COPY --from=build /app/out ./ +COPY --from=build /app . -EXPOSE 8080 +ENTRYPOINT ["./Benchmarks"] -ENTRYPOINT ["dotnet", "Benchmarks.dll"] \ No newline at end of file +EXPOSE 8080 diff --git a/frameworks/CSharp/netcoreserver/Benchmarks/Benchmarks.csproj b/frameworks/CSharp/netcoreserver/Benchmarks/Benchmarks.csproj index 6d372b01ee3..8315e4a6e83 100644 --- a/frameworks/CSharp/netcoreserver/Benchmarks/Benchmarks.csproj +++ b/frameworks/CSharp/netcoreserver/Benchmarks/Benchmarks.csproj @@ -1,24 +1,24 @@  - + - - net5.0 - 9.0 - + + net9.0 + 13.0 + EmbedIO Benchmarks Test suite to be executed with TechEmpower FrameworkBenchmarks. - - Benchmarks.Program + + Benchmarks.Program Exe - + true false - + - + - - + + - - \ No newline at end of file + + diff --git a/frameworks/CSharp/netcoreserver/Benchmarks/HttpBenchmarkSession.cs b/frameworks/CSharp/netcoreserver/Benchmarks/HttpBenchmarkSession.cs index 25e58bd5aa1..bb99ce8f2c1 100644 --- a/frameworks/CSharp/netcoreserver/Benchmarks/HttpBenchmarkSession.cs +++ b/frameworks/CSharp/netcoreserver/Benchmarks/HttpBenchmarkSession.cs @@ -27,7 +27,7 @@ protected override void OnReceivedRequest(HttpRequest request) } else { - SendResponseAsync(Response.MakeErrorResponse("Not found", 404)); + SendResponseAsync(Response.MakeErrorResponse(404, "Not found")); } } diff --git a/frameworks/CSharp/netcoreserver/Benchmarks/Program.cs b/frameworks/CSharp/netcoreserver/Benchmarks/Program.cs index 411569ffb2f..3a821463b10 100644 --- a/frameworks/CSharp/netcoreserver/Benchmarks/Program.cs +++ b/frameworks/CSharp/netcoreserver/Benchmarks/Program.cs @@ -8,7 +8,7 @@ namespace Benchmarks public static class Program { - private static readonly ManualResetEvent _WaitEvent = new ManualResetEvent(false); + private static readonly ManualResetEvent WaitEvent = new(false); public static int Main(string[] args) { @@ -18,12 +18,12 @@ public static int Main(string[] args) { AppDomain.CurrentDomain.ProcessExit += (_, __) => { - _WaitEvent.Set(); + WaitEvent.Set(); }; server.Start(); - _WaitEvent.WaitOne(); + WaitEvent.WaitOne(); return 0; } diff --git a/frameworks/CSharp/netcoreserver/README.md b/frameworks/CSharp/netcoreserver/README.md index 985758c2bc9..31c1e995dcd 100644 --- a/frameworks/CSharp/netcoreserver/README.md +++ b/frameworks/CSharp/netcoreserver/README.md @@ -6,17 +6,17 @@ See the [project website](https://github.com/chronoxor/NetCoreServer) for more i **Language** -* C# 9.0 +* C# 13.0 **Platforms** -* .NET 5 +* .NET 9 **Web Servers** * [NetCoreServer](https://github.com/chronoxor/NetCoreServer) -## Paths & Source for Tests +## Paths \& Source for Tests * [Plaintext](Benchmarks/HttpBenchmarkSession.cs): "/plaintext" * [JSON](Benchmarks/HttpBenchmarkSession.cs): "/json" diff --git a/frameworks/CSharp/netcoreserver/netcoreserver.dockerfile b/frameworks/CSharp/netcoreserver/netcoreserver.dockerfile index 675c16d8841..35e05ff1fc4 100644 --- a/frameworks/CSharp/netcoreserver/netcoreserver.dockerfile +++ b/frameworks/CSharp/netcoreserver/netcoreserver.dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/dotnet/sdk:5.0-alpine AS build +FROM mcr.microsoft.com/dotnet/sdk:9.0-alpine AS build WORKDIR /source # copy csproj and restore as distinct layers @@ -7,10 +7,10 @@ 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 +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:5.0-alpine +FROM mcr.microsoft.com/dotnet/runtime-deps:9.0-alpine WORKDIR /app COPY --from=build /app . diff --git a/frameworks/CSharp/reaper/README.md b/frameworks/CSharp/reaper/README.md new file mode 100755 index 00000000000..c524f6af577 --- /dev/null +++ b/frameworks/CSharp/reaper/README.md @@ -0,0 +1,17 @@ +# Reaper Benchmarking Test + +[Reaper](https://github.com/Reaper-Net/Reaper) is a .NET 8+ Source Generator-based REPR pattern API endpoint library. + +### Test Type Implementation Source Code + +* [JSON](src/Benchmark/JsonEndpoint.cs) +* [PLAINTEXT](src/Benchmark/PlainTextEndpoint.cs) + +## Test URLs +### JSON + +http://localhost:8080/json + +### PLAINTEXT + +http://localhost:8080/plaintext \ No newline at end of file diff --git a/frameworks/CSharp/reaper/ReaperTechEmpower.sln b/frameworks/CSharp/reaper/ReaperTechEmpower.sln new file mode 100644 index 00000000000..91fcb8bab43 --- /dev/null +++ b/frameworks/CSharp/reaper/ReaperTechEmpower.sln @@ -0,0 +1,16 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Benchmark", "src\Benchmark\Benchmark.csproj", "{F7BCAEA7-516A-4D65-915C-F9A43C6E875D}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F7BCAEA7-516A-4D65-915C-F9A43C6E875D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F7BCAEA7-516A-4D65-915C-F9A43C6E875D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F7BCAEA7-516A-4D65-915C-F9A43C6E875D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F7BCAEA7-516A-4D65-915C-F9A43C6E875D}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/frameworks/CSharp/reaper/benchmark_config.json b/frameworks/CSharp/reaper/benchmark_config.json new file mode 100755 index 00000000000..586e8f8d6c2 --- /dev/null +++ b/frameworks/CSharp/reaper/benchmark_config.json @@ -0,0 +1,26 @@ +{ + "framework": "reaper", + "tests": [ + { + "default": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "None", + "framework": "Reaper", + "language": "C#", + "flavor": "CoreCLR", + "orm": "None", + "platform": ".NET", + "webserver": "Kestrel", + "os": "Linux", + "database_os": "Linux", + "display_name": "Reaper [aot,slim]", + "notes": "", + "versus": "aspnetcore-minimal" + } + } + ] +} diff --git a/frameworks/CSharp/reaper/reaper.dockerfile b/frameworks/CSharp/reaper/reaper.dockerfile new file mode 100644 index 00000000000..7da5d03009f --- /dev/null +++ b/frameworks/CSharp/reaper/reaper.dockerfile @@ -0,0 +1,14 @@ +FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build +WORKDIR /src +COPY src . +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + clang zlib1g-dev +WORKDIR "/src/Benchmark" +RUN dotnet publish "Benchmark.csproj" -c Release -o /app/publish + +FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS final +WORKDIR /app +EXPOSE 8080 +COPY --from=build /app/publish . +ENTRYPOINT ["./Benchmark"] diff --git a/frameworks/CSharp/reaper/src/Benchmark/Benchmark.csproj b/frameworks/CSharp/reaper/src/Benchmark/Benchmark.csproj new file mode 100644 index 00000000000..b0e9fd09211 --- /dev/null +++ b/frameworks/CSharp/reaper/src/Benchmark/Benchmark.csproj @@ -0,0 +1,25 @@ + + + + net9.0 + enable + enable + Linux + true + $(InterceptorsPreviewNamespaces);Reaper.Generated + true + Speed + + + + + .dockerignore + + + + + + + + + diff --git a/frameworks/CSharp/reaper/src/Benchmark/JsonEndpoint.cs b/frameworks/CSharp/reaper/src/Benchmark/JsonEndpoint.cs new file mode 100644 index 00000000000..f2ba38be4ca --- /dev/null +++ b/frameworks/CSharp/reaper/src/Benchmark/JsonEndpoint.cs @@ -0,0 +1,20 @@ +using Reaper; +using Reaper.Attributes; + +namespace Benchmark; + +public class JsonResponse +{ + public string Message { get; set; } = default!; +} + +[ReaperRoute(HttpVerbs.Get, "/json")] +public class JsonEndpoint : ReaperEndpointXR +{ + public override Task ExecuteAsync() + { + Context.Response.ContentLength = 27; + Result = new JsonResponse { Message = "Hello, World!" }; + return Task.CompletedTask; + } +} \ No newline at end of file diff --git a/frameworks/CSharp/reaper/src/Benchmark/PlainTextEndpoint.cs b/frameworks/CSharp/reaper/src/Benchmark/PlainTextEndpoint.cs new file mode 100644 index 00000000000..eb88ca8bd58 --- /dev/null +++ b/frameworks/CSharp/reaper/src/Benchmark/PlainTextEndpoint.cs @@ -0,0 +1,17 @@ +using Reaper; +using Reaper.Attributes; + +namespace Benchmark; + +[ReaperRoute(HttpVerbs.Get, "/plaintext")] +public class PlainTextEndpoint : ReaperEndpointXR +{ + public override Task ExecuteAsync() + { + Context.Response.StatusCode = 200; + Context.Response.ContentType = "text/plain"; + Context.Response.ContentLength = 13; + Result = "Hello, World!"; + return Task.CompletedTask; + } +} \ No newline at end of file diff --git a/frameworks/CSharp/reaper/src/Benchmark/Program.cs b/frameworks/CSharp/reaper/src/Benchmark/Program.cs new file mode 100644 index 00000000000..1c109c2ee8b --- /dev/null +++ b/frameworks/CSharp/reaper/src/Benchmark/Program.cs @@ -0,0 +1,13 @@ +using Reaper; + +var builder = WebApplication.CreateSlimBuilder(args); +builder.Logging.ClearProviders(); +builder.Logging.Configure(o => o.ActivityTrackingOptions = ActivityTrackingOptions.None); +builder.UseReaper(); + +var app = builder.Build(); + +app.UseReaperMiddleware(); +app.MapReaperEndpoints(); + +app.Run(); \ No newline at end of file diff --git a/frameworks/CSharp/reaper/src/Benchmark/Properties/launchSettings.json b/frameworks/CSharp/reaper/src/Benchmark/Properties/launchSettings.json new file mode 100644 index 00000000000..0f693d699d9 --- /dev/null +++ b/frameworks/CSharp/reaper/src/Benchmark/Properties/launchSettings.json @@ -0,0 +1,38 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:55625", + "sslPort": 44373 + } + }, + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "applicationUrl": "http://localhost:5286", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "applicationUrl": "https://localhost:7035;http://localhost:5286", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/frameworks/CSharp/reaper/src/Benchmark/appsettings.Development.json b/frameworks/CSharp/reaper/src/Benchmark/appsettings.Development.json new file mode 100644 index 00000000000..1b2d3bafd88 --- /dev/null +++ b/frameworks/CSharp/reaper/src/Benchmark/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} \ No newline at end of file diff --git a/frameworks/CSharp/reaper/src/Benchmark/appsettings.json b/frameworks/CSharp/reaper/src/Benchmark/appsettings.json new file mode 100644 index 00000000000..10f68b8c8b4 --- /dev/null +++ b/frameworks/CSharp/reaper/src/Benchmark/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/frameworks/CSharp/revenj/benchmark_config.json b/frameworks/CSharp/revenj/benchmark_config.json index 8472ef41d12..402a5129f93 100644 --- a/frameworks/CSharp/revenj/benchmark_config.json +++ b/frameworks/CSharp/revenj/benchmark_config.json @@ -22,6 +22,7 @@ "os": "Linux", "display_name": "Revenj", "notes": "", + "tags": ["broken"], "versus": "Revenj" } }] diff --git a/frameworks/CSharp/simplew/.gitignore b/frameworks/CSharp/simplew/.gitignore new file mode 100644 index 00000000000..c8d1eed0116 --- /dev/null +++ b/frameworks/CSharp/simplew/.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/simplew/Benchmarks/Benchmarks.csproj b/frameworks/CSharp/simplew/Benchmarks/Benchmarks.csproj new file mode 100644 index 00000000000..2b894596a8e --- /dev/null +++ b/frameworks/CSharp/simplew/Benchmarks/Benchmarks.csproj @@ -0,0 +1,20 @@ + + + + Exe + net9.0 + enable + enable + SimpleW + + true + true + + linux-musl-x64 + + + + + + + diff --git a/frameworks/CSharp/simplew/Benchmarks/Program.cs b/frameworks/CSharp/simplew/Benchmarks/Program.cs new file mode 100644 index 00000000000..2c69f462d1f --- /dev/null +++ b/frameworks/CSharp/simplew/Benchmarks/Program.cs @@ -0,0 +1,48 @@ +using System; +using System.Buffers.Text; +using System.Net; +using System.Threading.Tasks; +using SimpleW; + +namespace Benchmarks; + +internal static class Program +{ + public static async Task Main(string[] args) + { + var server = new SimpleWServer(IPAddress.Any, 8080); + server.AddDynamicContent("/api"); + server.Start(); + + await Task.Delay(-1); + } + + public class BenchmarksController : Controller { + [Route("GET", "/json")] + public object Json() { + return Response.MakeResponse( + new { message = "Hello, World!" }, // object will be serialized + addHeaders: new Dictionary() + { + { "Server", "SimpleW" }, + { "Date", DateTime.Now.ToString("R") } + } + // compress parameter is default to null, so no compression + ); + } + + [Route("GET", "/plaintext")] + public object Plaintext() { + return Response.MakeResponse( + "Hello, World!", + "text/plain", + addHeaders: new Dictionary() + { + { "Server", "SimpleW" }, + { "Date", DateTime.Now.ToString("R") } + } + // compress parameter is default to null, so no compression + ); + } + } +} \ No newline at end of file diff --git a/frameworks/CSharp/simplew/README.md b/frameworks/CSharp/simplew/README.md new file mode 100644 index 00000000000..3d380883ca7 --- /dev/null +++ b/frameworks/CSharp/simplew/README.md @@ -0,0 +1,18 @@ +# SimpleW Tests on Linux + +See the [SimpleW website](https://stratdev3.github.io/SimpleW/) for more information. + +## Infrastructure Software Versions + +**Language** + +* C# 13.0 + +**Platforms** + +* .NET 8/9 + +## Paths & Source for Tests + +* [Plaintext](Benchmarks/Program.cs): "/api/plaintext" +* [JSON](Benchmarks/Tests/JsonResource.cs): "/api/json" \ No newline at end of file diff --git a/frameworks/CSharp/simplew/benchmark_config.json b/frameworks/CSharp/simplew/benchmark_config.json new file mode 100644 index 00000000000..e1396429d39 --- /dev/null +++ b/frameworks/CSharp/simplew/benchmark_config.json @@ -0,0 +1,22 @@ +{ + "framework": "simplew", + "tests": [{ + "default": { + "plaintext_url": "/api/plaintext", + "json_url": "/api/json", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "database": "None", + "framework": "SimpleW", + "language": "C#", + "orm": "None", + "platform": ".NET", + "webserver": "Netcoreserver", + "os": "Linux", + "database_os": "Linux", + "display_name": "SimpleW", + "notes": "Only plaintext and JSON benchmarks implemented yet" + } + }] +} diff --git a/frameworks/CSharp/simplew/config.toml b/frameworks/CSharp/simplew/config.toml new file mode 100644 index 00000000000..e9d267af88a --- /dev/null +++ b/frameworks/CSharp/simplew/config.toml @@ -0,0 +1,14 @@ +[framework] +name = "simplew" + +[main] +urls.plaintext = "/api/plaintext" +urls.json = "/api/json" +approach = "Realistic" +classification = "Fullstack" +os = "Linux" +database_os = "Linux" +orm = "None" +platform = ".NET" +webserver = "Netcoreserver" +versus = "None" \ No newline at end of file diff --git a/frameworks/CSharp/simplew/simplew.dockerfile b/frameworks/CSharp/simplew/simplew.dockerfile new file mode 100644 index 00000000000..8c473477a61 --- /dev/null +++ b/frameworks/CSharp/simplew/simplew.dockerfile @@ -0,0 +1,24 @@ +FROM mcr.microsoft.com/dotnet/sdk:9.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:9.0-alpine + +ENV DOTNET_GCDynamicAdaptationMode=0 +ENV DOTNET_ReadyToRun=0 +ENV DOTNET_HillClimbing_Disable=1 + +WORKDIR /app +COPY --from=build /app . + +ENTRYPOINT ["./Benchmarks"] + +EXPOSE 8080 diff --git a/frameworks/CSharp/sisk/.gitignore b/frameworks/CSharp/sisk/.gitignore new file mode 100644 index 00000000000..df5d0dc676b --- /dev/null +++ b/frameworks/CSharp/sisk/.gitignore @@ -0,0 +1,39 @@ +[Oo]bj/ +[Bb]in/ +TestResults/ +.nuget/ +*.sln +*.sln.ide/ +_ReSharper.*/ +.idea/ +packages/ +artifacts/ +PublishProfiles/ +*.sln +.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/sisk/README.md b/frameworks/CSharp/sisk/README.md new file mode 100644 index 00000000000..1ecb09ce930 --- /dev/null +++ b/frameworks/CSharp/sisk/README.md @@ -0,0 +1,18 @@ +# Sisk benchmark + +See the [Sisk Framework website](https://sisk.project-principium.dev/) for more information. + +## Infrastructure Software Versions + +**Language** + +* C# 11.0 + +**Platforms** + +* .NET Core + +## Paths & Source for Tests + +* [Plaintext](sisk/Program.cs): "/plaintext" +* [JSON](sisk/Program.cs): "/json" \ No newline at end of file diff --git a/frameworks/CSharp/sisk/benchmark_config.json b/frameworks/CSharp/sisk/benchmark_config.json new file mode 100644 index 00000000000..2cad348515b --- /dev/null +++ b/frameworks/CSharp/sisk/benchmark_config.json @@ -0,0 +1,39 @@ +{ + "framework": "sisk", + "tests": [ + { + "default": { + "plaintext_url": "/plaintext", + "json_url": "/json", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "None", + "framework": "Sisk", + "language": "C#", + "orm": "Raw", + "platform": ".NET", + "webserver": "HttpListener", + "os": "Linux", + "database_os": "Linux", + "display_name": "Sisk Framework" + }, + "cadente": { + "plaintext_url": "/plaintext", + "json_url": "/json", + "port": 8080, + "approach": "Realistic", + "classification": "Platform", + "database": "None", + "framework": "Sisk", + "language": "C#", + "orm": "Raw", + "platform": ".NET", + "webserver": "Cadente", + "os": "Linux", + "database_os": "Linux", + "display_name": "Sisk Framework (Cadente)" + } + } + ] +} diff --git a/frameworks/CSharp/sisk/config.toml b/frameworks/CSharp/sisk/config.toml new file mode 100644 index 00000000000..ac39e86d851 --- /dev/null +++ b/frameworks/CSharp/sisk/config.toml @@ -0,0 +1,28 @@ +[framework] +name = "sisk" + +[main] +urls.plaintext = "/plaintext" +urls.json = "/json" +approach = "Realistic" +classification = "Micro" +database = "None" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = ".NET" +webserver = "HttpListener" +versus = "None" + +[cadente] +urls.plaintext = "/plaintext" +urls.json = "/json" +approach = "Realistic" +classification = "Platform" +database = "None" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = ".NET" +webserver = "Cadente" +versus = "None" \ No newline at end of file diff --git a/frameworks/CSharp/sisk/sisk-cadente.dockerfile b/frameworks/CSharp/sisk/sisk-cadente.dockerfile new file mode 100644 index 00000000000..34092a0e15c --- /dev/null +++ b/frameworks/CSharp/sisk/sisk-cadente.dockerfile @@ -0,0 +1,23 @@ +FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build +WORKDIR /source + +# copy csproj and restore as distinct layers +COPY sisk-cadente/*.csproj . +RUN dotnet restore -r linux-musl-x64 + +# copy and publish app and libraries +COPY sisk-cadente/ . +RUN dotnet publish -c release -o /app + +ENV DOTNET_GCDynamicAdaptationMode=0 +ENV DOTNET_ReadyToRun=0 +ENV DOTNET_HillClimbing_Disable=1 + +# final stage/image +FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS runtime +WORKDIR /app +COPY --from=build /app . + +ENTRYPOINT ["dotnet", "./sisk.dll"] + +EXPOSE 8080 \ No newline at end of file diff --git a/frameworks/CSharp/sisk/sisk-cadente/Program.cs b/frameworks/CSharp/sisk/sisk-cadente/Program.cs new file mode 100644 index 00000000000..f198260cbde --- /dev/null +++ b/frameworks/CSharp/sisk/sisk-cadente/Program.cs @@ -0,0 +1,50 @@ +using System.Buffers.Text; +using System.Net; +using System.Text; +using System.Text.Json; +using Sisk.Cadente; + +using var host = new HttpHost ( new IPEndPoint ( IPAddress.Any, 8080 ) ); +host.Handler = new DefaultHandler(); + +host.Start (); +Thread.Sleep ( Timeout.Infinite ); + + +class DefaultHandler : HttpHostHandler +{ + public override async Task OnContextCreatedAsync(HttpHost host, HttpHostContext context) + { + var request = context.Request; + var response = context.Response; + + if (request.Path == "/plaintext") + { + var contentBytes = Encoding.UTF8.GetBytes("Hello, World!"); + + await SerializeResponseAsync(response, contentBytes, "text/plain; charset=utf-8"); + } + else if (request.Path == "/json") + { + var contentBytes = JsonSerializer.SerializeToUtf8Bytes(new + { + message = "Hello, World!" + }); + + await SerializeResponseAsync(response, contentBytes, "application/json; charset=utf-8"); + } + else + { + response.StatusCode = 404; + } + } + + static async ValueTask SerializeResponseAsync(HttpHostContext.HttpResponse response, Memory content, string contentType) + { + response.Headers.Add(new HttpHeader("Content-Type", contentType)); + response.Headers.Add(new HttpHeader("Content-Length", content.Length.ToString())); + + using var responseStream = await response.GetResponseStreamAsync(); + await responseStream.WriteAsync(content); + } +} \ No newline at end of file diff --git a/frameworks/CSharp/sisk/sisk-cadente/sisk.csproj b/frameworks/CSharp/sisk/sisk-cadente/sisk.csproj new file mode 100644 index 00000000000..12f1a5d7c2c --- /dev/null +++ b/frameworks/CSharp/sisk/sisk-cadente/sisk.csproj @@ -0,0 +1,15 @@ + + + + Exe + net9.0 + enable + enable + true + + + + + + + \ No newline at end of file diff --git a/frameworks/CSharp/sisk/sisk.dockerfile b/frameworks/CSharp/sisk/sisk.dockerfile new file mode 100644 index 00000000000..6509bffbd8a --- /dev/null +++ b/frameworks/CSharp/sisk/sisk.dockerfile @@ -0,0 +1,23 @@ +FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build +WORKDIR /source + +# copy csproj and restore as distinct layers +COPY sisk/*.csproj . +RUN dotnet restore -r linux-musl-x64 + +# copy and publish app and libraries +COPY sisk/ . +RUN dotnet publish -c release -o /app -r linux-musl-x64 + +ENV DOTNET_GCDynamicAdaptationMode=0 +ENV DOTNET_ReadyToRun=0 +ENV DOTNET_HillClimbing_Disable=1 + +# final stage/image +FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime +WORKDIR /app +COPY --from=build /app . + +ENTRYPOINT ["dotnet", "./sisk.dll"] + +EXPOSE 8080 \ No newline at end of file diff --git a/frameworks/CSharp/sisk/sisk/Program.cs b/frameworks/CSharp/sisk/sisk/Program.cs new file mode 100644 index 00000000000..7b80417d4b7 --- /dev/null +++ b/frameworks/CSharp/sisk/sisk/Program.cs @@ -0,0 +1,26 @@ +using System.Net.Http.Json; +using System.Text; +using Sisk.Core.Http; +using Sisk.Core.Routing; + +var app = HttpServer.CreateBuilder ( host => { + host.UseListeningPort ( "http://+:8080/" ); + host.UseConfiguration ( config => { + config.AccessLogsStream = null; + } ); +} ).Build (); + +app.Router.SetRoute ( RouteMethod.Get, "/plaintext", PlainText ); +app.Router.SetRoute ( RouteMethod.Get, "/json", Json ); + +app.Start (); + +static HttpResponse PlainText ( HttpRequest request ) { + return new HttpResponse ( new StringContent ( "Hello, World!", Encoding.UTF8, "text/plain" ) ); +} + +static HttpResponse Json ( HttpRequest request ) { + return new HttpResponse ( JsonContent.Create ( new { + message = "Hello, World!" + } ) ); +} \ No newline at end of file diff --git a/frameworks/CSharp/sisk/sisk/sisk.csproj b/frameworks/CSharp/sisk/sisk/sisk.csproj new file mode 100644 index 00000000000..e767d50ede0 --- /dev/null +++ b/frameworks/CSharp/sisk/sisk/sisk.csproj @@ -0,0 +1,15 @@ + + + + Exe + net8.0 + enable + enable + true + + + + + + + diff --git a/frameworks/CSharp/tetsuweb/.gitignore b/frameworks/CSharp/tetsuweb/.gitignore deleted file mode 100644 index 708c4155fa7..00000000000 --- a/frameworks/CSharp/tetsuweb/.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/tetsuweb/Benchmark/Benchmark.csproj b/frameworks/CSharp/tetsuweb/Benchmark/Benchmark.csproj deleted file mode 100644 index 2968d8c6b86..00000000000 --- a/frameworks/CSharp/tetsuweb/Benchmark/Benchmark.csproj +++ /dev/null @@ -1,13 +0,0 @@ - - - - Exe - net5.0 - - - - - - - - diff --git a/frameworks/CSharp/tetsuweb/Benchmark/Program.cs b/frameworks/CSharp/tetsuweb/Benchmark/Program.cs deleted file mode 100644 index bb3663e8a1f..00000000000 --- a/frameworks/CSharp/tetsuweb/Benchmark/Program.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using Newtonsoft.Json; -using Tetsu.Web; - -namespace Benchmark { - public class Program { - public static void Main() { - var server = new Server(); - - server.Handle("/plaintext", ctx => - ctx.Response.TextContent = "Hello, World!"); - - server.Handle("/json", ctx => { - ctx.Response.SetHeader("Content-Type", "application/json"); - ctx.Response.TextContent = JsonConvert.SerializeObject(new { - message = "Hello, World!" - }); - }); - - server.AddMiddleware(ctx => - ctx.Response.SetHeader("Date", DateTime.UtcNow.ToString("r"))); - - server.Listen("0.0.0.0", 1234).Wait(); - } - } -} diff --git a/frameworks/CSharp/tetsuweb/README.md b/frameworks/CSharp/tetsuweb/README.md deleted file mode 100644 index 84f38ef7f86..00000000000 --- a/frameworks/CSharp/tetsuweb/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# Tetsu.Web Benchmark - -## Infrastructure Software Versions - -**Language** - -* C# - -**Platforms** - -* .NET Core (Windows and Linux) - -**Web Stack** - -* [Tetsu.Web](https://github.com/gkbrk/TetsuWeb) diff --git a/frameworks/CSharp/tetsuweb/benchmark_config.json b/frameworks/CSharp/tetsuweb/benchmark_config.json deleted file mode 100644 index 9d081d854af..00000000000 --- a/frameworks/CSharp/tetsuweb/benchmark_config.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "framework": "tetsuweb", - "tests": [{ - "default": { - "plaintext_url": "/plaintext", - "json_url": "/json", - "port": 1234, - "approach": "Realistic", - "classification": "Micro", - "database": "None", - "framework": "Tetsu", - "language": "C#", - "orm": "Raw", - "platform": ".NET", - "flavor": "CoreCLR", - "webserver": "Tetsu", - "os": "Linux", - "database_os": "Linux", - "display_name": "Tetsu.Web", - "notes": "", - "versus": "aspcore" - } - }] -} diff --git a/frameworks/CSharp/tetsuweb/config.toml b/frameworks/CSharp/tetsuweb/config.toml deleted file mode 100644 index e290ddacab9..00000000000 --- a/frameworks/CSharp/tetsuweb/config.toml +++ /dev/null @@ -1,15 +0,0 @@ -[framework] -name = "tetsuweb" - -[main] -urls.plaintext = "/plaintext" -urls.json = "/json" -approach = "Realistic" -classification = "Micro" -database = "None" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = ".NET" -webserver = "Tetsu" -versus = "aspcore" diff --git a/frameworks/CSharp/tetsuweb/tetsuweb.dockerfile b/frameworks/CSharp/tetsuweb/tetsuweb.dockerfile deleted file mode 100644 index 8cdda17ad1e..00000000000 --- a/frameworks/CSharp/tetsuweb/tetsuweb.dockerfile +++ /dev/null @@ -1,12 +0,0 @@ -FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build -WORKDIR /app -COPY Benchmark . -RUN dotnet publish -c Release -o out - -FROM mcr.microsoft.com/dotnet/runtime:5.0 -WORKDIR /app -COPY --from=build /app/out ./ - -EXPOSE 8080 - -ENTRYPOINT ["dotnet", "Benchmark.dll"] diff --git a/frameworks/CSharp/touchsocket/.gitignore b/frameworks/CSharp/touchsocket/.gitignore new file mode 100644 index 00000000000..d20fe97fddd --- /dev/null +++ b/frameworks/CSharp/touchsocket/.gitignore @@ -0,0 +1,343 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ +# ASP.NET Core default setup: bower directory is configured as wwwroot/lib/ and bower restore is true +**/wwwroot/lib/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb +*.snupkg +SHFB/Help diff --git a/frameworks/CSharp/touchsocket/Benchmarks.sln b/frameworks/CSharp/touchsocket/Benchmarks.sln new file mode 100644 index 00000000000..8d41045e044 --- /dev/null +++ b/frameworks/CSharp/touchsocket/Benchmarks.sln @@ -0,0 +1,49 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 18 +VisualStudioVersion = 18.0.11109.219 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TouchSocketWebApi", "src\TouchSocketWebApi\TouchSocketWebApi.csproj", "{6BD9363A-D77F-5D90-8444-2BC37495C920}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TouchSocketHttp", "src\TouchSocketHttp\TouchSocketHttp.csproj", "{A7FB43AB-672B-8854-68D7-C2B383B0BC04}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TouchSocketHttp31", "src\TouchSocketHttp31\TouchSocketHttp31.csproj", "{DE261A06-A254-FD54-4ACF-EE4D4352BA77}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TouchSocketWebApi31", "src\TouchSocketWebApi31\TouchSocketWebApi31.csproj", "{6B6A57CE-1F69-FA6E-7458-0A4B6AB60683}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TouchSocketHttpPlatform", "src\TouchSocketHttpPlatform\TouchSocketHttpPlatform.csproj", "{BC320C24-941D-2109-FBC8-92780569BBA4}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {6BD9363A-D77F-5D90-8444-2BC37495C920}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6BD9363A-D77F-5D90-8444-2BC37495C920}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6BD9363A-D77F-5D90-8444-2BC37495C920}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6BD9363A-D77F-5D90-8444-2BC37495C920}.Release|Any CPU.Build.0 = Release|Any CPU + {A7FB43AB-672B-8854-68D7-C2B383B0BC04}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A7FB43AB-672B-8854-68D7-C2B383B0BC04}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A7FB43AB-672B-8854-68D7-C2B383B0BC04}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A7FB43AB-672B-8854-68D7-C2B383B0BC04}.Release|Any CPU.Build.0 = Release|Any CPU + {DE261A06-A254-FD54-4ACF-EE4D4352BA77}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DE261A06-A254-FD54-4ACF-EE4D4352BA77}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DE261A06-A254-FD54-4ACF-EE4D4352BA77}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DE261A06-A254-FD54-4ACF-EE4D4352BA77}.Release|Any CPU.Build.0 = Release|Any CPU + {6B6A57CE-1F69-FA6E-7458-0A4B6AB60683}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6B6A57CE-1F69-FA6E-7458-0A4B6AB60683}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6B6A57CE-1F69-FA6E-7458-0A4B6AB60683}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6B6A57CE-1F69-FA6E-7458-0A4B6AB60683}.Release|Any CPU.Build.0 = Release|Any CPU + {BC320C24-941D-2109-FBC8-92780569BBA4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BC320C24-941D-2109-FBC8-92780569BBA4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BC320C24-941D-2109-FBC8-92780569BBA4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BC320C24-941D-2109-FBC8-92780569BBA4}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {69C5D834-F31B-4F07-97EC-E4DD5AF417DE} + EndGlobalSection +EndGlobal diff --git a/frameworks/CSharp/touchsocket/README.md b/frameworks/CSharp/touchsocket/README.md new file mode 100644 index 00000000000..8a520d40eec --- /dev/null +++ b/frameworks/CSharp/touchsocket/README.md @@ -0,0 +1,41 @@ +# touchsocket benchmarks + +See [touchsocket](https://touchsocket.net/) for more information. + +## Variants Included + +* `touchsocket.webapi` (`TouchSocketWebApi`) – WebApi style. +* `touchsocket.webapi31` (`TouchSocketWebApi31`) – WebApi targeting .NET 8. +* `touchsocket.http` (`TouchSocketHttp`) – Minimal HTTP implementation. +* `touchsocket.http31` (`TouchSocketHttp31`) – Minimal HTTP targeting .NET 8. +* `touchsocket.httpplatform` (`TouchSocketHttpPlatform`) – High-performance custom pipeline-based HTTP server focusing on low-level parsing and zero-allocation response writing. + +## Infrastructure Software Versions + +**Language / Runtime** + +* C# / .NET (8.0 & 9.0 depending on variant) + +## Endpoints + +All variants implement: + +* `/plaintext` – Returns a plain text "Hello, World!" response. +* `/json` – Returns a JSON object `{"message": "Hello, World!"}`. + +The `httpplatform` variant manually parses request lines and headers via `System.IO.Pipelines` for maximum throughput. + +## Dockerfiles + +Each variant has a dedicated Dockerfile named: + +* `touchsocket.dockerfile` (webapi) +* `touchsocket-webapi31.dockerfile` +* `touchsocket-http.dockerfile` +* `touchsocket-http31.dockerfile` +* `touchsocket-httpplatform.dockerfile` + +## Notes + +The `httpplatform` variant is intended for benchmarking raw server performance. It omits higher-level abstractions to reduce overhead. + diff --git a/frameworks/CSharp/touchsocket/benchmark_config.json b/frameworks/CSharp/touchsocket/benchmark_config.json new file mode 100644 index 00000000000..86036458c9a --- /dev/null +++ b/frameworks/CSharp/touchsocket/benchmark_config.json @@ -0,0 +1,102 @@ +{ + "framework": "touchsocket", + "tests": [ + { + "default": { + "plaintext_url": "/plaintext", + "json_url": "/json", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "database": "Postgres", + "framework": "touchsocket.webapi", + "language": "C#", + "orm": "Raw", + "platform": ".NET", + "flavor": "CoreCLR", + "webserver": "touchsocket", + "os": "Linux", + "database_os": "Linux", + "display_name": "touchsocket.webapi", + "notes": "", + "versus": "aspnetcore-mvc" + }, + "http": { + "plaintext_url": "/plaintext", + "json_url": "/json", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "Postgres", + "framework": "touchsocket.http", + "language": "C#", + "orm": "Micro", + "platform": ".NET", + "flavor": "CoreCLR", + "webserver": "touchsocket", + "os": "Linux", + "database_os": "Linux", + "display_name": "touchsocket.http", + "notes": "", + "versus": "aspnetcore" + }, + "http31": { + "plaintext_url": "/plaintext", + "json_url": "/json", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "Postgres", + "framework": "touchsocket.http31", + "language": "C#", + "orm": "Micro", + "platform": ".NET", + "flavor": "CoreCLR", + "webserver": "touchsocket", + "os": "Linux", + "database_os": "Linux", + "display_name": "touchsocket.http31", + "notes": "", + "versus": "aspnetcore" + }, + "webapi31": { + "plaintext_url": "/plaintext", + "json_url": "/json", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "database": "Postgres", + "framework": "touchsocket.webapi31", + "language": "C#", + "orm": "Raw", + "platform": ".NET", + "flavor": "CoreCLR", + "webserver": "touchsocket", + "os": "Linux", + "database_os": "Linux", + "display_name": "touchsocket.webapi31", + "notes": "", + "versus": "aspnetcore-mvc" + }, + "httpplatform": { + "plaintext_url": "/plaintext", + "json_url": "/json", + "port": 8080, + "approach": "Realistic", + "classification": "Platform", + "database": "Postgres", + "framework": "touchsocket.httpplatform", + "language": "C#", + "orm": "Micro", + "platform": ".NET", + "flavor": "CoreCLR", + "webserver": "touchsocket", + "os": "Linux", + "database_os": "Linux", + "display_name": "touchsocket.httpplatform", + "notes": "High-performance custom pipeline-based implementation variant.", + "versus": "aspnetcore" + } + } + ] +} \ No newline at end of file diff --git a/frameworks/CSharp/touchsocket/config.toml b/frameworks/CSharp/touchsocket/config.toml new file mode 100644 index 00000000000..0d06cb4e331 --- /dev/null +++ b/frameworks/CSharp/touchsocket/config.toml @@ -0,0 +1,67 @@ +[framework] +name = "touchsocket" + +[main] +urls.plaintext = "/plaintext" +urls.json = "/json" +approach = "Realistic" +classification = "Fullstack" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = ".NET" +webserver = "touchsocket.webapi" +versus = "aspcore-mvc" + +[http] +urls.plaintext = "/plaintext" +urls.json = "/json" +approach = "Realistic" +classification = "Micro" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = ".NET" +webserver = "touchsocket.http" +versus = "aspcore" + +[http31] +urls.plaintext = "/plaintext" +urls.json = "/json" +approach = "Realistic" +classification = "Micro" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = ".NET" +webserver = "touchsocket.http31" +versus = "aspcore" + +[webapi31] +urls.plaintext = "/plaintext" +urls.json = "/json" +approach = "Realistic" +classification = "Fullstack" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = ".NET" +webserver = "touchsocket.webapi31" +versus = "aspcore-mvc" + +[httpplatform] +urls.plaintext = "/plaintext" +urls.json = "/json" +approach = "Realistic" +classification = "Micro" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = ".NET" +webserver = "touchsocket.httpplatform" +versus = "aspcore" diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketHttp/NuGet.Config b/frameworks/CSharp/touchsocket/src/TouchSocketHttp/NuGet.Config new file mode 100644 index 00000000000..f05d5867888 --- /dev/null +++ b/frameworks/CSharp/touchsocket/src/TouchSocketHttp/NuGet.Config @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketHttp/Program.cs b/frameworks/CSharp/touchsocket/src/TouchSocketHttp/Program.cs new file mode 100644 index 00000000000..baa00f9da87 --- /dev/null +++ b/frameworks/CSharp/touchsocket/src/TouchSocketHttp/Program.cs @@ -0,0 +1,82 @@ +using System.Text; +using TouchSocket.Core; +using TouchSocket.Http; +using HttpContent = TouchSocket.Http.HttpContent; + +namespace TouchSocketHttp; + +public class Program +{ + private static async Task Main(string[] args) + { + int port = 8080; + var service = new MyHttpService(); + + await service.SetupAsync(new TouchSocketConfig() + .SetListenIPHosts(port) + .SetMaxCount(1000000) + .SetTransportOption(options => + { + options.BufferOnDemand = false; + }) + .ConfigureContainer(a => + { + a.AddConsoleLogger(); + })); + + await service.StartAsync(); + service.Logger.Info($"server is started,port:{port}"); + while (true) + { + Console.ReadLine(); + } + } +} + +internal sealed class MyHttpService : HttpService +{ + protected override MyHttpSessionClient NewClient() + { + return new MyHttpSessionClient(); + } +} + +internal sealed class MyHttpSessionClient : HttpSessionClient +{ + private readonly HttpContent m_contentPlaintext = new StringHttpContent("Hello, World!", Encoding.UTF8, "text/plain"); + private readonly HttpContent m_contentJson = new StringHttpContent("{\"message\":\"Hello, World!\"}", Encoding.UTF8, "application/json"); + + protected override async Task OnReceivedHttpRequest(HttpContext httpContext) + { + var request = httpContext.Request; + var response = httpContext.Response; + + switch (request.RelativeURL) + { + case "/plaintext": + { + response.StatusCode = 200; + response.StatusMessage = "ok"; + response.Headers.Add(HttpHeaders.Server, "T"); + response.Headers.Add(HttpHeaders.Date, HttpExtensions.CurrentHttpDate); + response.Content = m_contentPlaintext; + await response.AnswerAsync().ConfigureAwait(false); + } + break; + case "/json": + { + response.StatusCode = 200; + response.StatusMessage = "ok"; + response.Headers.Add(HttpHeaders.Server, "T"); + response.Headers.Add(HttpHeaders.Date, HttpExtensions.CurrentHttpDate); + response.Content = m_contentJson; + await response.AnswerAsync().ConfigureAwait(false); + } + break; + default: + response.SetStatus(404, "not find"); + await response.AnswerAsync().ConfigureAwait(false); + break; + } + } +} \ No newline at end of file diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketHttp/TouchSocketHttp.csproj b/frameworks/CSharp/touchsocket/src/TouchSocketHttp/TouchSocketHttp.csproj new file mode 100644 index 00000000000..073c2d99413 --- /dev/null +++ b/frameworks/CSharp/touchsocket/src/TouchSocketHttp/TouchSocketHttp.csproj @@ -0,0 +1,14 @@ + + + + net9.0 + enable + Exe + enable + + + + + + + diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketHttp31/NuGet.Config b/frameworks/CSharp/touchsocket/src/TouchSocketHttp31/NuGet.Config new file mode 100644 index 00000000000..f05d5867888 --- /dev/null +++ b/frameworks/CSharp/touchsocket/src/TouchSocketHttp31/NuGet.Config @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketHttp31/Program.cs b/frameworks/CSharp/touchsocket/src/TouchSocketHttp31/Program.cs new file mode 100644 index 00000000000..a85a45ed82e --- /dev/null +++ b/frameworks/CSharp/touchsocket/src/TouchSocketHttp31/Program.cs @@ -0,0 +1,99 @@ +using System.Text; +using TouchSocket.Core; +using TouchSocket.Http; +using TouchSocket.Sockets; +using static System.Net.Mime.MediaTypeNames; +using HttpContent = TouchSocket.Http.HttpContent; + +namespace TouchSocketHttp; + +public class Program +{ + static async Task Main(string[] args) + { + int port = 8080; + + Console.WriteLine(DateHelper.DateString); + var service = new MyHttpService(); + + await service.SetupAsync(new TouchSocketConfig() + .SetListenIPHosts(port) + .SetNoDelay(true) + .SetMaxCount(1000000) + .ConfigureContainer(a => + { + a.AddConsoleLogger(); + })); + + await service.StartAsync(); + service.Logger.Info($"server is started,port:{port}"); + while (true) + { + Console.ReadLine(); + } + } +} + +sealed class MyHttpService : HttpService +{ + protected override MyHttpSessionClient NewClient() + { + return new MyHttpSessionClient(); + } +} + +sealed class MyHttpSessionClient : HttpSessionClient +{ + private readonly HttpContent m_contentPlaintext = new StringHttpContent("Hello, World!", Encoding.UTF8, $"text/plain"); + private readonly HttpContent m_contentJson = new StringHttpContent("{\"message\":\"Hello, World!\"}", Encoding.UTF8, $"application/json"); + + protected override async Task OnReceivedHttpRequest(HttpContext httpContext) + { + var request = httpContext.Request; + var response = httpContext.Response; + + switch (request.RelativeURL) + { + case "/plaintext": + { + response.StatusCode = 200; + response.StatusMessage = "success"; + response.Headers.Add(HttpHeaders.Server, "T"); + response.Headers.Add(HttpHeaders.Date, DateHelper.DateString); + response.Content = m_contentPlaintext; + await response.AnswerAsync().ConfigureAwait(false); + } + break; + case "/json": + { + response.StatusCode = 200; + response.StatusMessage = "success"; + response.Headers.Add(HttpHeaders.Server, "T"); + response.Headers.Add(HttpHeaders.Date, DateHelper.DateString); + response.Content = m_contentJson; + await response.AnswerAsync().ConfigureAwait(false); + } + break; + default: + response.SetStatus(404, "not find"); + await response.AnswerAsync().ConfigureAwait(false); + break; + } + } +} + +static class DateHelper +{ + static Timer m_timer; + static DateHelper() + { + DateString = DateTime.UtcNow.ToGMTString(); + m_timer = new Timer((state) => + { + DateString = DateTime.UtcNow.ToGMTString(); + }, null, 0, 1000); + } + + public static string DateString { get; private set; } +} + diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketHttp31/TouchSocketHttp31.csproj b/frameworks/CSharp/touchsocket/src/TouchSocketHttp31/TouchSocketHttp31.csproj new file mode 100644 index 00000000000..8f8a2d69035 --- /dev/null +++ b/frameworks/CSharp/touchsocket/src/TouchSocketHttp31/TouchSocketHttp31.csproj @@ -0,0 +1,17 @@ + + + + net8.0 + enable + Exe + enable + true + + true + dotnet-TouchSocketWebApi-987c185f-10b1-455b-beb6-47d798a5a131 + + + + + + diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/DateHeader.cs b/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/DateHeader.cs new file mode 100644 index 00000000000..9f0049fc54d --- /dev/null +++ b/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/DateHeader.cs @@ -0,0 +1,73 @@ +// ------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://touchsocket.net/ +// 交流QQ群:234762506 +// 感谢您的下载和使用 +// ------------------------------------------------------------------------------ + +using System.Buffers.Text; +using System.Diagnostics; +using TouchSocket.Core; +using TouchSocket.Sockets; + +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 suffixIndex = dateTimeRLength + prefixLength; + + // Wed, 14 Mar 2018 14:20:00 GMT + private const int suffixLength = 2; // crlf + private static readonly Timer s_timer = new((s) => + { + SetDateValues(DateTimeOffset.UtcNow); + }, null, 1000, 1000); + + private static byte[] s_headerBytesMaster = new byte[prefixLength + dateTimeRLength + 2 * suffixLength]; + private static byte[] s_headerBytesScratch = new byte[prefixLength + dateTimeRLength + 2 * suffixLength]; + + static DateHeader() + { + var utf8 = "Date: "u8; + + utf8.CopyTo(s_headerBytesMaster); + utf8.CopyTo(s_headerBytesScratch); + s_headerBytesMaster[suffixIndex] = (byte)'\r'; + s_headerBytesMaster[suffixIndex + 1] = (byte)'\n'; + s_headerBytesMaster[suffixIndex + 2] = (byte)'\r'; + s_headerBytesMaster[suffixIndex + 3] = (byte)'\n'; + s_headerBytesScratch[suffixIndex] = (byte)'\r'; + s_headerBytesScratch[suffixIndex + 1] = (byte)'\n'; + s_headerBytesScratch[suffixIndex + 2] = (byte)'\r'; + s_headerBytesScratch[suffixIndex + 3] = (byte)'\n'; + + SetDateValues(DateTimeOffset.UtcNow); + SyncDateTimer(); + } + + public static ReadOnlySpan HeaderBytes => s_headerBytesMaster; + + public static void SyncDateTimer() + { + s_timer.Change(1000, 1000); + } + private static void SetDateValues(DateTimeOffset value) + { + lock (s_headerBytesScratch) + { + if (!Utf8Formatter.TryFormat(value, s_headerBytesScratch.AsSpan(prefixLength), out var written, 'R')) + { + throw new Exception("date time format failed"); + } + Debug.Assert(written == dateTimeRLength); + (s_headerBytesScratch, s_headerBytesMaster) = (s_headerBytesMaster, s_headerBytesScratch); + } + } +} diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/MyServer.cs b/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/MyServer.cs new file mode 100644 index 00000000000..714b8ff367b --- /dev/null +++ b/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/MyServer.cs @@ -0,0 +1,24 @@ +// ------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://touchsocket.net/ +// 交流QQ群:234762506 +// 感谢您的下载和使用 +// ------------------------------------------------------------------------------ + +using TouchSocket.Sockets; + +namespace TouchSocketHttpPlatform; + +internal sealed class MyServer : TcpService +{ + /// + protected override MyTcpSessionClientBase NewClient() + { + return new MyTcpSessionClientBase(); + } +} diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/MyTcpSessionClientBase.cs b/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/MyTcpSessionClientBase.cs new file mode 100644 index 00000000000..1b95c2ddd72 --- /dev/null +++ b/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/MyTcpSessionClientBase.cs @@ -0,0 +1,299 @@ +// ------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://touchsocket.net/ +// 交流QQ群:234762506 +// 感谢您的下载和使用 +// ------------------------------------------------------------------------------ + +using System.Buffers; +using System.IO.Pipelines; +using System.Runtime.CompilerServices; +using TouchSocket.Sockets; + +namespace TouchSocketHttpPlatform; + +/// +/// 路由类型 +/// +internal enum RouteType +{ + /// + /// 未知路由 + /// + Unknown, + + /// + /// 纯文本路由 + /// + Plaintext, + + /// + /// JSON路由 + /// + Json +} + +internal sealed class MyTcpSessionClientBase : TcpSessionClient +{ + #region Paths + public static ReadOnlySpan Json => "/json"u8; + public static ReadOnlySpan Plaintext => "/plaintext"u8; + #endregion + + + private static ReadOnlySpan PlainTextBody => "Hello, World!"u8; + private static ReadOnlySpan JsonBody => "{\"message\":\"Hello, World!\"}"u8; + + private static ReadOnlySpan PlaintextPreamble => + "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; + + 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; + + protected override async Task ReceiveLoopAsync(ITransport transport) + { + var pipeReader = transport.Reader; + var pipeWriter = transport.Writer; + + while (true) + { + var readResult = await pipeReader.ReadAsync(); + var bufferSequence = readResult.Buffer; + + var totalConsumed = ProcessRequests(bufferSequence, pipeWriter, out var responseCount); + + if (responseCount > 0) + { + await pipeWriter.FlushAsync(); + } + + if (totalConsumed > 0) + { + pipeReader.AdvanceTo(bufferSequence.GetPosition(totalConsumed)); + } + else + { + pipeReader.AdvanceTo(bufferSequence.Start, bufferSequence.End); + } + + if (readResult.IsCompleted) + { + break; + } + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static long ProcessRequests(ReadOnlySequence buffer, PipeWriter writer, out int responseCount) + { + var seqReader = new SequenceReader(buffer); + var totalConsumed = 0L; + responseCount = 0; + + while (!seqReader.End) + { + var startConsumed = seqReader.Consumed; + + // 请求行 + if (!TryReadLine(ref seqReader, out var requestLineLength)) + { + // 请求行不完整,不消费任何数据 + break; + } + + var requestLineConsumed = requestLineLength + 2; + + // 读取Headers,直到空行;若不完整,回退并等待更多数据 + var headersStartConsumed = seqReader.Consumed; + bool headersComplete = false; + while (!seqReader.End) + { + if (!TryReadLine(ref seqReader, out var headerLength)) + { + // 回退到读取Headers前的位置,等待更多数据 + var rewind = seqReader.Consumed - headersStartConsumed; + if (rewind > 0) + { + seqReader.Rewind(rewind); + } + headersComplete = false; + break; + } + + if (headerLength == 0) + { + headersComplete = true; + break; // headers 结束 + } + } + + if (!headersComplete) + { + // 不完整,等待更多数据 + break; + } + + // 解析URL - 直接在原始位置解析,避免Slice + var routeType = ParseUrlFast(buffer.Slice(startConsumed), requestLineConsumed); + + // 计算本次消费的字节数 + var consumed = seqReader.Consumed - startConsumed; + totalConsumed += consumed; + + // 写入响应 + WriteResponseSync(writer, routeType); + responseCount++; + } + + return totalConsumed; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void WriteResponseSync(PipeWriter writer, RouteType routeType) + { + switch (routeType) + { + case RouteType.Plaintext: + writer.Write(PlaintextPreamble); + writer.Write(DateHeader.HeaderBytes); + writer.Write(PlainTextBody); + break; + case RouteType.Json: + writer.Write(JsonPreamble); + writer.Write(DateHeader.HeaderBytes); + writer.Write(JsonBody); + break; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool TryReadLine(ref SequenceReader reader, out long length) + { + var start = reader.Consumed; + + while (!reader.End) + { + if (reader.TryRead(out var b)) + { + if (b == '\r') + { + // 查看是否有'\n',若暂不可用则回退并判定不完整 + if (!reader.TryPeek(out var next)) + { + // 回退已读取的'\r' + reader.Rewind(1); + length = 0; + return false; + } + if (next == '\n') + { + // 消费'\n'并返回本行长度(不含CRLF) + reader.Advance(1); + length = reader.Consumed - start - 2; + return true; + } + } + } + } + + length = 0; + return false; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static RouteType ParseUrlFast(ReadOnlySequence sequence, long requestLineLength) + { + var reader = new SequenceReader(sequence); + + // 跳过方法 + var spaceCount = 0; + var urlStart = 0L; + var urlEnd = 0L; + + while (reader.Consumed < requestLineLength && !reader.End) + { + if (reader.TryRead(out var b)) + { + if (b == ' ') + { + spaceCount++; + if (spaceCount == 1) + { + urlStart = reader.Consumed; + } + else if (spaceCount == 2) + { + urlEnd = reader.Consumed - 1; + break; + } + } + } + } + + if (spaceCount < 2) + { + return RouteType.Unknown; + } + + var urlLength = urlEnd - urlStart; + + // 截取URL片段 + var startPos = sequence.GetPosition(urlStart); + var urlSlice = sequence.Slice(startPos, urlLength); + + // "/plaintext" + if (urlLength == Plaintext.Length) + { + if (urlSlice.IsSingleSegment) + { + if (urlSlice.FirstSpan.SequenceEqual(Plaintext)) + { + return RouteType.Plaintext; + } + } + else + { + Span tmp = stackalloc byte[(int)urlLength]; + urlSlice.CopyTo(tmp); + if (tmp.SequenceEqual(Plaintext)) + { + return RouteType.Plaintext; + } + } + } + // "/json" + else if (urlLength == Json.Length) + { + if (urlSlice.IsSingleSegment) + { + if (urlSlice.FirstSpan.SequenceEqual(Json)) + { + return RouteType.Json; + } + } + else + { + Span tmp = stackalloc byte[(int)urlLength]; + urlSlice.CopyTo(tmp); + if (tmp.SequenceEqual(Json)) + { + return RouteType.Json; + } + } + } + + return RouteType.Unknown; + } +} + diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/NuGet.Config b/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/NuGet.Config new file mode 100644 index 00000000000..f05d5867888 --- /dev/null +++ b/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/NuGet.Config @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/Program.cs b/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/Program.cs new file mode 100644 index 00000000000..95576ee70b5 --- /dev/null +++ b/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/Program.cs @@ -0,0 +1,39 @@ +// ------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 +// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 +// CSDN博客:https://blog.csdn.net/qq_40374647 +// 哔哩哔哩视频:https://space.bilibili.com/94253567 +// Gitee源代码仓库:https://gitee.com/RRQM_Home +// Github源代码仓库:https://github.com/RRQM +// API首页:https://touchsocket.net/ +// 交流QQ群:234762506 +// 感谢您的下载和使用 +// ------------------------------------------------------------------------------ + +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace TouchSocketHttpPlatform; + +internal class Program +{ + private static async Task Main(string[] args) + { + var server = new MyServer(); + await server.SetupAsync(new TouchSocketConfig() + .SetListenIPHosts(8080) + .SetMaxCount(1000000) + .ConfigureContainer(a => + { + a.AddConsoleLogger(); + })); + + await server.StartAsync(); + Console.WriteLine("HTTP服务器已启动,端口: 8080"); + + while (true) + { + Console.ReadLine(); + } + } +} diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/TouchSocketHttpPlatform.csproj b/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/TouchSocketHttpPlatform.csproj new file mode 100644 index 00000000000..8e9841293fc --- /dev/null +++ b/frameworks/CSharp/touchsocket/src/TouchSocketHttpPlatform/TouchSocketHttpPlatform.csproj @@ -0,0 +1,13 @@ + + + + Exe + net9.0 + enable + enable + + + + + + diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketWebApi/NuGet.Config b/frameworks/CSharp/touchsocket/src/TouchSocketWebApi/NuGet.Config new file mode 100644 index 00000000000..f05d5867888 --- /dev/null +++ b/frameworks/CSharp/touchsocket/src/TouchSocketWebApi/NuGet.Config @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketWebApi/Program.cs b/frameworks/CSharp/touchsocket/src/TouchSocketWebApi/Program.cs new file mode 100644 index 00000000000..4033ac03745 --- /dev/null +++ b/frameworks/CSharp/touchsocket/src/TouchSocketWebApi/Program.cs @@ -0,0 +1,89 @@ +using System.Text; +using System.Text.Json.Serialization; +using TouchSocket.Core; +using TouchSocket.Http; +using TouchSocket.Rpc; +using TouchSocket.WebApi; +using HttpContent = TouchSocket.Http.HttpContent; + +namespace TouchSocketWebApi; + +public class Program +{ + public static void Main(string[] args) + { + HostApplicationBuilder builder = Host.CreateApplicationBuilder(args); + + builder.Services.AddServiceHostedService(config => + { + config.SetListenIPHosts(8080) + .SetMaxCount(1000000) + .SetTransportOption(options => + { + options.BufferOnDemand = false; + }) + .ConfigureContainer(a => + { + a.AddConsoleLogger(); + a.AddRpcStore(store => + { + store.RegisterServer(); + }); + }) + .ConfigurePlugins(a => + { + a.UseWebApi(options => + { + options.ConfigureConverter(converter => + { + converter.Clear(); + converter.AddSystemTextJsonSerializerFormatter(jsonOptions => + { + jsonOptions.TypeInfoResolverChain.Insert(0, AppJsonSerializerContext.Default); + }); + }); + }); + + a.UseDefaultHttpServicePlugin(); + }); + }); + + IHost host = builder.Build(); + host.Run(); + } +} + +public partial class ApiServer : SingletonRpcServer +{ + private readonly HttpContent m_contentPlaintext = new StringHttpContent("Hello, World!", Encoding.UTF8, $"text/plain"); + + public static MyJson MyJson { get; set; } = new MyJson() { Message = "Hello, World!" }; + + [Router("/plaintext")] + [WebApi(Method = HttpMethodType.Get)] + public async Task Plaintext(IWebApiCallContext callContext) + { + HttpResponse response = callContext.HttpContext.Response; + response.SetStatus(200, "ok"); + response.Content = m_contentPlaintext; + await response.AnswerAsync().ConfigureAwait(false); + } + + [Router("/json")] + [WebApi(Method = HttpMethodType.Get)] + public MyJson Json() + { + return MyJson; + } +} + +[JsonSerializable(typeof(MyJson))] +internal partial class AppJsonSerializerContext : JsonSerializerContext +{ + +} + +public class MyJson +{ + public string? Message { get; set; } +} \ No newline at end of file diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketWebApi/TouchSocketWebApi.csproj b/frameworks/CSharp/touchsocket/src/TouchSocketWebApi/TouchSocketWebApi.csproj new file mode 100644 index 00000000000..909c2f984ee --- /dev/null +++ b/frameworks/CSharp/touchsocket/src/TouchSocketWebApi/TouchSocketWebApi.csproj @@ -0,0 +1,15 @@ + + + + net9.0 + enable + enable + dotnet-WorkerService1-19b37b17-6043-4334-ad9a-9e0e3c670da3 + + + + + + + + diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketWebApi/appsettings.Development.json b/frameworks/CSharp/touchsocket/src/TouchSocketWebApi/appsettings.Development.json new file mode 100644 index 00000000000..b2dcdb67421 --- /dev/null +++ b/frameworks/CSharp/touchsocket/src/TouchSocketWebApi/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.Hosting.Lifetime": "Information" + } + } +} diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketWebApi/appsettings.json b/frameworks/CSharp/touchsocket/src/TouchSocketWebApi/appsettings.json new file mode 100644 index 00000000000..b2dcdb67421 --- /dev/null +++ b/frameworks/CSharp/touchsocket/src/TouchSocketWebApi/appsettings.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.Hosting.Lifetime": "Information" + } + } +} diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketWebApi31/NuGet.Config b/frameworks/CSharp/touchsocket/src/TouchSocketWebApi31/NuGet.Config new file mode 100644 index 00000000000..f05d5867888 --- /dev/null +++ b/frameworks/CSharp/touchsocket/src/TouchSocketWebApi31/NuGet.Config @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketWebApi31/Program.cs b/frameworks/CSharp/touchsocket/src/TouchSocketWebApi31/Program.cs new file mode 100644 index 00000000000..472ab7b8b5e --- /dev/null +++ b/frameworks/CSharp/touchsocket/src/TouchSocketWebApi31/Program.cs @@ -0,0 +1,85 @@ +using System.Text; +using System.Text.Json.Serialization; +using TouchSocket.Core; +using TouchSocket.Http; +using TouchSocket.Rpc; +using TouchSocket.Sockets; +using TouchSocket.WebApi; + +using HttpContent = TouchSocket.Http.HttpContent; + +namespace TouchSocketWebApi31; + +public class Program +{ + public static void Main(string[] args) + { + var builder = Host.CreateApplicationBuilder(args); + + builder.Services.AddServiceHostedService(config => + { + config.SetListenIPHosts(8080) + .SetNoDelay(true) + .SetMaxCount(1000000) + .ConfigureContainer(a => + { + a.AddConsoleLogger(); + a.AddRpcStore(store => + { + store.RegisterServer(); + }); + }) + .ConfigurePlugins(a => + { + a.UseWebApi() + .ConfigureConverter(converter => + { + converter.Clear(); + converter.AddSystemTextJsonSerializerFormatter(options => + { + options.TypeInfoResolverChain.Insert(0, AppJsonSerializerContext.Default); + }); + }); + a.UseDefaultHttpServicePlugin(); + }); + }); + + var host = builder.Build(); + host.Run(); + } +} + +public partial class ApiServer : SingletonRpcServer +{ + private readonly HttpContent m_contentPlaintext = new StringHttpContent("Hello, World!", Encoding.UTF8, $"text/plain"); + + public static MyJson MyJson { get; set; } = new MyJson() { Message = "Hello, World!" }; + + [Router("/plaintext")] + [WebApi(Method = HttpMethodType.Get)] + public async Task Plaintext(IWebApiCallContext callContext) + { + var response= callContext.HttpContext.Response; + response.SetStatus(200, "ok"); + response.Content= m_contentPlaintext; + await response.AnswerAsync().ConfigureAwait(false); + } + + [Router("/json")] + [WebApi(Method = HttpMethodType.Get)] + public MyJson Json() + { + return MyJson; + } +} + +[JsonSerializable(typeof(MyJson))] +internal partial class AppJsonSerializerContext : JsonSerializerContext +{ + +} + +public class MyJson +{ + public string? Message { get; set; } +} \ No newline at end of file diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketWebApi31/TouchSocketWebApi31.csproj b/frameworks/CSharp/touchsocket/src/TouchSocketWebApi31/TouchSocketWebApi31.csproj new file mode 100644 index 00000000000..d385bc8caed --- /dev/null +++ b/frameworks/CSharp/touchsocket/src/TouchSocketWebApi31/TouchSocketWebApi31.csproj @@ -0,0 +1,18 @@ + + + + net8.0 + enable + enable + true + + true + dotnet-TouchSocketWebApi-987c185f-10b1-452b-beb7-47d798a5a131 + + + + + + + + diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketWebApi31/appsettings.Development.json b/frameworks/CSharp/touchsocket/src/TouchSocketWebApi31/appsettings.Development.json new file mode 100644 index 00000000000..b2dcdb67421 --- /dev/null +++ b/frameworks/CSharp/touchsocket/src/TouchSocketWebApi31/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.Hosting.Lifetime": "Information" + } + } +} diff --git a/frameworks/CSharp/touchsocket/src/TouchSocketWebApi31/appsettings.json b/frameworks/CSharp/touchsocket/src/TouchSocketWebApi31/appsettings.json new file mode 100644 index 00000000000..b2dcdb67421 --- /dev/null +++ b/frameworks/CSharp/touchsocket/src/TouchSocketWebApi31/appsettings.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.Hosting.Lifetime": "Information" + } + } +} diff --git a/frameworks/CSharp/touchsocket/touchsocket-http.dockerfile b/frameworks/CSharp/touchsocket/touchsocket-http.dockerfile new file mode 100644 index 00000000000..28def83f5e4 --- /dev/null +++ b/frameworks/CSharp/touchsocket/touchsocket-http.dockerfile @@ -0,0 +1,13 @@ +FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build +WORKDIR /app +COPY src/TouchSocketHttp . +RUN dotnet publish -c Release -o out + +FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS runtime + +WORKDIR /app +COPY --from=build /app/out ./ + +EXPOSE 8080 + +ENTRYPOINT ["dotnet", "TouchSocketHttp.dll"] diff --git a/frameworks/CSharp/touchsocket/touchsocket-http31.dockerfile b/frameworks/CSharp/touchsocket/touchsocket-http31.dockerfile new file mode 100644 index 00000000000..b7437e1068b --- /dev/null +++ b/frameworks/CSharp/touchsocket/touchsocket-http31.dockerfile @@ -0,0 +1,13 @@ +FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build +WORKDIR /app +COPY src/TouchSocketHttp31 . +RUN dotnet publish -c Release -o out + +FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime + +WORKDIR /app +COPY --from=build /app/out ./ + +EXPOSE 8080 + +ENTRYPOINT ["dotnet", "TouchSocketHttp31.dll"] diff --git a/frameworks/CSharp/touchsocket/touchsocket-httpplatform.dockerfile b/frameworks/CSharp/touchsocket/touchsocket-httpplatform.dockerfile new file mode 100644 index 00000000000..c20b0434e76 --- /dev/null +++ b/frameworks/CSharp/touchsocket/touchsocket-httpplatform.dockerfile @@ -0,0 +1,13 @@ +FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build +WORKDIR /app +COPY src/TouchSocketHttpPlatform . +RUN dotnet publish -c Release -o out + +FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS runtime + +WORKDIR /app +COPY --from=build /app/out ./ + +EXPOSE 8080 + +ENTRYPOINT ["dotnet", "TouchSocketHttpPlatform.dll"] diff --git a/frameworks/CSharp/touchsocket/touchsocket-webapi31.dockerfile b/frameworks/CSharp/touchsocket/touchsocket-webapi31.dockerfile new file mode 100644 index 00000000000..0d528dbfb91 --- /dev/null +++ b/frameworks/CSharp/touchsocket/touchsocket-webapi31.dockerfile @@ -0,0 +1,13 @@ +FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build +WORKDIR /app +COPY src/TouchSocketWebApi31 . +RUN dotnet publish -c Release -o out + +FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime + +WORKDIR /app +COPY --from=build /app/out ./ + +EXPOSE 8080 + +ENTRYPOINT ["dotnet", "TouchSocketWebApi31.dll"] diff --git a/frameworks/CSharp/touchsocket/touchsocket.dockerfile b/frameworks/CSharp/touchsocket/touchsocket.dockerfile new file mode 100644 index 00000000000..96f1a166854 --- /dev/null +++ b/frameworks/CSharp/touchsocket/touchsocket.dockerfile @@ -0,0 +1,13 @@ +FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build +WORKDIR /app +COPY src/TouchSocketWebApi . +RUN dotnet publish -c Release -o out + +FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS runtime + +WORKDIR /app +COPY --from=build /app/out ./ + +EXPOSE 8080 + +ENTRYPOINT ["dotnet", "TouchSocketWebApi.dll"] diff --git a/frameworks/CSharp/watson/Benchmarks/Benchmarks.csproj b/frameworks/CSharp/watson/Benchmarks/Benchmarks.csproj index f199ceb3b59..01a0483b2d4 100644 --- a/frameworks/CSharp/watson/Benchmarks/Benchmarks.csproj +++ b/frameworks/CSharp/watson/Benchmarks/Benchmarks.csproj @@ -2,8 +2,8 @@ - net5.0 - 9.0 + net9.0 + 13.0 EmbedIO Benchmarks Test suite to be executed with TechEmpower FrameworkBenchmarks. @@ -17,8 +17,8 @@ - - + + \ No newline at end of file diff --git a/frameworks/CSharp/watson/Benchmarks/Program.cs b/frameworks/CSharp/watson/Benchmarks/Program.cs index 99e4d5922e4..d15cdbd5db1 100644 --- a/frameworks/CSharp/watson/Benchmarks/Program.cs +++ b/frameworks/CSharp/watson/Benchmarks/Program.cs @@ -1,11 +1,10 @@ using System; -using System.Linq; -using System.Net; using System.Text.Json; using System.Threading; using System.Threading.Tasks; using WatsonWebserver; +using WatsonWebserver.Core; namespace Benchmarks { @@ -23,7 +22,7 @@ public class JsonResult public static class Program { - private static readonly ManualResetEvent _WaitEvent = new ManualResetEvent(false); + private static readonly ManualResetEvent WaitEvent = new(false); public static async Task Main(string[] args) { @@ -33,21 +32,23 @@ public static async Task Main(string[] args) var host = "tfb-server"; #endif - using var server = new Server(host, 8080, false, DefaultRoute); + var settings = new WebserverSettings(host, 8080, false); - server.Routes.Static.Add(HttpMethod.GET, "/plaintext", PlaintextRoute); - server.Routes.Static.Add(HttpMethod.GET, "/json", JsonRoute); + using var server = new Webserver(settings, DefaultRoute); + + server.Routes.PreAuthentication.Static.Add(HttpMethod.GET, "/plaintext", PlaintextRoute); + server.Routes.PreAuthentication.Static.Add(HttpMethod.GET, "/json", JsonRoute); try { AppDomain.CurrentDomain.ProcessExit += (_, __) => { - _WaitEvent.Set(); + WaitEvent.Set(); }; await server.StartAsync(); - _WaitEvent.WaitOne(); + WaitEvent.WaitOne(); return 0; } @@ -59,22 +60,21 @@ public static async Task Main(string[] args) } } - static async Task DefaultRoute(HttpContext ctx) + static async Task DefaultRoute(HttpContextBase ctx) { ctx.Response.StatusCode = 404; - ctx.Response.StatusDescription = "Not Found"; await ctx.Response.Send("Not found."); } - static async Task PlaintextRoute(HttpContext ctx) + static async Task PlaintextRoute(HttpContextBase ctx) { ctx.Response.Headers.Add("Content-Type", "text/plain; charset=UTF-8"); await ctx.Response.Send("Hello, World!"); } - static async Task JsonRoute(HttpContext ctx) + static async Task JsonRoute(HttpContextBase ctx) { var response = new JsonResult() { Message = "Hello, World!" }; var serialized = JsonSerializer.Serialize(response); diff --git a/frameworks/CSharp/watson/README.md b/frameworks/CSharp/watson/README.md index 549fa94b793..5ee00dc66d7 100644 --- a/frameworks/CSharp/watson/README.md +++ b/frameworks/CSharp/watson/README.md @@ -6,11 +6,11 @@ See the [project website](https://github.com/jchristn/WatsonWebserver) for more **Language** -* C# 9.0 +* C# 13.0 **Platforms** -* .NET 5 +* .NET 9 **Web Servers** diff --git a/frameworks/CSharp/watson/benchmark_config.json b/frameworks/CSharp/watson/benchmark_config.json index d6f8c86dece..6017f614566 100644 --- a/frameworks/CSharp/watson/benchmark_config.json +++ b/frameworks/CSharp/watson/benchmark_config.json @@ -16,8 +16,7 @@ "os": "Linux", "database_os": "Linux", "display_name": "Watson Webserver", - "notes": "", - "tags": ["broken"] + "notes": "" } }] } diff --git a/frameworks/CSharp/watson/watson.dockerfile b/frameworks/CSharp/watson/watson.dockerfile index 675c16d8841..35e05ff1fc4 100644 --- a/frameworks/CSharp/watson/watson.dockerfile +++ b/frameworks/CSharp/watson/watson.dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/dotnet/sdk:5.0-alpine AS build +FROM mcr.microsoft.com/dotnet/sdk:9.0-alpine AS build WORKDIR /source # copy csproj and restore as distinct layers @@ -7,10 +7,10 @@ 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 +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:5.0-alpine +FROM mcr.microsoft.com/dotnet/runtime-deps:9.0-alpine WORKDIR /app COPY --from=build /app . diff --git a/frameworks/CSharp/wiredio/.gitignore b/frameworks/CSharp/wiredio/.gitignore new file mode 100644 index 00000000000..c8d1eed0116 --- /dev/null +++ b/frameworks/CSharp/wiredio/.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/wiredio/README.md b/frameworks/CSharp/wiredio/README.md new file mode 100644 index 00000000000..7b852008832 --- /dev/null +++ b/frameworks/CSharp/wiredio/README.md @@ -0,0 +1,22 @@ +# Wired.IO Tests on Linux + +See the [Wired.IO Documentation](https://mda2av.github.io/Wired.IO.Docs/) for more information. + +## Infrastructure Software Versions + +**Language** + +* C# 13.0 + +**Platforms** + +* .NET 9 + +**Web Servers** + +* [Wired.IO](https://github.com/MDA2AV/Wired.IO) + +**Engines** + +* [Wired.IO](https://github.com/MDA2AV/Wired.IO) +* [Unhinged](https://github.com/MDA2AV/Unhinged) \ No newline at end of file diff --git a/frameworks/CSharp/wiredio/UnhGHttp/Program.cs b/frameworks/CSharp/wiredio/UnhGHttp/Program.cs new file mode 100644 index 00000000000..82acdd926d6 --- /dev/null +++ b/frameworks/CSharp/wiredio/UnhGHttp/Program.cs @@ -0,0 +1,40 @@ +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 / 2) + .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 new file mode 100644 index 00000000000..09308ff4747 --- /dev/null +++ b/frameworks/CSharp/wiredio/UnhGHttp/UnhGHttp.csproj @@ -0,0 +1,23 @@ + + + + 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 new file mode 100644 index 00000000000..2d9ebf4896f --- /dev/null +++ b/frameworks/CSharp/wiredio/benchmark_config.json @@ -0,0 +1,76 @@ +{ + "framework": "wiredio", + "maintainers": ["MDA2AV"], + "tests": [ + { + "default": { + "plaintext_url": "/plaintext", + "json_url": "/json", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "database": "None", + "framework": "Wired.IO", + "language": "C#", + "orm": "None", + "platform": ".NET", + "webserver": "Wired.IO", + "os": "Linux", + "database_os": "Linux", + "display_name": "Wired.IO", + "notes": "Only plaintext and JSON benchmarks implemented yet" + }, + "mcr": { + "plaintext_url": "/plaintext", + "json_url": "/json", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "None", + "framework": "Unhinged", + "language": "C#", + "orm": "None", + "platform": ".NET", + "webserver": "Unhinged", + "os": "Linux", + "database_os": "Linux", + "display_name": "Unhinged", + "notes": "epoll" + }, + "mcr-p": { + "plaintext_url": "/plaintext", + "json_url": "/json", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "None", + "framework": "Unhinged", + "language": "C#", + "orm": "None", + "platform": ".NET", + "webserver": "Unhinged", + "os": "Linux", + "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 new file mode 100644 index 00000000000..0b973f1f1fb --- /dev/null +++ b/frameworks/CSharp/wiredio/config.toml @@ -0,0 +1,50 @@ +[framework] +name = "wiredio" + +[main] +urls.plaintext = "/plaintext" +urls.json = "/json" +approach = "Realistic" +classification = "Fullstack" +os = "Linux" +database_os = "Linux" +orm = "None" +platform = ".NET" +webserver = "Wired.IO" +versus = "None" + +[mcr] +urls.plaintext = "/plaintext" +urls.json = "/json" +approach = "Realistic" +classification = "Micro" +os = "Linux" +database_os = "Linux" +orm = "None" +platform = ".NET" +webserver = "Unhinged" +versus = "None" + +[mcr-p] +urls.plaintext = "/plaintext" +urls.json = "/json" +approach = "Realistic" +classification = "Micro" +os = "Linux" +database_os = "Linux" +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/src/Fullstack/Fullstack.csproj b/frameworks/CSharp/wiredio/src/Fullstack/Fullstack.csproj new file mode 100644 index 00000000000..b8e2ca0256d --- /dev/null +++ b/frameworks/CSharp/wiredio/src/Fullstack/Fullstack.csproj @@ -0,0 +1,26 @@ + + + + Exe + net9.0 + enable + enable + true + true + true + true + + + linux-musl-x64 + true + + + + + + + + + + + \ No newline at end of file diff --git a/frameworks/CSharp/wiredio/src/Fullstack/Program.cs b/frameworks/CSharp/wiredio/src/Fullstack/Program.cs new file mode 100644 index 00000000000..6d658ff0441 --- /dev/null +++ b/frameworks/CSharp/wiredio/src/Fullstack/Program.cs @@ -0,0 +1,60 @@ +using System.IO.Pipelines; +using System.Text.Json; +using System.Text.Json.Serialization; +using Wired.IO.App; + +namespace Fullstack; + +internal class Program +{ + public static async Task Main(string[] args) + { + var expressBuilder = WiredApp.CreateExpressBuilder(); + + await expressBuilder + .Port(8080) + .NoScopedEndpoints() + .MapGet("/json", _ => async ctx => + { + var payload = new JsonMessage { Message = JsonBody }; + var myHandler = CreateBoundHandler(ctx.Writer, payload); + + ctx + .Respond() + .Type("application/json"u8) + .Content(myHandler, 27); + + }) + .MapGet("/plaintext", _ => async ctx => + { + ctx + .Respond() + .Type("text/plain"u8) + .Content(_plainTextBody); + }) + .Build() + .RunAsync(); + } + + private static ReadOnlySpan _plainTextBody => "Hello, World!"u8; + private const string JsonBody = "Hello, World!"; + + [ThreadStatic] + private static Utf8JsonWriter? t_writer; + private static readonly Action StaticHandler = HandleFast; + private static Action CreateBoundHandler(PipeWriter writer, JsonMessage message) => () => StaticHandler.Invoke(writer, message); + private static void HandleFast(PipeWriter writer, JsonMessage message) + { + var utf8JsonWriter = t_writer ??= new Utf8JsonWriter(writer, new JsonWriterOptions { SkipValidation = true }); + utf8JsonWriter.Reset(writer); + JsonSerializer.Serialize(utf8JsonWriter, message, SerializerContext.JsonMessage); + } + + private static readonly JsonContext SerializerContext = JsonContext.Default; +} + +public struct JsonMessage { public string Message { get; set; } } + +[JsonSourceGenerationOptions(GenerationMode = JsonSourceGenerationMode.Serialization | JsonSourceGenerationMode.Metadata)] +[JsonSerializable(typeof(JsonMessage))] +public partial class JsonContext : JsonSerializerContext { } \ No newline at end of file diff --git a/frameworks/CSharp/wiredio/src/Platform/Platform.csproj b/frameworks/CSharp/wiredio/src/Platform/Platform.csproj new file mode 100644 index 00000000000..16ae7e90e4c --- /dev/null +++ b/frameworks/CSharp/wiredio/src/Platform/Platform.csproj @@ -0,0 +1,25 @@ + + + + Exe + net9.0 + enable + enable + true + true + true + true + + + linux-musl-x64 + true + + + + + + + + + + diff --git a/frameworks/CSharp/wiredio/src/Platform/Program.cs b/frameworks/CSharp/wiredio/src/Platform/Program.cs new file mode 100644 index 00000000000..24a76794d6e --- /dev/null +++ b/frameworks/CSharp/wiredio/src/Platform/Program.cs @@ -0,0 +1,104 @@ +// ReSharper disable always SuggestVarOrType_BuiltInTypes +// (var is avoided intentionally in this project so that concrete types are visible at call sites.) +// ReSharper disable always StackAllocInsideLoop + +using System.Runtime.CompilerServices; +using System.Text.Json; +using Unhinged; + +#pragma warning disable CA2014 + +/* (MDA2AV)Dev notes: + * + * Wired.IO Platform benchmark using [Unhinged - https://github.com/MDA2AV/Unhinged] epoll engine. + * + * This test was created purely for benchmark/comparison between .NET solutions. + * It should not be considered EVER as a go-to framework to build any kind of webserver! + * For such purpose please use the main Wired.IO framework [Wired.IO - https://github.com/MDA2AV/Wired.IO]. + * + * This benchmarks follows the JsonSerialization and PlainText rules imposed by the TechEmpower team. + * + * The Http parsing by the Unhinged engine is still naive(work in progress), yet it's development will not have any impact + * on these benchmarks results as the extra request parsing overhead is much smaller than the read/send syscalls'. + */ + +namespace Platform; + +[SkipLocalsInit] +internal static class Program +{ + public static void Main(string[] args) + { + var builder = UnhingedEngine + .CreateBuilder() + .SetPort(8080) + + + // Number of working threads + // Reasoning behind Environment.ProcessorCount / 2 + // It's the number of real cpu cores not cpu threads + // This can improve the cache hits on L1/L2 since only one thread + // is running per cpu core. + .SetNWorkersSolver(() => Environment.ProcessorCount / 2) + + // Accept up to 16384 connections + .SetBacklog(16384) + + // Max 512 epoll events per wake (quite overkill) + .SetMaxEventsPerWake(512) + + // Max 1024 connection per thread + .SetMaxNumberConnectionsPerWorker(1024) + + // 32KB in and 16KB out slabs to handle 16 pipeline depth + .SetSlabSizes(32 * 1024, 16 * 1024) + .InjectRequestHandler(RequestHandler); + + var engine = builder.Build(); + engine.Run(); + } + + private const string Json = "/json"; + private const string PlainText = "/plaintext"; + + private static ValueTask RequestHandler(Connection connection) + { + // FNV-1a Hashed routes to avoid string allocations + if(connection.H1HeaderData.Route == Json) // /json + CommitJsonResponse(connection); + + else if (connection.H1HeaderData.Route == PlainText) // /plaintext + CommitPlainTextResponse(connection); + + return ValueTask.CompletedTask; + } + + [ThreadStatic] private static Utf8JsonWriter? t_utf8JsonWriter; + private static readonly JsonContext SerializerContext = JsonContext.Default; + private static void CommitJsonResponse(Connection connection) + { + connection.WriteBuffer.WriteUnmanaged("HTTP/1.1 200 OK\r\n"u8 + + "Server: W\r\n"u8 + + "Content-Type: application/json; charset=UTF-8\r\n"u8 + + "Content-Length: 27\r\n"u8); + connection.WriteBuffer.WriteUnmanaged(DateHelper.HeaderBytes); + + t_utf8JsonWriter ??= new Utf8JsonWriter(connection.WriteBuffer, new JsonWriterOptions { SkipValidation = true }); + t_utf8JsonWriter.Reset(connection.WriteBuffer); + + // Creating(Allocating) a new JsonMessage every request + var message = new JsonMessage { Message = "Hello, World!" }; + // Serializing it every request + JsonSerializer.Serialize(t_utf8JsonWriter, message, SerializerContext.JsonMessage); + } + + private static void CommitPlainTextResponse(Connection connection) + { + connection.WriteBuffer.WriteUnmanaged("HTTP/1.1 200 OK\r\n"u8 + + "Server: W\r\n"u8 + + "Content-Type: text/plain\r\n"u8 + + "Content-Length: 13\r\n"u8); + connection.WriteBuffer.WriteUnmanaged(DateHelper.HeaderBytes); + connection.WriteBuffer.WriteUnmanaged("Hello, World!"u8); + } +} \ No newline at end of file diff --git a/frameworks/CSharp/wiredio/src/PlatformP/Platform.csproj b/frameworks/CSharp/wiredio/src/PlatformP/Platform.csproj new file mode 100644 index 00000000000..ea26e67a376 --- /dev/null +++ b/frameworks/CSharp/wiredio/src/PlatformP/Platform.csproj @@ -0,0 +1,25 @@ + + + + Exe + net9.0 + enable + enable + true + true + true + true + + + linux-musl-x64 + true + + + + + + + + + + diff --git a/frameworks/CSharp/wiredio/src/PlatformP/Program.cs b/frameworks/CSharp/wiredio/src/PlatformP/Program.cs new file mode 100644 index 00000000000..46a7d69219c --- /dev/null +++ b/frameworks/CSharp/wiredio/src/PlatformP/Program.cs @@ -0,0 +1,98 @@ +// ReSharper disable always SuggestVarOrType_BuiltInTypes +// (var is avoided intentionally in this project so that concrete types are visible at call sites.) +// ReSharper disable always StackAllocInsideLoop + +using System.Runtime.CompilerServices; +using System.Text.Json; +using Unhinged; + +#pragma warning disable CA2014 + +/* (MDA2AV)Dev notes: + * + * Wired.IO Platform benchmark using [Unhinged - https://github.com/MDA2AV/Unhinged] epoll engine. + * + * This test was created purely for benchmark/comparison between .NET solutions. + * It should not be considered EVER as a go-to framework to build any kind of webserver! + * For such purpose please use the main Wired.IO framework [Wired.IO - https://github.com/MDA2AV/Wired.IO]. + * + * This benchmarks follows the JsonSerialization and PlainText rules imposed by the TechEmpower team. + * + * The Http parsing by the Unhinged engine is still naive(work in progress), yet it's development will not have any impact + * on these benchmarks results as the extra request parsing overhead is much smaller than the read/send syscalls'. + */ + +namespace Platform; + +[SkipLocalsInit] +internal static class Program +{ + public static void Main(string[] args) + { + var builder = UnhingedEngine + .CreateBuilder() + .SetPort(8080) + + .SetNWorkersSolver(() => Environment.ProcessorCount ) + + // Accept up to 16384 connections + .SetBacklog(16384) + + // Max 512 epoll events per wake (quite overkill) + .SetMaxEventsPerWake(512) + + // Max 1024 connection per thread + .SetMaxNumberConnectionsPerWorker(1024) + + // 32KB in and 16KB out slabs to handle 16 pipeline depth + .SetSlabSizes(32 * 1024, 16 * 1024) + .InjectRequestHandler(RequestHandler); + + var engine = builder.Build(); + engine.Run(); + } + + private const string Json = "/json"; + private const string PlainText = "/plaintext"; + + private static ValueTask RequestHandler(Connection connection) + { + // FNV-1a Hashed routes to avoid string allocations + if(connection.H1HeaderData.Route == Json) // /json + CommitJsonResponse(connection); + + else if (connection.H1HeaderData.Route == PlainText) // /plaintext + CommitPlainTextResponse(connection); + + return ValueTask.CompletedTask; + } + + [ThreadStatic] private static Utf8JsonWriter? t_utf8JsonWriter; + private static readonly JsonContext SerializerContext = JsonContext.Default; + private static void CommitJsonResponse(Connection connection) + { + connection.WriteBuffer.WriteUnmanaged("HTTP/1.1 200 OK\r\n"u8 + + "Server: W\r\n"u8 + + "Content-Type: application/json; charset=UTF-8\r\n"u8 + + "Content-Length: 27\r\n"u8); + connection.WriteBuffer.WriteUnmanaged(DateHelper.HeaderBytes); + + t_utf8JsonWriter ??= new Utf8JsonWriter(connection.WriteBuffer, new JsonWriterOptions { SkipValidation = true }); + t_utf8JsonWriter.Reset(connection.WriteBuffer); + + // Creating(Allocating) a new JsonMessage every request + var message = new JsonMessage { Message = "Hello, World!" }; + // Serializing it every request + JsonSerializer.Serialize(t_utf8JsonWriter, message, SerializerContext.JsonMessage); + } + + private static void CommitPlainTextResponse(Connection connection) + { + connection.WriteBuffer.WriteUnmanaged("HTTP/1.1 200 OK\r\n"u8 + + "Server: W\r\n"u8 + + "Content-Type: text/plain\r\n"u8 + + "Content-Length: 13\r\n"u8); + connection.WriteBuffer.WriteUnmanaged(DateHelper.HeaderBytes); + connection.WriteBuffer.WriteUnmanaged("Hello, World!"u8); + } +} \ No newline at end of file diff --git a/frameworks/CSharp/wiredio/wiredio-gen.dockerfile b/frameworks/CSharp/wiredio/wiredio-gen.dockerfile new file mode 100644 index 00000000000..5436527f964 --- /dev/null +++ b/frameworks/CSharp/wiredio/wiredio-gen.dockerfile @@ -0,0 +1,24 @@ +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/CSharp/wiredio/wiredio-mcr-p.dockerfile b/frameworks/CSharp/wiredio/wiredio-mcr-p.dockerfile new file mode 100644 index 00000000000..1ef18f083c2 --- /dev/null +++ b/frameworks/CSharp/wiredio/wiredio-mcr-p.dockerfile @@ -0,0 +1,22 @@ +# Build +FROM mcr.microsoft.com/dotnet/sdk:9.0-alpine AS build +RUN apk add --no-cache clang build-base zlib-dev linux-headers +WORKDIR /src +COPY src/PlatformP/ ./PlatformP/ +WORKDIR /src/PlatformP +RUN dotnet publish -c Release \ + -r linux-musl-x64 \ + --self-contained true \ + -p:PublishAot=true \ + -p:OptimizationPreference=Speed \ + -p:GarbageCollectionAdaptationMode=0 \ + -o /app/out + +# Runtime (musl) +FROM mcr.microsoft.com/dotnet/runtime-deps:9.0-alpine +ENV URLS=http://+:8080 +WORKDIR /app +COPY --from=build /app/out ./ +RUN chmod +x ./Platform +EXPOSE 8080 +ENTRYPOINT ["./Platform"] diff --git a/frameworks/CSharp/wiredio/wiredio-mcr.dockerfile b/frameworks/CSharp/wiredio/wiredio-mcr.dockerfile new file mode 100644 index 00000000000..9bd497eec84 --- /dev/null +++ b/frameworks/CSharp/wiredio/wiredio-mcr.dockerfile @@ -0,0 +1,22 @@ +# Build +FROM mcr.microsoft.com/dotnet/sdk:9.0-alpine AS build +RUN apk add --no-cache clang build-base zlib-dev linux-headers +WORKDIR /src +COPY src/Platform/ ./Platform/ +WORKDIR /src/Platform +RUN dotnet publish -c Release \ + -r linux-musl-x64 \ + --self-contained true \ + -p:PublishAot=true \ + -p:OptimizationPreference=Speed \ + -p:GarbageCollectionAdaptationMode=0 \ + -o /app/out + +# Runtime (musl) +FROM mcr.microsoft.com/dotnet/runtime-deps:9.0-alpine +ENV URLS=http://+:8080 +WORKDIR /app +COPY --from=build /app/out ./ +RUN chmod +x ./Platform +EXPOSE 8080 +ENTRYPOINT ["./Platform"] diff --git a/frameworks/CSharp/wiredio/wiredio.dockerfile b/frameworks/CSharp/wiredio/wiredio.dockerfile new file mode 100644 index 00000000000..2c6d853b0a2 --- /dev/null +++ b/frameworks/CSharp/wiredio/wiredio.dockerfile @@ -0,0 +1,22 @@ +# Build +FROM mcr.microsoft.com/dotnet/sdk:9.0-alpine AS build +RUN apk add --no-cache clang build-base zlib-dev linux-headers +WORKDIR /src +COPY src/Fullstack/ ./Fullstack/ +WORKDIR /src/Fullstack +RUN dotnet publish -c Release \ + -r linux-musl-x64 \ + --self-contained true \ + -p:PublishAot=true \ + -p:OptimizationPreference=Speed \ + -p:GarbageCollectionAdaptationMode=0 \ + -o /app/out + +# Runtime (musl) +FROM mcr.microsoft.com/dotnet/runtime-deps:9.0-alpine +ENV URLS=http://+:8080 +WORKDIR /app +COPY --from=build /app/out ./ +RUN chmod +x ./Fullstack +EXPOSE 8080 +ENTRYPOINT ["./Fullstack"] diff --git a/frameworks/CSharp/zysocket-v/PlatformBenchmarks.sln b/frameworks/CSharp/zysocket-v/PlatformBenchmarks.sln deleted file mode 100644 index 3879a0a6231..00000000000 --- a/frameworks/CSharp/zysocket-v/PlatformBenchmarks.sln +++ /dev/null @@ -1,25 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29230.47 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PlatformBenchmarks", "PlatformBenchmarks\PlatformBenchmarks.csproj", "{E4500562-635D-4DB9-99AE-B321F52A7C46}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {E4500562-635D-4DB9-99AE-B321F52A7C46}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E4500562-635D-4DB9-99AE-B321F52A7C46}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E4500562-635D-4DB9-99AE-B321F52A7C46}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E4500562-635D-4DB9-99AE-B321F52A7C46}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {9FD9812E-E78B-4B9F-8526-8C85458ABA2E} - EndGlobalSection -EndGlobal diff --git a/frameworks/CSharp/zysocket-v/PlatformBenchmarks/AsciiString.cs b/frameworks/CSharp/zysocket-v/PlatformBenchmarks/AsciiString.cs deleted file mode 100644 index 054160be587..00000000000 --- a/frameworks/CSharp/zysocket-v/PlatformBenchmarks/AsciiString.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace PlatformBenchmarks -{ - public readonly struct AsciiString : IEquatable - { - private readonly byte[] _data; - - public AsciiString(string s) => _data = Encoding.ASCII.GetBytes(s); - - public int Length => _data.Length; - - public byte[] Data => _data; - - public ReadOnlySpan AsSpan() => _data; - - public static implicit operator ReadOnlySpan(AsciiString str) => str._data; - public static implicit operator byte[](AsciiString str) => str._data; - - public static implicit operator AsciiString(string str) => new AsciiString(str); - - public static explicit operator string(AsciiString str) => str.ToString(); - - public bool Equals(AsciiString other) => ReferenceEquals(_data, other._data) || SequenceEqual(_data, other._data); - private bool SequenceEqual(byte[] data1, byte[] data2) => new Span(data1).SequenceEqual(data2); - - public static bool operator ==(AsciiString a, AsciiString b) => a.Equals(b); - public static bool operator !=(AsciiString a, AsciiString b) => !a.Equals(b); - public override bool Equals(object other) => (other is AsciiString) && Equals((AsciiString)other); - - public override int GetHashCode() - { - // Copied from x64 version of string.GetLegacyNonRandomizedHashCode() - // https://github.com/dotnet/coreclr/blob/master/src/mscorlib/src/System/String.Comparison.cs - var data = _data; - int hash1 = 5381; - int hash2 = hash1; - foreach (int b in data) - { - hash1 = ((hash1 << 5) + hash1) ^ b; - } - return hash1 + (hash2 * 1566083941); - } - - } -} diff --git a/frameworks/CSharp/zysocket-v/PlatformBenchmarks/ConcurrentRandom.cs b/frameworks/CSharp/zysocket-v/PlatformBenchmarks/ConcurrentRandom.cs deleted file mode 100644 index a75abc3bb31..00000000000 --- a/frameworks/CSharp/zysocket-v/PlatformBenchmarks/ConcurrentRandom.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Runtime.CompilerServices; -using System.Text; -using System.Threading; - -namespace PlatformBenchmarks -{ - 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/zysocket-v/PlatformBenchmarks/DBRaw.cs b/frameworks/CSharp/zysocket-v/PlatformBenchmarks/DBRaw.cs deleted file mode 100644 index 7af234af557..00000000000 --- a/frameworks/CSharp/zysocket-v/PlatformBenchmarks/DBRaw.cs +++ /dev/null @@ -1,123 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Data; -using System.Data.Common; -using System.Text; -using System.Threading.Tasks; - -namespace PlatformBenchmarks -{ - public class RawDb - { - - private readonly ConcurrentRandom _random; - - private readonly DbProviderFactory _dbProviderFactory; - - private readonly string _connectionString; - - public RawDb(ConcurrentRandom random, DbProviderFactory dbProviderFactory) - { - _random = random; - _dbProviderFactory = dbProviderFactory; - _connectionString = "Server=tfb-database;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;Maximum Pool Size=256;NoResetOnClose=true;Enlist=false;Max Auto Prepare=3"; - //_connectionString = "Server=192.168.1.55;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;Maximum Pool Size=256;NoResetOnClose=true;Enlist=false;Max Auto Prepare=3"; - OnCreateCommand(); - } - - private void OnCreateCommand() - { - SingleCommand = new Npgsql.NpgsqlCommand(); - SingleCommand.CommandText = "SELECT id, randomnumber FROM world WHERE id = @Id"; - var id = SingleCommand.CreateParameter(); - id.ParameterName = "@Id"; - id.DbType = DbType.Int32; - id.Value = _random.Next(1, 10001); - SingleCommand.Parameters.Add(id); - FortuneCommand = new Npgsql.NpgsqlCommand(); - FortuneCommand.CommandText = "SELECT id, message FROM fortune"; - } - - private DbCommand SingleCommand; - - private DbCommand FortuneCommand; - - public async Task LoadSingleQueryRow() - { - using (var db = _dbProviderFactory.CreateConnection()) - { - db.ConnectionString = _connectionString; - await db.OpenAsync(); - SingleCommand.Connection = db; - SingleCommand.Parameters[0].Value = _random.Next(1, 10001); - return await ReadSingleRow(db, SingleCommand); - - } - } - - async Task ReadSingleRow(DbConnection connection, DbCommand cmd) - { - using (var rdr = await cmd.ExecuteReaderAsync(CommandBehavior.SingleRow)) - { - await rdr.ReadAsync(); - - return new World - { - Id = rdr.GetInt32(0), - RandomNumber = rdr.GetInt32(1) - }; - } - } - - public async Task LoadMultipleQueriesRows(int count) - { - using (var db = _dbProviderFactory.CreateConnection()) - { - db.ConnectionString = _connectionString; - await db.OpenAsync(); - return await LoadMultipleRows(count, db); - } - - } - - private async Task LoadMultipleRows(int count, DbConnection db) - { - SingleCommand.Connection = db; - SingleCommand.Parameters[0].Value = _random.Next(1, 10001); - var result = new World[count]; - for (int i = 0; i < result.Length; i++) - { - result[i] = await ReadSingleRow(db, SingleCommand); - SingleCommand.Parameters[0].Value = _random.Next(1, 10001); - } - return result; - - } - - public async Task> LoadFortunesRows() - { - var result = new List(); - - using (var db = _dbProviderFactory.CreateConnection()) - { - db.ConnectionString = _connectionString; - await db.OpenAsync(); - FortuneCommand.Connection = db; - using (var rdr = await FortuneCommand.ExecuteReaderAsync(CommandBehavior.CloseConnection)) - { - while (await rdr.ReadAsync()) - { - result.Add(new Fortune - { - Id = rdr.GetInt32(0), - Message = rdr.GetString(1) - }); - } - } - } - result.Add(new Fortune { Message = "Additional fortune added at request time." }); - result.Sort(); - return result; - } - } -} diff --git a/frameworks/CSharp/zysocket-v/PlatformBenchmarks/Fortune.cs b/frameworks/CSharp/zysocket-v/PlatformBenchmarks/Fortune.cs deleted file mode 100644 index d970799d5ad..00000000000 --- a/frameworks/CSharp/zysocket-v/PlatformBenchmarks/Fortune.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace PlatformBenchmarks -{ - public class Fortune : IComparable, IComparable - { - public int Id { get; set; } - - public string Message { get; set; } - - public int CompareTo(object obj) - { - return CompareTo((Fortune)obj); - } - - public int CompareTo(Fortune other) - { - // Performance critical, using culture insensitive comparison - return String.CompareOrdinal(Message, other.Message); - } - } -} diff --git a/frameworks/CSharp/zysocket-v/PlatformBenchmarks/GMTDate.cs b/frameworks/CSharp/zysocket-v/PlatformBenchmarks/GMTDate.cs deleted file mode 100644 index 8cba0e9ae9c..00000000000 --- a/frameworks/CSharp/zysocket-v/PlatformBenchmarks/GMTDate.cs +++ /dev/null @@ -1,186 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; - -namespace PlatformBenchmarks -{ - internal class GMTDate - { - private List mWeekBuffers = new List(); - - public List mYears = new List(); - - public List mMoth = new List(); - - public List mNumber = new List(); - - private byte _1 = 58; - - private byte _s = 32; - - private byte _r = 13; - - private byte _n = 10; - - private byte[] GMT = new byte[3] - { - 71, - 77, - 84 - }; - - private static GMTDate mDefault; - - private Timer mUpdateTime; - - public static GMTDate Default - { - get - { - if (mDefault == null) - { - mDefault = new GMTDate(); - mDefault.Init(); - } - return mDefault; - } - } - - public ArraySegment DATE - { - get; - set; - } - - public GMTDate() - { - mWeekBuffers.Add(Encoding.ASCII.GetBytes("Sun")); - mWeekBuffers.Add(Encoding.ASCII.GetBytes("Mon")); - mWeekBuffers.Add(Encoding.ASCII.GetBytes("Tue")); - mWeekBuffers.Add(Encoding.ASCII.GetBytes("Wed")); - mWeekBuffers.Add(Encoding.ASCII.GetBytes("Thu")); - mWeekBuffers.Add(Encoding.ASCII.GetBytes("Fri")); - mWeekBuffers.Add(Encoding.ASCII.GetBytes("Sat")); - for (int j = 1970; j < 2470; j++) - { - mYears.Add(Encoding.ASCII.GetBytes(j.ToString())); - } - for (int i = 0; i <= 100; i++) - { - mNumber.Add(Encoding.ASCII.GetBytes(i.ToString("00"))); - } - mMoth.Add(Encoding.ASCII.GetBytes("Jan")); - mMoth.Add(Encoding.ASCII.GetBytes("Feb")); - mMoth.Add(Encoding.ASCII.GetBytes("Mar")); - mMoth.Add(Encoding.ASCII.GetBytes("Apr")); - mMoth.Add(Encoding.ASCII.GetBytes("May")); - mMoth.Add(Encoding.ASCII.GetBytes("Jun")); - mMoth.Add(Encoding.ASCII.GetBytes("Jul")); - mMoth.Add(Encoding.ASCII.GetBytes("Aug")); - mMoth.Add(Encoding.ASCII.GetBytes("Sep")); - mMoth.Add(Encoding.ASCII.GetBytes("Oct")); - mMoth.Add(Encoding.ASCII.GetBytes("Nov")); - mMoth.Add(Encoding.ASCII.GetBytes("Dec")); - } - - private void Init() - { - DATE = GetData(inLine: true); - mUpdateTime = new Timer(delegate - { - DATE = GetData(inLine: true); - }, null, 1000, 1000); - } - - private ArraySegment GetData(bool inLine = false) - { - return GetData(DateTime.Now, inLine); - } - - private ArraySegment GetData(DateTime date, bool inLine = false) - { - date = date.ToUniversalTime(); - int offset13 = 0; - byte[] GTM_BUFFER = new byte[50]; - Encoding.ASCII.GetBytes("Date: ", 0, 6, GTM_BUFFER, 0); - offset13 = 6; - byte[] buffer = GTM_BUFFER; - byte[] sub8 = mWeekBuffers[(int)date.DayOfWeek]; - buffer[offset13] = sub8[0]; - offset13++; - buffer[offset13] = sub8[1]; - offset13++; - buffer[offset13] = sub8[2]; - offset13++; - buffer[offset13] = 44; - offset13++; - buffer[offset13] = _s; - offset13++; - sub8 = mNumber[date.Day]; - buffer[offset13] = sub8[0]; - offset13++; - buffer[offset13] = sub8[1]; - offset13++; - buffer[offset13] = _s; - offset13++; - sub8 = mMoth[date.Month - 1]; - buffer[offset13] = sub8[0]; - offset13++; - buffer[offset13] = sub8[1]; - offset13++; - buffer[offset13] = sub8[2]; - offset13++; - buffer[offset13] = _s; - offset13++; - sub8 = mYears[date.Year - 1970]; - buffer[offset13] = sub8[0]; - offset13++; - buffer[offset13] = sub8[1]; - offset13++; - buffer[offset13] = sub8[2]; - offset13++; - buffer[offset13] = sub8[3]; - offset13++; - buffer[offset13] = _s; - offset13++; - sub8 = mNumber[date.Hour]; - buffer[offset13] = sub8[0]; - offset13++; - buffer[offset13] = sub8[1]; - offset13++; - buffer[offset13] = _1; - offset13++; - sub8 = mNumber[date.Minute]; - buffer[offset13] = sub8[0]; - offset13++; - buffer[offset13] = sub8[1]; - offset13++; - buffer[offset13] = _1; - offset13++; - sub8 = mNumber[date.Second]; - buffer[offset13] = sub8[0]; - offset13++; - buffer[offset13] = sub8[1]; - offset13++; - buffer[offset13] = _s; - offset13++; - sub8 = GMT; - buffer[offset13] = sub8[0]; - offset13++; - buffer[offset13] = sub8[1]; - offset13++; - buffer[offset13] = sub8[2]; - offset13++; - if (inLine) - { - buffer[offset13] = _r; - offset13++; - buffer[offset13] = _n; - offset13++; - } - return new ArraySegment(GTM_BUFFER, 0, offset13); - } - } - -} diff --git a/frameworks/CSharp/zysocket-v/PlatformBenchmarks/HttpHandler.cs b/frameworks/CSharp/zysocket-v/PlatformBenchmarks/HttpHandler.cs deleted file mode 100644 index e0e11b7f93d..00000000000 --- a/frameworks/CSharp/zysocket-v/PlatformBenchmarks/HttpHandler.cs +++ /dev/null @@ -1,200 +0,0 @@ -using System; -using System.Buffers; -using System.Text; -using System.Threading.Tasks; -using ZYSocket; -using ZYSocket.FiberStream; - -namespace PlatformBenchmarks -{ - public partial class HttpHandler - { - private static AsciiString _line = new AsciiString("\r\n"); - - private static AsciiString _2line = new AsciiString("\r\n\r\n"); - - private static AsciiString _httpsuccess = new AsciiString("HTTP/1.1 200 OK\r\n"); - - private static readonly AsciiString _headerServer = "Server: zysocket\r\n"; - - private static readonly AsciiString _headerContentLength = "Content-Length: "; - - private static readonly AsciiString _headerContentLengthZero = "Content-Length: 0\r\n"; - - private static readonly AsciiString _headerContentTypeText = "Content-Type: text/plain\r\n"; - - private static readonly AsciiString _headerContentTypeHtml = "Content-Type: text/html; charset=UTF-8\r\n"; - - private static readonly AsciiString _headerContentTypeJson = "Content-Type: application/json\r\n"; - - private static readonly AsciiString _path_Json = "/json"; - - private static readonly AsciiString _path_Db = "/db"; - - private static readonly AsciiString _path_Queries = "/queries"; - - private static readonly AsciiString _path_Plaintext = "/plaintext"; - - private static readonly AsciiString _path_Fortunes = "/fortunes"; - - private static readonly AsciiString _result_plaintext = "Hello, World!"; - - private static readonly byte[] LenData = new byte[10] { 32, 32, 32, 32, 32, 32, 32, 32, 32, 32 }; - - private static byte _Space = 32; - - private static byte _question = 63; - - - public HttpHandler() - { - - } - - public void Default(IFiberRw fiberRw,ref WriteBytes write) - { - write.Write(" zysocket server
"); - write.Write($"error not found!"); - - var length = write.Stream.Length - fiberRw.UserToken.HttpHandlerPostion; - write.Stream.Position = fiberRw.UserToken.ContentPostion.postion; - write.Write(length.ToString(), false); - write.Flush(); - } - - private async Task OnCompleted(IFiberRw fiberRw, WriteBytes write) - { - Task WSend() - { - var length = write.Stream.Length - fiberRw.UserToken.HttpHandlerPostion; - write.Stream.Position = fiberRw.UserToken.ContentPostion.postion; - write.Write(length.ToString(), false); - write.Flush(false); - return fiberRw.Flush(); - } - - if (fiberRw.UserToken != null) - await await fiberRw.Sync.Ask(WSend); - } - - private int AnalysisUrl(ReadOnlySpan url) - { - for (int i = 0; i < url.Length; i++) - { - if (url[i] == _question) - return i; - } - return -1; - - } - - public async Task Receive(IFiberRw fiberRw, Memory memory_r, WriteBytes write) - { - var data = (await fiberRw.ReadLine(memory_r)); - ReadHander(fiberRw,ref data,ref write); - fiberRw.StreamReadFormat.Position = fiberRw.StreamReadFormat.Length; - } - - - private void ReadHander(IFiberRw fiberRw,ref Memory linedata,ref WriteBytes write) - { - - var token = fiberRw.UserToken; - ReadOnlySpan line = linedata.Span; - ReadOnlySpan url = line; - - int offset2 = 0; - int count = 0; - for (int i = 0; i < line.Length; i++) - { - if (line[i] == _Space) - { - if (count != 0) - { - url = line.Slice(offset2, i - offset2); - break; - } - offset2 = i + 1; - count++; - } - } - - - int queryIndex = AnalysisUrl(url); - ReadOnlySpan queryString = default; - ReadOnlySpan baseUrl; - if (queryIndex > 0) - { - baseUrl = url.Slice(0, queryIndex); - queryString = url.Slice(queryIndex + 1, url.Length - queryIndex - 1); - } - else - { - baseUrl = url; - } - OnWriteHeader(ref write); - - if (baseUrl.Length == _path_Plaintext.Length && baseUrl.StartsWith(_path_Plaintext)) - { - write.Write(_headerContentTypeText.Data, 0, _headerContentTypeText.Length); - OnWriteContentLength(write, token); - Plaintext(fiberRw, write); - } - else if (baseUrl.Length == _path_Json.Length && baseUrl.StartsWith(_path_Json)) - { - write.Write(_headerContentTypeJson.Data, 0, _headerContentTypeJson.Length); - OnWriteContentLength(write, token); - Json(fiberRw, write); - } - else if (baseUrl.Length == _path_Db.Length && baseUrl.StartsWith(_path_Db)) - { - write.Write(_headerContentTypeJson.Data, 0, _headerContentTypeJson.Length); - OnWriteContentLength(write, token); - db(fiberRw, write); - } - else if (baseUrl.Length == _path_Queries.Length && baseUrl.StartsWith(_path_Queries)) - { - write.Write(_headerContentTypeJson.Data, 0, _headerContentTypeJson.Length); - OnWriteContentLength(write, token); - queries(Encoding.ASCII.GetString(queryString),fiberRw, write); - } - else if (baseUrl.Length == _path_Fortunes.Length && baseUrl.StartsWith(_path_Fortunes)) - { - write.Write(_headerContentTypeHtml.Data, 0, _headerContentTypeHtml.Length); - OnWriteContentLength(write, token); - fortunes(fiberRw, write); - } - else - { - write.Write(_headerContentTypeHtml.Data, 0, _headerContentTypeHtml.Length); - OnWriteContentLength(write, token); - Default( fiberRw, ref write); - } - - } - - - private void OnWriteHeader(ref WriteBytes write) - { - write.Write(_httpsuccess.Data, 0, _httpsuccess.Length); - write.Write(_headerServer.Data, 0, _headerServer.Length); - ArraySegment date = GMTDate.Default.DATE; - write.Write(date.Array, date.Offset, date.Count); - } - - - - private void OnWriteContentLength(WriteBytes write, HttpToken token) - { - write.Write(_headerContentLength.Data, 0, _headerContentLength.Length); - token.ContentPostion = write.Allocate(LenData); - write.Write(_2line, 0, 4); - token.HttpHandlerPostion = (int)write.Stream.Position; - } - - - - - - } -} diff --git a/frameworks/CSharp/zysocket-v/PlatformBenchmarks/HttpToken.cs b/frameworks/CSharp/zysocket-v/PlatformBenchmarks/HttpToken.cs deleted file mode 100644 index a1dff0166e6..00000000000 --- a/frameworks/CSharp/zysocket-v/PlatformBenchmarks/HttpToken.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace PlatformBenchmarks -{ - public class HttpToken - { - public (int postion, int size) ContentPostion { get; set; } - public long HttpHandlerPostion { get; set; } - public RawDb Db { get; set; } - } -} diff --git a/frameworks/CSharp/zysocket-v/PlatformBenchmarks/JsonMessage.cs b/frameworks/CSharp/zysocket-v/PlatformBenchmarks/JsonMessage.cs deleted file mode 100644 index 5a2e3b27c8e..00000000000 --- a/frameworks/CSharp/zysocket-v/PlatformBenchmarks/JsonMessage.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace PlatformBenchmarks -{ - public struct JsonMessage - { - public string message - { - get; - set; - } - } -} diff --git a/frameworks/CSharp/zysocket-v/PlatformBenchmarks/PlatformBenchmarks.csproj b/frameworks/CSharp/zysocket-v/PlatformBenchmarks/PlatformBenchmarks.csproj deleted file mode 100644 index 90f99f0507b..00000000000 --- a/frameworks/CSharp/zysocket-v/PlatformBenchmarks/PlatformBenchmarks.csproj +++ /dev/null @@ -1,17 +0,0 @@ - - - - Exe - netcoreapp3.0 - 8.0 - true - - - - - - - - - - diff --git a/frameworks/CSharp/zysocket-v/PlatformBenchmarks/Program.cs b/frameworks/CSharp/zysocket-v/PlatformBenchmarks/Program.cs deleted file mode 100644 index 3ca384da857..00000000000 --- a/frameworks/CSharp/zysocket-v/PlatformBenchmarks/Program.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using System; - -namespace PlatformBenchmarks -{ - class Program - { - public static void Main(string[] args) - { - new HostBuilder().ConfigureServices(delegate (HostBuilderContext hostContext, IServiceCollection services) - { - services.AddHostedService(); - - }).Build().Run(); - - } - } -} diff --git a/frameworks/CSharp/zysocket-v/PlatformBenchmarks/Properties/PublishProfiles/FolderProfile.pubxml b/frameworks/CSharp/zysocket-v/PlatformBenchmarks/Properties/PublishProfiles/FolderProfile.pubxml deleted file mode 100644 index d0d006df42c..00000000000 --- a/frameworks/CSharp/zysocket-v/PlatformBenchmarks/Properties/PublishProfiles/FolderProfile.pubxml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - FileSystem - Release - Any CPU - net5.0 - bin\Release\netcoreapp2.2\publish\ - - \ No newline at end of file diff --git a/frameworks/CSharp/zysocket-v/PlatformBenchmarks/World.cs b/frameworks/CSharp/zysocket-v/PlatformBenchmarks/World.cs deleted file mode 100644 index 7a0c4567e27..00000000000 --- a/frameworks/CSharp/zysocket-v/PlatformBenchmarks/World.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Runtime.InteropServices; -using System.Text; - -namespace PlatformBenchmarks -{ - [StructLayout(LayoutKind.Sequential, Size = 8)] - public struct World - { - public int Id { get; set; } - - public int RandomNumber { get; set; } - } -} diff --git a/frameworks/CSharp/zysocket-v/PlatformBenchmarks/ZYHttpServer.cs b/frameworks/CSharp/zysocket-v/PlatformBenchmarks/ZYHttpServer.cs deleted file mode 100644 index ff7fd9ce3cc..00000000000 --- a/frameworks/CSharp/zysocket-v/PlatformBenchmarks/ZYHttpServer.cs +++ /dev/null @@ -1,85 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using ZYSocket; -using ZYSocket.Server; -using ZYSocket.Server.Builder; - -namespace PlatformBenchmarks -{ - public class ZYHttpServer : IHostedService - { - public ISocketServer SocketServer { get; private set; } - public IServiceProvider serviceProvider { get; private set; } - - public HttpHandler @HttpHandler { get; private set; } - - public ZYHttpServer() - { - ArraySegment date = GMTDate.Default.DATE; - var containerBuilder = new ServiceCollection(); - new SockServBuilder(containerBuilder, p => - { - return new ZYSocketSuper(p) - { - BinaryInput = new BinaryInputHandler(BinaryInputHandler), - Connetions = new ConnectionFilter(ConnectionFilter), - MessageInput = new DisconnectHandler(DisconnectHandler) - }; - }) - .ConfigServer(p => - { - p.Port = 8080; - p.MaxBufferSize = 1024; - p.MaxConnectCout = 20000; - }); - - serviceProvider = containerBuilder.BuildServiceProvider(); - SocketServer = serviceProvider.GetRequiredService(); - @HttpHandler = new HttpHandler(); - } - - - public Task StartAsync(CancellationToken cancellationToken) - { - SocketServer.Start(); - return Task.CompletedTask; - } - - public Task StopAsync(CancellationToken cancellationToken) - { - SocketServer.Stop(); - return Task.CompletedTask; - } - - bool ConnectionFilter(ISockAsyncEvent socketAsync) => true; - - void DisconnectHandler(string message, ISockAsyncEvent socketAsync, int erorr) - { - socketAsync.UserToken = null; - socketAsync.AcceptSocket.Dispose(); - } - - - async void BinaryInputHandler(ISockAsyncEvent socketAsync) - { - var fiberRw = await socketAsync.GetFiberRw(); - fiberRw.UserToken = new HttpToken - { - Db = new RawDb(new ConcurrentRandom(), Npgsql.NpgsqlFactory.Instance) - }; - - using var data_r = fiberRw.GetMemory(1024); - using var write = new WriteBytes(fiberRw); - for (; ; ) - { - await HttpHandler.Receive(fiberRw, data_r.Memory, write); - } - - } - } -} diff --git a/frameworks/CSharp/zysocket-v/PlatformBenchmarks/db.cs b/frameworks/CSharp/zysocket-v/PlatformBenchmarks/db.cs deleted file mode 100644 index 9a2fac87c71..00000000000 --- a/frameworks/CSharp/zysocket-v/PlatformBenchmarks/db.cs +++ /dev/null @@ -1,29 +0,0 @@ - -using Swifter.Json; -using System; -using System.Threading.Tasks; -using ZYSocket; -using ZYSocket.FiberStream; - -namespace PlatformBenchmarks -{ - public partial class HttpHandler - { - - public async void db(IFiberRw fiberRw, WriteBytes write) - { - try - { - var data = await fiberRw.UserToken.Db.LoadSingleQueryRow(); - await JsonFormatter.SerializeObjectAsync(data, write.Stream, System.Text.Encoding.UTF8); - } - catch (Exception e_) - { - write.Write(e_.Message); - } - - await OnCompleted(fiberRw, write); - - } - } -} diff --git a/frameworks/CSharp/zysocket-v/PlatformBenchmarks/fortunes.cs b/frameworks/CSharp/zysocket-v/PlatformBenchmarks/fortunes.cs deleted file mode 100644 index 643ddb541d8..00000000000 --- a/frameworks/CSharp/zysocket-v/PlatformBenchmarks/fortunes.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Threading.Tasks; -using ZYSocket; -using ZYSocket.FiberStream; - -namespace PlatformBenchmarks -{ - public partial class HttpHandler - { - - private readonly static AsciiString _fortunesTableStart = "Fortunes"; - private readonly static AsciiString _fortunesRowStart = ""; - private readonly static AsciiString _fortunesTableEnd = "
idmessage
"; - private readonly static AsciiString _fortunesColumn = ""; - private readonly static AsciiString _fortunesRowEnd = "
"; - - public async void fortunes(IFiberRw fiberRw, WriteBytes write) - { - - - try - { - var data = await fiberRw.UserToken.Db.LoadFortunesRows(); - - Task WSend() - { - write.Write(_fortunesTableStart.Data, 0, _fortunesTableStart.Length); - foreach (var item in data) - { - write.Write(_fortunesRowStart.Data, 0, _fortunesRowStart.Length); - write.Write(item.Id.ToString(CultureInfo.InvariantCulture),false); - write.Write(_fortunesColumn.Data, 0, _fortunesColumn.Length); - write.Write(System.Web.HttpUtility.HtmlEncode(item.Message),false); - write.Write(_fortunesRowEnd.Data, 0, _fortunesRowEnd.Length); - } - write.Write(_fortunesTableEnd.Data, 0, _fortunesTableEnd.Length); - - var length = write.Stream.Length - fiberRw.UserToken.HttpHandlerPostion; - write.Stream.Position = fiberRw.UserToken.ContentPostion.postion; - write.Write(length.ToString(), false); - write.Flush(false); - return fiberRw.Flush(); - } - if (fiberRw.UserToken != null) - await await fiberRw.Sync.Ask(WSend); - } - catch (Exception e_) - { - write.Write(e_.Message); - await OnCompleted(fiberRw, write); - } - - - } - } -} diff --git a/frameworks/CSharp/zysocket-v/PlatformBenchmarks/json.cs b/frameworks/CSharp/zysocket-v/PlatformBenchmarks/json.cs deleted file mode 100644 index ffae41e70b6..00000000000 --- a/frameworks/CSharp/zysocket-v/PlatformBenchmarks/json.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Swifter.Json; -using System; -using System.Threading.Tasks; -using ZYSocket; -using ZYSocket.FiberStream; - -namespace PlatformBenchmarks -{ - public partial class HttpHandler - { - public async void Json(IFiberRw fiberRw,WriteBytes write) - { - JsonMessage jsonMessage = default(JsonMessage); - jsonMessage.message = "Hello, World!"; - JsonFormatter.SerializeObject(jsonMessage,write.Stream,System.Text.Encoding.UTF8); - var length = write.Stream.Length - fiberRw.UserToken.HttpHandlerPostion; - write.Stream.Position = fiberRw.UserToken.ContentPostion.postion; - write.Write(length.ToString(), false); - await write.Flush(); - } - } -} diff --git a/frameworks/CSharp/zysocket-v/PlatformBenchmarks/plaintext.cs b/frameworks/CSharp/zysocket-v/PlatformBenchmarks/plaintext.cs deleted file mode 100644 index 3975047e5b9..00000000000 --- a/frameworks/CSharp/zysocket-v/PlatformBenchmarks/plaintext.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using System.Threading.Tasks; -using ZYSocket; -using ZYSocket.FiberStream; - -namespace PlatformBenchmarks -{ - public partial class HttpHandler - { - public async void Plaintext( IFiberRw fiberRw, WriteBytes write) - { - write.Write(_result_plaintext.Data, 0, _result_plaintext.Length); - var length = write.Stream.Length - fiberRw.UserToken.HttpHandlerPostion; - write.Stream.Position = fiberRw.UserToken.ContentPostion.postion; - write.Write(length.ToString(), false); - await write.Flush(); - } - } -} diff --git a/frameworks/CSharp/zysocket-v/PlatformBenchmarks/queries.cs b/frameworks/CSharp/zysocket-v/PlatformBenchmarks/queries.cs deleted file mode 100644 index 5d6ed0ee6a6..00000000000 --- a/frameworks/CSharp/zysocket-v/PlatformBenchmarks/queries.cs +++ /dev/null @@ -1,41 +0,0 @@ -using Swifter.Json; -using System; -using ZYSocket; -using ZYSocket.FiberStream; - -namespace PlatformBenchmarks -{ - public partial class HttpHandler - { - public async void queries(string queryString, IFiberRw fiberRw, WriteBytes write) - { - int count = 1; - if (!string.IsNullOrEmpty(queryString)) - { - var values = queryString.Split('='); - if (values.Length > 1) - { - if (int.TryParse(values[1], out int size)) - { - count = size; - } - } - } - if (count > 500) - count = 500; - if (count < 1) - count = 1; - try - { - var data = await fiberRw.UserToken.Db.LoadMultipleQueriesRows(count); - - await JsonFormatter.SerializeObjectAsync(data, write.Stream, System.Text.Encoding.UTF8); - } - catch (Exception e_) - { - write.Write(e_.Message); - } - await OnCompleted(fiberRw, write); - } - } -} diff --git a/frameworks/CSharp/zysocket-v/README.md b/frameworks/CSharp/zysocket-v/README.md deleted file mode 100644 index 967311371e7..00000000000 --- a/frameworks/CSharp/zysocket-v/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# [ZYSOCKET-V](https://github.com/luyikk/zysocket-v)(.Net) Benchmarking Test -This includes tests for plaintext, json, db. - -## Infrastructure Software Versions -**Language** - -* C# 7.2 - -**Platforms** - -* .NET Core (Windows and Linux) - -**Web Servers** - -* [ZYSOCKET-V](https://github.com/luyikk/zysocket-v) - -## Paths & Source for Tests - -* [Plaintext](PlatformBenchmarks/Program.cs): "/plaintext" -* [JSON Serialization](PlatformBenchmarks/Program.cs): "/json" -* [Single query](PlatformBenchmarks/Program.cs): "/db" -* [Multiple query](PlatformBenchmarks/Program.cs): "/queries" -* [Fortune](PlatformBenchmarks/Program.cs): "/fortune" diff --git a/frameworks/CSharp/zysocket-v/benchmark_config.json b/frameworks/CSharp/zysocket-v/benchmark_config.json deleted file mode 100644 index d2d83161b68..00000000000 --- a/frameworks/CSharp/zysocket-v/benchmark_config.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "framework": "zysocket-v", - "tests": [ - { - "default": { - "fortune_url": "/fortunes", - "plaintext_url": "/plaintext", - "json_url": "/json", - "db_url": "/db", - "query_url": "/queries?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "Postgres", - "framework": "zysocket-v", - "language": "C#", - "orm": "Raw", - "platform": ".NET", - "flavor": "CoreCLR", - "webserver": "zysocket-v", - "os": "Linux", - "database_os": "Linux", - "display_name": "zysocket-v", - "notes": "", - "versus": "aspcore-mvc" - } - } - ] -} diff --git a/frameworks/CSharp/zysocket-v/config.toml b/frameworks/CSharp/zysocket-v/config.toml deleted file mode 100644 index b21e6a223c6..00000000000 --- a/frameworks/CSharp/zysocket-v/config.toml +++ /dev/null @@ -1,18 +0,0 @@ -[framework] -name = "zysocket-v" - -[main] -urls.plaintext = "/plaintext" -urls.json = "/json" -urls.db = "/db" -urls.query = "/queries?queries=" -urls.fortune = "/fortunes" -approach = "Realistic" -classification = "Fullstack" -database = "Postgres" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = ".NET" -webserver = "zysocket-v" -versus = "aspcore-mvc" diff --git a/frameworks/CSharp/zysocket-v/zysocket-v.dockerfile b/frameworks/CSharp/zysocket-v/zysocket-v.dockerfile deleted file mode 100644 index 9739314dda6..00000000000 --- a/frameworks/CSharp/zysocket-v/zysocket-v.dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM mcr.microsoft.com/dotnet/core/sdk:3.0 AS build -WORKDIR /app -COPY PlatformBenchmarks . -RUN dotnet publish -c Release -o out - -FROM mcr.microsoft.com/dotnet/core/aspnet:3.0 AS runtime -ENV COMPlus_ReadyToRun 0 -WORKDIR /app -COPY --from=build /app/out ./ - -EXPOSE 8080 - -ENTRYPOINT ["dotnet", "PlatformBenchmarks.dll"] diff --git a/frameworks/Clojure/aleph/aleph.dockerfile b/frameworks/Clojure/aleph/aleph.dockerfile index 5b35fe895d2..7f5e9642a2c 100644 --- a/frameworks/Clojure/aleph/aleph.dockerfile +++ b/frameworks/Clojure/aleph/aleph.dockerfile @@ -1,20 +1,14 @@ -FROM clojure:temurin-19-lein +FROM clojure:lein as lein WORKDIR /aleph COPY src src COPY project.clj project.clj RUN lein uberjar -# HTTP server -EXPOSE 8080 -# async-profiler HTTP-server -EXPOSE 8081 -# JMX port -EXPOSE 9999 +FROM amazoncorretto:25 -RUN apt update -y -RUN apt install perl -y +WORKDIR /aleph +COPY --from=lein /aleph/target/hello-aleph-standalone.jar app.jar -CMD ["java", "-server", "-Xms2G", "-Xmx2G", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-Djava.net.preferIPv4Stack=true", "-Dio.netty.leakDetection.level=disabled", "-jar", "target/hello-aleph-standalone.jar"] +EXPOSE 8080 -# To enable JMX and async-profiler -#CMD ["java", "-XX:+UnlockDiagnosticVMOptions", "-XX:+DebugNonSafepoints", "-Djdk.attach.allowAttachSelf", "-Dcom.sun.management.jmxremote=true", "-Djava.rmi.server.hostname=0.0.0.0","-Dcom.sun.management.jmxremote.rmi.port=9999" ,"-Dcom.sun.management.jmxremote.port=9999", "-Dcom.sun.management.jmxremote.ssl=false", "-Dcom.sun.management.jmxremote.authenticate=false", "-server", "-Xms2G", "-Xmx2G", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-Djava.net.preferIPv4Stack=true", "-jar", "target/hello-aleph-standalone.jar"] +CMD ["java", "-server", "--enable-native-access=ALL-UNNAMED", "-XX:+UseParallelGC", "-jar", "app.jar"] diff --git a/frameworks/Clojure/aleph/project.clj b/frameworks/Clojure/aleph/project.clj index b63dc7a0abe..1c20d439829 100644 --- a/frameworks/Clojure/aleph/project.clj +++ b/frameworks/Clojure/aleph/project.clj @@ -1,23 +1,12 @@ (defproject hello "aleph" :description "Aleph benchmarks" - :dependencies [[org.clojure/clojure "1.11.1"] - [aleph "0.6.1"] - [metosin/jsonista "0.3.7"] - [hiccup "1.0.5"] - [com.github.arnaudgeiser/porsas "0.0.1-alpha14" - :exclusions [io.netty/netty-codec-dns - io.netty/netty-codec - io.netty/netty-buffer - io.netty/netty-common - io.netty/netty-codec-http - io.netty/netty-codec-http2 - io.netty/netty-codec-socks - io.netty/netty-handler - io.netty/netty-handler-proxy - io.netty/netty-transport - io.netty/netty-resolver-dns - io.netty/netty-resolver]] - [com.clojure-goes-fast/clj-async-profiler "1.0.3"]] + :dependencies [[org.clojure/clojure "1.12.3"] + [aleph "0.9.3"] + [metosin/jsonista "0.3.13"] + [hiccup "2.0.0"] + [seancorfield/next.jdbc "1.2.659"] + [hikari-cp "3.3.0"] + [org.postgresql/postgresql "42.7.8"] + ] :main hello.handler - :jvm-opts ^:replace ["-Dclojure.compiler.direct-linking=true"] :aot :all) diff --git a/frameworks/Clojure/aleph/src/hello/handler.clj b/frameworks/Clojure/aleph/src/hello/handler.clj index 2130bae1136..758f5e8c98d 100644 --- a/frameworks/Clojure/aleph/src/hello/handler.clj +++ b/frameworks/Clojure/aleph/src/hello/handler.clj @@ -1,89 +1,73 @@ (ns hello.handler (:require - [aleph.http :as http] - [aleph.netty :as netty] - [byte-streams :as bs] - [clj-async-profiler.core :as prof] - [hiccup.page :as hp] - [hiccup.util :as hu] - [jsonista.core :as json] - [manifold.deferred :as d] - [porsas.async :as async]) - (:import (clojure.lang IDeref) - (io.netty.channel ChannelOption) + [aleph.http :as http] + [aleph.netty :as netty] + [hiccup.page :as hp] + [hiccup.util :as hu] + [jsonista.core :as json] + [manifold.deferred :as d] + [next.jdbc :as jdbc] + [next.jdbc.connection :as connection] + [next.jdbc.result-set :as rs]) + + (:import (com.zaxxer.hikari HikariDataSource) (io.netty.buffer PooledByteBufAllocator) - (java.util.function Supplier) - (java.util.concurrent ThreadLocalRandom) - (porsas.async Context)) + (io.netty.channel ChannelOption) + (java.util.concurrent ThreadLocalRandom)) (:gen-class)) +(def jdbc-opts {:builder-fn rs/as-unqualified-maps}) + +(def db-spec + {:jdbcUrl "jdbc:postgresql://tfb-database/hello_world?user=benchmarkdbuser&password=benchmarkdbpass"}) + +(def datasource + (connection/->pool HikariDataSource db-spec)) + (def plaintext-response - {:status 200 + {:status 200 :headers {"Content-Type" "text/plain"} - :body (bs/to-byte-array "Hello, World!")}) + :body (.getBytes "Hello, World!")}) (def json-response - {:status 200 + {:status 200 :headers {"Content-Type" "application/json"}}) (def html-response - {:status 200 + {:status 200 :headers {"Content-Type" "text/html; charset=utf-8"}}) -(def db-spec - {:uri "postgresql://tfb-database:5432/hello_world" - :user "benchmarkdbuser" - :password "benchmarkdbpass" - :size 1}) - -(defmacro thread-local [& body] - `(let [tl# (ThreadLocal/withInitial (reify Supplier (get [_] ~@body)))] - (reify IDeref (deref [_] (.get tl#))))) -(def pool - "PostgreSQL pool of connections (`PgPool`)." - (thread-local (async/pool db-spec))) - -(defn random +(defn- random "Generate a random number between 1 and 10'000." [] (unchecked-inc (.nextInt (ThreadLocalRandom/current) 10000))) -(defn sanitize-queries-param - "Sanitizes the `queries` parameter. Clamps the value between 1 and 500. - Invalid (string) values become 1." +(defn- sanitize-queries-param [request] (let [queries (-> request :query-string (subs 8)) n (try (Integer/parseInt queries) - (catch Exception _ 1))] ; default to 1 on parse failure + (catch Exception _ 1))] ; default to 1 on parse failure (cond (< n 1) 1 (> n 500) 500 :else n))) -(def ^Context - query-mapper - "Map each row into a record." - (async/context {:row (async/rs->compiled-record)})) -(defn query-one-random-world - "Query a random world on the database. - Return a `CompletableFuture`." - [] - (async/query-one query-mapper - @pool - ["SELECT id, randomnumber FROM world WHERE id=$1" (random)])) - -(defn update-world - "Update a world on the database. - Return a `CompletableFuture`." - [{:keys [randomNumber id]}] - (async/query @pool - ["UPDATE world SET randomnumber=$1 WHERE id=$2" randomNumber id])) - -(defn run-queries +(defn- query-one-random-world [] + (jdbc/execute-one! datasource + ["select * from \"World\" where id = ?;" (random)] + jdbc-opts)) + +(defn- update-world + [{:keys [randomnumber id]}] + (jdbc/execute-one! datasource + ["update \"World\" set randomNumber = ? where id = ? returning *;" randomnumber id] + jdbc-opts)) + +(defn- run-queries "Run a number of `queries` on the database to fetch a random world. Return a `manifold.deferred`." [queries] @@ -91,13 +75,13 @@ (take queries (repeatedly query-one-random-world)))) -(defn query-fortunes - "Query the fortunes on database. - Return a `CompletableFuture`." - [] - (async/query query-mapper @pool ["SELECT id, message from FORTUNE"])) -(defn get-fortunes +(defn query-fortunes [] + (jdbc/execute! datasource + ["select * from \"Fortune\";"] + jdbc-opts)) + +(defn- get-fortunes "Fetch the full list of Fortunes from the database, sort them by the fortune message text. Return a `CompletableFuture` with the results." @@ -106,35 +90,31 @@ (fn [fortunes] (sort-by :message (conj fortunes - {:id 0 + {:id 0 :message "Additional fortune added at request time."}))))) -(defn update-and-persist - "Fetch a number of `queries` random world from the database. - Compute a new `randomNumber` for each of them a return a `CompletableFuture` - with the updated worlds." - [queries] +(defn- update-and-persist [queries] (d/chain' (run-queries queries) (fn [worlds] - (let [worlds' (mapv #(assoc % :randomNumber (random)) worlds)] + (let [worlds' (mapv #(assoc % :randomnumber (random)) worlds)] (d/chain' (apply d/zip (mapv update-world worlds')) (fn [_] worlds')))))) -(defn fortunes-hiccup +(defn- fortunes-hiccup "Render the given fortunes to simple HTML using Hiccup." [fortunes] (hp/html5 - [:head - [:title "Fortunes"]] - [:body - [:table - [:tr - [:th "id"] - [:th "message"]] - (for [x fortunes] - [:tr - [:td (:id x)] - [:td (hu/escape-html (:message x))]])]])) + [:head + [:title "Fortunes"]] + [:body + [:table + [:tr + [:th "id"] + [:th "message"]] + (for [x fortunes] + [:tr + [:td (:id x)] + [:td (hu/escape-html (:message x))]])]])) (defn handler "Ring handler representing the different tests." @@ -142,47 +122,38 @@ (let [uri (:uri req)] (cond (.equals "/plaintext" uri) plaintext-response - (.equals "/json" uri) (assoc json-response - :body (json/write-value-as-bytes {:message "Hello, World!"})) - (.equals "/db" uri) (-> (query-one-random-world) - (d/chain (fn [world] - (assoc json-response - :body (json/write-value-as-bytes world))))) - (.equals "/queries" uri) (-> (sanitize-queries-param req) - (run-queries) - (d/chain (fn [worlds] - (assoc json-response - :body (json/write-value-as-bytes worlds))))) - (.equals "/fortunes" uri) (d/chain' (get-fortunes) - fortunes-hiccup - (fn [body] - (assoc html-response :body body))) - (.equals "/updates" uri) (-> (sanitize-queries-param req) - (update-and-persist) - (d/chain (fn [worlds] - (assoc json-response - :body (json/write-value-as-bytes worlds))))) - :else {:status 404}))) - -;;; + (.equals "/json" uri) (assoc json-response + :body (json/write-value-as-bytes {:message "Hello, World!"})) + (.equals "/db" uri) (-> (query-one-random-world) + (d/chain (fn [world] + (assoc json-response + :body (json/write-value-as-bytes world))))) + (.equals "/queries" uri) (-> (sanitize-queries-param req) + (run-queries) + (d/chain (fn [worlds] + (assoc json-response + :body (json/write-value-as-bytes worlds))))) + (.equals "/fortunes" uri) (d/chain' (get-fortunes) + fortunes-hiccup + (fn [body] + (assoc html-response :body body))) + (.equals "/updates" uri) (-> (sanitize-queries-param req) + (update-and-persist) + (d/chain (fn [worlds] + (assoc json-response + :body (json/write-value-as-bytes worlds))))) + :else {:body "Not found" + :status 404}))) + (defn -main [& _] (netty/leak-detector-level! :disabled) - (http/start-server handler {:port 8080 - :raw-stream? true - :epoll? true - :executor :none + (println "starting server on port 8080") + (http/start-server handler {:port 8080 + :raw-stream? true + :executor :none :bootstrap-transform (fn [bootstrap] (.option bootstrap ChannelOption/ALLOCATOR PooledByteBufAllocator/DEFAULT) (.childOption bootstrap ChannelOption/ALLOCATOR PooledByteBufAllocator/DEFAULT)) - :pipeline-transform (fn [pipeline] - (.remove pipeline "continue-handler"))}) - ;; Uncomment to enable async-profiler - #_ - (do - (prof/profile-for 60 - #_ - {:transform (fn [s] - (when-not (re-find #"(writev|__libc|epoll_wait|write|__pthread)" s) - s))}) - (prof/serve-files 8081))) + :pipeline-transform (fn [pipeline] + (.remove pipeline "continue-handler"))})) diff --git a/frameworks/Clojure/donkey/donkey.dockerfile b/frameworks/Clojure/donkey/donkey.dockerfile index d93b82c7c10..5afe93e10c3 100644 --- a/frameworks/Clojure/donkey/donkey.dockerfile +++ b/frameworks/Clojure/donkey/donkey.dockerfile @@ -1,10 +1,10 @@ -FROM clojure:openjdk-11-lein-2.9.3 as lein +FROM clojure:lein as lein WORKDIR /donkey COPY src src COPY project.clj project.clj RUN lein uberjar -FROM openjdk:11.0.9.1-jdk-slim +FROM amazoncorretto:25 COPY --from=lein /donkey/target/hello-donkey-standalone.jar app.jar EXPOSE 8080 diff --git a/frameworks/Clojure/donkey/project.clj b/frameworks/Clojure/donkey/project.clj index 00dd3bd84e3..55818a8751a 100644 --- a/frameworks/Clojure/donkey/project.clj +++ b/frameworks/Clojure/donkey/project.clj @@ -1,7 +1,7 @@ (defproject hello "donkey" :description "Donkey Server" - :dependencies [[org.clojure/clojure "1.10.1"] - [com.appsflyer/donkey "0.4.1"]] + :dependencies [[org.clojure/clojure "1.12.3"] + [com.appsflyer/donkey "0.5.2"]] :jvm-opts ^:replace ["-Dclojure.compiler.direct-linking=true"] :main hello.handler :aot :all) diff --git a/frameworks/Clojure/kit/benchmark_config.json b/frameworks/Clojure/kit/benchmark_config.json index f5e13d358bb..21581010726 100755 --- a/frameworks/Clojure/kit/benchmark_config.json +++ b/frameworks/Clojure/kit/benchmark_config.json @@ -25,6 +25,42 @@ "display_name": "Kit", "notes": "", "versus": "None" + }, + "majavat": { + "fortune_url": "/majavat-fortunes", + "port": 8080, + "approach": "Realistic", + "classification": "Platform", + "database": "postgres", + "framework": "None", + "language": "Clojure", + "flavor": "None", + "orm": "Raw", + "platform": "None", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "kit-majavat", + "notes": "", + "versus": "kit" + }, + "hiccup": { + "fortune_url": "/hiccup-fortunes", + "port": 8080, + "approach": "Realistic", + "classification": "Platform", + "database": "postgres", + "framework": "None", + "language": "Clojure", + "flavor": "None", + "orm": "Raw", + "platform": "None", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "kit-hiccup", + "notes": "", + "versus": "kit" } } ] diff --git a/frameworks/Clojure/kit/deps.edn b/frameworks/Clojure/kit/deps.edn index 29ff4d19400..972f7bb3d3f 100644 --- a/frameworks/Clojure/kit/deps.edn +++ b/frameworks/Clojure/kit/deps.edn @@ -1,29 +1,33 @@ {:paths ["src/clj" "resources"] - :deps {org.clojure/clojure {:mvn/version "1.11.1"} + :deps {org.clojure/clojure {:mvn/version "1.12.3"} ;; Routing - metosin/reitit {:mvn/version "0.5.18"} + metosin/reitit {:mvn/version "0.9.1"} ;; Ring - metosin/ring-http-response {:mvn/version "0.9.3"} - ring/ring-core {:mvn/version "1.9.5"} + metosin/ring-http-response {:mvn/version "0.9.5"} + ring/ring-core {:mvn/version "1.15.3"} ;; Data coercion - metosin/muuntaja {:mvn/version "0.6.8"} + metosin/muuntaja {:mvn/version "0.6.11"} ;; HTML templating - selmer/selmer {:mvn/version "1.12.55"} + selmer/selmer {:mvn/version "1.12.62"} + org.clojars.jj/majavat {:mvn/version "1.12.3"} + hiccup/hiccup {:mvn/version "2.0.0"} ;; Database - org.postgresql/postgresql {:mvn/version "42.5.1"} + org.postgresql/postgresql {:mvn/version "42.7.8"} + org.clojars.jj/boa-sql {:mvn/version "1.0.0"} + ;; kit Libs - io.github.kit-clj/kit-core {:mvn/version "1.0.3"} - io.github.kit-clj/kit-undertow {:mvn/version "1.0.4"} - io.github.kit-clj/kit-sql-hikari {:mvn/version "1.0.2"} - org.clojure/core.cache {:mvn/version "1.0.225"} + io.github.kit-clj/kit-core {:mvn/version "1.0.9"} + io.github.kit-clj/kit-undertow {:mvn/version "1.0.9"} + io.github.kit-clj/kit-sql-hikari {:mvn/version "1.0.6"} + org.clojure/core.cache {:mvn/version "1.1.234"} } diff --git a/frameworks/Clojure/kit/kit-hiccup.dockerfile b/frameworks/Clojure/kit/kit-hiccup.dockerfile new file mode 100644 index 00000000000..c4b1990a3f8 --- /dev/null +++ b/frameworks/Clojure/kit/kit-hiccup.dockerfile @@ -0,0 +1,19 @@ +# syntax = docker/dockerfile:1.2 +FROM clojure:openjdk-17 AS build + +WORKDIR / +COPY . / + +RUN clj -Sforce -T:build all + +FROM amazoncorretto:25 + +COPY --from=build /target/te-bench-standalone.jar /te-bench/te-bench-standalone.jar + +EXPOSE 8080 + +ENV PORT=8080 +ENV JAVA_OPTS="-XX:+UseContainerSupport -Dfile.encoding=UTF-8" +ENV JDBC_URL="jdbc:postgresql://tfb-database/hello_world?user=benchmarkdbuser&password=benchmarkdbpass" + +ENTRYPOINT exec java $JAVA_OPTS -jar /te-bench/te-bench-standalone.jar diff --git a/frameworks/Clojure/kit/kit-majavat.dockerfile b/frameworks/Clojure/kit/kit-majavat.dockerfile new file mode 100644 index 00000000000..c4b1990a3f8 --- /dev/null +++ b/frameworks/Clojure/kit/kit-majavat.dockerfile @@ -0,0 +1,19 @@ +# syntax = docker/dockerfile:1.2 +FROM clojure:openjdk-17 AS build + +WORKDIR / +COPY . / + +RUN clj -Sforce -T:build all + +FROM amazoncorretto:25 + +COPY --from=build /target/te-bench-standalone.jar /te-bench/te-bench-standalone.jar + +EXPOSE 8080 + +ENV PORT=8080 +ENV JAVA_OPTS="-XX:+UseContainerSupport -Dfile.encoding=UTF-8" +ENV JDBC_URL="jdbc:postgresql://tfb-database/hello_world?user=benchmarkdbuser&password=benchmarkdbpass" + +ENTRYPOINT exec java $JAVA_OPTS -jar /te-bench/te-bench-standalone.jar diff --git a/frameworks/Clojure/kit/kit.dockerfile b/frameworks/Clojure/kit/kit.dockerfile index 55b27b6f122..c4b1990a3f8 100644 --- a/frameworks/Clojure/kit/kit.dockerfile +++ b/frameworks/Clojure/kit/kit.dockerfile @@ -6,7 +6,7 @@ COPY . / RUN clj -Sforce -T:build all -FROM azul/zulu-openjdk-alpine:17 +FROM amazoncorretto:25 COPY --from=build /target/te-bench-standalone.jar /te-bench/te-bench-standalone.jar diff --git a/frameworks/Clojure/kit/resources/sql/fortunes.sql b/frameworks/Clojure/kit/resources/sql/fortunes.sql new file mode 100644 index 00000000000..2fff964d0f4 --- /dev/null +++ b/frameworks/Clojure/kit/resources/sql/fortunes.sql @@ -0,0 +1 @@ +select * from "Fortune"; \ 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 872d2d31334..fe893e40441 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 @@ -17,11 +17,10 @@ ;; log uncaught exceptions in threads (Thread/setDefaultUncaughtExceptionHandler - (reify Thread$UncaughtExceptionHandler - (uncaughtException [_ thread ex] - (log/error {:what :uncaught-exception - :exception ex - :where (str "Uncaught exception on" (.getName thread))})))) + (fn [thread ex] + (log/error {:what :uncaught-exception + :exception ex + :where (str "Uncaught exception on" (.getName thread))}))) (defonce system (atom nil)) diff --git a/frameworks/Clojure/kit/src/clj/io/github/kit_clj/te_bench/db/sql/hikari.clj b/frameworks/Clojure/kit/src/clj/io/github/kit_clj/te_bench/db/sql/hikari.clj index 7fd502127cf..f37b2f526f8 100644 --- a/frameworks/Clojure/kit/src/clj/io/github/kit_clj/te_bench/db/sql/hikari.clj +++ b/frameworks/Clojure/kit/src/clj/io/github/kit_clj/te_bench/db/sql/hikari.clj @@ -5,5 +5,4 @@ (defmethod ig/prep-key :db.sql/hikari-connection [_ config] - (let [cpus (.availableProcessors (Runtime/getRuntime))] - (assoc config :maximum-pool-size (* 8 cpus)))) + (assoc config :maximum-pool-size 520)) 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 71cda1008ec..c02f3621c49 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 @@ -3,6 +3,12 @@ [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.renderer :refer [->StringRenderer]] + [jj.majavat.renderer.sanitizer :refer [->Html]] [ring.util.http-response :as http-response] [selmer.parser :as parser])) @@ -13,15 +19,44 @@ (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)})})) + +(defn render-hiccup-fortune [fortunes] + (hp/html5 + [:head + [:title "Fortunes"]] + [:body + [:table + [:tr + [:th "id"] + [:th "message"]] + (for [x fortunes] + [:tr + [:td (:id x)] + [:td (hu/escape-html (:message x))]])]])) + +(def query-fortunes (boa/execute (boa/->NextJdbcAdapter) "sql/fortunes.sql")) (def selmer-opts {:custom-resource-path (clojure.java.io/resource "html")}) -(defn html-response +(defn selmer-html-response [template & [params]] (-> (parser/render-file template params selmer-opts) (http-response/ok) (http-response/content-type "text/html; charset=utf-8"))) +(defn majavat-html-response + [context] + (-> (render-fortune context) + (http-response/ok) + (http-response/content-type "text/html; charset=utf-8"))) + +(defn hiccup-html-response + [body] + (-> (http-response/ok body) + (http-response/content-type "text/html; charset=utf-8"))) + (defn rand-id [n] (inc (rand-int n))) @@ -31,7 +66,7 @@ "Parse provided string value of query count, clamping values to between 1 and 500." [^String queries] (let [n (try (Integer/parseInt queries) - (catch Exception _ 1))] ; default to 1 on parse failure + (catch Exception _ 1))] ; default to 1 on parse failure (cond (< n 1) 1 (> n 500) 500 @@ -101,7 +136,7 @@ (defn update-db-handler [db-conn request] - (let [items (db-multi-query-world! db-conn request)] + (let [items (db-multi-query-world! db-conn request)] (http-response/ok (mapv (fn [{:keys [id]}] @@ -122,9 +157,24 @@ [] (range-from-req request)))) -(defn fortune-handler +(defn selmer-fortune-handler [db-conn _request] (as-> (jdbc/execute! db-conn ["select * from \"Fortune\";"] jdbc-opts) fortunes (conj fortunes {:id 0 :message "Additional fortune added at request time."}) (sort-by :message fortunes) - (html-response "fortunes.html" {:messages fortunes}))) \ No newline at end of file + (selmer-html-response "fortunes.html" {:messages fortunes}))) + +(defn majavat-fortune-handler + [db-conn _request] + (as-> (query-fortunes db-conn) fortunes + (conj fortunes {:id 0 :message "Additional fortune added at request time."}) + (sort-by :message fortunes) + (majavat-html-response {:messages fortunes}))) + +(defn hiccup-fortune-handler + [db-conn _request] + (as-> (query-fortunes db-conn) fortunes + (conj fortunes {:id 0 :message "Additional fortune added at request time."}) + (sort-by :message fortunes) + (render-hiccup-fortune fortunes) + (hiccup-html-response fortunes))) diff --git a/frameworks/Clojure/kit/src/clj/io/github/kit_clj/te_bench/web/routes/bench.clj b/frameworks/Clojure/kit/src/clj/io/github/kit_clj/te_bench/web/routes/bench.clj index 2b81a381c86..070fa899c17 100644 --- a/frameworks/Clojure/kit/src/clj/io/github/kit_clj/te_bench/web/routes/bench.clj +++ b/frameworks/Clojure/kit/src/clj/io/github/kit_clj/te_bench/web/routes/bench.clj @@ -17,7 +17,10 @@ ["/queries" {:get (partial bench/multi-db-handler db-conn)}] ["/updates" {:get (partial bench/update-db-handler db-conn)}] ["/cached-queries" {:get (partial bench/cached-query-handler db-conn cache)}] - ["/fortunes" {:get (partial bench/fortune-handler db-conn)}]]) + ["/fortunes" {:get (partial bench/selmer-fortune-handler db-conn)}] + ["/majavat-fortunes" {:get (partial bench/majavat-fortune-handler db-conn)}] + ["/hiccup-fortunes" {:get (partial bench/hiccup-fortune-handler db-conn)}] + ]) (defmethod ig/init-key :reitit.routes/bench [_ {:keys [base-path] @@ -25,10 +28,7 @@ :as opts}] [base-path {:muuntaja formats/instance - :middleware [;; query-params & form-params - parameters/parameters-middleware - ;; encoding response body + :middleware [parameters/parameters-middleware muuntaja/format-response-middleware - ;; default header middleware default-headers/default-headers-middleware]} (bench-routes opts)]) diff --git a/frameworks/Clojure/luminus/luminus.dockerfile b/frameworks/Clojure/luminus/luminus.dockerfile index ff837b7cc0a..9ea8a1607ac 100644 --- a/frameworks/Clojure/luminus/luminus.dockerfile +++ b/frameworks/Clojure/luminus/luminus.dockerfile @@ -1,13 +1,15 @@ -FROM clojure:lein-2.8.1 +FROM clojure:lein as lein WORKDIR /luminus COPY env env +COPY project.clj project.clj COPY resources resources COPY src src -COPY test test -COPY Procfile Procfile -COPY project.clj project.clj RUN lein uberjar -EXPOSE 3000 +FROM amazoncorretto:25 +WORKDIR /luminus +COPY --from=lein /luminus/target/hello.jar app.jar + +EXPOSE 8080 -CMD ["java", "-server", "-jar", "target/hello.jar"] +CMD ["java", "-server", "-XX:+UseParallelGC", "-jar", "app.jar"] diff --git a/frameworks/Clojure/luminus/project.clj b/frameworks/Clojure/luminus/project.clj index 42857020495..ade881af545 100644 --- a/frameworks/Clojure/luminus/project.clj +++ b/frameworks/Clojure/luminus/project.clj @@ -3,32 +3,21 @@ :description "TechEmpower Luminus benchmark" :url "https://github.com/TechEmpower/FrameworkBenchmarks" - :dependencies [[org.clojure/clojure "1.10.0"] - [cheshire "5.7.0"] - [selmer "1.10.7"] - [markdown-clj "0.9.98"] - [metosin/muuntaja "0.2.1"] - [metosin/ring-http-response "0.8.2"] - [bouncer "1.0.1"] - [org.webjars/bootstrap "4.2.1"] - [org.webjars/font-awesome "5.6.1"] - [org.webjars.bower/tether "1.4.4"] - [org.webjars/jquery "3.3.1"] - [org.clojure/tools.logging "0.4.1"] - [com.taoensso/tower "3.0.2"] - [compojure "1.5.2"] - [ring-webjars "0.1.1"] - [ring/ring-defaults "0.2.3"] - [mount "0.1.11"] - [cprop "0.1.10"] - [org.clojure/tools.cli "0.3.5"] - [luminus-nrepl "0.1.4"] - [org.webjars/webjars-locator-jboss-vfs "0.1.0"] - [luminus-immutant "0.2.3"] - [luminus-migrations "0.3.0"] - [conman "0.6.3"] - [org.postgresql/postgresql "42.2.5"] - [luminus-log4j "0.1.5"]] + :dependencies [[org.clojure/clojure "1.12.3"] + [cheshire "6.1.0"] + [selmer "1.12.67"] + [metosin/ring-http-response "0.9.5"] + [org.webjars/bootstrap "5.3.8"] + [org.clojure/tools.logging "1.3.0"] + [compojure "1.7.2"] + [mount "0.1.23"] + [cprop "0.1.21"] + [org.clojure/tools.cli "1.2.245"] + [luminus-immutant "0.2.5"] + [luminus-migrations "0.7.5"] + [conman "0.9.6"] + [org.postgresql/postgresql "42.7.8"] + [luminus-log4j "0.1.7"]] :min-lein-version "2.0.0" @@ -39,8 +28,6 @@ :main hello.core :migratus {:store :database :db ~(get (System/getenv) "DATABASE_URL")} - :plugins [[lein-cprop "1.0.1"] - [migratus-lein "0.2.6"]] :profiles {:uberjar {:omit-source true :jvm-opts ["-D\"clojure.compiler.direct-linking=true\""] diff --git a/frameworks/Clojure/luminus/src/clj/hello/core.clj b/frameworks/Clojure/luminus/src/clj/hello/core.clj index 29db03ce711..67b0ef7072f 100644 --- a/frameworks/Clojure/luminus/src/clj/hello/core.clj +++ b/frameworks/Clojure/luminus/src/clj/hello/core.clj @@ -1,6 +1,5 @@ (ns hello.core (:require [hello.handler :as handler] - [luminus.repl-server :as repl] [luminus.http-server :as http] [hello.config :refer [env]] [clojure.tools.cli :refer [parse-opts]] @@ -28,14 +27,6 @@ :stop (http/stop http-server)) -(mount/defstate repl-server - :start - (when-let [nrepl-port (env :nrepl-port)] - (repl/start {:port nrepl-port})) - :stop - (when repl-server - (repl/stop repl-server))) - (defn stop-app [] (doseq [component (:stopped (mount/stop))] (log/info component "stopped")) diff --git a/frameworks/Clojure/luminus/src/clj/hello/db/core.clj b/frameworks/Clojure/luminus/src/clj/hello/db/core.clj index edf0e08a57d..3af4ed1e35a 100644 --- a/frameworks/Clojure/luminus/src/clj/hello/db/core.clj +++ b/frameworks/Clojure/luminus/src/clj/hello/db/core.clj @@ -1,10 +1,9 @@ (ns hello.db.core (:require - [cheshire.core :refer [generate-string parse-string]] - [clojure.java.jdbc :as jdbc] [conman.core :as conman] [hello.config :refer [env]] - [mount.core :refer [defstate]])) + [mount.core :refer [defstate]]) + (:import (java.sql BatchUpdateException))) (defstate ^:dynamic *db* :start (conman/connect! @@ -53,7 +52,7 @@ (let [w {:id id :randomnumber (unchecked-inc ^long (rand-int 9999))}] (try (update-world! w) - (catch java.sql.BatchUpdateException e + (catch BatchUpdateException e (throw (.getNextException e)))) w)) diff --git a/frameworks/Clojure/luminus/src/clj/hello/handler.clj b/frameworks/Clojure/luminus/src/clj/hello/handler.clj index c5d2559be4f..9588a159e5f 100644 --- a/frameworks/Clojure/luminus/src/clj/hello/handler.clj +++ b/frameworks/Clojure/luminus/src/clj/hello/handler.clj @@ -1,8 +1,8 @@ (ns hello.handler - (:require [compojure.core :refer [routes wrap-routes]] + (:require [compojure.core :refer [routes]] + [compojure.route :as route] [hello.layout :refer [error-page]] - [hello.routes.home :refer [default-routes io-routes]] - [compojure.route :as route])) + [hello.routes.home :refer [default-routes io-routes]])) (def default-handler (routes diff --git a/frameworks/Clojure/luminus/src/clj/hello/layout.clj b/frameworks/Clojure/luminus/src/clj/hello/layout.clj index b65b9fd1f91..2c4ae9008b6 100644 --- a/frameworks/Clojure/luminus/src/clj/hello/layout.clj +++ b/frameworks/Clojure/luminus/src/clj/hello/layout.clj @@ -1,15 +1,9 @@ (ns hello.layout - (:require [selmer.parser :as parser] - [selmer.filters :as filters] - [markdown.core :refer [md-to-html-string]] - [ring.util.http-response :refer [content-type ok]] - [ring.util.anti-forgery :refer [anti-forgery-field]] - [ring.middleware.anti-forgery :refer [*anti-forgery-token*]])) + (:require + [ring.util.http-response :refer [content-type ok]] + [selmer.parser :as parser])) - -(parser/set-resource-path! (clojure.java.io/resource "templates")) -(parser/add-tag! :csrf-field (fn [_ _] (anti-forgery-field))) -(filters/add-filter! :markdown (fn [content] [:safe (md-to-html-string content)])) +(parser/set-resource-path! (clojure.java.io/resource "templates")) (defn render "renders the HTML template located relative to resources/templates" @@ -18,9 +12,7 @@ (ok (parser/render-file template - (assoc params - :page template - :csrf-token *anti-forgery-token*))) + (assoc params :page template))) "text/html; charset=utf-8")) (defn error-page diff --git a/frameworks/Clojure/luminus/src/clj/hello/routes/home.clj b/frameworks/Clojure/luminus/src/clj/hello/routes/home.clj index 92736169fc9..b7ca0e0cdc0 100644 --- a/frameworks/Clojure/luminus/src/clj/hello/routes/home.clj +++ b/frameworks/Clojure/luminus/src/clj/hello/routes/home.clj @@ -1,11 +1,10 @@ (ns hello.routes.home - (:require [hello.layout :as layout] + (:require [cheshire.core :refer [generate-string]] + [compojure.core :refer [GET defroutes]] [hello.db.core :as db] - [compojure.core :refer [defroutes GET]] + [hello.layout :as layout] [ring.util.http-response :as response] - [clojure.java.io :as io] - [ring.util.response :refer [content-type]] - [cheshire.core :refer [generate-string]])) + [ring.util.response :refer [content-type]])) (defn encode-json-response [rsp] (-> rsp diff --git a/frameworks/Clojure/reitit/benchmark_config.json b/frameworks/Clojure/reitit/benchmark_config.json index 713c812c206..e3793e46827 100755 --- a/frameworks/Clojure/reitit/benchmark_config.json +++ b/frameworks/Clojure/reitit/benchmark_config.json @@ -54,7 +54,8 @@ "database_os": "Linux", "display_name": "reitit-async", "notes": "", - "versus": "undertow" + "versus": "undertow", + "tags": ["broken"] } }] } diff --git a/frameworks/Clojure/reitit/project.clj b/frameworks/Clojure/reitit/project.clj index 03baa1441ec..00953515ebc 100644 --- a/frameworks/Clojure/reitit/project.clj +++ b/frameworks/Clojure/reitit/project.clj @@ -1,11 +1,10 @@ (defproject hello "reitit" :description "pohjavirta, reitit, jsonista & porsas" - :dependencies [[org.clojure/clojure "1.10.1"] + :dependencies [[org.clojure/clojure "1.12.3"] [metosin/pohjavirta "0.0.1-alpha5"] [metosin/porsas "0.0.1-alpha13"] - [metosin/jsonista "0.2.5"] - [metosin/reitit "0.3.10"] - [hikari-cp "2.9.0"]] - :jvm-opts ^:replace ["-Dclojure.compiler.direct-linking=true"] + [metosin/jsonista "0.3.13"] + [metosin/reitit "0.9.1"] + [hikari-cp "3.3.0"]] :main hello.handler :aot :all) diff --git a/frameworks/Clojure/reitit/reitit-async.dockerfile b/frameworks/Clojure/reitit/reitit-async.dockerfile index 74029c7be3d..2d07ee7f7b7 100644 --- a/frameworks/Clojure/reitit/reitit-async.dockerfile +++ b/frameworks/Clojure/reitit/reitit-async.dockerfile @@ -1,9 +1,13 @@ -FROM clojure:openjdk-11-lein-2.9.1 +FROM clojure:lein as lein WORKDIR /reitit -COPY src src COPY project.clj project.clj +COPY src src RUN lein uberjar +FROM amazoncorretto:25 +WORKDIR /reitit +COPY --from=lein /reitit/target/hello-reitit-standalone.jar app.jar + EXPOSE 8080 -CMD ["java", "-server", "-Xms2G", "-Xmx2G", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AggressiveOpts", "-Dvertx.disableMetrics=true", "-Dvertx.threadChecks=false", "-Dvertx.disableContextTimings=true", "-Dvertx.disableTCCL=true", "-XX:+UseStringDeduplication", "-Djava.net.preferIPv4Stack=true", "-jar", "target/hello-reitit-standalone.jar", "async"] +CMD ["java", "-server", "-XX:+UseParallelGC", "-jar", "app.jar", "async"] diff --git a/frameworks/Clojure/reitit/reitit-jdbc.dockerfile b/frameworks/Clojure/reitit/reitit-jdbc.dockerfile index 26998e5abb9..e202481097a 100644 --- a/frameworks/Clojure/reitit/reitit-jdbc.dockerfile +++ b/frameworks/Clojure/reitit/reitit-jdbc.dockerfile @@ -1,9 +1,13 @@ -FROM clojure:openjdk-11-lein-2.9.1 +FROM clojure:lein as lein WORKDIR /reitit -COPY src src COPY project.clj project.clj +COPY src src RUN lein uberjar +FROM amazoncorretto:25 +WORKDIR /reitit +COPY --from=lein /reitit/target/hello-reitit-standalone.jar app.jar + EXPOSE 8080 -CMD ["java", "-server", "-Xms2G", "-Xmx2G", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AggressiveOpts", "-XX:+UseStringDeduplication", "-Djava.net.preferIPv4Stack=true", "-jar", "target/hello-reitit-standalone.jar", "sync"] +CMD ["java", "-server", "-XX:+UseParallelGC", "-jar", "app.jar", "sync"] diff --git a/frameworks/Clojure/reitit/reitit.dockerfile b/frameworks/Clojure/reitit/reitit.dockerfile index d9b45794959..2915a6efd2c 100644 --- a/frameworks/Clojure/reitit/reitit.dockerfile +++ b/frameworks/Clojure/reitit/reitit.dockerfile @@ -1,6 +1,13 @@ -FROM clojure:openjdk-11-lein-2.9.1 +FROM clojure:lein as lein WORKDIR /reitit -COPY src src COPY project.clj project.clj +COPY src src RUN lein uberjar -CMD ["java", "-server", "-Xms2G", "-Xmx2G", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AggressiveOpts", "-Dvertx.disableMetrics=true", "-Dvertx.threadChecks=false", "-Dvertx.disableContextTimings=true", "-Dvertx.disableTCCL=true", "-XX:+UseStringDeduplication", "-Djava.net.preferIPv4Stack=true", "-jar", "target/hello-reitit-standalone.jar"] + +FROM amazoncorretto:25 +WORKDIR /reitit +COPY --from=lein /reitit/target/hello-reitit-standalone.jar app.jar + +EXPOSE 8080 + +CMD ["java", "-server", "-XX:+UseParallelGC", "-jar", "app.jar"] diff --git a/frameworks/Clojure/reitit/src/hello/handler.clj b/frameworks/Clojure/reitit/src/hello/handler.clj index 7075cd4e5b6..97a8d8d1411 100644 --- a/frameworks/Clojure/reitit/src/hello/handler.clj +++ b/frameworks/Clojure/reitit/src/hello/handler.clj @@ -84,7 +84,7 @@ :else (constantly nil))] (-> (ring/ring-handler (ring/router - [["/plaintext" (exchange/constantly plain-text-handler)] + [["/plaintext" plain-text-handler] ["/json" json-handler] ["/db" db-handler]]) (ring/create-default-handler) diff --git a/frameworks/Clojure/ring-http-exchange/README.md b/frameworks/Clojure/ring-http-exchange/README.md new file mode 100755 index 00000000000..66d19f7ef4e --- /dev/null +++ b/frameworks/Clojure/ring-http-exchange/README.md @@ -0,0 +1,17 @@ +# ring-http-exchange Benchmarking Test + +## Test Type Implementation Source Code +* [JSON](src/ring_http_exchange/benchmark.clj) +* [PLAINTEXT](src/ring_http_exchange/benchmark.clj) + +## Important Libraries +The tests were run with: +* [ring-http-exchange](https://github.com/ruroru/ring-http-exchange) +* [jsonista](https://github.com/metosin/jsonista) + +## Test URLs +### JSON +http://localhost:8080/json + +### PLAINTEXT +http://localhost:8080/plaintext diff --git a/frameworks/Clojure/ring-http-exchange/benchmark_config.json b/frameworks/Clojure/ring-http-exchange/benchmark_config.json new file mode 100755 index 00000000000..b0381b921ac --- /dev/null +++ b/frameworks/Clojure/ring-http-exchange/benchmark_config.json @@ -0,0 +1,107 @@ +{ + "framework": "ring-http-exchange", + "tests": [ + { + "default": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "fortune_url": "/fortunes", + "port": 8080, + "approach": "Realistic", + "classification": "Platform", + "database": "postgres", + "framework": "None", + "language": "Clojure", + "flavor": "None", + "orm": "Raw", + "platform": "None", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "ring-http-exchange", + "notes": "", + "versus": "httpserver" + }, + "robaho": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "fortune_url": "/fortunes", + "port": 8080, + "approach": "Realistic", + "classification": "Platform", + "database": "postgres", + "framework": "None", + "language": "Clojure", + "flavor": "None", + "orm": "Raw", + "platform": "None", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "ring-http-exchange-robaho", + "notes": "", + "versus": "httpserver-robaho" + }, + "graalvm": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "fortune_url": "/fortunes", + "port": 8080, + "approach": "Realistic", + "classification": "Platform", + "database": "postgres", + "framework": "None", + "language": "Clojure", + "flavor": "None", + "orm": "Raw", + "platform": "None", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "ring-http-exchange-graalvm", + "notes": "", + "versus": "ring-http-exchange" + }, + "robaho-graalvm": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "fortune_url": "/fortunes", + "port": 8080, + "approach": "Realistic", + "classification": "Platform", + "database": "postgres", + "framework": "None", + "language": "Clojure", + "flavor": "None", + "orm": "Raw", + "platform": "None", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "ring-http-exchange-robaho-graalvm", + "notes": "", + "versus": "ring-http-exchange-robaho" + }, + "robaho-semeru": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "fortune_url": "/fortunes", + "port": 8080, + "approach": "Realistic", + "classification": "Platform", + "database": "postgres", + "framework": "None", + "language": "Clojure", + "flavor": "None", + "orm": "Raw", + "platform": "None", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "ring-http-exchange-robaho-semeru", + "notes": "", + "versus": "ring-http-exchange-robaho" + } + } + ] +} diff --git a/frameworks/Clojure/ring-http-exchange/config.toml b/frameworks/Clojure/ring-http-exchange/config.toml new file mode 100644 index 00000000000..17193d6169a --- /dev/null +++ b/frameworks/Clojure/ring-http-exchange/config.toml @@ -0,0 +1,59 @@ +[framework] +name = "ring-http-exchange" + +[main] +urls.plaintext = "/plaintext" +urls.json = "/json" +urls.fortune = "/fortunes" +approach = "Realistic" +classification = "Platform" +database = "postgres" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "httpserver" +webserver = "None" +versus = "httpserver" + + +[graalvm] +urls.plaintext = "/plaintext" +urls.json = "/json" +urls.fortune = "/fortunes" +approach = "Realistic" +classification = "Platform" +database = "postgres" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "httpserver" +webserver = "None" +versus = "httpserver-graalvm" + +[robaho] +urls.plaintext = "/plaintext" +urls.json = "/json" +urls.fortune = "/fortunes" +approach = "Realistic" +classification = "Platform" +database = "postgres" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "httpserver" +webserver = "None" +versus = "httpserver-robaho" + +[robaho-graalvm] +urls.plaintext = "/plaintext" +urls.json = "/json" +urls.fortune = "/fortunes" +approach = "Realistic" +classification = "Platform" +database = "postgres" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "httpserver" +webserver = "None" +versus = "httpserver-robaho-graalvm" diff --git a/frameworks/Clojure/ring-http-exchange/project.clj b/frameworks/Clojure/ring-http-exchange/project.clj new file mode 100644 index 00000000000..448d887f73e --- /dev/null +++ b/frameworks/Clojure/ring-http-exchange/project.clj @@ -0,0 +1,20 @@ +(defproject ring-http-server "1.0.0" + :description "ring benchmark" + :url "" + :license {:name "EPL-2.0" + :url "https://www.eclipse.org/legal/epl-2.0/"} + + :dependencies [[org.clojure/clojure "1.12.3"] + [org.clojure/tools.logging "1.3.0"] + [org.clojars.jj/ring-http-exchange "1.2.4"] + [seancorfield/next.jdbc "1.2.659"] + [org.clojars.jj/majavat "1.12.3"] + [hikari-cp "3.3.0"] + [org.clojars.jj/boa-sql "1.0.0"] + [org.postgresql/postgresql "42.7.8"] + [metosin/jsonista "0.3.13"] + ] + + :profiles {:robaho {:dependencies [[io.github.robaho/httpserver "1.0.29"]]}} + :resource-paths ["resources"] + :main ring-http-exchange.benchmark) diff --git a/frameworks/Clojure/ring-http-exchange/resources/fortune.html b/frameworks/Clojure/ring-http-exchange/resources/fortune.html new file mode 100644 index 00000000000..3f4dd2fca9e --- /dev/null +++ b/frameworks/Clojure/ring-http-exchange/resources/fortune.html @@ -0,0 +1,15 @@ + + +Fortunes + + + + {% for message in messages %} + + + + + {% endfor %} +
idmessage
{{message.id}}{{message.message}}
+ + \ No newline at end of file diff --git a/frameworks/Clojure/ring-http-exchange/resources/fortune.sql b/frameworks/Clojure/ring-http-exchange/resources/fortune.sql new file mode 100644 index 00000000000..47c21ba2b0e --- /dev/null +++ b/frameworks/Clojure/ring-http-exchange/resources/fortune.sql @@ -0,0 +1 @@ +SELECT * FROM "Fortune"; \ 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 new file mode 100644 index 00000000000..53a3998cd03 --- /dev/null +++ b/frameworks/Clojure/ring-http-exchange/ring-http-exchange-graalvm.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 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:+UseParallelGC", "-jar", "app.jar"] 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 new file mode 100644 index 00000000000..8af31aebae0 --- /dev/null +++ b/frameworks/Clojure/ring-http-exchange/ring-http-exchange-robaho-graalvm.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 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:+UseParallelGC", "-jar", "app.jar"] 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 new file mode 100644 index 00000000000..64f06a3418a --- /dev/null +++ b/frameworks/Clojure/ring-http-exchange/ring-http-exchange-robaho-semeru.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 ibm-semeru-runtimes:open-25-jre-jammy +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", "-jar", "app.jar"] diff --git a/frameworks/Clojure/ring-http-exchange/ring-http-exchange-robaho.dockerfile b/frameworks/Clojure/ring-http-exchange/ring-http-exchange-robaho.dockerfile new file mode 100644 index 00000000000..b53eb194c09 --- /dev/null +++ b/frameworks/Clojure/ring-http-exchange/ring-http-exchange-robaho.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", "-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 new file mode 100644 index 00000000000..0910a6d9850 --- /dev/null +++ b/frameworks/Clojure/ring-http-exchange/ring-http-exchange.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 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", "-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 new file mode 100644 index 00000000000..24063d085e6 --- /dev/null +++ b/frameworks/Clojure/ring-http-exchange/src/ring_http_exchange/benchmark.clj @@ -0,0 +1,72 @@ +(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]) + (:import + (com.zaxxer.hikari HikariDataSource) + (java.util.concurrent Executors))) + +(def query-fortunes (boa/execute (boa/->NextJdbcAdapter) "fortune.sql")) + +(def db-spec {:auto-commit false + :connection-timeout 3000 + :validation-timeout 1000 + :idle-timeout 300000 + :max-lifetime 1800000 + :minimum-idle 128 + :maximum-pool-size 1024 + :register-mbeans false + :jdbcUrl "jdbc:postgresql://tfb-database/hello_world?user=benchmarkdbuser&password=benchmarkdbpass&prepareThreshold=1"}) + +(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 render-fortune (majavat/build-renderer "fortune.html" + {:renderer (->StringRenderer + {:sanitizer (->Html)})})) + + +(defn- plaintext-response [] + {:status 200 + :headers {"Server" "ring-http-exchange" + "Content-Type" "text/plain"} + :body "Hello, World!"}) + +(defn- get-body [datasource] + (let [context (as-> (query-fortunes datasource) fortunes + (conj fortunes additional-message) + (sort-by :message fortunes))] + (render-fortune {:messages context}))) + +(defn -main + [& _] + (System/setProperty "jdk.virtualThreadScheduler.parallelism" + (str (* 4 (.availableProcessors (Runtime/getRuntime))))) + + (println "Starting server on port 8080") + (let [datasource (connection/->pool HikariDataSource db-spec)] + (server/run-http-server + (fn [req] + (case (req :uri) + "/plaintext" (plaintext-response) + "/json" {:status 200 + :headers json-headers + :body (json/write-value-as-bytes {:message "Hello, World!"})} + "/fortunes" (let [body (get-body datasource)] + {:status 200 + :headers fortune-headers + :body body}) + (plaintext-response))) + {:port 8080 + :host "0.0.0.0" + :executor (Executors/newVirtualThreadPerTaskExecutor)}))) \ No newline at end of file diff --git a/frameworks/Crystal/amber/README.md b/frameworks/Crystal/amber/README.md index 470813e8c34..3bb70081119 100644 --- a/frameworks/Crystal/amber/README.md +++ b/frameworks/Crystal/amber/README.md @@ -8,17 +8,12 @@ This is the [Amber](https://amberframework.org) test of the Framework Benchmarks The purpose of Amber is not to create yet another framework, but to take advantage of the beautiful Crystal language capabilities and provide engineers an efficient, cohesive, and well maintain web framework for the crystal community that embraces the language philosophies, conventions, and guides. -Amber Crystal borrows concepts that already have been battle tested, successful, and embrace new concepts through team and community collaboration and analysis, that aligns with Crystal philosophies. +Amber borrows concepts that already have been battle tested, successful, and embrace new concepts through team and community collaboration and analysis, that aligns with Crystal philosophies. -## Contributors +Updated for Amber 1.4.1 and Crystal 1.14.0 -- Dru Jensen [drujensen](https://github.com/drujensen) -- Elias Perez [eliasjpr](https://github.com/eliasjpr) -- Isaac Sloan [elorest](https://github.com/elorest) -- Faustino Aguilar [faustinoaq](https://github.com/faustinoaq) -- Nick Franken [fridgerator](https://github.com/fridgerator) -- Mark Siemers [marksiemers](https://github.com/marksiemers) -- Robert Carpenter [robacarp](https://github.com/robacarp) +## Contributors +- Seth Tucker [crimson-knight](https://github.com/crimson-knight) See more [Amber contributors](https://github.com/amberframework/amber/graphs/contributors) diff --git a/frameworks/Crystal/amber/amber.dockerfile b/frameworks/Crystal/amber/amber.dockerfile index 4acf62ab32c..f04867c3205 100644 --- a/frameworks/Crystal/amber/amber.dockerfile +++ b/frameworks/Crystal/amber/amber.dockerfile @@ -21,7 +21,7 @@ FROM ubuntu:22.04 WORKDIR /amber ENV AMBER_ENV production -ENV DATABASE_URL postgres://benchmarkdbuser:benchmarkdbpass@tfb-database:5432/hello_world?initial_pool_size=10&max_idle_pool_size=10&retry_attempts=3&retry_delay=1 +ENV DATABASE_URL postgres://benchmarkdbuser:benchmarkdbpass@tfb-database:5432/hello_world RUN apt-get update RUN apt-get install -yqq libyaml-dev diff --git a/frameworks/Crystal/amber/config/initializers/database.cr b/frameworks/Crystal/amber/config/initializers/database.cr index 2e94e830821..cf60c82de5a 100644 --- a/frameworks/Crystal/amber/config/initializers/database.cr +++ b/frameworks/Crystal/amber/config/initializers/database.cr @@ -1,3 +1,10 @@ require "granite/adapter/pg" -Granite::Connections << Granite::Adapter::Pg.new(name: "pg", url: ENV["DATABASE_URL"]) +cpu_count = System.cpu_count - 1 # Always leave 1 core for the system +pool_size = cpu_count * 4 # 4x the number of cores, should be plenty of room for concurrency +database_url = ENV["DATABASE_URL"] +url = "#{database_url}?initial_pool_size=#{pool_size}&max_idle_pool_size=#{pool_size}" + +puts url + +Granite::Connections << Granite::Adapter::Pg.new(name: "pg", url: url) diff --git a/frameworks/Crystal/amber/shard.lock b/frameworks/Crystal/amber/shard.lock index 635edcb60c1..4fb6d6ef1e4 100644 --- a/frameworks/Crystal/amber/shard.lock +++ b/frameworks/Crystal/amber/shard.lock @@ -28,10 +28,6 @@ shards: git: https://github.com/crystal-lang/crystal-db.git version: 0.11.0 - dotenv: - git: https://github.com/gdotdesign/cr-dotenv.git - version: 1.0.0 - exception_page: git: https://github.com/crystal-loot/exception_page.git version: 0.3.1 @@ -44,22 +40,10 @@ shards: git: https://github.com/amberframework/granite.git version: 0.23.3 - i18n: - git: https://github.com/crimson-knight/i18n.cr.git - version: 0.4.1 - - ifrit: - git: https://github.com/imdrasil/ifrit.git - version: 0.1.3 - inflector: git: https://github.com/phoffer/inflector.cr.git version: 1.0.0 - jennifer: - git: https://github.com/imdrasil/jennifer.cr.git - version: 0.13.0 - json_mapping: git: https://github.com/crystal-lang/json_mapping.cr.git version: 0.1.1 @@ -74,7 +58,7 @@ shards: micrate: git: https://github.com/amberframework/micrate.git - version: 0.15.0 + version: 0.15.1 mysql: git: https://github.com/crystal-lang/crystal-mysql.git @@ -82,7 +66,7 @@ shards: optarg: git: https://github.com/amberframework/optarg.git - version: 0.9.3 + version: 0.9.5 pg: git: https://github.com/will/crystal-pg.git @@ -96,10 +80,6 @@ shards: git: https://github.com/stefanwille/crystal-redis.git version: 2.8.3 - sam: - git: https://github.com/imdrasil/sam.cr.git - version: 0.5.0 - shell-table: git: https://github.com/luckyframework/shell-table.cr.git version: 0.9.3 @@ -116,10 +96,6 @@ shards: git: https://github.com/amberframework/teeplate.git version: 0.11.2 - wordsmith: - git: https://github.com/luckyframework/wordsmith.git - version: 0.4.0 - yaml_mapping: git: https://github.com/crystal-lang/yaml_mapping.cr.git version: 0.1.1 diff --git a/frameworks/Crystal/amber/shard.yml b/frameworks/Crystal/amber/shard.yml index c48994d4d4e..4b75672f88d 100644 --- a/frameworks/Crystal/amber/shard.yml +++ b/frameworks/Crystal/amber/shard.yml @@ -15,26 +15,10 @@ dependencies: github: amberframework/amber version: 1.4.1 - jennifer: - github: imdrasil/jennifer.cr - version: "~> 0.13.0" - - sam: - github: imdrasil/sam.cr - version: 0.5.0 - pg: github: will/crystal-pg version: "= 0.26.0" - mysql: - github: crystal-lang/crystal-mysql - version: 0.14.0 - - dotenv: - github: gdotdesign/cr-dotenv - version: 1.0.0 - granite: github: amberframework/granite version: 0.23.3 diff --git a/frameworks/Crystal/crystal/crystal-radix.dockerfile b/frameworks/Crystal/crystal/crystal-radix.dockerfile index aaef65c87d9..deda5e21148 100644 --- a/frameworks/Crystal/crystal/crystal-radix.dockerfile +++ b/frameworks/Crystal/crystal/crystal-radix.dockerfile @@ -1,4 +1,4 @@ -FROM crystallang/crystal:1.0.0 +FROM crystallang/crystal:1.12.1 WORKDIR /crystal COPY shard.yml shard.yml diff --git a/frameworks/Crystal/crystal/crystal.dockerfile b/frameworks/Crystal/crystal/crystal.dockerfile index ab51249b129..678dd214cd4 100644 --- a/frameworks/Crystal/crystal/crystal.dockerfile +++ b/frameworks/Crystal/crystal/crystal.dockerfile @@ -1,4 +1,4 @@ -FROM crystallang/crystal:1.0.0 +FROM crystallang/crystal:1.12.1 WORKDIR /crystal COPY shard.yml shard.yml diff --git a/frameworks/Crystal/crystal/shard.yml b/frameworks/Crystal/crystal/shard.yml index 6bea5905b84..dc20f8e0679 100644 --- a/frameworks/Crystal/crystal/shard.yml +++ b/frameworks/Crystal/crystal/shard.yml @@ -7,7 +7,7 @@ crystal: "~> 1.0" dependencies: pg: github: will/crystal-pg - version: ~> 0.23.2 + version: ~> 0.28.0 radix: github: luislavena/radix version: ~> 0.4.1 diff --git a/frameworks/Crystal/grip/benchmark_config.json b/frameworks/Crystal/grip/benchmark_config.json index 56cd319dfc9..fbd828243a3 100644 --- a/frameworks/Crystal/grip/benchmark_config.json +++ b/frameworks/Crystal/grip/benchmark_config.json @@ -23,6 +23,7 @@ "database_os": "Linux", "display_name": "Grip", "notes": "", + "tags": ["broken"], "versus": "None" } } diff --git a/frameworks/Crystal/grip/grip.cr b/frameworks/Crystal/grip/grip.cr index 3a910eebdd3..1b8a64b6667 100644 --- a/frameworks/Crystal/grip/grip.cr +++ b/frameworks/Crystal/grip/grip.cr @@ -121,7 +121,7 @@ end class Application < Grip::Application def initialize - super(environment: "production", serve_static: false) + super(environment: "production") get "/json", Json get "/plaintext", Plaintext diff --git a/frameworks/Crystal/grip/grip.dockerfile b/frameworks/Crystal/grip/grip.dockerfile index 244aa5dbf70..4d98926effb 100644 --- a/frameworks/Crystal/grip/grip.dockerfile +++ b/frameworks/Crystal/grip/grip.dockerfile @@ -1,4 +1,4 @@ -FROM crystallang/crystal:1.0.0 +FROM crystallang/crystal:1.12.1 WORKDIR /grip COPY views views diff --git a/frameworks/Crystal/grip/shard.yml b/frameworks/Crystal/grip/shard.yml index e5500bfe11f..ed1f5ab0a2e 100644 --- a/frameworks/Crystal/grip/shard.yml +++ b/frameworks/Crystal/grip/shard.yml @@ -4,11 +4,11 @@ version: 0.2.0 dependencies: grip: github: grip-framework/grip - version: 2.0.0 + version: 3.0.0 pg: github: will/crystal-pg - version: 0.26.0 + version: 0.28.0 targets: grip: main: grip.cr diff --git a/frameworks/Crystal/h2o.cr/README.md b/frameworks/Crystal/h2o.cr/README.md deleted file mode 100644 index 72d68953ed5..00000000000 --- a/frameworks/Crystal/h2o.cr/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# h2o.cr - -Crystal bindings to h2o - -### notes - -h2o.cr currently only support plaintext and json requests diff --git a/frameworks/Crystal/h2o.cr/benchmark_config.json b/frameworks/Crystal/h2o.cr/benchmark_config.json deleted file mode 100644 index f2446c191b8..00000000000 --- a/frameworks/Crystal/h2o.cr/benchmark_config.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "framework": "h2o.cr", - "tests": [ - { - "default": { - "json_url": "/json", - "plaintext_url": "/plaintext", - "port": 7890, - "approach": "Realistic", - "classification": "Micro", - "database": "None", - "framework": "h2o.cr", - "language": "Crystal", - "flavor": "None", - "orm": "Raw", - "platform": "None", - "webserver": "h2o", - "os": "Linux", - "database_os": "Linux", - "display_name": "crystal-h2o", - "notes": "", - "versus": "None" - } - } - ] -} diff --git a/frameworks/Crystal/h2o.cr/config.toml b/frameworks/Crystal/h2o.cr/config.toml deleted file mode 100644 index 2905fb412bb..00000000000 --- a/frameworks/Crystal/h2o.cr/config.toml +++ /dev/null @@ -1,15 +0,0 @@ -[framework] -name = "h2o.cr" - -[main] -urls.plaintext = "/plaintext" -urls.json = "/json" -approach = "Realistic" -classification = "Micro" -database = "None" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "None" -webserver = "h2o" -versus = "None" diff --git a/frameworks/Crystal/h2o.cr/h2o.cr.dockerfile b/frameworks/Crystal/h2o.cr/h2o.cr.dockerfile deleted file mode 100644 index 690ca6fe783..00000000000 --- a/frameworks/Crystal/h2o.cr/h2o.cr.dockerfile +++ /dev/null @@ -1,24 +0,0 @@ -FROM debian:sid - -RUN apt-get update \ - && apt-get install -yqq libh2o-evloop-dev libwslay-dev libyaml-0-2 libevent-dev libpcre3-dev \ - gcc wget git libssl-dev libuv1-dev ca-certificates --no-install-recommends - -RUN wget -q https://github.com/crystal-lang/crystal/releases/download/0.26.1/crystal-0.26.1-1-linux-x86_64.tar.gz \ - && tar --strip-components=1 -xzf crystal-0.26.1-1-linux-x86_64.tar.gz -C /usr/ \ - && rm -f *.tar.gz - -WORKDIR /crystal - -ENV GC_MARKERS 1 - -COPY ./ ./ - -RUN shards install -RUN gcc -shared -O3 lib/h2o/src/ext/h2o.c -I/usr/include -fPIC -o h2o.o -ENV CRYSTAL_PATH=lib:/usr/share/crystal/src -RUN crystal build --prelude=empty --no-debug --release -Dgc_none -Dfiber_none -Dexcept_none -Dhash_none -Dtime_none -Dregex_none -Dextreme h2o_evloop_hello.cr --link-flags="-Wl,-s $PWD/h2o.o -DH2O_USE_LIBUV=0" -o server.out - -EXPOSE 7890 - -CMD sh run.sh diff --git a/frameworks/Crystal/h2o.cr/h2o_evloop_hello.cr b/frameworks/Crystal/h2o.cr/h2o_evloop_hello.cr deleted file mode 100644 index 558a1ec0ac3..00000000000 --- a/frameworks/Crystal/h2o.cr/h2o_evloop_hello.cr +++ /dev/null @@ -1,114 +0,0 @@ -require "reset/prelude" -require "reset/patches" -require "reset/json" -require "h2o/h2o_evloop" - -class H2oHello < H2o - @config = LibH2o::H2oGlobalconfT.new - @ctx = LibH2o::H2oContextT.new - @accept_ctx = LibH2o::H2oAcceptCtxT.new - @loop : LibH2o::H2oLoopT* - - macro hello - Handler.new do |handler, req| - generator = uninitialized LibH2o::H2oGeneratorT[2] - body = h2o_iovec_init("Hello, World!") - req.value.res.status = 200 - req.value.res.reason = "OK" - req.value.res.content_length = body.len - - # require h2o.c extension - h2o_add_header(req, H2O_TOKEN_CONTENT_TYPE, "text/plain") - h2o_start_response(req, generator) - h2o_send(req, pointerof(body), 1, LibH2o::H2oSendState::H2OSendStateFinal) - 0 - end - end - - macro json - Handler.new do |handler, req| - generator = uninitialized LibH2o::H2oGeneratorT[2] - alloc = uninitialized UInt8[32] - buf = StackBuffer.new(alloc.to_unsafe) - - len = {message: "Hello, World!"}.to_json(buf) - body = LibH2o::H2oIovecT.new(base: buf, len: len) - - req.value.res.status = 200 - req.value.res.reason = "OK" - req.value.res.content_length = body.len - - h2o_add_header(req, H2O_TOKEN_CONTENT_TYPE, "application/json") - h2o_start_response(req, generator) - h2o_send(req, pointerof(body), 1, LibH2o::H2oSendState::H2OSendStateFinal) - 0 - end - end - - def on_accept(listener : LibH2o::H2oSocketT*, err : LibC::Char*) : Void - return if err - return unless s = h2o_evloop_socket_accept(listener) - h2o_accept(pointerof(@accept_ctx), s) - end - - def create_listener : Int32 - addr = uninitialized LibC::SockaddrIn - - pointerof(addr).clear - addr.sin_family = LibC::AF_INET - addr.sin_addr.s_addr = 0 # 0x100007f # b32(0x7f000001) - addr.sin_port = 0xd21e # b16(7890) - - option = 1 - if (fd = socket(LibC::AF_INET, LibC::SOCK_STREAM | LibC::O_NONBLOCK | LibC::O_CLOEXEC, 0)) == -1 || - setsockopt(fd, LibC::SOL_SOCKET, LibC::SO_REUSEADDR, pointerof(option), 4) != 0 || - setsockopt(fd, LibC::SOL_SOCKET, LibC::SO_REUSEPORT, pointerof(option), 4) != 0 || - setsockopt(fd, LibC::IPPROTO_TCP, LibC::TCP_QUICKACK, pointerof(option), 4) != 0 || - ((option = H2O_DEFAULT_HANDSHAKE_TIMEOUT_IN_SECS) && - setsockopt(fd, LibC::IPPROTO_TCP, LibC::TCP_DEFER_ACCEPT, pointerof(option), 4) != 0) || - ((option = DEFAULT_TCP_FASTOPEN_QUEUE_LEN) && - setsockopt(fd, LibC::IPPROTO_TCP, LibC::TCP_FASTOPEN, pointerof(option), 4) != 0) || - bind(fd, pointerof(addr).as(LibC::Sockaddr*), sizeof(LibC::SockaddrIn)) != 0 || - listen(fd, LibC::SOMAXCONN) != 0 - return -1 - end - - sock = h2o_evloop_socket_create(@ctx.loop, fd, H2O_SOCKET_FLAG_DONT_READ) - h2o_socket_read_start(sock, LibH2o::H2oSocketCb.new { |listener, err| - {{@type}}.instance.on_accept(listener, err) - }) - 0 - end - - def register_handler(hostconf : LibH2o::H2oHostconfT*, path : String, on_req : Handler) : Void - pathconf = h2o_config_register_path(hostconf, path, 0) - handler = h2o_create_handler(pathconf, sizeof(LibH2o::H2oHandlerT)) - handler.value.on_req = on_req - end - - def initialize - @loop = h2o_evloop_create() - end - - def run : Void - h2o_config_init(pointerof(@config)) - @config.server_name = h2o_iovec_init("h2o") - - hostconf = h2o_config_register_host(pointerof(@config), h2o_iovec_init("default"), 65535) - register_handler(hostconf, "/plaintext", hello) - register_handler(hostconf, "/json", json) - - h2o_context_init(pointerof(@ctx), @loop, pointerof(@config)) - - @accept_ctx.ctx = pointerof(@ctx) - @accept_ctx.hosts = @config.hosts - - if create_listener != 0 - return 1 - end - - while h2o_evloop_run(@ctx.loop, Int32::MAX) == 0; end - end -end - -H2oHello.run diff --git a/frameworks/Crystal/h2o.cr/run.sh b/frameworks/Crystal/h2o.cr/run.sh deleted file mode 100644 index 44f9c8a4db9..00000000000 --- a/frameworks/Crystal/h2o.cr/run.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh - -for i in $(seq 1 $(nproc --all)); do - ./server.out & -done - -wait diff --git a/frameworks/Crystal/h2o.cr/shard.yml b/frameworks/Crystal/h2o.cr/shard.yml deleted file mode 100755 index e203604b6cd..00000000000 --- a/frameworks/Crystal/h2o.cr/shard.yml +++ /dev/null @@ -1,15 +0,0 @@ -name: crystal-h2o -version: 0.0.1 - -license: MIT - -crystal: 0.26.1 - -dependencies: - h2o: - github: s-you/h2o.cr - uv: - github: s-you/uv.cr - reset: - github: s-you/reset.cr - branch: h2o diff --git a/frameworks/Crystal/kemal/kemal-concurrent-queries.dockerfile b/frameworks/Crystal/kemal/kemal-concurrent-queries.dockerfile index 549ca8e3cb6..0f4f2b39231 100644 --- a/frameworks/Crystal/kemal/kemal-concurrent-queries.dockerfile +++ b/frameworks/Crystal/kemal/kemal-concurrent-queries.dockerfile @@ -1,4 +1,4 @@ -FROM crystallang/crystal:0.32.1 +FROM crystallang/crystal:1.12.1 WORKDIR /kemal COPY views views diff --git a/frameworks/Crystal/kemal/kemal.dockerfile b/frameworks/Crystal/kemal/kemal.dockerfile index 03bdf0c4ef3..d5890857891 100644 --- a/frameworks/Crystal/kemal/kemal.dockerfile +++ b/frameworks/Crystal/kemal/kemal.dockerfile @@ -1,4 +1,4 @@ -FROM crystallang/crystal:0.32.1 +FROM crystallang/crystal:1.14.0 WORKDIR /kemal COPY views views diff --git a/frameworks/Crystal/kemal/shard.lock b/frameworks/Crystal/kemal/shard.lock index 8d4253e5645..9340b31d88b 100644 --- a/frameworks/Crystal/kemal/shard.lock +++ b/frameworks/Crystal/kemal/shard.lock @@ -1,38 +1,38 @@ -version: 1.0 +version: 2.0 shards: + backtracer: + git: https://github.com/sija/backtracer.cr.git + version: 1.2.2 + commander: - github: snluu/commander - commit: 9396efd427f06f0f6de5206f6e81d54fcd254abe + git: https://github.com/snluu/commander.git + version: 0.1.0+git.commit.9396efd427f06f0f6de5206f6e81d54fcd254abe db: - github: crystal-lang/crystal-db - version: 0.8.0 + git: https://github.com/crystal-lang/crystal-db.git + version: 0.13.1 exception_page: - github: crystal-loot/exception_page - version: 0.1.2 + git: https://github.com/crystal-loot/exception_page.git + version: 0.4.1 kemal: - github: kemalcr/kemal - version: 0.26.1 - - kilt: - github: jeromegn/kilt - version: 0.4.0 + git: https://github.com/kemalcr/kemal.git + version: 1.6.0 pg: - github: will/crystal-pg - version: 0.20.0 + git: https://github.com/will/crystal-pg.git + version: 0.28.0 pool: - github: ysbaddaden/pool - version: 0.2.3 + git: https://github.com/ysbaddaden/pool.git + version: 0.3.0 radix: - github: luislavena/radix - version: 0.3.9 + git: https://github.com/luislavena/radix.git + version: 0.4.1 redis: - github: stefanwille/crystal-redis - version: 2.5.3 + git: https://github.com/stefanwille/crystal-redis.git + version: 2.8.0 diff --git a/frameworks/Crystal/kemal/shard.yml b/frameworks/Crystal/kemal/shard.yml index 1a9a88e8e8a..6ab59c26264 100644 --- a/frameworks/Crystal/kemal/shard.yml +++ b/frameworks/Crystal/kemal/shard.yml @@ -6,12 +6,12 @@ license: MIT dependencies: pg: github: will/crystal-pg - version: 0.20.0 + version: 0.28.0 kemal: github: kemalcr/kemal - version: 0.26.1 + version: 1.6.0 redis: github: stefanwille/crystal-redis - version: 2.5.3 + version: 2.8.0 commander: github: snluu/commander diff --git a/frameworks/Crystal/lucky/config/server.cr b/frameworks/Crystal/lucky/config/server.cr index 16f458c361c..cdfeda684ef 100644 --- a/frameworks/Crystal/lucky/config/server.cr +++ b/frameworks/Crystal/lucky/config/server.cr @@ -6,7 +6,7 @@ Lucky::Server.configure do |settings| settings.secret_key_base = "u4PWnhZfOFXdTOtoiSBF+6jn0zHbYS6/yumo3WXYNSw" settings.host = "0.0.0.0" settings.port = 8080 - settings.gzip_enabled = true + settings.gzip_enabled = false settings.asset_host = "" end diff --git a/frameworks/Crystal/lucky/lucky.dockerfile b/frameworks/Crystal/lucky/lucky.dockerfile index 6e849625ca8..1f352cf53bd 100644 --- a/frameworks/Crystal/lucky/lucky.dockerfile +++ b/frameworks/Crystal/lucky/lucky.dockerfile @@ -1,4 +1,4 @@ -FROM crystallang/crystal:1.1.0 +FROM crystallang/crystal:1.14.0 WORKDIR /lucky COPY shard.lock shard.lock @@ -14,7 +14,7 @@ ENV LUCKY_ENV production RUN shards build bench --release --no-debug -ENV DATABASE_URL postgres://benchmarkdbuser:benchmarkdbpass@tfb-database:5432/hello_world?initial_pool_size=56&max_idle_pool_size=56 +ENV DATABASE_URL postgres://benchmarkdbuser:benchmarkdbpass@tfb-database:5432/hello_world?initial_pool_size=10&max_idle_pool_size=10 EXPOSE 8080 diff --git a/frameworks/Crystal/lucky/shard.lock b/frameworks/Crystal/lucky/shard.lock index ec0cee06660..34f8bfcfea6 100644 --- a/frameworks/Crystal/lucky/shard.lock +++ b/frameworks/Crystal/lucky/shard.lock @@ -2,11 +2,15 @@ version: 2.0 shards: avram: git: https://github.com/luckyframework/avram.git - version: 0.21.0 + version: 1.3.0 backtracer: git: https://github.com/sija/backtracer.cr.git - version: 1.2.1 + version: 1.2.2 + + cadmium_transliterator: + git: https://github.com/cadmiumcr/transliterator.git + version: 0.1.0+git.commit.46c4c14594057dbcfaf27e7e7c8c164d3f0ce3f1 cry: git: https://github.com/luckyframework/cry.git @@ -14,53 +18,57 @@ shards: db: git: https://github.com/crystal-lang/crystal-db.git - version: 0.10.1 + version: 0.13.1 dexter: git: https://github.com/luckyframework/dexter.git - version: 0.3.3 + version: 0.3.4 exception_page: git: https://github.com/crystal-loot/exception_page.git - version: 0.2.0 - - future: - git: https://github.com/crystal-community/future.cr.git - version: 1.0.0+git.commit.9fe168418c6884cb3552c13b004763eb4815ceb9 + version: 0.4.1 habitat: git: https://github.com/luckyframework/habitat.git - version: 0.4.7 + version: 0.4.9 lucky: git: https://github.com/luckyframework/lucky.git - version: 0.28.0 + version: 1.2.0 + + lucky_cache: + git: https://github.com/luckyframework/lucky_cache.git + version: 0.1.1 lucky_router: git: https://github.com/luckyframework/lucky_router.git - version: 0.5.0 + version: 0.5.2 lucky_task: git: https://github.com/luckyframework/lucky_task.git - version: 0.1.0 + version: 0.3.0 + + lucky_template: + git: https://github.com/luckyframework/lucky_template.git + version: 0.2.0 pg: git: https://github.com/will/crystal-pg.git - version: 0.24.0 + version: 0.28.0 pulsar: git: https://github.com/luckyframework/pulsar.git - version: 0.2.2 + version: 0.2.3 shell-table: git: https://github.com/luckyframework/shell-table.cr.git - version: 0.9.3+git.commit.fefbc8b19d18630660b2653de755217597808b1b + version: 0.9.3 - teeplate: - git: https://github.com/luckyframework/teeplate.git - version: 0.8.3 + splay_tree_map: + git: https://github.com/wyhaines/splay_tree_map.cr.git + version: 0.3.0 wordsmith: git: https://github.com/luckyframework/wordsmith.git - version: 0.3.0 + version: 0.4.0 diff --git a/frameworks/Crystal/lucky/shard.yml b/frameworks/Crystal/lucky/shard.yml index dd33a9517fe..c5afbdd49fd 100644 --- a/frameworks/Crystal/lucky/shard.yml +++ b/frameworks/Crystal/lucky/shard.yml @@ -8,9 +8,11 @@ targets: bench: main: src/bench.cr -crystal: ">= 1.0.0" +crystal: ">= 1.12.1" dependencies: + avram: + github: luckyframework/avram lucky: github: luckyframework/lucky - version: ~> 0.28.0 + version: ~> 1.2.0 diff --git a/frameworks/Crystal/lucky/src/actions/mixins/add_required_headers.cr b/frameworks/Crystal/lucky/src/actions/mixins/add_required_headers.cr index 32d0d957f2c..8c076dcb84e 100644 --- a/frameworks/Crystal/lucky/src/actions/mixins/add_required_headers.cr +++ b/frameworks/Crystal/lucky/src/actions/mixins/add_required_headers.cr @@ -5,7 +5,6 @@ module AddRequiredHeaders def add_required_headers response.headers["Server"] = "Lucky" - response.headers["Date"] = HTTP.format_time(Time.local) continue end end diff --git a/frameworks/Crystal/raze/README.md b/frameworks/Crystal/raze/README.md deleted file mode 100644 index b419b54e543..00000000000 --- a/frameworks/Crystal/raze/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Crystal-Raze - -This is the [Raze](https://github.com/samueleaton/raze) test of the Framework Benchmarks. Crystal is a new language that closely resembles Ruby with a goal of removing typed variables and parameters (instead inferencing), whilst maintaining top speed through bindings into C. - -Raze is a Modular, light web framework for Crystal https://razecr.com/ diff --git a/frameworks/Crystal/raze/benchmark_config.json b/frameworks/Crystal/raze/benchmark_config.json deleted file mode 100644 index e167df98c2d..00000000000 --- a/frameworks/Crystal/raze/benchmark_config.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "framework": "raze", - "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": "Postgres", - "framework": "raze", - "language": "Crystal", - "flavor": "None", - "orm": "micro", - "platform": "None", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "Raze (PostgreSQL)", - "notes": "", - "versus": "crystal" - } - }] -} diff --git a/frameworks/Crystal/raze/config.toml b/frameworks/Crystal/raze/config.toml deleted file mode 100644 index c1db97a8713..00000000000 --- a/frameworks/Crystal/raze/config.toml +++ /dev/null @@ -1,19 +0,0 @@ -[framework] -name = "raze" - -[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 = "None" -webserver = "None" -versus = "crystal" diff --git a/frameworks/Crystal/raze/raze.cr b/frameworks/Crystal/raze/raze.cr deleted file mode 100644 index d27fbfb390d..00000000000 --- a/frameworks/Crystal/raze/raze.cr +++ /dev/null @@ -1,107 +0,0 @@ -require "raze" -require "pg" - -BENCH_DB = DB.open(ENV["DATABASE_URL"]) - -class CONTENT - ID_MAX = 10_000 - JSON = "application/json" - PLAIN = "text/plain" - HTML = "text/html; charset=UTF-8" -end - -private def get_world - id = Random.rand(CONTENT::ID_MAX).succ - random_number = BENCH_DB.query_one("SELECT id, randomNumber FROM world WHERE id = $1", id, as: Int32) - { id: id, randomNumber: random_number } -end - -private def set_world(world) - BENCH_DB.exec("UPDATE world SET randomNumber = $1 WHERE id = $2", world[:randomNumber], world[:id]) - world -end - -private def fortunes - data = Array(NamedTuple(id: Int32, message: String)).new - - BENCH_DB.query_each("SELECT id, message FROM Fortune") do |rs| - data.push({id: rs.read(Int32), message: rs.read(String)}) - end - - data -end - -private def sanitized_query_count(ctx) - queries = ctx.query["queries"].as(String) - queries = queries.to_i? || 1 - queries.clamp(1..500) -end - -# Test 1: JSON Serialization -get "/json" do |ctx| - ctx.response.headers["Server"] = "Raze" - ctx.response.headers["Date"] = HTTP.format_time(Time.now) - ctx.response.content_type = CONTENT::JSON - { message: "Hello, World!" }.to_json -end - -# Postgres Test 2: Single database query -get "/db" do |ctx| - ctx.response.headers["Server"] = "Raze" - ctx.response.headers["Date"] = HTTP.format_time(Time.now) - ctx.response.content_type = CONTENT::JSON - get_world.to_json -end - -# Postgres Test 3: Multiple database query -get "/queries" do |ctx| - results = (1..sanitized_query_count(ctx)).map do - get_world - end - ctx.response.headers["Server"] = "Raze" - ctx.response.headers["Date"] = HTTP.format_time(Time.now) - ctx.response.content_type = CONTENT::JSON - results.to_json -end - -# Postgres Test 4: Fortunes -get "/fortunes" do |ctx| - ctx.response.headers["Server"] = "Raze" - ctx.response.headers["Date"] = HTTP.format_time(Time.now) - ctx.response.content_type = CONTENT::HTML - data = fortunes - additional_fortune = { - id: 0, - message: "Additional fortune added at request time.", - } - data.push(additional_fortune) - - data.sort_by! { |fortune| fortune[:message] } - - render "views/fortunes.ecr" -end - -# Postgres Test 5: Database Updates -get "/updates" do |ctx| - updated = (1..sanitized_query_count(ctx)).map do - set_world({id: get_world[:id], randomNumber: Random.rand(CONTENT::ID_MAX).succ}) - end - ctx.response.headers["Server"] = "Raze" - ctx.response.headers["Date"] = HTTP.format_time(Time.now) - ctx.response.content_type = CONTENT::JSON - updated.to_json -end - -# Test 6: Plaintext -get "/plaintext" do |ctx| - ctx.response.headers["Server"] = "Raze" - ctx.response.headers["Date"] = HTTP.format_time(Time.now) - ctx.response.content_type = CONTENT::PLAIN - "Hello, World!" -end - -Raze.config.logging = false -Raze.config.port = 8080 -Raze.config.env = "production" -Raze.config.reuse_port = true -Raze.run diff --git a/frameworks/Crystal/raze/raze.dockerfile b/frameworks/Crystal/raze/raze.dockerfile deleted file mode 100644 index c83de74401d..00000000000 --- a/frameworks/Crystal/raze/raze.dockerfile +++ /dev/null @@ -1,17 +0,0 @@ -FROM crystallang/crystal:0.26.1 - -WORKDIR /raze -COPY views views -COPY run.sh run.sh -COPY raze.cr raze.cr -COPY shard.lock shard.lock -COPY shard.yml shard.yml - -ENV DATABASE_URL postgres://benchmarkdbuser:benchmarkdbpass@tfb-database:5432/hello_world?initial_pool_size=56&max_pool_size=56&max_idle_pool_size=56 - -RUN shards install -RUN crystal build --release --no-debug raze.cr - -EXPOSE 8080 - -CMD bash run.sh diff --git a/frameworks/Crystal/raze/run.sh b/frameworks/Crystal/raze/run.sh deleted file mode 100644 index a9e373e6683..00000000000 --- a/frameworks/Crystal/raze/run.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -for i in $(seq 1 $(nproc --all)); do - ./raze -p 8080 & -done - -wait diff --git a/frameworks/Crystal/raze/shard.lock b/frameworks/Crystal/raze/shard.lock deleted file mode 100644 index c2aa6f2798d..00000000000 --- a/frameworks/Crystal/raze/shard.lock +++ /dev/null @@ -1,22 +0,0 @@ -version: 1.0 -shards: - db: - github: crystal-lang/crystal-db - version: 0.5.0 - - kilt: - github: jeromegn/kilt - version: 0.4.0 - - pg: - github: will/crystal-pg - version: 0.15.0 - - radix: - github: luislavena/radix - version: 0.3.8 - - raze: - github: samueleaton/raze - version: 0.3.0 - diff --git a/frameworks/Crystal/raze/shard.yml b/frameworks/Crystal/raze/shard.yml deleted file mode 100644 index a18ffe5e277..00000000000 --- a/frameworks/Crystal/raze/shard.yml +++ /dev/null @@ -1,18 +0,0 @@ -name: raze -version: 0.1.0 - -targets: - raze: - main: src/raze.cr - -crystal: 0.26.1 - -license: MIT - -dependencies: - raze: - github: samueleaton/raze - version: 0.3.0 - pg: - github: will/crystal-pg - version: 0.15.0 diff --git a/frameworks/Crystal/raze/views/fortunes.ecr b/frameworks/Crystal/raze/views/fortunes.ecr deleted file mode 100644 index d2842b8bf4b..00000000000 --- a/frameworks/Crystal/raze/views/fortunes.ecr +++ /dev/null @@ -1,20 +0,0 @@ - - - - Fortunes - - - - - - - - <% data.each do |fortune| %> - - - - - <% end %> -
idmessage
<%= fortune[:id] %><%= HTML.escape(fortune[:message]) %>
- - diff --git a/frameworks/Crystal/spider-gazelle/shard.lock b/frameworks/Crystal/spider-gazelle/shard.lock index 5069278751c..a73d29d085c 100644 --- a/frameworks/Crystal/spider-gazelle/shard.lock +++ b/frameworks/Crystal/spider-gazelle/shard.lock @@ -2,11 +2,11 @@ version: 2.0 shards: action-controller: git: https://github.com/spider-gazelle/action-controller.git - version: 5.6.2 + version: 7.4.3 active-model: git: https://github.com/spider-gazelle/active-model.git - version: 4.2.3 + version: 4.3.2 backtracer: git: https://github.com/sija/backtracer.cr.git @@ -14,27 +14,23 @@ shards: db: git: https://github.com/crystal-lang/crystal-db.git - version: 0.11.0 + version: 0.13.1 eventbus: git: https://github.com/spider-gazelle/eventbus.git - version: 0.9.9+git.commit.086b2ba92475b88e8481b0387eb56c735cbfd7bd + version: 1.0.0+git.commit.af63536d718348885a553dc4aa6debccc2946289 exception_page: git: https://github.com/crystal-loot/exception_page.git - version: 0.3.0 - - future: - git: https://github.com/crystal-community/future.cr.git - version: 1.0.0 + version: 0.5.0 habitat: git: https://github.com/luckyframework/habitat.git - version: 0.4.7 + version: 0.4.9 hot_topic: git: https://github.com/jgaskins/hot_topic.git - version: 0.1.0+git.commit.c4577d949221d535f29162343bf503b578308954 + version: 0.1.0+git.commit.3c901e77b6e000930398738260a2944b6f5785dc http-params-serializable: git: https://github.com/place-labs/http-params-serializable.git @@ -42,7 +38,7 @@ shards: json-schema: git: https://github.com/spider-gazelle/json-schema.git - version: 1.3.0 + version: 1.3.1 kilt: git: https://github.com/jeromegn/kilt.git @@ -50,21 +46,21 @@ shards: lucky_router: git: https://github.com/luckyframework/lucky_router.git - version: 0.5.2 + version: 0.6.0 pg: git: https://github.com/will/crystal-pg.git - version: 0.26.0 + version: 0.28.0 pg-orm: git: https://github.com/spider-gazelle/pg-orm.git - version: 1.0.0+git.commit.2bbafec9579f175880281279d33168360176540c + version: 1.1.2+git.commit.9b340ee269cd4a10ed6c5b51235cbaf45fc380e1 pool: git: https://github.com/ysbaddaden/pool.git - version: 0.3.0 + version: 0.2.4 redis: git: https://github.com/stefanwille/crystal-redis.git - version: 2.8.3 + version: 2.9.1 diff --git a/frameworks/Crystal/spider-gazelle/spider-gazelle.dockerfile b/frameworks/Crystal/spider-gazelle/spider-gazelle.dockerfile index 5962a201dc1..c836b434c44 100644 --- a/frameworks/Crystal/spider-gazelle/spider-gazelle.dockerfile +++ b/frameworks/Crystal/spider-gazelle/spider-gazelle.dockerfile @@ -1,5 +1,4 @@ -FROM 84codes/crystal:1.7.2-alpine -RUN apk add --update --no-cache bash gmp-dev +FROM crystallang/crystal:1.14.0 WORKDIR /usr/src/app @@ -10,7 +9,7 @@ COPY run.sh run.sh # Build App RUN shards build --release --no-debug -ENV DATABASE_URL postgres://benchmarkdbuser:benchmarkdbpass@tfb-database:5432/hello_world?initial_pool_size=56&max_idle_pool_size=56 +ENV DATABASE_URL postgres://benchmarkdbuser:benchmarkdbpass@tfb-database:5432/hello_world?initial_pool_size=5&max_idle_pool_size=5 ENV SG_ENV production diff --git a/frameworks/Crystal/toro/shard.yml b/frameworks/Crystal/toro/shard.yml index 1c84495533e..9a8953d4d04 100644 --- a/frameworks/Crystal/toro/shard.yml +++ b/frameworks/Crystal/toro/shard.yml @@ -4,13 +4,13 @@ version: 0.1.0 dependencies: toro: github: soveran/toro - version: 0.4.1 + version: 0.5.1 pg: github: will/crystal-pg - version: 0.20.0 + version: 0.28.0 targets: toro: main: toro.cr -crystal: 0.34.0 \ No newline at end of file +crystal: 1.12.1 diff --git a/frameworks/Crystal/toro/toro.cr b/frameworks/Crystal/toro/toro.cr index db1c3cef3ba..7ff01b5a7c7 100644 --- a/frameworks/Crystal/toro/toro.cr +++ b/frameworks/Crystal/toro/toro.cr @@ -129,6 +129,6 @@ class App < Toro::Router end # Start the app on port 8080. -App.run(8080) do |server| +App.run do |server| server.listen("0.0.0.0", 8080, reuse_port: true) end diff --git a/frameworks/Crystal/toro/toro.dockerfile b/frameworks/Crystal/toro/toro.dockerfile index b4f0677f11c..ce47dad0746 100644 --- a/frameworks/Crystal/toro/toro.dockerfile +++ b/frameworks/Crystal/toro/toro.dockerfile @@ -1,4 +1,4 @@ -FROM crystallang/crystal:0.34.0 +FROM crystallang/crystal:1.12.1 WORKDIR /toro COPY views views diff --git a/frameworks/D/juptune/README.md b/frameworks/D/juptune/README.md new file mode 100755 index 00000000000..afdc1ae5708 --- /dev/null +++ b/frameworks/D/juptune/README.md @@ -0,0 +1,19 @@ +# Juptune Benchmarking Test + +Benchmarks for the WIP Juptune library - an upcoming async I/O library based around io_uring. + +### Test Type Implementation Source Code + +* [PLAINTEXT](./src/tests/plaintext.d) + +## Important Libraries + +The tests were run with: + +* [Juptune](https://github.com/Juptune/juptune) + +## Test URLs + +### PLAINTEXT + +http://localhost:8080/plaintext \ No newline at end of file diff --git a/frameworks/D/juptune/benchmark_config.json b/frameworks/D/juptune/benchmark_config.json new file mode 100755 index 00000000000..0a091dc9fa6 --- /dev/null +++ b/frameworks/D/juptune/benchmark_config.json @@ -0,0 +1,26 @@ +{ + "framework": "juptune", + "tests": [ + { + "default": { + "plaintext_url": "/plaintext", + "json_url": "/json", + "port": 8080, + "approach": "Realistic", + "classification": "Platform", + "database": "None", + "framework": "juptune", + "language": "D", + "flavor": "ldc2", + "orm": "None", + "platform": "None", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "Juptune", + "notes": "", + "versus": "None" + } + } + ] +} diff --git a/frameworks/D/juptune/juptune.dockerfile b/frameworks/D/juptune/juptune.dockerfile new file mode 100644 index 00000000000..0a671e08d8d --- /dev/null +++ b/frameworks/D/juptune/juptune.dockerfile @@ -0,0 +1,30 @@ +FROM debian:bookworm-slim + +ARG LDC_VERSION=1.41.0 +ARG JUPTUNE_REF=52294fa45912dacac24efc80b4a2fad8db958841 +ARG TFB_TEST_NAME + +ENV TEST_NAME=${TFB_TEST_NAME} + +# Install system deps & LDC +RUN apt update \ + && apt install -y curl xz-utils gnupg libsodium-dev meson unzip pkg-config \ + && curl -fsS https://dlang.org/install.sh | bash -s ldc-${LDC_VERSION} + +# Install Juptune +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 \ + && 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 compile -C build + +ENTRYPOINT [ "/app/build/juptune-tfb" ] \ No newline at end of file diff --git a/frameworks/D/juptune/src/main.d b/frameworks/D/juptune/src/main.d new file mode 100644 index 00000000000..fb8c2100d7c --- /dev/null +++ b/frameworks/D/juptune/src/main.d @@ -0,0 +1,291 @@ +import core.time : msecs; +import std.parallelism : totalCPUs; +import std.process : environment; + +import juptune.core.util, + juptune.core.ds, + juptune.event, + juptune.event.fiber, + juptune.http; + +import tests.common : log; +import tests.plaintext, tests.json; + +/++++ Constant config ++++/ + +enum SOCKET_BACKLOG_PER_THREAD = 1000; +enum FIBER_CALL_STACK_BYTES = 1024 * 100; +enum HTTP_READ_BUFFER_BYTES = 1024; +enum HTTP_WRITE_BUFFER_BYTES = 1024; + +enum HTTP_CONFIG = Http1Config() + .withReadTimeout(1000.msecs) + .withWriteTimeout(1000.msecs); + +static assert( + HTTP_READ_BUFFER_BYTES + HTTP_WRITE_BUFFER_BYTES < FIBER_CALL_STACK_BYTES / 4, + "To be safe, please ensure the buffer bytes are only a quarter the size of a fiber call stack." +); + +/++++ Globals ++++/ + +__gshared TcpSocket server; // Currently there's no mechanism to directly pass data to new threads, so global state has to be used. + +/++++ Functions ++++/ + +void main() +{ + auto loop = EventLoop( + EventLoopConfig() + .withFiberAllocatorConfig( + FiberAllocatorConfig() + .withBlockStackSize(FIBER_CALL_STACK_BYTES) + ) + ); + + // open() and listen() can't be ran outside of an event loop thread, so currently this is the janky way to setup the server. + loop.addNoGCThread(() @nogc nothrow { + server.open().resultAssert; + server.listen("0.0.0.0:8080", SOCKET_BACKLOG_PER_THREAD*totalCPUs).resultAssert; + juptuneEventLoopCancelThread(); + }); + loop.join(); + + // Then we can setup the proper loop threads. + foreach(i; 0..totalCPUs) + loop.addGCThread(&router); + loop.join(); +} + +// Juptune currently does not provide higher-level server features out of the box, so we have +// to hand-make a custom router. +// +// This is realistic in the sense that building a custom router is a completely valid, supported pattern +// for people who want/need something very specialised. +// +// This is unrealistic in the sense that once Juptune has a native router, the native router would +// almost certainly be used in a case like this (but since that's a TODO, this will have to do for now). +void router() nothrow +{ + try + { + enum Route + { + FAILSAFE, + plaintext, + json, + } + + enum Method + { + FAILSAFE, + get + } + + union RouteInput + { + PlainTextHeaderInput plaintext; + JsonHeaderInput json; + } + + while(!juptuneEventLoopIsThreadCanceled()) + { + TcpSocket client; + + auto result = server.accept(client); + if(result.isError) + { + log("error accepting socket: ", result); + continue; + } + + result = async(function () nothrow { + auto client = juptuneEventLoopGetContext!TcpSocket; + scope(exit) if(client.isOpen) + auto _ = client.close(); + + Http1MessageSummary readSummary, writeSummary; + + // Read & Write primitives + ubyte[HTTP_READ_BUFFER_BYTES] readBuffer; + ubyte[HTTP_WRITE_BUFFER_BYTES] writeBuffer; + auto reader = Http1Reader(client, readBuffer, HTTP_CONFIG); + auto writer = Http1Writer(client, writeBuffer, HTTP_CONFIG); + + do + { + if(!client.isOpen) + return; + + // Routing state + Route route; + Method method; + RouteInput input; + + // Error handling + uint errorCode; + string errorMsg; + void setError(uint code, string msg) + { + if(errorMsg !is null) + return; + errorCode = code; + errorMsg = msg; + } + + // Parse request line + { + Http1RequestLine requestLine; + auto result = reader.readRequestLine(requestLine); + if(result.isError) + { + log("readRequestLine() failed: ", result.error, ": ", result.context.slice); + return; + } + + requestLine.access((scope methodString, scope uri){ + switch(methodString) + { + case "GET": + method = Method.get; + break; + + default: + setError(405, "Unexpected method"); + break; + } + + switch(uri.path) + { + case "/plaintext": + route = Route.plaintext; + break; + + case "/json": + route = Route.json; + break; + + default: + setError(404, "Not found"); + break; + } + }); + } + + // Read headers + bool foundEndOfHeaders; + while(!foundEndOfHeaders) + { + auto result = reader.checkEndOfHeaders(foundEndOfHeaders); + if(result.isError) + { + log("checkEndOfHeaders() failed: ", result); + return; + } + else if(foundEndOfHeaders) + break; + + Http1Header header; + result = reader.readHeader(header); + if(result.isError) + { + log("readHeader() failed: ", result); + return; + } + + // Since we're using a custom router, we have the luxury of handling/ignoring headers during routing rather + // than stuffing them all into a hashmap, and doing the processing post-routing. + header.access((scope name, scope value){ + final switch(route) with(Route) + { + case FAILSAFE: break; + + case plaintext: + break; + + case json: + break; + } + }); + } + + // Read body + Http1BodyChunk chunk; + do { + chunk = Http1BodyChunk(); + auto result = reader.readBody(chunk); + if(result.isError) + { + log("readBody() failed: ", result); + return; + } + + // Likewise, we only need to deal with body data in certain routes, so we can ignore them in others. + chunk.access((scope data){ + final switch(route) with(Route) + { + case FAILSAFE: break; + + case plaintext: + break; + + case json: + break; + } + }); + } while(chunk.hasDataLeft); + + // Finish reading the message, and either dispatch it to a handler, or report an error back. + auto result = reader.finishMessage(readSummary); + if(result.isError) + { + log("finishMessage() failed: ", result); + return; + } + + if(errorMsg !is null) + { + import tests.common : putServerAndDate; + result = writer.putResponseLine(Http1Version.http11, errorCode, errorMsg).then!( + () => writer.putServerAndDate(), + () => writer.finishHeaders(), + () => writer.finishBody(), + () => writer.finishTrailers(), + () => writer.finishMessage(writeSummary), + ); + if(result.isError) + { + log("finishing a message [error variant] failed: ", result); + return; + } + continue; + } + + final switch(route) with(Route) + { + case FAILSAFE: break; + + case plaintext: + handlePlainText(input.plaintext, writer, writeSummary); + break; + + case json: + handleJson(input.json, writer, writeSummary); + break; + } + } while(!readSummary.connectionClosed && !writeSummary.connectionClosed); + }, client, &asyncMoveSetter!TcpSocket); + if(result.isError) + { + log("error calling async(): ", result); + continue; + } + } + } + catch(Throwable ex) // @suppress(dscanner.suspicious.catch_em_all) + { + import std.exception : assumeWontThrow; + log("uncaught exception: ", ex.msg).assumeWontThrow; + debug log(ex.info).assumeWontThrow; + } +} \ No newline at end of file diff --git a/frameworks/D/juptune/src/meson.build b/frameworks/D/juptune/src/meson.build new file mode 100644 index 00000000000..e4feb4ac896 --- /dev/null +++ b/frameworks/D/juptune/src/meson.build @@ -0,0 +1,26 @@ +#### Project configuration #### + +project('juptune-tfb', 'd') + +#### Sources #### + +srcs = files( + './main.d', + './tests/common.d', + './tests/json.d', + './tests/plaintext.d', +) + +#### Dependencies #### + +juptune_dep = dependency('juptune') + +dep = declare_dependency( + include_directories: include_directories('.'), + sources: srcs, + dependencies: [juptune_dep], +) + +#### Executables #### + +main_exe = executable('juptune-tfb', dependencies: [dep]) \ No newline at end of file diff --git a/frameworks/D/juptune/src/tests/common.d b/frameworks/D/juptune/src/tests/common.d new file mode 100644 index 00000000000..a27ace1e712 --- /dev/null +++ b/frameworks/D/juptune/src/tests/common.d @@ -0,0 +1,81 @@ +module tests.common; + +import juptune.core.util : Result, then; +import juptune.http : Http1Writer; + +enum ENABLE_LOGGING = false; + +void log(Args...)(scope auto ref Args args) +{ + import std.exception : assumeWontThrow; + import std.stdio : writeln; + static if(ENABLE_LOGGING) + writeln(args).assumeWontThrow; +} + +Result putServerAndDate(scope ref Http1Writer writer) nothrow +{ + import std.datetime : Clock, DayOfWeek, Month; + import std.exception : assumeWontThrow; + + char[256] dateBuffer; + size_t dateCursor; + + void put(const(char)[] value) + { + dateBuffer[dateCursor..dateCursor+value.length] = value[0..$]; + dateCursor += value.length; + } + + void putInt(int value) + { + import juptune.core.util.conv : toBase10, IntToCharBuffer; + IntToCharBuffer buffer; + put(toBase10(value, buffer)); + } + + const currTime = Clock.currTime.assumeWontThrow.toUTC(); + final switch(currTime.dayOfWeek) with(DayOfWeek) + { + case mon: put("Mon, "); break; + case tue: put("Tue, "); break; + case wed: put("Wed, "); break; + case thu: put("Thu, "); break; + case fri: put("Fri, "); break; + case sat: put("Sat, "); break; + case sun: put("Sun, "); break; + } + + putInt(currTime.day); + put(" "); + + final switch(currTime.month) with(Month) + { + case jan: put("Jan "); break; + case feb: put("Feb "); break; + case mar: put("Mar "); break; + case apr: put("Apr "); break; + case may: put("May "); break; + case jun: put("Jun "); break; + case jul: put("Jul "); break; + case aug: put("Aug "); break; + case sep: put("Sep "); break; + case oct: put("Oct "); break; + case nov: put("Nov "); break; + case dec: put("Dec "); break; + } + + putInt(currTime.year); + put(" "); + + putInt(currTime.hour); + put(":"); + putInt(currTime.minute); + put(":"); + putInt(currTime.second); + put(" GMT"); + + return writer.putHeader("Server", "Juptune (Linux)").then!( + () => writer.putHeader("Date", dateBuffer[0..dateCursor]) + ); +} \ No newline at end of file diff --git a/frameworks/D/juptune/src/tests/json.d b/frameworks/D/juptune/src/tests/json.d new file mode 100644 index 00000000000..cb363d7939c --- /dev/null +++ b/frameworks/D/juptune/src/tests/json.d @@ -0,0 +1,103 @@ +module tests.json; + +import juptune.core.ds : ArrayNonShrink; +import juptune.core.util : Result; +import juptune.http : Http1Writer, Http1Version, Http1MessageSummary; + +import tests.common : putServerAndDate, log; + +struct JsonHeaderInput +{ + // No header input, it's here just so the overarching logic exists. +} + +private struct Message +{ + string message; +} + +void handleJson( + scope ref JsonHeaderInput input, + scope ref Http1Writer writer, + scope ref Http1MessageSummary summary, +) nothrow +{ + import juptune.core.util : then; + import juptune.core.util.conv : IntToCharBuffer, toBase10; + + ArrayNonShrink!char buffer; + buffer.reserve(256); + + auto result = serialise(buffer, Message("Hello, World!")); + if(result.isError) + { + result = writer.putResponseLine(Http1Version.http11, 500, "Internal Error").then!( + () => writer.putServerAndDate(), + () => writer.finishHeaders(), + () => writer.finishBody(), + () => writer.finishTrailers(), + () => writer.finishMessage(summary) + ); + if(result.isError) + { + log("writing error response [json] failed: ", result); + return; + } + + log("serialising value failed: ", result); + return; + } + + IntToCharBuffer contentLengthBuffer; + const contentLength = toBase10(buffer.length, contentLengthBuffer); + + result = writer.putResponseLine(Http1Version.http11, 200, "OK").then!( + () => writer.putServerAndDate(), + () => writer.putHeader("Content-Length", contentLength), + () => writer.putHeader("Content-Type", "application/json"), + () => writer.finishHeaders(), + () => writer.putBody(buffer.slice), + () => writer.finishBody(), + () => writer.finishTrailers(), + () => writer.finishMessage(summary) + ); + if(result.isError) + { + 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/D/juptune/src/tests/plaintext.d b/frameworks/D/juptune/src/tests/plaintext.d new file mode 100644 index 00000000000..c2a26634b0a --- /dev/null +++ b/frameworks/D/juptune/src/tests/plaintext.d @@ -0,0 +1,41 @@ +module tests.plaintext; + +import juptune.http : Http1Writer, Http1Version, Http1MessageSummary; + +import tests.common : putServerAndDate, log; + +struct PlainTextHeaderInput +{ + // No header input, it's here just so the overarching logic exists. +} + +void handlePlainText( + scope ref PlainTextHeaderInput input, + scope ref Http1Writer writer, + scope ref Http1MessageSummary summary, +) nothrow +{ + import juptune.core.util : then; + import juptune.core.util.conv : IntToCharBuffer, toBase10; + + immutable RESPONSE = "Hello, World!"; + + IntToCharBuffer contentLengthBuffer; + const contentLength = toBase10(RESPONSE.length, contentLengthBuffer); + + auto result = writer.putResponseLine(Http1Version.http11, 200, "OK").then!( + () => writer.putServerAndDate(), + () => writer.putHeader("Content-Length", contentLength), + () => writer.putHeader("Content-Type", "text/plain"), + () => writer.finishHeaders(), + () => writer.putBody("Hello, World!"), + () => writer.finishBody(), + () => writer.finishTrailers(), + () => writer.finishMessage(summary) + ); + if(result.isError) + { + log("writing response [plaintext] failed: ", result); + return; + } +} \ No newline at end of file diff --git a/frameworks/D/photon-http/.gitignore b/frameworks/D/photon-http/.gitignore new file mode 100644 index 00000000000..190749e53b9 --- /dev/null +++ b/frameworks/D/photon-http/.gitignore @@ -0,0 +1,16 @@ +.dub +docs.json +__dummy.html +docs/ +/photon-http +photon-http.so +photon-http.dylib +photon-http.dll +photon-http.a +photon-http.lib +photon-http-test-* +*.exe +*.pdb +*.o +*.obj +*.lst diff --git a/frameworks/D/photon-http/README.md b/frameworks/D/photon-http/README.md new file mode 100755 index 00000000000..3376e6f55b1 --- /dev/null +++ b/frameworks/D/photon-http/README.md @@ -0,0 +1,43 @@ +# photon-http benchmark + +A benchmark for photon fiber scheduler for D running with minimalistic http server library photon-http. + +# photon-http Benchmarking Test + +### Test Type Implementation Source Code + +* [JSON](./source/app.d) +* [PLAINTEXT](./source/app.d) +* [DB](./source/app.d) +* [QUERIES](./source/app.d) +* [UPDATES](./source/app.d) + +## Important Libraries + +The tests were run with: +* [photon](https://github.com/DmitryOlshansky/photon) +* [photon-http][https://github.com/DmitryOlshansky/photon-http] +* [dpq2](https://github.com/denizzzka/dpq2) + +## Test URLs + +### JSON + +http://localhost:8080/json + +### PLAINTEXT + +http://localhost:8080/plaintext + +### Data-Store/Database Mapping Test + +http://localhost:8080/db + +### Multiple queries + +http://localhost:8080/queries?queries=... + +### Multiple queries with updates + +http://localhost:8080/updates?queries=... + diff --git a/frameworks/D/photon-http/benchmark_config.json b/frameworks/D/photon-http/benchmark_config.json new file mode 100755 index 00000000000..48b08c89288 --- /dev/null +++ b/frameworks/D/photon-http/benchmark_config.json @@ -0,0 +1,30 @@ +{ + "framework": "photon-http", + "tests": [ + { + "default": { + "fortune_url": "/fortunes", + "update_url": "/updates?queries=", + "query_url": "/queries?queries=", + "db_url": "/db", + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Platform", + "database": "Postgres", + "framework": "None", + "language": "D", + "flavor": "None", + "orm": "raw", + "platform": "None", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "photon-http", + "notes": "", + "versus": "None" + } + } + ] +} diff --git a/frameworks/D/photon-http/dub.json b/frameworks/D/photon-http/dub.json new file mode 100644 index 00000000000..57d3056cc04 --- /dev/null +++ b/frameworks/D/photon-http/dub.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "Dmitry Olshansky" + ], + "copyright": "Copyright © 2025, Dmitry Olshansky", + "dependencies": { + "dpq2": "~>1.2.4", + "mir-random": "~>2.2.20", + "mir-ion": "~>2.3.4", + "xbuf" : "~>0.2.1", + "photon": "~>0.18.10", + "photon-http": "~>0.6.8", + "photon-mustache": "~>0.1.1" + }, + "dflags": ["-J."], + "description": "Benchmark of photon-http", + "license": "BSL-1.0", + "name": "photon-http-benchmark" +} \ No newline at end of file diff --git a/frameworks/D/photon-http/photon-http.dockerfile b/frameworks/D/photon-http/photon-http.dockerfile new file mode 100644 index 00000000000..96090d87812 --- /dev/null +++ b/frameworks/D/photon-http/photon-http.dockerfile @@ -0,0 +1,15 @@ +FROM dlangdockerized/ldc + + +WORKDIR /app + +COPY . . + +RUN apt-get update -yqq && apt-get install -yqq libpq-dev zlib1g-dev + +RUN dub build -b release --compiler=ldc2 + +EXPOSE 8080 + +CMD ["/app/photon-http-benchmark"] + diff --git a/frameworks/D/photon-http/source/app.d b/frameworks/D/photon-http/source/app.d new file mode 100644 index 00000000000..b21b1f145dd --- /dev/null +++ b/frameworks/D/photon-http/source/app.d @@ -0,0 +1,256 @@ +import std.stdio; +import std.socket; +import std.array; +import std.algorithm; +import std.conv; +import std.ascii; +import core.stdc.stdlib; +import core.stdc.string; + +import mir.ser; +import mir.ser.json; + +import core.time; + +import std.range.primitives; + +import glow.xbuf; + +import photon, photon.http, photon.mustache; + +import mir.random : unpredictableSeedOf; +import mir.random.variable : UniformVariable; +import mir.random.engine.xorshift : Xorshift; + +import dpq2; +import dpq2.conv.to_d_types; + +struct Message { + string message; +} + +struct WorldResponse { + int id; + int randomNumber; +} + +struct FortuneResponse { + int id; + string message; +} + +enum connectionInfo = "host=tfb-database port=5432 " + ~ "dbname=hello_world user=benchmarkdbuser password=benchmarkdbpass"; +enum worldSize = 10000; +enum poolSize = 64; + +shared Pool!Connection connectionPool; + +class BenchmarkProcessor : HttpProcessor { + HttpHeader[] plainTextHeaders = [HttpHeader("Content-Type", "text/plain; charset=utf-8")]; + HttpHeader[] jsonHeaders = [HttpHeader("Content-Type", "application/json")]; + HttpHeader[] htmlHeaders = [HttpHeader("Content-Type", "text/html; charset=utf-8")]; + Buffer!char outBuf; + Buffer!WorldResponse worlds; + UniformVariable!uint uniformVariable; + Xorshift gen; + + this(Socket sock) { + super(sock); + gen = Xorshift(unpredictableSeed!uint); + uniformVariable = UniformVariable!uint(1, worldSize); + outBuf = Buffer!char(256); + worlds = Buffer!WorldResponse(500); + } + + override void handle(HttpRequest req) { + if (req.uri == "/plaintext") { + plaintext(); + } else if(req.uri == "/json") { + json(); + } else if(req.uri == "/db") { + db(); + } else if(req.uri.startsWith("/queries")) { + queries(req.uri); + } else if(req.uri.startsWith("/updates")) { + updates(req.uri); + } else if(req.uri == "/fortunes") { + fortunes(); + } else { + respondWith("Not found", HttpStatus.NotFound, plainTextHeaders); + } + } + + final void plaintext() { + respondWith("Hello, world!", HttpStatus.OK, plainTextHeaders); + } + + final void json() { + outBuf.clear(); + serializeJsonPretty!""(outBuf, Message("Hello, World!")); + respondWith(outBuf.data, HttpStatus.OK, jsonHeaders); + } + + final void db() { + outBuf.clear(); + int id = uniformVariable(gen); + auto c = connectionPool.acquire(); + scope(exit) connectionPool.release(c); + QueryParams qp; + qp.preparedStatementName("db_prpq"); + qp.argsVariadic(id); + immutable result = c.execPrepared(qp).rangify.front; + auto w = WorldResponse(id, result[0].as!PGinteger); + serializeJsonPretty!""(outBuf, w); + respondWith(outBuf.data, HttpStatus.OK, jsonHeaders); + } + + // GET /queries?queries=... + final void queries(const(char)[] uri) { + outBuf.clear(); + worlds.clear(); + auto c = connectionPool.acquire(); + scope(exit) connectionPool.release(c); + + int count = 1; + auto i = uri.indexOf("?queries="); + if (i > 0 && i + 9 <= uri.length && isDigit(uri[i+9])) + { + try count = min(max(uri[i+9..$].to!int, 1), 500); + catch (ConvException) {} + } + + QueryParams qp; + qp.preparedStatementName("db_prpq"); + foreach (_; 0..count) { + int id = uniformVariable(gen); + qp.argsVariadic(id); + immutable result = c.execPrepared(qp).rangify.front; + worlds.put(WorldResponse(id, result[0].as!PGinteger)); + } + serializeJsonPretty!""(outBuf, worlds.data); + respondWith(outBuf.data, HttpStatus.OK, jsonHeaders); + } + + // GET /updates?queries=... + final void updates(const(char)[] uri) { + outBuf.clear(); + worlds.clear(); + auto c = connectionPool.acquire(); + scope(exit) connectionPool.release(c); + + int count = 1; + auto i = uri.indexOf("?queries="); + if (i > 0 && i + 9 <= uri.length && isDigit(uri[i+9])) + { + try count = min(max(uri[i+9..$].to!int, 1), 500); + catch (ConvException) {} + } + + QueryParams qp; + qp.preparedStatementName("db_prpq"); + + QueryParams qp_update; + qp_update.preparedStatementName("db_update_prpq"); + + foreach (_; 0..count) { + int id = uniformVariable(gen); + qp.argsVariadic(id); + immutable result = c.execPrepared(qp).rangify.front; + auto w = WorldResponse(id, result[0].as!PGinteger); + + // update random number + w.randomNumber = uniformVariable(gen); + qp_update.argsVariadic(w.randomNumber, id); + + // persist to DB + c.execPrepared(qp_update); + worlds.put(w); + } + serializeJsonPretty!""(outBuf, worlds.data); + respondWith(outBuf.data, HttpStatus.OK, jsonHeaders); + } + + final void fortunes() { + outBuf.clear(); + auto c = connectionPool.acquire(); + scope(exit) connectionPool.release(c); + import std.algorithm : map, sort; + + auto buf = Buffer!FortuneResponse(20); + QueryParams qp; + qp.preparedStatementName("fortune_prpq"); + auto result = c.execPrepared(qp).rangify; + foreach (ref f; result) { + buf.put(FortuneResponse(f[0].as!PGinteger, f[1].data.alloced)); + } + buf.put(FortuneResponse(0, "Additional fortune added at request time.")); + auto data = buf.data; + data.sort!((a, b) => a.message < b.message); + mustache!(import("template.mustache"))(data, outBuf); + foreach (ref v; data) { + if (v.id != 0) dealloc(v.message); + } + respondWith(outBuf.data, HttpStatus.OK, htmlHeaders); + } +} + +string alloced(const(ubyte)[] data) { + void* ptr = malloc(data.length); + memcpy(ptr, data.ptr, data.length); + return (cast(immutable(char)*)ptr)[0..data.length]; +} + +void dealloc(const(char)[] slice) { + free(cast(void*)slice.ptr); +} + +void server_worker(Socket client) { + scope processor = new BenchmarkProcessor(client); + try { + processor.run(); + } + catch(Exception e) { + debug stderr.writeln(e); + } +} + +void server() { + Socket server = new TcpSocket(); + server.setOption(SocketOptionLevel.SOCKET, SocketOption.REUSEADDR, true); + server.bind(new InternetAddress("0.0.0.0", 8080)); + server.listen(1000); + + debug writeln("Started server"); + + void processClient(Socket client) { + go(() => server_worker(client)); + } + + while(true) { + try { + debug writeln("Waiting for server.accept()"); + Socket client = server.accept(); + debug writeln("New client accepted"); + processClient(client); + } + catch(Exception e) { + writefln("Failure to accept %s", e); + } + } +} + +void main() { + initPhoton(); + connectionPool = pool(poolSize, 15.seconds, () { + auto c = new Connection(connectionInfo); + c.prepareEx("fortune_prpq", "SELECT id, message::text FROM Fortune"); + c.prepareEx("db_prpq", "SELECT randomNumber, id FROM world WHERE id = $1"); + c.prepareEx("db_update_prpq", "UPDATE world SET randomNumber = $1 WHERE id = $2"); + return c; + }, (ref Connection c) { + destroy(c); + }); + go(() => server()); + runScheduler(); +} diff --git a/frameworks/D/photon-http/template.mustache b/frameworks/D/photon-http/template.mustache new file mode 100644 index 00000000000..eeff5ba4c11 --- /dev/null +++ b/frameworks/D/photon-http/template.mustache @@ -0,0 +1,12 @@ + + + Fortunes + + + + {{#.}} + + {{/.}} +
idmessage
{{id}}{{message}}
+ + diff --git a/frameworks/D/serverino/.gitignore b/frameworks/D/serverino/.gitignore new file mode 100644 index 00000000000..cbf457ea779 --- /dev/null +++ b/frameworks/D/serverino/.gitignore @@ -0,0 +1,16 @@ +.dub +docs.json +__dummy.html +docs/ +/serverino +serverino.so +serverino.dylib +serverino.dll +serverino.a +serverino.lib +serverino-test-* +*.exe +*.pdb +*.o +*.obj +*.lst diff --git a/frameworks/D/serverino/README.md b/frameworks/D/serverino/README.md new file mode 100755 index 00000000000..ab101f91a85 --- /dev/null +++ b/frameworks/D/serverino/README.md @@ -0,0 +1,22 @@ +# serverino Benchmarking Test + +## About Serverino + +Serverino is a small and ready-to-go http server written in D. + +- Homepage: https://github.com/trikko/serverino + +### Test Type Implementation Source Code + +* [JSON](source/app.d) +* [PLAINTEXT](source/app.d) + +## Test URLs +### JSON + +http://localhost:8080/json + +### PLAINTEXT + +http://localhost:8080/plaintext + diff --git a/frameworks/D/serverino/benchmark_config.json b/frameworks/D/serverino/benchmark_config.json new file mode 100755 index 00000000000..9265e4f55e6 --- /dev/null +++ b/frameworks/D/serverino/benchmark_config.json @@ -0,0 +1,26 @@ +{ + "framework": "serverino", + "tests": [ + { + "default": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "None", + "framework": "serverino", + "language": "D", + "flavor": "None", + "orm": "None", + "platform": "None", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "serverino", + "notes": "", + "versus": "None" + } + } + ] +} diff --git a/frameworks/D/serverino/dub.json b/frameworks/D/serverino/dub.json new file mode 100644 index 00000000000..d5b733728eb --- /dev/null +++ b/frameworks/D/serverino/dub.json @@ -0,0 +1,14 @@ +{ + "authors": [ + "Andrea Fontana" + ], + "dependencies": { + "serverino": "~>0.7.19" + }, + "dflags-ldc": [ + "-static", + "-nodefaultlib" + ], + "license": "proprietary", + "name": "serverino-benchmark" +} \ No newline at end of file diff --git a/frameworks/D/serverino/serverino.dockerfile b/frameworks/D/serverino/serverino.dockerfile new file mode 100644 index 00000000000..26e39be0a41 --- /dev/null +++ b/frameworks/D/serverino/serverino.dockerfile @@ -0,0 +1,16 @@ +FROM alpine:latest +RUN apk update && apk upgrade +RUN apk add gcc musl-dev ldc dub llvm-libunwind-static openssl-libs-static git make +RUN ln -fs /usr/share/zoneinfo/Europe/Rome /etc/localtime +RUN apk add tzdata +RUN apk cache clean + +RUN adduser -D -S www-data + +WORKDIR /app +COPY . . +RUN dub build --build=release-nobounds + +EXPOSE 8080 +USER www-data +CMD ["./serverino-benchmark"] diff --git a/frameworks/D/serverino/source/app.d b/frameworks/D/serverino/source/app.d new file mode 100644 index 00000000000..ca787c4af95 --- /dev/null +++ b/frameworks/D/serverino/source/app.d @@ -0,0 +1,36 @@ +module app; + +import std.logger; +import std.json; +import serverino; +import std.parallelism: totalCPUs; + +mixin ServerinoMain; + +void catchAll(Request request, Output output) +{ + if (request.path == "/json") { + + output ~= JSONValue(["message" : "Hello, World!"]).toString(); + output.addHeader("content-type", "application/json"); + } + else if (request.path == "/plaintext") { + output ~= "Hello, World!"; + output.addHeader("content-type", "text/plain"); + } + else output.status = 200; +} + + +@onServerInit ServerinoConfig configure() +{ + return ServerinoConfig + .create() + .setLogLevel(LogLevel.off) + .enableServerSignature(true) + .setWorkers(4) + .setDaemonInstances(10) + .addListener("0.0.0.0", 8080); +} + + diff --git a/frameworks/D/vibed/README.md b/frameworks/D/vibed/README.md index ef06b49ed93..fe71e0720f0 100644 --- a/frameworks/D/vibed/README.md +++ b/frameworks/D/vibed/README.md @@ -12,7 +12,7 @@ This is the Vibe.D portion of a benchmarking test suite comparing a variety of w ## Infrastructure Software Versions The tests were run with: -* [Vibe.D v0.9.4](http://vibed.org/) +* [Vibe.D v0.10.2](http://vibed.org/) ## Test URLs ### JSON Encoding Test diff --git a/frameworks/D/vibed/benchmark_config.json b/frameworks/D/vibed/benchmark_config.json index 8c69d8f25ad..af453d64312 100644 --- a/frameworks/D/vibed/benchmark_config.json +++ b/frameworks/D/vibed/benchmark_config.json @@ -73,8 +73,10 @@ "ldc-pgsql": { "db_url": "/db", "query_url": "/queries?queries=", + "plaintext_url": "/plaintext", "fortune_url": "/fortunes", "update_url": "/updates?queries=", + "json_url": "/json", "port": 8080, "approach": "Realistic", "classification": "Platform", diff --git a/frameworks/D/vibed/dub.json b/frameworks/D/vibed/dub.json index 9b81c6bdbcd..3940efbe323 100644 --- a/frameworks/D/vibed/dub.json +++ b/frameworks/D/vibed/dub.json @@ -7,14 +7,13 @@ "Sönke Ludwig" ], "dependencies": { - "vibe-d": "0.9.5", - "mir-random": "2.2.15", - "vibe-d:tls": "0.9.5" + "vibe-d": "0.10.2", + "mir-random": "2.2.20", + "vibe-d:tls": "0.10.2" }, "targetType": "executable", "sourcePaths": [], "subConfigurations": { - "vibe-d": "vibe-core", "vibe-d:tls": "notls" }, "versions": [ @@ -30,11 +29,8 @@ "name": "postgresql", "mainSourceFile": "source/postgresql.d", "dependencies": { - "vibe-d-postgresql": "3.1.0-rc.1", - "dpq2": "1.0.17" - }, - "subConfigurations": { - "dpq2": "dynamic" + "vibe-d-postgresql": "3.2.0-rc1", + "dpq2": "1.2.3" } } ], diff --git a/frameworks/D/vibed/dub.selections.json b/frameworks/D/vibed/dub.selections.json index 7ef3c64873f..2b548c24919 100644 --- a/frameworks/D/vibed/dub.selections.json +++ b/frameworks/D/vibed/dub.selections.json @@ -1,26 +1,28 @@ { "fileVersion": 1, "versions": { - "botan": "1.12.19", - "botan-math": "1.0.3", "derelict-pq": "4.0.0", "derelict-util": "3.0.0-beta.2", - "diet-ng": "1.8.1", - "dpq2": "1.0.17", - "eventcore": "0.9.20", - "libasync": "0.8.6", - "memutils": "1.0.4", - "mir-algorithm": "3.14.19", - "mir-core": "1.1.111", - "mir-linux-kernel": "1.0.1", - "mir-random": "2.2.15", - "money": "2.3.1", - "openssl": "3.2.2", + "diet-ng": "1.8.4", + "dpq2": "1.2.3", + "eventcore": "0.9.36", + "mir-algorithm": "3.22.4", + "mir-core": "1.7.3", + "mir-linux-kernel": "1.2.1", + "mir-random": "2.2.20", + "money": "3.0.2", + "openssl": "3.3.4", + "openssl-static": "1.0.5+3.0.8", "silly": "1.1.1", "stdx-allocator": "2.77.5", - "taggedalgebraic": "0.11.22", - "vibe-core": "1.22.4", - "vibe-d": "0.9.5", - "vibe-d-postgresql": "3.1.0-rc.1" + "taggedalgebraic": "1.0.0", + "vibe-container": "1.6.2", + "vibe-core": "2.12.0", + "vibe-d": "0.10.2", + "vibe-d-postgresql": "3.2.0-rc1", + "vibe-http": "1.2.2", + "vibe-inet": "1.1.3", + "vibe-serialization": "1.0.7", + "vibe-stream": "1.1.1" } } diff --git a/frameworks/D/vibed/source/postgresql.d b/frameworks/D/vibed/source/postgresql.d index c853a56dadc..97cd48d3351 100644 --- a/frameworks/D/vibed/source/postgresql.d +++ b/frameworks/D/vibed/source/postgresql.d @@ -16,23 +16,27 @@ enum poolSize = 64; PostgresClient client; -shared static this() -{ - import derelict.pq.pq; - import derelict.util.exception : ShouldThrow; - ShouldThrow myMissingSymCB( string symbolName ) { return ShouldThrow.No; } - DerelictPQ.missingSymbolCallback = &myMissingSymCB; -} - void main() { - runWorkerTaskDist(&runServer); - runApplication(); -} + auto connectionInfo = "host=tfb-database port=5432 " + ~ "dbname=hello_world user=benchmarkdbuser password=benchmarkdbpass"; + + client = new PostgresClient(connectionInfo, poolSize, (Connection cn){ + cn.prepareEx("fortune_prpq", "SELECT id, message::text FROM Fortune"); + cn.prepareEx("db_prpq", "SELECT randomNumber, id FROM world WHERE id = $1"); + cn.prepareEx("db_update_prpq", "UPDATE world SET randomNumber = $1 WHERE id = $2"); + } ); + + { + // Establishing each connection in the pool and performing the PREPARE procedures + LockedConnection[poolSize] conns; + + foreach(ref c; conns) + c = client.lockConnection(); + } -void runServer() -{ import std.datetime : seconds; + auto router = new URLRouter; router.registerWebInterface(new WebInterface); router.rebuild(); @@ -42,6 +46,7 @@ void runServer() settings.options |= HTTPServerOption.reusePort; settings.port = 8080; listenHTTP(settings, router); + runEventLoop(); } class WebInterface { @@ -79,7 +84,6 @@ class WebInterface { int id = _uniformVariable(_gen); QueryParams qp; qp.preparedStatementName("db_prpq"); - qp.resultFormat = ValueFormat.BINARY; qp.argsVariadic(id); immutable result = conn.execPrepared(qp).rangify.front; auto w = WorldResponse(id, result[0].as!PGinteger); @@ -109,11 +113,9 @@ class WebInterface { scope data = new WorldResponse[count]; QueryParams qp; qp.preparedStatementName("db_prpq"); - qp.resultFormat = ValueFormat.BINARY; foreach (ref w; data) { int id = _uniformVariable(_gen); qp.argsVariadic(id); - immutable query = "SELECT randomNumber, id FROM world WHERE id = " ~ id.to!string; immutable result = conn.execPrepared(qp).rangify.front; w = WorldResponse(id, result[0].as!PGinteger); } @@ -147,7 +149,6 @@ class WebInterface { import std.uni : isNumber; auto conn = client.lockConnection(); - scope(exit) destroy(conn); int count = 1; if (queries.length && isNumber(queries[0])) @@ -159,24 +160,22 @@ class WebInterface { scope data = new WorldResponse[count]; QueryParams qp; qp.preparedStatementName("db_prpq"); - qp.resultFormat = ValueFormat.BINARY; QueryParams qp_update; qp_update.preparedStatementName("db_update_prpq"); - qp_update.resultFormat = ValueFormat.BINARY; foreach (ref w; data) { int id = _uniformVariable(_gen); qp.argsVariadic(id); - immutable query = "SELECT id, randomNumber FROM world WHERE id = " ~ id.to!string; immutable result = conn.execPrepared(qp).rangify.front; w = WorldResponse(id, result[0].as!PGinteger); // update random number w.randomNumber = _uniformVariable(_gen); qp_update.argsVariadic(w.randomNumber, id); + // persist to DB - conn.sendQueryPrepared(qp_update); + conn.execPrepared(qp_update); } // write response as JSON @@ -203,15 +202,3 @@ struct FortuneResponse { int id; string message; } - -static this() -{ - import std.process : environment; - auto connectionInfo = "host=tfb-database port=5432 " - ~ "dbname=hello_world user=benchmarkdbuser password=benchmarkdbpass"; - client = new PostgresClient(connectionInfo, poolSize, (Connection cn){ - cn.prepare("fortune_prpq", "SELECT id, message::text FROM Fortune"); - cn.prepare("db_prpq", "SELECT randomNumber, id FROM world WHERE id = $1"); - cn.prepare("db_update_prpq", "UPDATE world SET randomNumber = $1 WHERE id = $2"); - } ); -} diff --git a/frameworks/Dart/angel3/README.md b/frameworks/Dart/angel3/README.md index b78d395dab1..865387be4fe 100644 --- a/frameworks/Dart/angel3/README.md +++ b/frameworks/Dart/angel3/README.md @@ -1,10 +1,10 @@ # Angel3 Framework Benchmarking Test -This is the Angel3 framework portion of a [benchmarking test suite](../) comparing a variety of web development platforms. +This is the Angel3 framework portion of a [benchmarking test suite](../) comparing a variety of web development platforms. ## Description -All the tests are implemented using the [Angel3 Framework](https://angel3-framework.web.app) with ORM for Postgresql database enabled. The directory layout follows the standard ORM boilerplate template. +All the tests are implemented using the [Angel3 Framework](https://angel3-framework.web.app) with ORM for Postgresql and MySQL database on Dart 3.6. The directory layout follows the standard ORM boilerplate template. ### Test Type Implementation Source Code @@ -28,24 +28,24 @@ The tests were run with: ### JSON -http://localhost:8080/json + ### PLAINTEXT -http://localhost:8080/plaintext + ### DB -http://localhost:8080/db + ### QUERY -http://localhost:8080/query?queries= + ### UPDATE -http://localhost:8080/updates?queries= + ### FORTUNES -http://localhost:8080/fortunes + diff --git a/frameworks/Dart/angel3/angel3-mysql.dockerfile b/frameworks/Dart/angel3/angel3-mysql.dockerfile index 614663423f4..0a796a8da8e 100644 --- a/frameworks/Dart/angel3/angel3-mysql.dockerfile +++ b/frameworks/Dart/angel3/angel3-mysql.dockerfile @@ -1,4 +1,4 @@ -FROM dart:2.19.6 +FROM dart:3.6.1 COPY ./orm-mysql/config /app/config COPY ./orm-mysql/lib /app/lib diff --git a/frameworks/Dart/angel3/angel3.dockerfile b/frameworks/Dart/angel3/angel3.dockerfile index 47ea08cb073..01c25265247 100644 --- a/frameworks/Dart/angel3/angel3.dockerfile +++ b/frameworks/Dart/angel3/angel3.dockerfile @@ -1,4 +1,4 @@ -FROM dart:2.19.6 +FROM dart:3.6.1 COPY ./orm/config /app/config COPY ./orm/lib /app/lib diff --git a/frameworks/Dart/angel3/benchmark_config.json b/frameworks/Dart/angel3/benchmark_config.json index 98ab2c0fde9..414d3bf1b0e 100644 --- a/frameworks/Dart/angel3/benchmark_config.json +++ b/frameworks/Dart/angel3/benchmark_config.json @@ -26,9 +26,12 @@ "versus": "None" }, "mysql": { + "json_url": "/json", "db_url": "/db", + "plaintext_url": "/plaintext", "query_url": "/query?queries=", "fortune_url": "/fortunes", + "update_url": "/updates?queries=", "port": 8080, "approach": "Realistic", "classification": "Fullstack", diff --git a/frameworks/Dart/angel3/orm-mysql/config/default.yaml b/frameworks/Dart/angel3/orm-mysql/config/default.yaml index 3363993352c..4771b8ef9ff 100644 --- a/frameworks/Dart/angel3/orm-mysql/config/default.yaml +++ b/frameworks/Dart/angel3/orm-mysql/config/default.yaml @@ -2,7 +2,6 @@ host: 127.0.0.1 port: 8080 mysql: - #host: localhost host: tfb-database port: 3306 database_name: hello_world diff --git a/frameworks/Dart/angel3/orm-mysql/lib/benchmark_app.dart b/frameworks/Dart/angel3/orm-mysql/lib/benchmark_app.dart new file mode 100644 index 00000000000..f97da4a2ccd --- /dev/null +++ b/frameworks/Dart/angel3/orm-mysql/lib/benchmark_app.dart @@ -0,0 +1,18 @@ +import 'dart:async'; +import 'package:angel3_framework/angel3_framework.dart'; +import 'package:file/local.dart'; +import 'src/config/config.dart' as configuration; +import 'src/routes/routes.dart' as routes; +import 'src/services/services.dart' as services; + +/// Configures the server instance. +Future configureServer(Angel app) async { + // Grab a handle to the file system, so that we can do things like + // serve static files. + var fs = const LocalFileSystem(); + + // Set up our application, using the plug-ins defined with this project. + await app.configure(configuration.configureServer(fs)); + await app.configure(services.configureServer); + await app.configure(routes.configureServer(fs)); +} diff --git a/frameworks/Dart/angel3/orm-mysql/lib/orm_mysql_app.dart b/frameworks/Dart/angel3/orm-mysql/lib/orm_mysql_app.dart deleted file mode 100644 index baaf97ce234..00000000000 --- a/frameworks/Dart/angel3/orm-mysql/lib/orm_mysql_app.dart +++ /dev/null @@ -1,19 +0,0 @@ -/// Your very own web application! -import 'dart:async'; -import 'package:angel3_framework/angel3_framework.dart'; -import 'package:file/local.dart'; -import 'src/config/config.dart' as configuration; -import 'src/routes/routes.dart' as routes; -import 'src/services/services.dart' as services; - -/// Configures the server instance. -Future configureServer(Angel app) async { - // Grab a handle to the file system, so that we can do things like - // serve static files. - var fs = const LocalFileSystem(); - - // Set up our application, using the plug-ins defined with this project. - await app.configure(configuration.configureServer(fs)); - await app.configure(services.configureServer); - await app.configure(routes.configureServer(fs)); -} diff --git a/frameworks/Dart/angel3/orm-mysql/lib/src/config/config.dart b/frameworks/Dart/angel3/orm-mysql/lib/src/config/config.dart index c485448be83..0f11e856089 100644 --- a/frameworks/Dart/angel3/orm-mysql/lib/src/config/config.dart +++ b/frameworks/Dart/angel3/orm-mysql/lib/src/config/config.dart @@ -1,4 +1,3 @@ -/// Configuration for this Angel instance. import 'package:angel3_configuration/angel3_configuration.dart'; import 'package:angel3_framework/angel3_framework.dart'; import 'package:angel3_jael/angel3_jael.dart'; diff --git a/frameworks/Dart/angel3/orm-mysql/lib/src/config/plugins/orm.dart b/frameworks/Dart/angel3/orm-mysql/lib/src/config/plugins/orm.dart index 04a1549a976..429dd1bed37 100644 --- a/frameworks/Dart/angel3/orm-mysql/lib/src/config/plugins/orm.dart +++ b/frameworks/Dart/angel3/orm-mysql/lib/src/config/plugins/orm.dart @@ -3,45 +3,9 @@ import 'dart:io'; import 'package:angel3_framework/angel3_framework.dart'; import 'package:angel3_orm/angel3_orm.dart'; import 'package:angel3_orm_mysql/angel3_orm_mysql.dart'; -import 'package:mysql1/mysql1.dart'; import 'package:mysql_client/mysql_client.dart'; -// For MariaDb -Future configureServer2(Angel app) async { - try { - var connection = await connectToMariaDb(app.configuration); - var executor = MariaDbExecutor(connection, logger: app.logger); - - app - ..container.registerSingleton(executor) - ..shutdownHooks.add((_) => connection.close()); - } catch (e) { - app.logger.severe("Failed to connect to MariaDB. ORM disabled.", e); - } -} - -// MariaDB connection -Future connectToMariaDb(Map configuration) async { - var mariaDbConfig = configuration['mysql'] as Map? ?? {}; - var settings = ConnectionSettings( - host: mariaDbConfig['host'] as String? ?? 'localhost', - port: mariaDbConfig['port'] as int? ?? 3306, - db: mariaDbConfig['database_name'] as String? ?? - Platform.environment['USER'] ?? - Platform.environment['USERNAME'] ?? - '', - user: mariaDbConfig['username'] as String?, - password: mariaDbConfig['password'] as String?, - timeout: Duration( - seconds: mariaDbConfig['timeout_in_seconds'] as int? ?? 30000), - useSSL: mariaDbConfig['use_ssl'] as bool? ?? false); - - var connection = await MySqlConnection.connect(settings); - return connection; -} - // For Mysql - Future configureServer(Angel app) async { try { var connection = await connectToMysql(app.configuration); diff --git a/frameworks/Dart/angel3/orm-mysql/lib/src/config/plugins/plugins.dart b/frameworks/Dart/angel3/orm-mysql/lib/src/config/plugins/plugins.dart index f6200eb62a2..08ebc81a0bf 100644 --- a/frameworks/Dart/angel3/orm-mysql/lib/src/config/plugins/plugins.dart +++ b/frameworks/Dart/angel3/orm-mysql/lib/src/config/plugins/plugins.dart @@ -1,4 +1,3 @@ -/// Custom plugins go here. import 'dart:async'; import 'package:angel3_framework/angel3_framework.dart'; import 'orm.dart' as orm; diff --git a/frameworks/Dart/angel3/orm-mysql/lib/src/models/fortune.dart b/frameworks/Dart/angel3/orm-mysql/lib/src/models/fortune.dart index 3f0a612c0df..03d2ab4c589 100644 --- a/frameworks/Dart/angel3/orm-mysql/lib/src/models/fortune.dart +++ b/frameworks/Dart/angel3/orm-mysql/lib/src/models/fortune.dart @@ -1,5 +1,4 @@ import 'package:angel3_migration/angel3_migration.dart'; -//import 'package:angel3_model/angel3_model.dart'; import 'package:angel3_serialize/angel3_serialize.dart'; import 'package:angel3_orm/angel3_orm.dart'; import 'package:optional/optional.dart'; diff --git a/frameworks/Dart/angel3/orm-mysql/lib/src/models/fortune.g.dart b/frameworks/Dart/angel3/orm-mysql/lib/src/models/fortune.g.dart index 4f706492a2a..d4bd661a8cd 100644 --- a/frameworks/Dart/angel3/orm-mysql/lib/src/models/fortune.g.dart +++ b/frameworks/Dart/angel3/orm-mysql/lib/src/models/fortune.g.dart @@ -26,8 +26,10 @@ class FortuneMigration extends Migration { // ************************************************************************** class FortuneQuery extends Query { - FortuneQuery({Query? parent, Set? trampoline}) - : super(parent: parent) { + FortuneQuery({ + Query? parent, + Set? trampoline, + }) : super(parent: parent) { trampoline ??= {}; trampoline.add(tableName); _where = FortuneQueryWhere(this); @@ -52,7 +54,10 @@ class FortuneQuery extends Query { @override List get fields { - const _fields = ['id', 'message']; + const _fields = [ + 'id', + 'message', + ]; return _selectedFields.isEmpty ? _fields : _fields.where((field) => _selectedFields.contains(field)).toList(); @@ -78,8 +83,9 @@ class FortuneQuery extends Query { return Optional.empty(); } var model = Fortune( - id: fields.contains('id') ? (row[0] as int?) : null, - message: fields.contains('message') ? (row[1] as String?) : null); + id: fields.contains('id') ? mapToInt(row[0]) : null, + message: fields.contains('message') ? (row[1] as String?) : null, + ); return Optional.of(model); } @@ -91,8 +97,14 @@ class FortuneQuery extends Query { class FortuneQueryWhere extends QueryWhere { FortuneQueryWhere(FortuneQuery query) - : id = NumericSqlExpressionBuilder(query, 'id'), - message = StringSqlExpressionBuilder(query, 'message'); + : id = NumericSqlExpressionBuilder( + query, + 'id', + ), + message = StringSqlExpressionBuilder( + query, + 'message', + ); final NumericSqlExpressionBuilder id; @@ -100,7 +112,10 @@ class FortuneQueryWhere extends QueryWhere { @override List get expressionBuilders { - return [id, message]; + return [ + id, + message, + ]; } } @@ -115,11 +130,13 @@ class FortuneQueryValues extends MapQueryValues { } set id(int? value) => values['id'] = value; + String? get message { return (values['message'] as String?); } set message(String? value) => values['message'] = value; + void copyFrom(Fortune model) { id = model.id; message = model.message; @@ -132,7 +149,10 @@ class FortuneQueryValues extends MapQueryValues { @generatedSerializable class Fortune extends _Fortune { - Fortune({this.id, this.message}); + Fortune({ + this.id, + this.message, + }); @override int? id; @@ -140,7 +160,10 @@ class Fortune extends _Fortune { @override String? message; - Fortune copyWith({int? id, String? message}) { + Fortune copyWith({ + int? id, + String? message, + }) { return Fortune(id: id ?? this.id, message: message ?? this.message); } @@ -151,7 +174,10 @@ class Fortune extends _Fortune { @override int get hashCode { - return hashObjects([id, message]); + return hashObjects([ + id, + message, + ]); } @override @@ -189,22 +215,27 @@ class FortuneSerializer extends Codec { @override FortuneEncoder get encoder => const FortuneEncoder(); + @override FortuneDecoder get decoder => const FortuneDecoder(); + static Fortune fromMap(Map map) { return Fortune(id: map['id'] as int?, message: map['message'] as String?); } static Map toMap(_Fortune? model) { if (model == null) { - return {}; + throw FormatException("Required field [model] cannot be null"); } return {'id': model.id, 'message': model.message}; } } abstract class FortuneFields { - static const List allFields = [id, message]; + static const List allFields = [ + id, + message, + ]; static const String id = 'id'; diff --git a/frameworks/Dart/angel3/orm-mysql/lib/src/models/world.g.dart b/frameworks/Dart/angel3/orm-mysql/lib/src/models/world.g.dart index b5c66b9c5e5..5b51631b790 100644 --- a/frameworks/Dart/angel3/orm-mysql/lib/src/models/world.g.dart +++ b/frameworks/Dart/angel3/orm-mysql/lib/src/models/world.g.dart @@ -26,7 +26,10 @@ class WorldMigration extends Migration { // ************************************************************************** class WorldQuery extends Query { - WorldQuery({Query? parent, Set? trampoline}) : super(parent: parent) { + WorldQuery({ + Query? parent, + Set? trampoline, + }) : super(parent: parent) { trampoline ??= {}; trampoline.add(tableName); _where = WorldQueryWhere(this); @@ -51,7 +54,10 @@ class WorldQuery extends Query { @override List get fields { - const _fields = ['id', 'randomNumber']; + const _fields = [ + 'id', + 'randomNumber', + ]; return _selectedFields.isEmpty ? _fields : _fields.where((field) => _selectedFields.contains(field)).toList(); @@ -77,9 +83,9 @@ class WorldQuery extends Query { return Optional.empty(); } var model = World( - id: fields.contains('id') ? (row[0] as int?) : null, - randomNumber: - fields.contains('randomNumber') ? (row[1] as int?) : null); + id: fields.contains('id') ? mapToInt(row[0]) : null, + randomNumber: fields.contains('randomNumber') ? mapToInt(row[1]) : null, + ); return Optional.of(model); } @@ -91,8 +97,14 @@ class WorldQuery extends Query { class WorldQueryWhere extends QueryWhere { WorldQueryWhere(WorldQuery query) - : id = NumericSqlExpressionBuilder(query, 'id'), - randomNumber = NumericSqlExpressionBuilder(query, 'randomNumber'); + : id = NumericSqlExpressionBuilder( + query, + 'id', + ), + randomNumber = NumericSqlExpressionBuilder( + query, + 'randomNumber', + ); final NumericSqlExpressionBuilder id; @@ -100,7 +112,10 @@ class WorldQueryWhere extends QueryWhere { @override List get expressionBuilders { - return [id, randomNumber]; + return [ + id, + randomNumber, + ]; } } @@ -115,11 +130,13 @@ class WorldQueryValues extends MapQueryValues { } set id(int? value) => values['id'] = value; + int? get randomNumber { return (values['randomNumber'] as int?); } set randomNumber(int? value) => values['randomNumber'] = value; + void copyFrom(World model) { id = model.id; randomNumber = model.randomNumber; @@ -132,7 +149,10 @@ class WorldQueryValues extends MapQueryValues { @generatedSerializable class World extends _World { - World({this.id, this.randomNumber}); + World({ + this.id, + this.randomNumber, + }); @override int? id; @@ -140,7 +160,10 @@ class World extends _World { @override int? randomNumber; - World copyWith({int? id, int? randomNumber}) { + World copyWith({ + int? id, + int? randomNumber, + }) { return World( id: id ?? this.id, randomNumber: randomNumber ?? this.randomNumber); } @@ -154,7 +177,10 @@ class World extends _World { @override int get hashCode { - return hashObjects([id, randomNumber]); + return hashObjects([ + id, + randomNumber, + ]); } @override @@ -192,8 +218,10 @@ class WorldSerializer extends Codec { @override WorldEncoder get encoder => const WorldEncoder(); + @override WorldDecoder get decoder => const WorldDecoder(); + static World fromMap(Map map) { return World( id: map['id'] as int?, randomNumber: map['randomNumber'] as int?); @@ -201,14 +229,17 @@ class WorldSerializer extends Codec { static Map toMap(_World? model) { if (model == null) { - return {}; + throw FormatException("Required field [model] cannot be null"); } return {'id': model.id, 'randomNumber': model.randomNumber}; } } abstract class WorldFields { - static const List allFields = [id, randomNumber]; + static const List allFields = [ + id, + randomNumber, + ]; static const String id = 'id'; diff --git a/frameworks/Dart/angel3/orm-mysql/lib/src/routes/controllers/controllers.dart b/frameworks/Dart/angel3/orm-mysql/lib/src/routes/controllers/controllers.dart index 34fb213ecf9..771995d66a9 100644 --- a/frameworks/Dart/angel3/orm-mysql/lib/src/routes/controllers/controllers.dart +++ b/frameworks/Dart/angel3/orm-mysql/lib/src/routes/controllers/controllers.dart @@ -1,5 +1,4 @@ import 'dart:async'; -import 'dart:convert'; import 'dart:math'; import 'package:angel3_framework/angel3_framework.dart'; import 'package:angel3_orm/angel3_orm.dart'; @@ -12,12 +11,12 @@ Future configureServer(Angel app) async { var executor = app.container.make(); // Generate a random number between 1 and 10000 - int _genRandomId() { + int genRandomId() { var rand = Random(); return rand.nextInt(10000) + 1; } - int _parseQueryCount(String? count) { + int parseQueryCount(String? count) { if (count == null) { return 1; } @@ -30,11 +29,11 @@ Future configureServer(Angel app) async { return limit; } - List _generateIds(int maxCount) { + List generateIds(int maxCount) { var result = []; while (result.length < maxCount) { - var id = _genRandomId(); + var id = genRandomId(); if (!result.contains(id)) { result.add(id); } @@ -56,25 +55,18 @@ Future configureServer(Angel app) async { // Add an entry and sort a list of fortune app.get('/fortunes', (req, res) async { - //var stopwatch = Stopwatch()..start(); - var list = await FortuneQuery().get(executor); - //print('Query Time: ${stopwatch.elapsed.inMilliseconds}ms'); - list.add( Fortune(id: 0, message: 'Additional fortune added at request time.')); list.sort((a, b) => a.message?.compareTo(b.message ?? '') ?? 0); - //print('Process Time: ${stopwatch.elapsed.inMilliseconds}ms'); - //stopwatch.stop(); - res.render('listing', {'fortunes': list}); }); // Find a random World app.get('/db', (req, res) async { - var id = _genRandomId(); + var id = genRandomId(); var query = WorldQuery()..where?.id.equals(id); var result = await query.get(executor); if (result.isNotEmpty) { @@ -88,12 +80,12 @@ Future configureServer(Angel app) async { app.get('/query', (req, res) async { var params = req.queryParameters; - var queryLimit = _parseQueryCount(params['queries'] as String?); + var queryLimit = parseQueryCount(params['queries'] as String?); - var list = _generateIds(queryLimit); - var query = WorldQuery(); + var list = generateIds(queryLimit); var result = []; for (var id in list) { + var query = WorldQuery(); query.where?.id.equals(id); var optWorld = await query.getOne(executor); result.add(optWorld.value); @@ -104,28 +96,23 @@ Future configureServer(Angel app) async { // Update a list of worlds app.get('/updates', (req, res) async { - //var stopwatch = Stopwatch()..start(); - var params = req.queryParameters; - var queryLimit = _parseQueryCount(params['queries'] as String?); - var listOfIds = _generateIds(queryLimit); + var queryLimit = parseQueryCount(params['queries'] as String?); + var listOfIds = generateIds(queryLimit); - var query = WorldQuery(); var result = []; for (var id in listOfIds) { + var query = WorldQuery(); query.where?.id.equals(id); var optWorld = await query.getOne(executor); query ..where?.id.equals(optWorld.value.id!) - ..values.randomNumber = _genRandomId(); + ..values.randomNumber = genRandomId(); var updatedRec = await query.updateOne(executor); result.add(updatedRec.value); } - //rint('Process Time: ${stopwatch.elapsed.inMilliseconds}ms'); - //stopwatch.stop(); - res.json(result); }); } diff --git a/frameworks/Dart/angel3/orm-mysql/lib/src/routes/routes.dart b/frameworks/Dart/angel3/orm-mysql/lib/src/routes/routes.dart index f09c7af933c..560fc1f8ba9 100644 --- a/frameworks/Dart/angel3/orm-mysql/lib/src/routes/routes.dart +++ b/frameworks/Dart/angel3/orm-mysql/lib/src/routes/routes.dart @@ -1,4 +1,3 @@ -/// This app's route configuration. import 'package:angel3_framework/angel3_framework.dart'; import 'package:angel3_static/angel3_static.dart'; import 'package:file/file.dart'; diff --git a/frameworks/Dart/angel3/orm-mysql/lib/src/services/services.dart b/frameworks/Dart/angel3/orm-mysql/lib/src/services/services.dart index 188d0b89f81..bf1ce7cb251 100644 --- a/frameworks/Dart/angel3/orm-mysql/lib/src/services/services.dart +++ b/frameworks/Dart/angel3/orm-mysql/lib/src/services/services.dart @@ -1,4 +1,3 @@ -/// Declare services here! import 'dart:async'; import 'package:angel3_framework/angel3_framework.dart'; diff --git a/frameworks/Dart/angel3/orm-mysql/pubspec.lock b/frameworks/Dart/angel3/orm-mysql/pubspec.lock index a9ffdd5bb48..bb10156745f 100644 --- a/frameworks/Dart/angel3/orm-mysql/pubspec.lock +++ b/frameworks/Dart/angel3/orm-mysql/pubspec.lock @@ -5,841 +5,977 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - url: "https://pub.dartlang.org" + sha256: dc27559385e905ad30838356c5f5d574014ba39872d732111cd07ac0beff4c57 + url: "https://pub.dev" source: hosted - version: "47.0.0" + version: "80.0.0" analyzer: dependency: transitive description: name: analyzer - url: "https://pub.dartlang.org" + sha256: "192d1c5b944e7e53b24b5586db760db934b177d4147c42fbca8c8c5f1eb8d11e" + url: "https://pub.dev" source: hosted - version: "4.7.0" + version: "7.3.0" angel3_auth: dependency: "direct main" description: name: angel3_auth - url: "https://pub.dartlang.org" + sha256: "3996219fca7a49174c3745732a1e438ec94d55936697f2504196be4f3dbf191a" + url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "8.3.0" angel3_client: dependency: transitive description: name: angel3_client - url: "https://pub.dartlang.org" + sha256: e2886fdb41f243d85003f94127850bdd70f79fa5f7cf1f2b79b4f7029198e9dd + url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "8.4.0" angel3_configuration: dependency: "direct main" description: name: angel3_configuration - url: "https://pub.dartlang.org" + sha256: f585699cf0ea5376d7ed6310e9fc57ccdd4645e5746ea0bae1fa6c05efe4e810 + url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "8.3.0" angel3_container: - dependency: transitive + dependency: "direct main" description: name: angel3_container - url: "https://pub.dartlang.org" + sha256: c08ea6b426242861d11109b748792503652a7eb0db4005409c0a031e80820c7f + url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "8.3.0" angel3_framework: dependency: "direct main" description: name: angel3_framework - url: "https://pub.dartlang.org" + sha256: "91d56825b78846d9294e8aae789362644d4e24df4870d52d6c2cc6d8adf8d2c9" + url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "8.5.0" angel3_hot: dependency: "direct dev" description: name: angel3_hot - url: "https://pub.dartlang.org" + sha256: "8e1e7409631a49f05483e2067d1f27f594d558459712311b5ea4317b5519975b" + url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "8.4.0" angel3_http_exception: dependency: transitive description: name: angel3_http_exception - url: "https://pub.dartlang.org" + sha256: "9484b425a1aece1af3f2f0521fba429cd48f0a952521d40281333694c750e4ab" + url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "8.3.0" angel3_jael: dependency: "direct main" description: name: angel3_jael - url: "https://pub.dartlang.org" + sha256: "4ce85198613faff74ac8706065c619e7d6fc609aeb63b2fa7d9dba6f5a981f5c" + url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "8.3.0" angel3_migration: dependency: "direct main" description: name: angel3_migration - url: "https://pub.dartlang.org" + sha256: de7180ce8e48b0fe551c0b96cc83d0cafdcb71de3c75e13b0b08c3fdaf9df351 + url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "8.4.0" angel3_migration_runner: dependency: "direct dev" description: name: angel3_migration_runner - url: "https://pub.dartlang.org" + sha256: "30596dd82471dcddd35afb8b245c1dd56c8c53bdf77dee5e131c353e37e05f9b" + url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "8.4.1" angel3_mock_request: dependency: transitive description: name: angel3_mock_request - url: "https://pub.dartlang.org" + sha256: "8c8513a649d33c0c0531a120183da558000b4f044a4f30fd3ae22dfe11355a04" + url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "8.3.0" angel3_model: dependency: transitive description: name: angel3_model - url: "https://pub.dartlang.org" + sha256: "9a3f50b02bf119bb160d5f94580940b93973589d9b5949d284d2427b8fb65e16" + url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "8.3.0" angel3_orm: dependency: "direct main" description: name: angel3_orm - url: "https://pub.dartlang.org" + sha256: "9d1831b6b91820e312b52cf4c8c3cebb067be59b47123276fbc7741a01ae2ac5" + url: "https://pub.dev" source: hosted - version: "7.0.1" + version: "8.3.2" angel3_orm_generator: dependency: "direct dev" description: name: angel3_orm_generator - url: "https://pub.dartlang.org" + sha256: "18426152dc86e1f0cd5fab14470f07a5b5ac7dd1b78f7e1bf8986d2625a898ec" + url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "8.4.1" angel3_orm_mysql: dependency: "direct main" description: name: angel3_orm_mysql - url: "https://pub.dartlang.org" + sha256: "63e7a6c36a0e492b89b4677bec9f79042d098063bbecb920705ab60d4415a3c6" + url: "https://pub.dev" source: hosted - version: "7.0.1" + version: "8.3.1" angel3_production: dependency: "direct main" description: name: angel3_production - url: "https://pub.dartlang.org" + sha256: "286d4b6dcd5e4297eea3db93cb419282ca14ef920f77439ef7b42c6229ab6219" + url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "8.4.1" angel3_route: dependency: transitive description: name: angel3_route - url: "https://pub.dartlang.org" + sha256: f2ebf4b134e13f804271d4e164a92de5dd25ad0bb651303df2c9e6fb397f32a8 + url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "8.4.0" angel3_serialize: dependency: "direct main" description: name: angel3_serialize - url: "https://pub.dartlang.org" + sha256: "4a4658b8af0d0eec6b8816699f137367c6af7c6f6a1f83a84e43fee55f892f5e" + url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "8.3.0" angel3_serialize_generator: dependency: "direct dev" description: name: angel3_serialize_generator - url: "https://pub.dartlang.org" + sha256: "0fd91dd1162f5c0d1b3c0f2734f48787202693926e6d6c97bca18658c8b812f4" + url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "8.4.1" angel3_static: dependency: "direct main" description: name: angel3_static - url: "https://pub.dartlang.org" + sha256: "534e827500304fa4e95f3613b130aad832dc65681b9a4c47a83891f65b04b554" + url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "8.3.0" angel3_test: dependency: "direct dev" description: name: angel3_test - url: "https://pub.dartlang.org" + sha256: "2ae3d83f83fb6c0834948b4ae3afc02da8c7ee38da3e164bd455564267e39ff8" + url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "8.3.0" angel3_validate: dependency: "direct main" description: name: angel3_validate - url: "https://pub.dartlang.org" + sha256: "661ef636583b0e60b35756d3d296d2ef7b257277fa703a494278ace9fcbe4f0c" + url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "8.3.0" angel3_websocket: dependency: transitive description: name: angel3_websocket - url: "https://pub.dartlang.org" + sha256: "160399b1898d5fd9c8294b4321691567687d9d86d8940aea83cc528b85427229" + url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "8.4.0" args: dependency: transitive description: name: args - url: "https://pub.dartlang.org" + sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 + url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.7.0" async: dependency: transitive description: name: async - url: "https://pub.dartlang.org" + sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" + url: "https://pub.dev" source: hosted - version: "2.9.0" + version: "2.13.0" belatuk_code_buffer: dependency: transitive description: name: belatuk_code_buffer - url: "https://pub.dartlang.org" + sha256: "06c4329570e2cb72cb808c5f19d2004865b7c1f18447d4af16d465776416ccfc" + url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "5.3.0" belatuk_combinator: dependency: transitive description: name: belatuk_combinator - url: "https://pub.dartlang.org" + sha256: "0c54ddf1a6a7c94585c55a5852ccc13ad1a871e3e0709d3322d0286eb7afb7d7" + url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "5.3.0" belatuk_html_builder: dependency: transitive description: name: belatuk_html_builder - url: "https://pub.dartlang.org" + sha256: "0bdd783a54aa7435c86231b319bfffa06259aea6df59dbec62d351456062e67f" + url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "5.3.0" belatuk_http_server: dependency: transitive description: name: belatuk_http_server - url: "https://pub.dartlang.org" + sha256: "2a4ae9409f3586a95a3393b924c86fd38c30d955aa2437070c3198a1ec0a1686" + url: "https://pub.dev" source: hosted - version: "3.0.0" + version: "4.5.0" belatuk_json_serializer: dependency: transitive description: name: belatuk_json_serializer - url: "https://pub.dartlang.org" + sha256: b0b6ee6b4aa0552d84b487c5d1a97f72c9d5c4cbc4e2828f57e24635d5d75be8 + url: "https://pub.dev" source: hosted - version: "6.0.1" + version: "7.3.0" belatuk_merge_map: dependency: transitive description: name: belatuk_merge_map - url: "https://pub.dartlang.org" + sha256: "1eb3c77417598e1d40c11d8d93b3c7bb5f10ca0977b2f942c623698bf3745f43" + url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "5.3.0" belatuk_pretty_logging: dependency: "direct main" description: name: belatuk_pretty_logging - url: "https://pub.dartlang.org" + sha256: "29fb3127ce58643e59fc4510ce41fa4d795f56997cbc661dffdf07e9a65e7021" + url: "https://pub.dev" source: hosted - version: "5.0.0" + version: "6.3.0" belatuk_pub_sub: dependency: transitive description: name: belatuk_pub_sub - url: "https://pub.dartlang.org" + sha256: "08c4f458165f7e2d76a3a4796e94092b98579aedd1fc8a64f39cfbbd18db249d" + url: "https://pub.dev" source: hosted - version: "5.0.0" + version: "6.4.0" belatuk_range_header: dependency: transitive description: name: belatuk_range_header - url: "https://pub.dartlang.org" + sha256: "78f315c8a53415a04a77dee3fcec6f867bac77d2e5d3e13ffc7532d1800adc53" + url: "https://pub.dev" source: hosted - version: "5.0.0" + version: "6.4.0" belatuk_symbol_table: dependency: transitive description: name: belatuk_symbol_table - url: "https://pub.dartlang.org" + sha256: "154f50623b2c5a669561588d86a445f97cf081de6e690ba9bc866dcd98508f50" + url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "5.3.0" boolean_selector: dependency: transitive description: name: boolean_selector - url: "https://pub.dartlang.org" + sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.2" buffer: dependency: transitive description: name: buffer - url: "https://pub.dartlang.org" + sha256: "389da2ec2c16283c8787e0adaede82b1842102f8c8aae2f49003a766c5c6b3d1" + url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.2.3" build: dependency: transitive description: name: build - url: "https://pub.dartlang.org" + sha256: cef23f1eda9b57566c81e2133d196f8e3df48f244b317368d65c5943d91148f0 + url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.4.2" build_config: dependency: transitive description: name: build_config - url: "https://pub.dartlang.org" + sha256: "4ae2de3e1e67ea270081eaee972e1bd8f027d459f249e0f1186730784c2e7e33" + url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.2" build_daemon: dependency: transitive description: name: build_daemon - url: "https://pub.dartlang.org" + sha256: "8e928697a82be082206edb0b9c99c5a4ad6bc31c9e9b8b2f291ae65cd4a25daa" + url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "4.0.4" build_resolvers: dependency: transitive description: name: build_resolvers - url: "https://pub.dartlang.org" + sha256: b9e4fda21d846e192628e7a4f6deda6888c36b5b69ba02ff291a01fd529140f0 + url: "https://pub.dev" source: hosted - version: "2.0.10" + version: "2.4.4" build_runner: dependency: "direct dev" description: name: build_runner - url: "https://pub.dartlang.org" + sha256: "058fe9dce1de7d69c4b84fada934df3e0153dd000758c4d65964d0166779aa99" + url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.4.15" build_runner_core: dependency: transitive description: name: build_runner_core - url: "https://pub.dartlang.org" + sha256: "22e3aa1c80e0ada3722fe5b63fd43d9c8990759d0a2cf489c8c5d7b2bdebc021" + url: "https://pub.dev" source: hosted - version: "7.2.4" + version: "8.0.0" built_collection: dependency: transitive description: name: built_collection - url: "https://pub.dartlang.org" + sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100" + url: "https://pub.dev" source: hosted version: "5.1.1" built_value: dependency: transitive description: name: built_value - url: "https://pub.dartlang.org" + sha256: ea90e81dc4a25a043d9bee692d20ed6d1c4a1662a28c03a96417446c093ed6b4 + url: "https://pub.dev" source: hosted - version: "8.4.1" + version: "8.9.5" charcode: dependency: transitive description: name: charcode - url: "https://pub.dartlang.org" + sha256: fb0f1107cac15a5ea6ef0a6ef71a807b9e4267c713bb93e00e92d737cc8dbd8a + url: "https://pub.dev" source: hosted - version: "1.3.1" + version: "1.4.0" checked_yaml: dependency: transitive description: name: checked_yaml - url: "https://pub.dartlang.org" + sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff + url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "2.0.3" clock: dependency: transitive description: name: clock - url: "https://pub.dartlang.org" + sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b + url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.1.2" code_builder: dependency: transitive description: name: code_builder - url: "https://pub.dartlang.org" + sha256: "0ec10bf4a89e4c613960bf1e8b42c64127021740fb21640c29c909826a5eea3e" + url: "https://pub.dev" source: hosted - version: "4.3.0" + version: "4.10.1" collection: dependency: transitive description: name: collection - url: "https://pub.dartlang.org" + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" + url: "https://pub.dev" source: hosted - version: "1.16.0" + version: "1.19.1" convert: dependency: transitive description: name: convert - url: "https://pub.dartlang.org" + sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 + url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "3.1.2" coverage: dependency: transitive description: name: coverage - url: "https://pub.dartlang.org" + sha256: e3493833ea012784c740e341952298f1cc77f1f01b1bbc3eb4eecf6984fb7f43 + url: "https://pub.dev" source: hosted - version: "1.6.0" + version: "1.11.1" crypto: dependency: transitive description: name: crypto - url: "https://pub.dartlang.org" + sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" + url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "3.0.6" dart_style: dependency: transitive description: name: dart_style - url: "https://pub.dartlang.org" + sha256: "27eb0ae77836989a3bc541ce55595e8ceee0992807f14511552a898ddd0d88ac" + url: "https://pub.dev" source: hosted - version: "2.2.4" + version: "3.0.1" dotenv: dependency: transitive description: name: dotenv - url: "https://pub.dartlang.org" + sha256: "379e64b6fc82d3df29461d349a1796ecd2c436c480d4653f3af6872eccbc90e1" + url: "https://pub.dev" source: hosted - version: "4.0.1" + version: "4.2.0" file: - dependency: transitive + dependency: "direct main" description: name: file - url: "https://pub.dartlang.org" + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 + url: "https://pub.dev" source: hosted - version: "6.1.4" + version: "7.0.1" fixnum: dependency: transitive description: name: fixnum - url: "https://pub.dartlang.org" + sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be + url: "https://pub.dev" source: hosted - version: "1.0.1" + version: "1.1.1" frontend_server_client: dependency: transitive description: name: frontend_server_client - url: "https://pub.dartlang.org" + sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 + url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "4.0.0" glob: dependency: transitive description: name: glob - url: "https://pub.dartlang.org" + sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.3" graphs: dependency: transitive description: name: graphs - url: "https://pub.dartlang.org" + sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.3.2" http: dependency: transitive description: name: http - url: "https://pub.dartlang.org" + sha256: fe7ab022b76f3034adc518fb6ea04a82387620e19977665ea18d30a1cf43442f + url: "https://pub.dev" source: hosted - version: "0.13.5" + version: "1.3.0" http2: dependency: transitive description: name: http2 - url: "https://pub.dartlang.org" + sha256: "382d3aefc5bd6dc68c6b892d7664f29b5beb3251611ae946a98d35158a82bbfa" + url: "https://pub.dev" source: hosted - version: "2.0.0" + version: "2.3.1" http_multi_server: dependency: transitive description: name: http_multi_server - url: "https://pub.dartlang.org" + sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8 + url: "https://pub.dev" source: hosted - version: "3.2.1" + version: "3.2.2" http_parser: dependency: transitive description: name: http_parser - url: "https://pub.dartlang.org" + sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" + url: "https://pub.dev" source: hosted - version: "4.0.1" + version: "4.1.2" inflection3: dependency: transitive description: name: inflection3 - url: "https://pub.dartlang.org" + sha256: cb54689bcfe3c0168a6979ee3191df584dcef4f870c5ef41c798bcb35ff5aca3 + url: "https://pub.dev" source: hosted version: "0.5.3+2" intl: dependency: transitive description: name: intl - url: "https://pub.dartlang.org" + sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5" + url: "https://pub.dev" source: hosted - version: "0.17.0" + version: "0.20.2" io: dependency: "direct dev" description: name: io - url: "https://pub.dartlang.org" + sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b + url: "https://pub.dev" source: hosted - version: "1.0.3" + version: "1.0.5" jael3: dependency: "direct main" description: name: jael3 - url: "https://pub.dartlang.org" + sha256: bee0b8d328898dac9008caf7392400d03bc2035a3dd9acebe7ebee052ef9132b + url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "8.2.0" jael3_preprocessor: dependency: transitive description: name: jael3_preprocessor - url: "https://pub.dartlang.org" + sha256: "8e70b92608e61c032f08bed82fa63b82e26b4ede4f4924b81bd75329fae9e9b8" + url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "8.2.0" js: dependency: transitive description: name: js - url: "https://pub.dartlang.org" + sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf + url: "https://pub.dev" source: hosted - version: "0.6.4" + version: "0.7.1" json_annotation: dependency: transitive description: name: json_annotation - url: "https://pub.dartlang.org" + sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" + url: "https://pub.dev" source: hosted - version: "4.6.0" + version: "4.9.0" json_rpc_2: dependency: transitive description: name: json_rpc_2 - url: "https://pub.dartlang.org" + sha256: "246b321532f0e8e2ba474b4d757eaa558ae4fdd0688fdbc1e1ca9705f9b8ca0e" + url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "3.0.3" lints: dependency: "direct dev" description: name: lints - url: "https://pub.dartlang.org" + sha256: c35bb79562d980e9a453fc715854e1ed39e24e7d0297a880ef54e17f9874a9d7 + url: "https://pub.dev" source: hosted - version: "2.0.0" + version: "5.1.1" logging: dependency: "direct main" description: name: logging - url: "https://pub.dartlang.org" + sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 + url: "https://pub.dev" source: hosted - version: "1.0.2" + version: "1.3.0" matcher: dependency: transitive description: name: matcher - url: "https://pub.dartlang.org" + sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 + url: "https://pub.dev" source: hosted - version: "0.12.12" + version: "0.12.17" meta: dependency: transitive description: name: meta - url: "https://pub.dartlang.org" + sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c + url: "https://pub.dev" source: hosted - version: "1.8.0" + version: "1.16.0" mime: dependency: transitive description: name: mime - url: "https://pub.dartlang.org" + sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" + url: "https://pub.dev" source: hosted - version: "1.0.2" + version: "2.0.0" mysql1: dependency: transitive description: name: mysql1 - url: "https://pub.dartlang.org" + sha256: "68aec7003d2abc85769bafa1777af3f4a390a90c31032b89636758ff8eb839e9" + url: "https://pub.dev" source: hosted version: "0.20.0" mysql_client: - dependency: transitive + dependency: "direct main" description: name: mysql_client - url: "https://pub.dartlang.org" + sha256: "6a0fdcbe3e0721c637f97ad24649be2f70dbce2b21ede8f962910e640f753fc2" + url: "https://pub.dev" source: hosted - version: "0.0.26" + version: "0.0.27" node_preamble: dependency: transitive description: name: node_preamble - url: "https://pub.dartlang.org" + sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db" + url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "2.0.2" optional: dependency: "direct main" description: name: optional - url: "https://pub.dartlang.org" + sha256: f80327d7a3335a0be68418072668043c7ab291df575c21aa42e0c5633641da39 + url: "https://pub.dev" source: hosted version: "6.1.0+1" package_config: dependency: transitive description: name: package_config - url: "https://pub.dartlang.org" + sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.2.0" path: dependency: transitive description: name: path - url: "https://pub.dartlang.org" + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" + url: "https://pub.dev" source: hosted - version: "1.8.2" - pedantic: - dependency: transitive - description: - name: pedantic - url: "https://pub.dartlang.org" - source: hosted - version: "1.11.1" + version: "1.9.1" pool: dependency: transitive description: name: pool - url: "https://pub.dartlang.org" + sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" + url: "https://pub.dev" source: hosted version: "1.5.1" postgres: dependency: transitive description: name: postgres - url: "https://pub.dartlang.org" + sha256: "7a7f9805d33e41cb14fa22535959f3af51843a792015cdbd8f2fa78bcd1b501b" + url: "https://pub.dev" source: hosted - version: "2.5.2" + version: "3.5.4" pub_semver: dependency: transitive description: name: pub_semver - url: "https://pub.dartlang.org" + sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585" + url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.2.0" pubspec_parse: dependency: transitive description: name: pubspec_parse - url: "https://pub.dartlang.org" + sha256: "0560ba233314abbed0a48a2956f7f022cce7c3e1e73df540277da7544cad4082" + url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.5.0" quiver: dependency: transitive description: name: quiver - url: "https://pub.dartlang.org" + sha256: ea0b925899e64ecdfbf9c7becb60d5b50e706ade44a85b2363be2a22d88117d2 + url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.2.2" recase: dependency: transitive description: name: recase - url: "https://pub.dartlang.org" + sha256: e4eb4ec2dcdee52dcf99cb4ceabaffc631d7424ee55e56f280bc039737f89213 + url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "4.1.0" sasl_scram: dependency: transitive description: name: sasl_scram - url: "https://pub.dartlang.org" + sha256: a47207a436eb650f8fdcf54a2e2587b850dc3caef9973ce01f332b07a6fc9cb9 + url: "https://pub.dev" source: hosted version: "0.1.1" saslprep: dependency: transitive description: name: saslprep - url: "https://pub.dartlang.org" + sha256: "3d421d10be9513bf4459c17c5e70e7b8bc718c9fc5ad4ba5eb4f5fd27396f740" + url: "https://pub.dev" source: hosted - version: "1.0.2" + version: "1.0.3" shelf: dependency: transitive description: name: shelf - url: "https://pub.dartlang.org" + sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12 + url: "https://pub.dev" source: hosted - version: "1.3.2" + version: "1.4.2" shelf_packages_handler: dependency: transitive description: name: shelf_packages_handler - url: "https://pub.dartlang.org" + sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e" + url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.0.2" shelf_static: dependency: transitive description: name: shelf_static - url: "https://pub.dartlang.org" + sha256: c87c3875f91262785dade62d135760c2c69cb217ac759485334c5857ad89f6e3 + url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.1.3" shelf_web_socket: dependency: transitive description: name: shelf_web_socket - url: "https://pub.dartlang.org" + sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925" + url: "https://pub.dev" source: hosted - version: "1.0.2" + version: "3.0.0" source_gen: dependency: transitive description: name: source_gen - url: "https://pub.dartlang.org" + sha256: "35c8150ece9e8c8d263337a265153c3329667640850b9304861faea59fc98f6b" + url: "https://pub.dev" source: hosted - version: "1.2.3" + version: "2.0.0" source_map_stack_trace: dependency: transitive description: name: source_map_stack_trace - url: "https://pub.dartlang.org" + sha256: c0713a43e323c3302c2abe2a1cc89aa057a387101ebd280371d6a6c9fa68516b + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.2" source_maps: dependency: transitive description: name: source_maps - url: "https://pub.dartlang.org" + sha256: "190222579a448b03896e0ca6eca5998fa810fda630c1d65e2f78b3f638f54812" + url: "https://pub.dev" source: hosted - version: "0.10.10" + version: "0.10.13" source_span: dependency: transitive description: name: source_span - url: "https://pub.dartlang.org" + sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" + url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.10.1" + sprintf: + dependency: transitive + description: + name: sprintf + sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23" + url: "https://pub.dev" + source: hosted + version: "7.0.0" stack_trace: dependency: transitive description: name: stack_trace - url: "https://pub.dartlang.org" + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" + url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.12.1" stream_channel: dependency: transitive description: name: stream_channel - url: "https://pub.dartlang.org" + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.4" stream_transform: dependency: transitive description: name: stream_transform - url: "https://pub.dartlang.org" + sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871 + url: "https://pub.dev" source: hosted - version: "2.0.0" + version: "2.1.1" string_scanner: dependency: transitive description: name: string_scanner - url: "https://pub.dartlang.org" + sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" + url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.4.1" term_glyph: dependency: transitive description: name: term_glyph - url: "https://pub.dartlang.org" + sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" + url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.2.2" test: dependency: "direct dev" description: name: test - url: "https://pub.dartlang.org" + sha256: "301b213cd241ca982e9ba50266bd3f5bd1ea33f1455554c5abb85d1be0e2d87e" + url: "https://pub.dev" source: hosted - version: "1.21.6" + version: "1.25.15" test_api: dependency: transitive description: name: test_api - url: "https://pub.dartlang.org" + sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd + url: "https://pub.dev" source: hosted - version: "0.4.14" + version: "0.7.4" test_core: dependency: transitive description: name: test_core - url: "https://pub.dartlang.org" + sha256: "84d17c3486c8dfdbe5e12a50c8ae176d15e2a771b96909a9442b40173649ccaa" + url: "https://pub.dev" source: hosted - version: "0.4.18" + version: "0.6.8" timing: dependency: transitive description: name: timing - url: "https://pub.dartlang.org" + sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe" + url: "https://pub.dev" source: hosted - version: "1.0.0" + version: "1.0.2" tuple: dependency: transitive description: name: tuple - url: "https://pub.dartlang.org" + sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151 + url: "https://pub.dev" source: hosted - version: "2.0.0" + version: "2.0.2" typed_data: dependency: transitive description: name: typed_data - url: "https://pub.dartlang.org" + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 + url: "https://pub.dev" source: hosted - version: "1.3.1" + version: "1.4.0" unorm_dart: dependency: transitive description: name: unorm_dart - url: "https://pub.dartlang.org" + sha256: "23d8bf65605401a6a32cff99435fed66ef3dab3ddcad3454059165df46496a3b" + url: "https://pub.dev" source: hosted - version: "0.2.0" + version: "0.3.0" uuid: dependency: transitive description: name: uuid - url: "https://pub.dartlang.org" + sha256: a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff + url: "https://pub.dev" source: hosted - version: "3.0.6" + version: "4.5.1" vm_service: dependency: transitive description: name: vm_service - url: "https://pub.dartlang.org" + sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02 + url: "https://pub.dev" source: hosted - version: "9.4.0" + version: "15.0.0" watcher: dependency: transitive description: name: watcher - url: "https://pub.dartlang.org" + sha256: "69da27e49efa56a15f8afe8f4438c4ec02eff0a117df1b22ea4aad194fe1c104" + url: "https://pub.dev" source: hosted - version: "1.0.1" + version: "1.1.1" + web: + dependency: transitive + description: + name: web + sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" + url: "https://pub.dev" + source: hosted + version: "1.1.1" + web_socket: + dependency: transitive + description: + name: web_socket + sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83" + url: "https://pub.dev" + source: hosted + version: "0.1.6" web_socket_channel: dependency: transitive description: name: web_socket_channel - url: "https://pub.dartlang.org" + sha256: "0b8e2457400d8a859b7b2030786835a28a8e80836ef64402abef392ff4f1d0e5" + url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "3.0.2" webkit_inspection_protocol: dependency: transitive description: name: webkit_inspection_protocol - url: "https://pub.dartlang.org" + sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572" + url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.2.1" yaml: dependency: transitive description: name: yaml - url: "https://pub.dartlang.org" + sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce + url: "https://pub.dev" source: hosted - version: "3.1.1" + version: "3.1.3" sdks: - dart: ">=2.18.0 <3.0.0" + dart: ">=3.6.0 <4.0.0" diff --git a/frameworks/Dart/angel3/orm-mysql/pubspec.yaml b/frameworks/Dart/angel3/orm-mysql/pubspec.yaml index 4744712db06..1cd83585e76 100644 --- a/frameworks/Dart/angel3/orm-mysql/pubspec.yaml +++ b/frameworks/Dart/angel3/orm-mysql/pubspec.yaml @@ -1,40 +1,38 @@ name: orm_mysql_app -version: 1.0.0 +version: 2.0.0 description: A basic starter application template for Angel3 framework publish_to: none environment: - sdk: '>=2.17.0 <3.0.0' + sdk: '>=3.6.0 <4.0.0' + dependencies: - angel3_auth: ^7.0.0 - angel3_configuration: ^7.0.0 - angel3_framework: ^7.0.0 - angel3_jael: ^7.0.0 - angel3_migration: ^7.0.0 - angel3_orm: ^7.0.0 - angel3_orm_mysql: ^7.0.0 - angel3_serialize: ^7.0.0 - angel3_production: ^7.0.0 - angel3_static: ^7.0.0 - angel3_validate: ^7.0.0 - jael3: ^7.0.0 - belatuk_pretty_logging: ^5.0.0 + angel3_auth: ^8.3.0 + angel3_configuration: ^8.3.0 + angel3_framework: ^8.5.0 + angel3_jael: ^8.3.0 + angel3_migration: ^8.3.0 + angel3_orm: ^8.3.0 + angel3_orm_mysql: ^8.3.0 + angel3_serialize: ^8.3.0 + angel3_production: ^8.3.0 + angel3_static: ^8.3.0 + angel3_validate: ^8.3.0 + jael3: ^8.0.0 + belatuk_pretty_logging: ^6.0.0 optional: ^6.0.0 - logging: ^1.0.0 + logging: ^1.2.0 + angel3_container: ^8.3.0 + file: ^7.0.1 + mysql_client: ^0.0.27 + dev_dependencies: - angel3_hot: ^7.0.0 - angel3_migration_runner: ^7.0.0 - angel3_orm_generator: ^7.0.0 - angel3_serialize_generator: ^7.0.0 - angel3_test: ^7.0.0 - build_runner: ^2.0.3 + angel3_hot: ^8.0.0 + angel3_migration_runner: ^8.0.0 + angel3_orm_generator: ^8.0.0 + angel3_serialize_generator: ^8.0.0 + angel3_test: ^8.0.0 + build_runner: ^2.4.0 io: ^1.0.0 - test: ^1.17.5 - lints: ^2.0.0 -# dependency_overrides: -# angel3_orm: -# path: ../../../../../belatuk/packages/orm/angel_orm -# angel3_orm_postgres: -# path: ../../../../../belatuk/packages/orm/angel_orm_postgres -# angel3_jael: -# path: ../../../../../belatuk/packages/jael/angel_jael + test: ^1.25.0 + lints: ^5.0.0 \ No newline at end of file diff --git a/frameworks/Dart/angel3/orm-mysql/run/dev.dart b/frameworks/Dart/angel3/orm-mysql/run/dev.dart index cecd1abacbf..33b104e04be 100644 --- a/frameworks/Dart/angel3/orm-mysql/run/dev.dart +++ b/frameworks/Dart/angel3/orm-mysql/run/dev.dart @@ -4,7 +4,7 @@ import 'package:belatuk_pretty_logging/belatuk_pretty_logging.dart'; import 'package:angel3_container/mirrors.dart'; import 'package:angel3_framework/angel3_framework.dart'; import 'package:angel3_hot/angel3_hot.dart'; -import 'package:orm_mysql_app/orm_mysql_app.dart'; +import 'package:orm_mysql_app/benchmark_app.dart'; void main() async { // Watch the config/ and web/ directories for changes, and hot-reload the server. diff --git a/frameworks/Dart/angel3/orm-mysql/run/prod.dart b/frameworks/Dart/angel3/orm-mysql/run/prod.dart index 158bc09a567..dfcda79585a 100644 --- a/frameworks/Dart/angel3/orm-mysql/run/prod.dart +++ b/frameworks/Dart/angel3/orm-mysql/run/prod.dart @@ -1,29 +1,6 @@ import 'package:angel3_container/mirrors.dart'; import 'package:angel3_production/angel3_production.dart'; -import 'package:orm_mysql_app/orm_mysql_app.dart'; +import 'package:orm_mysql_app/benchmark_app.dart'; -// NOTE: By default, the Runner class does not use the `MirrorsReflector`, or any -// reflector, by default. -// -// If your application is using any sort of functionality reliant on annotations or reflection, -// either include the MirrorsReflector, or use a static reflector variant. -// -// The following use cases require reflection: -// * Use of Controllers, via @Expose() or @ExposeWS() -// * Use of dependency injection into constructors, whether in controllers or plain `container.make` calls -// * Use of the `ioc` function in any route -// -// The `MirrorsReflector` from `package:angel_container/mirrors.dart` is by far the most convenient pattern, -// so use it if possible. -// -// However, the following alternatives exist: -// * Generation via `package:angel_container_generator` -// * Creating an instance of `StaticReflector` -// * Manually implementing the `Reflector` interface (cumbersome; not recommended) -// -// As of January 4th, 2018, the documentation has not yet been updated to state this, -// so in the meantime, visit the Angel chat for further questions: -// -// https://gitter.im/angel_dart/discussion void main(List args) => Runner('Angel3', configureServer, reflector: MirrorsReflector()).run(args); diff --git a/frameworks/Dart/angel3/orm-mysql/test/all_test.dart b/frameworks/Dart/angel3/orm-mysql/test/all_test.dart index 4fed3057fb5..e8025b27b28 100644 --- a/frameworks/Dart/angel3/orm-mysql/test/all_test.dart +++ b/frameworks/Dart/angel3/orm-mysql/test/all_test.dart @@ -1,22 +1,17 @@ import 'package:angel3_framework/angel3_framework.dart'; import 'package:angel3_test/angel3_test.dart'; import 'package:test/test.dart'; -import 'package:orm_mysql_app/orm_mysql_app.dart'; +import 'package:orm_mysql_app/benchmark_app.dart'; -// Angel also includes facilities to make testing easier. +// Angel3 also includes facilities to make testing easier. // -// `package:angel_test` ships a client that can test -// both plain HTTP and WebSockets. +// `package:angel3_test` ships a client that can test both plain HTTP and WebSockets. // // Tests do not require your server to actually be mounted on a port, // so they will run faster than they would in other frameworks, where you // would have to first bind a socket, and then account for network latency. // -// See the documentation here: -// https://github.com/angel-dart/test -// -// If you are unfamiliar with Dart's advanced testing library, you can read up -// here: +// If you are unfamiliar with Dart's advanced testing library, you can read up here: // https://github.com/dart-lang/test void main() async { diff --git a/frameworks/Dart/angel3/orm/config/default.yaml b/frameworks/Dart/angel3/orm/config/default.yaml index e43fde7a80c..11a3f44e235 100644 --- a/frameworks/Dart/angel3/orm/config/default.yaml +++ b/frameworks/Dart/angel3/orm/config/default.yaml @@ -2,7 +2,6 @@ host: 127.0.0.1 port: 8080 postgres: - #host: localhost host: tfb-database port: 5432 database_name: hello_world diff --git a/frameworks/Dart/angel3/orm/lib/benchmark_app.dart b/frameworks/Dart/angel3/orm/lib/benchmark_app.dart index baaf97ce234..f97da4a2ccd 100644 --- a/frameworks/Dart/angel3/orm/lib/benchmark_app.dart +++ b/frameworks/Dart/angel3/orm/lib/benchmark_app.dart @@ -1,4 +1,3 @@ -/// Your very own web application! import 'dart:async'; import 'package:angel3_framework/angel3_framework.dart'; import 'package:file/local.dart'; diff --git a/frameworks/Dart/angel3/orm/lib/src/config/plugins/orm.dart b/frameworks/Dart/angel3/orm/lib/src/config/plugins/orm.dart index 87d9defb170..5700708d619 100644 --- a/frameworks/Dart/angel3/orm/lib/src/config/plugins/orm.dart +++ b/frameworks/Dart/angel3/orm/lib/src/config/plugins/orm.dart @@ -3,45 +3,23 @@ import 'dart:io'; import 'package:angel3_framework/angel3_framework.dart'; import 'package:angel3_orm/angel3_orm.dart'; import 'package:angel3_orm_postgres/angel3_orm_postgres.dart'; -import 'package:postgres_pool/postgres_pool.dart'; +import 'package:postgres/postgres.dart'; Future configureServer(Angel app) async { var logger = app.environment.isProduction ? null : app.logger; - var connection = await connectToPostgres(app.configuration); - await connection.open(); - var executor = PostgreSqlExecutor(connection, logger: logger); - - //var executor = await connectToPostgresPool(app.configuration, logger); + var connector = await pooledPostgresConnections(app.configuration); + var executor = PostgreSqlPoolExecutor(connector, logger: logger); app ..container.registerSingleton(executor) - ..shutdownHooks.add((_) => connection.close()); -// ..shutdownHooks.add((_) => executor.close()); -} - -Future connectToPostgres(Map configuration) async { - var postgresConfig = configuration['postgres'] as Map? ?? {}; - var connection = PostgreSQLConnection( - postgresConfig['host'] as String? ?? 'localhost', - postgresConfig['port'] as int? ?? 5432, - postgresConfig['database_name'] as String? ?? - Platform.environment['USER'] ?? - Platform.environment['USERNAME'] ?? - '', - username: postgresConfig['username'] as String?, - password: postgresConfig['password'] as String?, - timeZone: postgresConfig['time_zone'] as String? ?? 'UTC', - timeoutInSeconds: postgresConfig['timeout_in_seconds'] as int? ?? 30, - useSSL: postgresConfig['use_ssl'] as bool? ?? false); - return connection; + ..shutdownHooks.add((_) => connector.close()); } -Future connectToPostgresPool( - Map configuration, dynamic logger) async { +Future> pooledPostgresConnections(Map configuration) async { var postgresConfig = configuration['postgres'] as Map? ?? {}; - var _pool = PgPool( - PgEndpoint( + return Pool.withEndpoints([ + Endpoint( host: postgresConfig['host'] as String? ?? 'localhost', port: postgresConfig['port'] as int? ?? 5432, database: postgresConfig['database_name'] as String? ?? @@ -49,18 +27,13 @@ Future connectToPostgresPool( Platform.environment['USERNAME'] ?? '', username: postgresConfig['username'] as String?, - password: postgresConfig['password'] as String?), - settings: PgPoolSettings() - ..maxConnectionAge = Duration(hours: 1) - ..concurrency = 10, - ); - - // Run sql to create the tables in a transaction - //await _pool.runTx((conn) async { - // for (var s in schemas) { - // await conn.execute(await File('test/migrations/$s.sql').readAsString()); - // } - //}); - - return PostgreSqlPoolExecutor(_pool, logger: logger); + password: postgresConfig['password'] as String?) + ], + settings: PoolSettings( + maxConnectionAge: Duration(hours: 1), + maxConnectionCount: 20, + connectTimeout: Duration( + seconds: postgresConfig['timeout_in_seconds'] as int? ?? 30), + timeZone: postgresConfig['time_zone'] as String? ?? 'UTC', + sslMode: SslMode.disable)); } diff --git a/frameworks/Dart/angel3/orm/lib/src/models/fortune.g.dart b/frameworks/Dart/angel3/orm/lib/src/models/fortune.g.dart index 4f706492a2a..d4bd661a8cd 100644 --- a/frameworks/Dart/angel3/orm/lib/src/models/fortune.g.dart +++ b/frameworks/Dart/angel3/orm/lib/src/models/fortune.g.dart @@ -26,8 +26,10 @@ class FortuneMigration extends Migration { // ************************************************************************** class FortuneQuery extends Query { - FortuneQuery({Query? parent, Set? trampoline}) - : super(parent: parent) { + FortuneQuery({ + Query? parent, + Set? trampoline, + }) : super(parent: parent) { trampoline ??= {}; trampoline.add(tableName); _where = FortuneQueryWhere(this); @@ -52,7 +54,10 @@ class FortuneQuery extends Query { @override List get fields { - const _fields = ['id', 'message']; + const _fields = [ + 'id', + 'message', + ]; return _selectedFields.isEmpty ? _fields : _fields.where((field) => _selectedFields.contains(field)).toList(); @@ -78,8 +83,9 @@ class FortuneQuery extends Query { return Optional.empty(); } var model = Fortune( - id: fields.contains('id') ? (row[0] as int?) : null, - message: fields.contains('message') ? (row[1] as String?) : null); + id: fields.contains('id') ? mapToInt(row[0]) : null, + message: fields.contains('message') ? (row[1] as String?) : null, + ); return Optional.of(model); } @@ -91,8 +97,14 @@ class FortuneQuery extends Query { class FortuneQueryWhere extends QueryWhere { FortuneQueryWhere(FortuneQuery query) - : id = NumericSqlExpressionBuilder(query, 'id'), - message = StringSqlExpressionBuilder(query, 'message'); + : id = NumericSqlExpressionBuilder( + query, + 'id', + ), + message = StringSqlExpressionBuilder( + query, + 'message', + ); final NumericSqlExpressionBuilder id; @@ -100,7 +112,10 @@ class FortuneQueryWhere extends QueryWhere { @override List get expressionBuilders { - return [id, message]; + return [ + id, + message, + ]; } } @@ -115,11 +130,13 @@ class FortuneQueryValues extends MapQueryValues { } set id(int? value) => values['id'] = value; + String? get message { return (values['message'] as String?); } set message(String? value) => values['message'] = value; + void copyFrom(Fortune model) { id = model.id; message = model.message; @@ -132,7 +149,10 @@ class FortuneQueryValues extends MapQueryValues { @generatedSerializable class Fortune extends _Fortune { - Fortune({this.id, this.message}); + Fortune({ + this.id, + this.message, + }); @override int? id; @@ -140,7 +160,10 @@ class Fortune extends _Fortune { @override String? message; - Fortune copyWith({int? id, String? message}) { + Fortune copyWith({ + int? id, + String? message, + }) { return Fortune(id: id ?? this.id, message: message ?? this.message); } @@ -151,7 +174,10 @@ class Fortune extends _Fortune { @override int get hashCode { - return hashObjects([id, message]); + return hashObjects([ + id, + message, + ]); } @override @@ -189,22 +215,27 @@ class FortuneSerializer extends Codec { @override FortuneEncoder get encoder => const FortuneEncoder(); + @override FortuneDecoder get decoder => const FortuneDecoder(); + static Fortune fromMap(Map map) { return Fortune(id: map['id'] as int?, message: map['message'] as String?); } static Map toMap(_Fortune? model) { if (model == null) { - return {}; + throw FormatException("Required field [model] cannot be null"); } return {'id': model.id, 'message': model.message}; } } abstract class FortuneFields { - static const List allFields = [id, message]; + static const List allFields = [ + id, + message, + ]; static const String id = 'id'; diff --git a/frameworks/Dart/angel3/orm/lib/src/models/world.g.dart b/frameworks/Dart/angel3/orm/lib/src/models/world.g.dart index b5c66b9c5e5..5b51631b790 100644 --- a/frameworks/Dart/angel3/orm/lib/src/models/world.g.dart +++ b/frameworks/Dart/angel3/orm/lib/src/models/world.g.dart @@ -26,7 +26,10 @@ class WorldMigration extends Migration { // ************************************************************************** class WorldQuery extends Query { - WorldQuery({Query? parent, Set? trampoline}) : super(parent: parent) { + WorldQuery({ + Query? parent, + Set? trampoline, + }) : super(parent: parent) { trampoline ??= {}; trampoline.add(tableName); _where = WorldQueryWhere(this); @@ -51,7 +54,10 @@ class WorldQuery extends Query { @override List get fields { - const _fields = ['id', 'randomNumber']; + const _fields = [ + 'id', + 'randomNumber', + ]; return _selectedFields.isEmpty ? _fields : _fields.where((field) => _selectedFields.contains(field)).toList(); @@ -77,9 +83,9 @@ class WorldQuery extends Query { return Optional.empty(); } var model = World( - id: fields.contains('id') ? (row[0] as int?) : null, - randomNumber: - fields.contains('randomNumber') ? (row[1] as int?) : null); + id: fields.contains('id') ? mapToInt(row[0]) : null, + randomNumber: fields.contains('randomNumber') ? mapToInt(row[1]) : null, + ); return Optional.of(model); } @@ -91,8 +97,14 @@ class WorldQuery extends Query { class WorldQueryWhere extends QueryWhere { WorldQueryWhere(WorldQuery query) - : id = NumericSqlExpressionBuilder(query, 'id'), - randomNumber = NumericSqlExpressionBuilder(query, 'randomNumber'); + : id = NumericSqlExpressionBuilder( + query, + 'id', + ), + randomNumber = NumericSqlExpressionBuilder( + query, + 'randomNumber', + ); final NumericSqlExpressionBuilder id; @@ -100,7 +112,10 @@ class WorldQueryWhere extends QueryWhere { @override List get expressionBuilders { - return [id, randomNumber]; + return [ + id, + randomNumber, + ]; } } @@ -115,11 +130,13 @@ class WorldQueryValues extends MapQueryValues { } set id(int? value) => values['id'] = value; + int? get randomNumber { return (values['randomNumber'] as int?); } set randomNumber(int? value) => values['randomNumber'] = value; + void copyFrom(World model) { id = model.id; randomNumber = model.randomNumber; @@ -132,7 +149,10 @@ class WorldQueryValues extends MapQueryValues { @generatedSerializable class World extends _World { - World({this.id, this.randomNumber}); + World({ + this.id, + this.randomNumber, + }); @override int? id; @@ -140,7 +160,10 @@ class World extends _World { @override int? randomNumber; - World copyWith({int? id, int? randomNumber}) { + World copyWith({ + int? id, + int? randomNumber, + }) { return World( id: id ?? this.id, randomNumber: randomNumber ?? this.randomNumber); } @@ -154,7 +177,10 @@ class World extends _World { @override int get hashCode { - return hashObjects([id, randomNumber]); + return hashObjects([ + id, + randomNumber, + ]); } @override @@ -192,8 +218,10 @@ class WorldSerializer extends Codec { @override WorldEncoder get encoder => const WorldEncoder(); + @override WorldDecoder get decoder => const WorldDecoder(); + static World fromMap(Map map) { return World( id: map['id'] as int?, randomNumber: map['randomNumber'] as int?); @@ -201,14 +229,17 @@ class WorldSerializer extends Codec { static Map toMap(_World? model) { if (model == null) { - return {}; + throw FormatException("Required field [model] cannot be null"); } return {'id': model.id, 'randomNumber': model.randomNumber}; } } abstract class WorldFields { - static const List allFields = [id, randomNumber]; + static const List allFields = [ + id, + randomNumber, + ]; static const String id = 'id'; diff --git a/frameworks/Dart/angel3/orm/lib/src/routes/controllers/controllers.dart b/frameworks/Dart/angel3/orm/lib/src/routes/controllers/controllers.dart index 81e4ac83e4d..771995d66a9 100644 --- a/frameworks/Dart/angel3/orm/lib/src/routes/controllers/controllers.dart +++ b/frameworks/Dart/angel3/orm/lib/src/routes/controllers/controllers.dart @@ -1,5 +1,4 @@ import 'dart:async'; -import 'dart:convert'; import 'dart:math'; import 'package:angel3_framework/angel3_framework.dart'; import 'package:angel3_orm/angel3_orm.dart'; @@ -12,12 +11,12 @@ Future configureServer(Angel app) async { var executor = app.container.make(); // Generate a random number between 1 and 10000 - int _genRandomId() { + int genRandomId() { var rand = Random(); return rand.nextInt(10000) + 1; } - int _parseQueryCount(String? count) { + int parseQueryCount(String? count) { if (count == null) { return 1; } @@ -30,11 +29,11 @@ Future configureServer(Angel app) async { return limit; } - List _generateIds(int maxCount) { + List generateIds(int maxCount) { var result = []; while (result.length < maxCount) { - var id = _genRandomId(); + var id = genRandomId(); if (!result.contains(id)) { result.add(id); } @@ -56,25 +55,18 @@ Future configureServer(Angel app) async { // Add an entry and sort a list of fortune app.get('/fortunes', (req, res) async { - //var stopwatch = Stopwatch()..start(); - var list = await FortuneQuery().get(executor); - //print('Query Time: ${stopwatch.elapsed.inMilliseconds}ms'); - list.add( Fortune(id: 0, message: 'Additional fortune added at request time.')); list.sort((a, b) => a.message?.compareTo(b.message ?? '') ?? 0); - //print('Process Time: ${stopwatch.elapsed.inMilliseconds}ms'); - //stopwatch.stop(); - res.render('listing', {'fortunes': list}); }); // Find a random World app.get('/db', (req, res) async { - var id = _genRandomId(); + var id = genRandomId(); var query = WorldQuery()..where?.id.equals(id); var result = await query.get(executor); if (result.isNotEmpty) { @@ -88,12 +80,12 @@ Future configureServer(Angel app) async { app.get('/query', (req, res) async { var params = req.queryParameters; - var queryLimit = _parseQueryCount(params['queries'] as String?); + var queryLimit = parseQueryCount(params['queries'] as String?); - var list = _generateIds(queryLimit); - var query = WorldQuery(); + var list = generateIds(queryLimit); var result = []; for (var id in list) { + var query = WorldQuery(); query.where?.id.equals(id); var optWorld = await query.getOne(executor); result.add(optWorld.value); @@ -104,28 +96,23 @@ Future configureServer(Angel app) async { // Update a list of worlds app.get('/updates', (req, res) async { - //var stopwatch = Stopwatch()..start(); - var params = req.queryParameters; - var queryLimit = _parseQueryCount(params['queries'] as String?); - var listOfIds = _generateIds(queryLimit); + var queryLimit = parseQueryCount(params['queries'] as String?); + var listOfIds = generateIds(queryLimit); - var query = WorldQuery(); var result = []; for (var id in listOfIds) { + var query = WorldQuery(); query.where?.id.equals(id); var optWorld = await query.getOne(executor); query ..where?.id.equals(optWorld.value.id!) - ..values.randomNumber = _genRandomId(); + ..values.randomNumber = genRandomId(); var updatedRec = await query.updateOne(executor); result.add(updatedRec.value); } - //print('Process Time: ${stopwatch.elapsed.inMilliseconds}ms'); - //stopwatch.stop(); - res.json(result); }); } diff --git a/frameworks/Dart/angel3/orm/pubspec.lock b/frameworks/Dart/angel3/orm/pubspec.lock index 875804ad750..10a54530573 100644 --- a/frameworks/Dart/angel3/orm/pubspec.lock +++ b/frameworks/Dart/angel3/orm/pubspec.lock @@ -5,862 +5,977 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - url: "https://pub.dartlang.org" + sha256: dc27559385e905ad30838356c5f5d574014ba39872d732111cd07ac0beff4c57 + url: "https://pub.dev" source: hosted - version: "47.0.0" + version: "80.0.0" analyzer: dependency: transitive description: name: analyzer - url: "https://pub.dartlang.org" + sha256: "192d1c5b944e7e53b24b5586db760db934b177d4147c42fbca8c8c5f1eb8d11e" + url: "https://pub.dev" source: hosted - version: "4.7.0" + version: "7.3.0" angel3_auth: dependency: "direct main" description: name: angel3_auth - url: "https://pub.dartlang.org" + sha256: "3996219fca7a49174c3745732a1e438ec94d55936697f2504196be4f3dbf191a" + url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "8.3.0" angel3_client: dependency: transitive description: name: angel3_client - url: "https://pub.dartlang.org" + sha256: e2886fdb41f243d85003f94127850bdd70f79fa5f7cf1f2b79b4f7029198e9dd + url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "8.4.0" angel3_configuration: dependency: "direct main" description: name: angel3_configuration - url: "https://pub.dartlang.org" + sha256: f585699cf0ea5376d7ed6310e9fc57ccdd4645e5746ea0bae1fa6c05efe4e810 + url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "8.3.0" angel3_container: - dependency: transitive + dependency: "direct main" description: name: angel3_container - url: "https://pub.dartlang.org" + sha256: c08ea6b426242861d11109b748792503652a7eb0db4005409c0a031e80820c7f + url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "8.3.0" angel3_framework: dependency: "direct main" description: name: angel3_framework - url: "https://pub.dartlang.org" + sha256: "91d56825b78846d9294e8aae789362644d4e24df4870d52d6c2cc6d8adf8d2c9" + url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "8.5.0" angel3_hot: dependency: "direct dev" description: name: angel3_hot - url: "https://pub.dartlang.org" + sha256: "8e1e7409631a49f05483e2067d1f27f594d558459712311b5ea4317b5519975b" + url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "8.4.0" angel3_http_exception: dependency: transitive description: name: angel3_http_exception - url: "https://pub.dartlang.org" + sha256: "9484b425a1aece1af3f2f0521fba429cd48f0a952521d40281333694c750e4ab" + url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "8.3.0" angel3_jael: dependency: "direct main" description: name: angel3_jael - url: "https://pub.dartlang.org" + sha256: "4ce85198613faff74ac8706065c619e7d6fc609aeb63b2fa7d9dba6f5a981f5c" + url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "8.3.0" angel3_migration: dependency: "direct main" description: name: angel3_migration - url: "https://pub.dartlang.org" + sha256: de7180ce8e48b0fe551c0b96cc83d0cafdcb71de3c75e13b0b08c3fdaf9df351 + url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "8.4.0" angel3_migration_runner: dependency: "direct dev" description: name: angel3_migration_runner - url: "https://pub.dartlang.org" + sha256: "30596dd82471dcddd35afb8b245c1dd56c8c53bdf77dee5e131c353e37e05f9b" + url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "8.4.1" angel3_mock_request: dependency: transitive description: name: angel3_mock_request - url: "https://pub.dartlang.org" + sha256: "8c8513a649d33c0c0531a120183da558000b4f044a4f30fd3ae22dfe11355a04" + url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "8.3.0" angel3_model: dependency: transitive description: name: angel3_model - url: "https://pub.dartlang.org" + sha256: "9a3f50b02bf119bb160d5f94580940b93973589d9b5949d284d2427b8fb65e16" + url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "8.3.0" angel3_orm: dependency: "direct main" description: name: angel3_orm - url: "https://pub.dartlang.org" + sha256: "9d1831b6b91820e312b52cf4c8c3cebb067be59b47123276fbc7741a01ae2ac5" + url: "https://pub.dev" source: hosted - version: "7.0.1" + version: "8.3.2" angel3_orm_generator: dependency: "direct dev" description: name: angel3_orm_generator - url: "https://pub.dartlang.org" + sha256: "18426152dc86e1f0cd5fab14470f07a5b5ac7dd1b78f7e1bf8986d2625a898ec" + url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "8.4.1" angel3_orm_postgres: dependency: "direct main" description: name: angel3_orm_postgres - url: "https://pub.dartlang.org" + sha256: "7ecaec40b62b8d573ee72b1694f97353be4b6581b4da847d4bfe857f2540bd29" + url: "https://pub.dev" source: hosted - version: "7.0.1" + version: "8.3.1" angel3_production: dependency: "direct main" description: name: angel3_production - url: "https://pub.dartlang.org" + sha256: "286d4b6dcd5e4297eea3db93cb419282ca14ef920f77439ef7b42c6229ab6219" + url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "8.4.1" angel3_route: dependency: transitive description: name: angel3_route - url: "https://pub.dartlang.org" + sha256: f2ebf4b134e13f804271d4e164a92de5dd25ad0bb651303df2c9e6fb397f32a8 + url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "8.4.0" angel3_serialize: dependency: "direct main" description: name: angel3_serialize - url: "https://pub.dartlang.org" + sha256: "4a4658b8af0d0eec6b8816699f137367c6af7c6f6a1f83a84e43fee55f892f5e" + url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "8.3.0" angel3_serialize_generator: dependency: "direct dev" description: name: angel3_serialize_generator - url: "https://pub.dartlang.org" + sha256: "0fd91dd1162f5c0d1b3c0f2734f48787202693926e6d6c97bca18658c8b812f4" + url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "8.4.1" angel3_static: dependency: "direct main" description: name: angel3_static - url: "https://pub.dartlang.org" + sha256: "534e827500304fa4e95f3613b130aad832dc65681b9a4c47a83891f65b04b554" + url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "8.3.0" angel3_test: dependency: "direct dev" description: name: angel3_test - url: "https://pub.dartlang.org" + sha256: "2ae3d83f83fb6c0834948b4ae3afc02da8c7ee38da3e164bd455564267e39ff8" + url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "8.3.0" angel3_validate: dependency: "direct main" description: name: angel3_validate - url: "https://pub.dartlang.org" + sha256: "661ef636583b0e60b35756d3d296d2ef7b257277fa703a494278ace9fcbe4f0c" + url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "8.3.0" angel3_websocket: dependency: transitive description: name: angel3_websocket - url: "https://pub.dartlang.org" + sha256: "160399b1898d5fd9c8294b4321691567687d9d86d8940aea83cc528b85427229" + url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "8.4.0" args: dependency: transitive description: name: args - url: "https://pub.dartlang.org" + sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 + url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.7.0" async: dependency: transitive description: name: async - url: "https://pub.dartlang.org" + sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" + url: "https://pub.dev" source: hosted - version: "2.9.0" + version: "2.13.0" belatuk_code_buffer: dependency: transitive description: name: belatuk_code_buffer - url: "https://pub.dartlang.org" + sha256: "06c4329570e2cb72cb808c5f19d2004865b7c1f18447d4af16d465776416ccfc" + url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "5.3.0" belatuk_combinator: dependency: transitive description: name: belatuk_combinator - url: "https://pub.dartlang.org" + sha256: "0c54ddf1a6a7c94585c55a5852ccc13ad1a871e3e0709d3322d0286eb7afb7d7" + url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "5.3.0" belatuk_html_builder: dependency: transitive description: name: belatuk_html_builder - url: "https://pub.dartlang.org" + sha256: "0bdd783a54aa7435c86231b319bfffa06259aea6df59dbec62d351456062e67f" + url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "5.3.0" belatuk_http_server: dependency: transitive description: name: belatuk_http_server - url: "https://pub.dartlang.org" + sha256: "2a4ae9409f3586a95a3393b924c86fd38c30d955aa2437070c3198a1ec0a1686" + url: "https://pub.dev" source: hosted - version: "3.0.0" + version: "4.5.0" belatuk_json_serializer: dependency: transitive description: name: belatuk_json_serializer - url: "https://pub.dartlang.org" + sha256: b0b6ee6b4aa0552d84b487c5d1a97f72c9d5c4cbc4e2828f57e24635d5d75be8 + url: "https://pub.dev" source: hosted - version: "6.0.1" + version: "7.3.0" belatuk_merge_map: dependency: transitive description: name: belatuk_merge_map - url: "https://pub.dartlang.org" + sha256: "1eb3c77417598e1d40c11d8d93b3c7bb5f10ca0977b2f942c623698bf3745f43" + url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "5.3.0" belatuk_pretty_logging: dependency: "direct main" description: name: belatuk_pretty_logging - url: "https://pub.dartlang.org" + sha256: "29fb3127ce58643e59fc4510ce41fa4d795f56997cbc661dffdf07e9a65e7021" + url: "https://pub.dev" source: hosted - version: "5.0.0" + version: "6.3.0" belatuk_pub_sub: dependency: transitive description: name: belatuk_pub_sub - url: "https://pub.dartlang.org" + sha256: "08c4f458165f7e2d76a3a4796e94092b98579aedd1fc8a64f39cfbbd18db249d" + url: "https://pub.dev" source: hosted - version: "5.0.0" + version: "6.4.0" belatuk_range_header: dependency: transitive description: name: belatuk_range_header - url: "https://pub.dartlang.org" + sha256: "78f315c8a53415a04a77dee3fcec6f867bac77d2e5d3e13ffc7532d1800adc53" + url: "https://pub.dev" source: hosted - version: "5.0.0" + version: "6.4.0" belatuk_symbol_table: dependency: transitive description: name: belatuk_symbol_table - url: "https://pub.dartlang.org" + sha256: "154f50623b2c5a669561588d86a445f97cf081de6e690ba9bc866dcd98508f50" + url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "5.3.0" boolean_selector: dependency: transitive description: name: boolean_selector - url: "https://pub.dartlang.org" + sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.2" buffer: dependency: transitive description: name: buffer - url: "https://pub.dartlang.org" + sha256: "389da2ec2c16283c8787e0adaede82b1842102f8c8aae2f49003a766c5c6b3d1" + url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.2.3" build: dependency: transitive description: name: build - url: "https://pub.dartlang.org" + sha256: cef23f1eda9b57566c81e2133d196f8e3df48f244b317368d65c5943d91148f0 + url: "https://pub.dev" source: hosted - version: "2.3.0" + version: "2.4.2" build_config: dependency: transitive description: name: build_config - url: "https://pub.dartlang.org" + sha256: "4ae2de3e1e67ea270081eaee972e1bd8f027d459f249e0f1186730784c2e7e33" + url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.2" build_daemon: dependency: transitive description: name: build_daemon - url: "https://pub.dartlang.org" + sha256: "8e928697a82be082206edb0b9c99c5a4ad6bc31c9e9b8b2f291ae65cd4a25daa" + url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "4.0.4" build_resolvers: dependency: transitive description: name: build_resolvers - url: "https://pub.dartlang.org" + sha256: b9e4fda21d846e192628e7a4f6deda6888c36b5b69ba02ff291a01fd529140f0 + url: "https://pub.dev" source: hosted - version: "2.0.9" + version: "2.4.4" build_runner: dependency: "direct dev" description: name: build_runner - url: "https://pub.dartlang.org" + sha256: "058fe9dce1de7d69c4b84fada934df3e0153dd000758c4d65964d0166779aa99" + url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.4.15" build_runner_core: dependency: transitive description: name: build_runner_core - url: "https://pub.dartlang.org" + sha256: "22e3aa1c80e0ada3722fe5b63fd43d9c8990759d0a2cf489c8c5d7b2bdebc021" + url: "https://pub.dev" source: hosted - version: "7.2.3" + version: "8.0.0" built_collection: dependency: transitive description: name: built_collection - url: "https://pub.dartlang.org" + sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100" + url: "https://pub.dev" source: hosted version: "5.1.1" built_value: dependency: transitive description: name: built_value - url: "https://pub.dartlang.org" + sha256: ea90e81dc4a25a043d9bee692d20ed6d1c4a1662a28c03a96417446c093ed6b4 + url: "https://pub.dev" source: hosted - version: "8.4.1" + version: "8.9.5" charcode: dependency: transitive description: name: charcode - url: "https://pub.dartlang.org" + sha256: fb0f1107cac15a5ea6ef0a6ef71a807b9e4267c713bb93e00e92d737cc8dbd8a + url: "https://pub.dev" source: hosted - version: "1.3.1" + version: "1.4.0" checked_yaml: dependency: transitive description: name: checked_yaml - url: "https://pub.dartlang.org" + sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff + url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "2.0.3" clock: dependency: transitive description: name: clock - url: "https://pub.dartlang.org" + sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b + url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.1.2" code_builder: dependency: transitive description: name: code_builder - url: "https://pub.dartlang.org" + sha256: "0ec10bf4a89e4c613960bf1e8b42c64127021740fb21640c29c909826a5eea3e" + url: "https://pub.dev" source: hosted - version: "4.2.0" + version: "4.10.1" collection: dependency: transitive description: name: collection - url: "https://pub.dartlang.org" + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" + url: "https://pub.dev" source: hosted - version: "1.16.0" + version: "1.19.1" convert: dependency: transitive description: name: convert - url: "https://pub.dartlang.org" + sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 + url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "3.1.2" coverage: dependency: transitive description: name: coverage - url: "https://pub.dartlang.org" + sha256: e3493833ea012784c740e341952298f1cc77f1f01b1bbc3eb4eecf6984fb7f43 + url: "https://pub.dev" source: hosted - version: "1.5.0" + version: "1.11.1" crypto: dependency: transitive description: name: crypto - url: "https://pub.dartlang.org" + sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" + url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "3.0.6" dart_style: dependency: transitive description: name: dart_style - url: "https://pub.dartlang.org" + sha256: "27eb0ae77836989a3bc541ce55595e8ceee0992807f14511552a898ddd0d88ac" + url: "https://pub.dev" source: hosted - version: "2.2.3" + version: "3.0.1" dotenv: dependency: transitive description: name: dotenv - url: "https://pub.dartlang.org" - source: hosted - version: "4.0.1" - executor: - dependency: transitive - description: - name: executor - url: "https://pub.dartlang.org" + sha256: "379e64b6fc82d3df29461d349a1796ecd2c436c480d4653f3af6872eccbc90e1" + url: "https://pub.dev" source: hosted - version: "2.2.2" + version: "4.2.0" file: - dependency: transitive + dependency: "direct main" description: name: file - url: "https://pub.dartlang.org" + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 + url: "https://pub.dev" source: hosted - version: "6.1.4" + version: "7.0.1" fixnum: dependency: transitive description: name: fixnum - url: "https://pub.dartlang.org" + sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be + url: "https://pub.dev" source: hosted - version: "1.0.1" + version: "1.1.1" frontend_server_client: dependency: transitive description: name: frontend_server_client - url: "https://pub.dartlang.org" + sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 + url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "4.0.0" glob: dependency: transitive description: name: glob - url: "https://pub.dartlang.org" + sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.3" graphs: dependency: transitive description: name: graphs - url: "https://pub.dartlang.org" + sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.3.2" http: dependency: transitive description: name: http - url: "https://pub.dartlang.org" + sha256: fe7ab022b76f3034adc518fb6ea04a82387620e19977665ea18d30a1cf43442f + url: "https://pub.dev" source: hosted - version: "0.13.5" + version: "1.3.0" http2: dependency: transitive description: name: http2 - url: "https://pub.dartlang.org" + sha256: "382d3aefc5bd6dc68c6b892d7664f29b5beb3251611ae946a98d35158a82bbfa" + url: "https://pub.dev" source: hosted - version: "2.0.0" + version: "2.3.1" http_multi_server: dependency: transitive description: name: http_multi_server - url: "https://pub.dartlang.org" + sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8 + url: "https://pub.dev" source: hosted - version: "3.2.1" + version: "3.2.2" http_parser: dependency: transitive description: name: http_parser - url: "https://pub.dartlang.org" + sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" + url: "https://pub.dev" source: hosted - version: "4.0.1" + version: "4.1.2" inflection3: dependency: transitive description: name: inflection3 - url: "https://pub.dartlang.org" + sha256: cb54689bcfe3c0168a6979ee3191df584dcef4f870c5ef41c798bcb35ff5aca3 + url: "https://pub.dev" source: hosted version: "0.5.3+2" intl: dependency: transitive description: name: intl - url: "https://pub.dartlang.org" + sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5" + url: "https://pub.dev" source: hosted - version: "0.17.0" + version: "0.20.2" io: dependency: "direct dev" description: name: io - url: "https://pub.dartlang.org" + sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b + url: "https://pub.dev" source: hosted - version: "1.0.3" + version: "1.0.5" jael3: dependency: "direct main" description: name: jael3 - url: "https://pub.dartlang.org" + sha256: bee0b8d328898dac9008caf7392400d03bc2035a3dd9acebe7ebee052ef9132b + url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "8.2.0" jael3_preprocessor: dependency: transitive description: name: jael3_preprocessor - url: "https://pub.dartlang.org" + sha256: "8e70b92608e61c032f08bed82fa63b82e26b4ede4f4924b81bd75329fae9e9b8" + url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "8.2.0" js: dependency: transitive description: name: js - url: "https://pub.dartlang.org" + sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf + url: "https://pub.dev" source: hosted - version: "0.6.4" + version: "0.7.1" json_annotation: dependency: transitive description: name: json_annotation - url: "https://pub.dartlang.org" + sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" + url: "https://pub.dev" source: hosted - version: "4.6.0" + version: "4.9.0" json_rpc_2: dependency: transitive description: name: json_rpc_2 - url: "https://pub.dartlang.org" + sha256: "246b321532f0e8e2ba474b4d757eaa558ae4fdd0688fdbc1e1ca9705f9b8ca0e" + url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "3.0.3" lints: dependency: "direct dev" description: name: lints - url: "https://pub.dartlang.org" + sha256: c35bb79562d980e9a453fc715854e1ed39e24e7d0297a880ef54e17f9874a9d7 + url: "https://pub.dev" source: hosted - version: "2.0.0" + version: "5.1.1" logging: dependency: "direct main" description: name: logging - url: "https://pub.dartlang.org" + sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 + url: "https://pub.dev" source: hosted - version: "1.0.2" + version: "1.3.0" matcher: dependency: transitive description: name: matcher - url: "https://pub.dartlang.org" + sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 + url: "https://pub.dev" source: hosted - version: "0.12.12" + version: "0.12.17" meta: dependency: transitive description: name: meta - url: "https://pub.dartlang.org" + sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c + url: "https://pub.dev" source: hosted - version: "1.8.0" + version: "1.16.0" mime: dependency: transitive description: name: mime - url: "https://pub.dartlang.org" + sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" + url: "https://pub.dev" source: hosted - version: "1.0.2" + version: "2.0.0" mysql1: dependency: transitive description: name: mysql1 - url: "https://pub.dartlang.org" + sha256: "68aec7003d2abc85769bafa1777af3f4a390a90c31032b89636758ff8eb839e9" + url: "https://pub.dev" source: hosted version: "0.20.0" mysql_client: dependency: transitive description: name: mysql_client - url: "https://pub.dartlang.org" + sha256: "6a0fdcbe3e0721c637f97ad24649be2f70dbce2b21ede8f962910e640f753fc2" + url: "https://pub.dev" source: hosted - version: "0.0.25" + version: "0.0.27" node_preamble: dependency: transitive description: name: node_preamble - url: "https://pub.dartlang.org" + sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db" + url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "2.0.2" optional: dependency: "direct main" description: name: optional - url: "https://pub.dartlang.org" + sha256: f80327d7a3335a0be68418072668043c7ab291df575c21aa42e0c5633641da39 + url: "https://pub.dev" source: hosted version: "6.1.0+1" package_config: dependency: transitive description: name: package_config - url: "https://pub.dartlang.org" + sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.2.0" path: dependency: transitive description: name: path - url: "https://pub.dartlang.org" - source: hosted - version: "1.8.2" - pedantic: - dependency: transitive - description: - name: pedantic - url: "https://pub.dartlang.org" + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" + url: "https://pub.dev" source: hosted - version: "1.11.1" + version: "1.9.1" pool: dependency: transitive description: name: pool - url: "https://pub.dartlang.org" + sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" + url: "https://pub.dev" source: hosted version: "1.5.1" postgres: - dependency: transitive + dependency: "direct main" description: name: postgres - url: "https://pub.dartlang.org" - source: hosted - version: "2.4.6" - postgres_pool: - dependency: transitive - description: - name: postgres_pool - url: "https://pub.dartlang.org" + sha256: "7a7f9805d33e41cb14fa22535959f3af51843a792015cdbd8f2fa78bcd1b501b" + url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "3.5.4" pub_semver: dependency: transitive description: name: pub_semver - url: "https://pub.dartlang.org" + sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585" + url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.2.0" pubspec_parse: dependency: transitive description: name: pubspec_parse - url: "https://pub.dartlang.org" + sha256: "0560ba233314abbed0a48a2956f7f022cce7c3e1e73df540277da7544cad4082" + url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.5.0" quiver: dependency: transitive description: name: quiver - url: "https://pub.dartlang.org" + sha256: ea0b925899e64ecdfbf9c7becb60d5b50e706ade44a85b2363be2a22d88117d2 + url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.2.2" recase: dependency: transitive description: name: recase - url: "https://pub.dartlang.org" + sha256: e4eb4ec2dcdee52dcf99cb4ceabaffc631d7424ee55e56f280bc039737f89213 + url: "https://pub.dev" source: hosted - version: "4.0.0" - retry: - dependency: transitive - description: - name: retry - url: "https://pub.dartlang.org" - source: hosted - version: "3.1.0" + version: "4.1.0" sasl_scram: dependency: transitive description: name: sasl_scram - url: "https://pub.dartlang.org" + sha256: a47207a436eb650f8fdcf54a2e2587b850dc3caef9973ce01f332b07a6fc9cb9 + url: "https://pub.dev" source: hosted version: "0.1.1" saslprep: dependency: transitive description: name: saslprep - url: "https://pub.dartlang.org" + sha256: "3d421d10be9513bf4459c17c5e70e7b8bc718c9fc5ad4ba5eb4f5fd27396f740" + url: "https://pub.dev" source: hosted - version: "1.0.2" + version: "1.0.3" shelf: dependency: transitive description: name: shelf - url: "https://pub.dartlang.org" + sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12 + url: "https://pub.dev" source: hosted - version: "1.3.2" + version: "1.4.2" shelf_packages_handler: dependency: transitive description: name: shelf_packages_handler - url: "https://pub.dartlang.org" + sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e" + url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.0.2" shelf_static: dependency: transitive description: name: shelf_static - url: "https://pub.dartlang.org" + sha256: c87c3875f91262785dade62d135760c2c69cb217ac759485334c5857ad89f6e3 + url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.1.3" shelf_web_socket: dependency: transitive description: name: shelf_web_socket - url: "https://pub.dartlang.org" + sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925" + url: "https://pub.dev" source: hosted - version: "1.0.2" + version: "3.0.0" source_gen: dependency: transitive description: name: source_gen - url: "https://pub.dartlang.org" + sha256: "35c8150ece9e8c8d263337a265153c3329667640850b9304861faea59fc98f6b" + url: "https://pub.dev" source: hosted - version: "1.2.2" + version: "2.0.0" source_map_stack_trace: dependency: transitive description: name: source_map_stack_trace - url: "https://pub.dartlang.org" + sha256: c0713a43e323c3302c2abe2a1cc89aa057a387101ebd280371d6a6c9fa68516b + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.2" source_maps: dependency: transitive description: name: source_maps - url: "https://pub.dartlang.org" + sha256: "190222579a448b03896e0ca6eca5998fa810fda630c1d65e2f78b3f638f54812" + url: "https://pub.dev" source: hosted - version: "0.10.10" + version: "0.10.13" source_span: dependency: transitive description: name: source_span - url: "https://pub.dartlang.org" + sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" + url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.10.1" + sprintf: + dependency: transitive + description: + name: sprintf + sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23" + url: "https://pub.dev" + source: hosted + version: "7.0.0" stack_trace: dependency: transitive description: name: stack_trace - url: "https://pub.dartlang.org" + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" + url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.12.1" stream_channel: dependency: transitive description: name: stream_channel - url: "https://pub.dartlang.org" + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.4" stream_transform: dependency: transitive description: name: stream_transform - url: "https://pub.dartlang.org" + sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871 + url: "https://pub.dev" source: hosted - version: "2.0.0" + version: "2.1.1" string_scanner: dependency: transitive description: name: string_scanner - url: "https://pub.dartlang.org" + sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" + url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.4.1" term_glyph: dependency: transitive description: name: term_glyph - url: "https://pub.dartlang.org" + sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" + url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.2.2" test: dependency: "direct dev" description: name: test - url: "https://pub.dartlang.org" + sha256: "301b213cd241ca982e9ba50266bd3f5bd1ea33f1455554c5abb85d1be0e2d87e" + url: "https://pub.dev" source: hosted - version: "1.21.5" + version: "1.25.15" test_api: dependency: transitive description: name: test_api - url: "https://pub.dartlang.org" + sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd + url: "https://pub.dev" source: hosted - version: "0.4.13" + version: "0.7.4" test_core: dependency: transitive description: name: test_core - url: "https://pub.dartlang.org" + sha256: "84d17c3486c8dfdbe5e12a50c8ae176d15e2a771b96909a9442b40173649ccaa" + url: "https://pub.dev" source: hosted - version: "0.4.17" + version: "0.6.8" timing: dependency: transitive description: name: timing - url: "https://pub.dartlang.org" + sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe" + url: "https://pub.dev" source: hosted - version: "1.0.0" + version: "1.0.2" tuple: dependency: transitive description: name: tuple - url: "https://pub.dartlang.org" + sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151 + url: "https://pub.dev" source: hosted - version: "2.0.0" + version: "2.0.2" typed_data: dependency: transitive description: name: typed_data - url: "https://pub.dartlang.org" + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 + url: "https://pub.dev" source: hosted - version: "1.3.1" + version: "1.4.0" unorm_dart: dependency: transitive description: name: unorm_dart - url: "https://pub.dartlang.org" + sha256: "23d8bf65605401a6a32cff99435fed66ef3dab3ddcad3454059165df46496a3b" + url: "https://pub.dev" source: hosted - version: "0.2.0" + version: "0.3.0" uuid: dependency: transitive description: name: uuid - url: "https://pub.dartlang.org" + sha256: a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff + url: "https://pub.dev" source: hosted - version: "3.0.6" + version: "4.5.1" vm_service: dependency: transitive description: name: vm_service - url: "https://pub.dartlang.org" + sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02 + url: "https://pub.dev" source: hosted - version: "9.3.0" + version: "15.0.0" watcher: dependency: transitive description: name: watcher - url: "https://pub.dartlang.org" + sha256: "69da27e49efa56a15f8afe8f4438c4ec02eff0a117df1b22ea4aad194fe1c104" + url: "https://pub.dev" + source: hosted + version: "1.1.1" + web: + dependency: transitive + description: + name: web + sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" + url: "https://pub.dev" source: hosted - version: "1.0.1" + version: "1.1.1" + web_socket: + dependency: transitive + description: + name: web_socket + sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83" + url: "https://pub.dev" + source: hosted + version: "0.1.6" web_socket_channel: dependency: transitive description: name: web_socket_channel - url: "https://pub.dartlang.org" + sha256: "0b8e2457400d8a859b7b2030786835a28a8e80836ef64402abef392ff4f1d0e5" + url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "3.0.2" webkit_inspection_protocol: dependency: transitive description: name: webkit_inspection_protocol - url: "https://pub.dartlang.org" + sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572" + url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.2.1" yaml: dependency: transitive description: name: yaml - url: "https://pub.dartlang.org" + sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce + url: "https://pub.dev" source: hosted - version: "3.1.1" + version: "3.1.3" sdks: - dart: ">=2.18.0-146.0.dev <3.0.0" + dart: ">=3.6.0 <4.0.0" diff --git a/frameworks/Dart/angel3/orm/pubspec.yaml b/frameworks/Dart/angel3/orm/pubspec.yaml index 299c020ff43..bea8b753b68 100644 --- a/frameworks/Dart/angel3/orm/pubspec.yaml +++ b/frameworks/Dart/angel3/orm/pubspec.yaml @@ -1,40 +1,38 @@ name: benchmark_app -version: 1.0.0 +version: 2.0.0 description: A basic starter application template for Angel3 framework publish_to: none environment: - sdk: '>=2.17.0 <3.0.0' + sdk: '>=3.6.0 <4.0.0' + dependencies: - angel3_auth: ^7.0.0 - angel3_configuration: ^7.0.0 - angel3_framework: ^7.0.0 - angel3_jael: ^7.0.0 - angel3_migration: ^7.0.0 - angel3_orm: ^7.0.0 - angel3_orm_postgres: ^7.0.0 - angel3_serialize: ^7.0.0 - angel3_production: ^7.0.0 - angel3_static: ^7.0.0 - angel3_validate: ^7.0.0 - jael3: ^7.0.0 - belatuk_pretty_logging: ^5.0.0 + angel3_auth: ^8.3.0 + angel3_configuration: ^8.3.0 + angel3_framework: ^8.5.0 + angel3_jael: ^8.3.0 + angel3_migration: ^8.4.0 + angel3_orm: ^8.3.0 + angel3_orm_postgres: ^8.3.0 + angel3_serialize: ^8.3.0 + angel3_production: ^8.3.0 + angel3_static: ^8.3.0 + angel3_validate: ^8.3.0 + jael3: ^8.0.0 + belatuk_pretty_logging: ^6.0.0 + postgres: ^3.5.0 optional: ^6.0.0 - logging: ^1.0.0 + logging: ^1.3.0 + angel3_container: ^8.3.0 + file: ^7.0.1 + dev_dependencies: - angel3_hot: ^7.0.0 - angel3_migration_runner: ^7.0.0 - angel3_orm_generator: ^7.0.0 - angel3_serialize_generator: ^7.0.0 - angel3_test: ^7.0.0 - build_runner: ^2.0.3 + angel3_hot: ^8.3.0 + angel3_migration_runner: ^8.3.0 + angel3_orm_generator: ^8.3.0 + angel3_serialize_generator: ^8.3.0 + angel3_test: ^8.3.0 + build_runner: ^2.4.0 io: ^1.0.0 - test: ^1.17.5 - lints: ^2.0.0 -#dependency_overrides: -# angel3_orm: -# path: ../../../../../belatuk/packages/orm/angel_orm -# angel3_orm_postgres: -# path: ../../../../../belatuk/packages/orm/angel_orm_postgres -# angel3_jael: -# path: ../../../../../belatuk/packages/jael/angel_jael + test: ^1.25.0 + lints: ^5.0.0 \ No newline at end of file diff --git a/frameworks/Dart/angel3/orm/run/prod.dart b/frameworks/Dart/angel3/orm/run/prod.dart index cf7c0c692e4..62cb1486a2f 100644 --- a/frameworks/Dart/angel3/orm/run/prod.dart +++ b/frameworks/Dart/angel3/orm/run/prod.dart @@ -2,28 +2,5 @@ import 'package:angel3_container/mirrors.dart'; import 'package:angel3_production/angel3_production.dart'; import 'package:benchmark_app/benchmark_app.dart'; -// NOTE: By default, the Runner class does not use the `MirrorsReflector`, or any -// reflector, by default. -// -// If your application is using any sort of functionality reliant on annotations or reflection, -// either include the MirrorsReflector, or use a static reflector variant. -// -// The following use cases require reflection: -// * Use of Controllers, via @Expose() or @ExposeWS() -// * Use of dependency injection into constructors, whether in controllers or plain `container.make` calls -// * Use of the `ioc` function in any route -// -// The `MirrorsReflector` from `package:angel_container/mirrors.dart` is by far the most convenient pattern, -// so use it if possible. -// -// However, the following alternatives exist: -// * Generation via `package:angel_container_generator` -// * Creating an instance of `StaticReflector` -// * Manually implementing the `Reflector` interface (cumbersome; not recommended) -// -// As of January 4th, 2018, the documentation has not yet been updated to state this, -// so in the meantime, visit the Angel chat for further questions: -// -// https://gitter.im/angel_dart/discussion void main(List args) => Runner('Angel3', configureServer, reflector: MirrorsReflector()).run(args); diff --git a/frameworks/Dart/angel3/orm/test/all_test.dart b/frameworks/Dart/angel3/orm/test/all_test.dart index 8a5dad86ead..01978ff328f 100644 --- a/frameworks/Dart/angel3/orm/test/all_test.dart +++ b/frameworks/Dart/angel3/orm/test/all_test.dart @@ -5,16 +5,12 @@ import 'package:benchmark_app/benchmark_app.dart'; // Angel also includes facilities to make testing easier. // -// `package:angel_test` ships a client that can test -// both plain HTTP and WebSockets. +// `package:angel3_test` ships a client that can test both plain HTTP and WebSockets. // // Tests do not require your server to actually be mounted on a port, // so they will run faster than they would in other frameworks, where you // would have to first bind a socket, and then account for network latency. // -// See the documentation here: -// https://github.com/angel-dart/test -// // If you are unfamiliar with Dart's advanced testing library, you can read up // here: // https://github.com/dart-lang/test diff --git a/frameworks/Dart/dart3/.dockerignore b/frameworks/Dart/dart3/.dockerignore new file mode 100644 index 00000000000..6a6cc8727a7 --- /dev/null +++ b/frameworks/Dart/dart3/.dockerignore @@ -0,0 +1,9 @@ +# From https://hub.docker.com/_/dart +.dockerignore +Dockerfile +build/ +.dart_tool/ +.git/ +.github/ +.gitignore +.packages diff --git a/frameworks/Dart/dart3/.gitignore b/frameworks/Dart/dart3/.gitignore new file mode 100644 index 00000000000..27fe9f77a4b --- /dev/null +++ b/frameworks/Dart/dart3/.gitignore @@ -0,0 +1,5 @@ +# https://dart.dev/guides/libraries/private-files +# Created by `dart pub` +.dart_tool/ +*.lock +!bin diff --git a/frameworks/Dart/dart3/README.md b/frameworks/Dart/dart3/README.md new file mode 100644 index 00000000000..7152e705637 --- /dev/null +++ b/frameworks/Dart/dart3/README.md @@ -0,0 +1,22 @@ +# 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/) + +## Test URLs + +### 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 new file mode 100644 index 00000000000..572dd239d09 --- /dev/null +++ b/frameworks/Dart/dart3/analysis_options.yaml @@ -0,0 +1 @@ +include: package:lints/recommended.yaml diff --git a/frameworks/Dart/dart3/benchmark_config.json b/frameworks/Dart/dart3/benchmark_config.json new file mode 100644 index 00000000000..059fb368d0e --- /dev/null +++ b/frameworks/Dart/dart3/benchmark_config.json @@ -0,0 +1,26 @@ +{ + "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" + } + } + ] +} diff --git a/frameworks/Dart/dart3/bin/server.dart b/frameworks/Dart/dart3/bin/server.dart new file mode 100755 index 00000000000..5859cc51f82 --- /dev/null +++ b/frameworks/Dart/dart3/bin/server.dart @@ -0,0 +1,83 @@ +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.dockerfile b/frameworks/Dart/dart3/dart3.dockerfile new file mode 100644 index 00000000000..812b7e959ee --- /dev/null +++ b/frameworks/Dart/dart3/dart3.dockerfile @@ -0,0 +1,14 @@ + +FROM dart:3.8 AS builder + +COPY . /app +WORKDIR /app +RUN mkdir build +RUN dart compile exe ./bin/server.dart -o build/server + +FROM scratch +COPY --from=builder /runtime/ / +COPY --from=builder /app/build /bin + +EXPOSE 8080 +CMD ["server"] diff --git a/frameworks/Dart/dart3/pubspec.yaml b/frameworks/Dart/dart3/pubspec.yaml new file mode 100644 index 00000000000..5a99e258055 --- /dev/null +++ b/frameworks/Dart/dart3/pubspec.yaml @@ -0,0 +1,7 @@ +name: dartbenchmark +description: A benchmark of dart +environment: + sdk: ^3.8.0 + +dev_dependencies: + lints: ^4.0.0 diff --git a/frameworks/Dart/dart_frog/.dockerignore b/frameworks/Dart/dart_frog/.dockerignore new file mode 100644 index 00000000000..6a6cc8727a7 --- /dev/null +++ b/frameworks/Dart/dart_frog/.dockerignore @@ -0,0 +1,9 @@ +# From https://hub.docker.com/_/dart +.dockerignore +Dockerfile +build/ +.dart_tool/ +.git/ +.github/ +.gitignore +.packages diff --git a/frameworks/Dart/dart_frog/.gitignore b/frameworks/Dart/dart_frog/.gitignore new file mode 100644 index 00000000000..75e470c7bc8 --- /dev/null +++ b/frameworks/Dart/dart_frog/.gitignore @@ -0,0 +1,6 @@ +# https://dart.dev/guides/libraries/private-files +# Created by `dart pub` +.dart_tool/ +*.lock +!bin +build/ \ No newline at end of file diff --git a/frameworks/Dart/dart_frog/README.md b/frameworks/Dart/dart_frog/README.md new file mode 100644 index 00000000000..b7f5351b7e2 --- /dev/null +++ b/frameworks/Dart/dart_frog/README.md @@ -0,0 +1,23 @@ +# Dart Frog Benchmarking Test + +### Test Type Implementation Source Code + +- [JSON](server.dart) +- [PLAINTEXT](server.dart) + +## Important Libraries + +The tests were run with: + +- [pkg:dart_frog](https://pub.dev/packages/dart_frog) +- [Dart](https://dart.dev/) + +## Test URLs + +### JSON + +http://localhost:8080/json + +### PLAINTEXT + +http://localhost:8080/plaintext diff --git a/frameworks/Dart/dart_frog/benchmark_config.json b/frameworks/Dart/dart_frog/benchmark_config.json new file mode 100644 index 00000000000..06b90f52372 --- /dev/null +++ b/frameworks/Dart/dart_frog/benchmark_config.json @@ -0,0 +1,26 @@ +{ + "framework": "dart_frog", + "tests": [ + { + "default": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "None", + "framework": "dart_frog", + "language": "Dart", + "flavor": "None", + "orm": "None", + "platform": "dart_frog", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "dart_frog", + "notes": "", + "versus": "None" + } + } + ] +} diff --git a/frameworks/Dart/dart_frog/dart_frog.dockerfile b/frameworks/Dart/dart_frog/dart_frog.dockerfile new file mode 100644 index 00000000000..345f891c6db --- /dev/null +++ b/frameworks/Dart/dart_frog/dart_frog.dockerfile @@ -0,0 +1,16 @@ +FROM dart:3.8 AS builder + +COPY . /app +WORKDIR /app + +RUN dart pub global activate dart_frog_cli +RUN dart_frog build + +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/ + +EXPOSE 8080 +CMD ["/app/build/bin/server"] diff --git a/frameworks/Dart/dart_frog/pubspec.yaml b/frameworks/Dart/dart_frog/pubspec.yaml new file mode 100644 index 00000000000..e521d43a053 --- /dev/null +++ b/frameworks/Dart/dart_frog/pubspec.yaml @@ -0,0 +1,7 @@ +name: dartfrogbenchmark +description: A benchmark of pkg:dart_frog +environment: + sdk: ^3.8.0 + +dependencies: + dart_frog: ^1.0.0 diff --git a/frameworks/Dart/dart_frog/routes/json.dart b/frameworks/Dart/dart_frog/routes/json.dart new file mode 100644 index 00000000000..1bd5d704d02 --- /dev/null +++ b/frameworks/Dart/dart_frog/routes/json.dart @@ -0,0 +1,13 @@ +import 'dart:io'; + +import 'package:dart_frog/dart_frog.dart'; + +Response onRequest(RequestContext context) { + return Response.json( + body: {'message': 'Hello, World!'}, + headers: { + HttpHeaders.dateHeader: '${HttpDate.format(DateTime.now())}', + HttpHeaders.serverHeader: 'dart_frog', + }, + ); +} diff --git a/frameworks/Dart/dart_frog/routes/plaintext.dart b/frameworks/Dart/dart_frog/routes/plaintext.dart new file mode 100644 index 00000000000..b54a1c91f83 --- /dev/null +++ b/frameworks/Dart/dart_frog/routes/plaintext.dart @@ -0,0 +1,13 @@ +import 'dart:io'; +import 'package:dart_frog/dart_frog.dart'; + +Response onRequest(RequestContext context) { + return Response( + body: 'Hello, World!', + headers: { + HttpHeaders.contentTypeHeader: ContentType.text.mimeType, + HttpHeaders.dateHeader: '${HttpDate.format(DateTime.now())}', + HttpHeaders.serverHeader: 'dart_frog', + }, + ); +} diff --git a/frameworks/Dart/relic/.dockerignore b/frameworks/Dart/relic/.dockerignore new file mode 100644 index 00000000000..6a6cc8727a7 --- /dev/null +++ b/frameworks/Dart/relic/.dockerignore @@ -0,0 +1,9 @@ +# From https://hub.docker.com/_/dart +.dockerignore +Dockerfile +build/ +.dart_tool/ +.git/ +.github/ +.gitignore +.packages diff --git a/frameworks/Dart/relic/.gitignore b/frameworks/Dart/relic/.gitignore new file mode 100644 index 00000000000..27fe9f77a4b --- /dev/null +++ b/frameworks/Dart/relic/.gitignore @@ -0,0 +1,5 @@ +# https://dart.dev/guides/libraries/private-files +# Created by `dart pub` +.dart_tool/ +*.lock +!bin diff --git a/frameworks/Dart/relic/README.md b/frameworks/Dart/relic/README.md new file mode 100644 index 00000000000..4c70cc1fd20 --- /dev/null +++ b/frameworks/Dart/relic/README.md @@ -0,0 +1,23 @@ +# Relic Benchmarking Test + +### Test Type Implementation Source Code + +- [JSON](server.dart) +- [PLAINTEXT](server.dart) + +## Important Libraries + +The tests were run with: + +- [pkg:relic](https://pub.dev/packages/relic) +- [Dart](https://dart.dev/) + +## Test URLs + +### JSON + +http://localhost:8080/json + +### PLAINTEXT + +http://localhost:8080/plaintext diff --git a/frameworks/Dart/relic/benchmark_config.json b/frameworks/Dart/relic/benchmark_config.json new file mode 100644 index 00000000000..1f309015336 --- /dev/null +++ b/frameworks/Dart/relic/benchmark_config.json @@ -0,0 +1,26 @@ +{ + "framework": "relic", + "tests": [ + { + "default": { + "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", + "notes": "", + "versus": "None" + } + } + ] +} diff --git a/frameworks/Dart/relic/bin/server.dart b/frameworks/Dart/relic/bin/server.dart new file mode 100644 index 00000000000..b020cb396d4 --- /dev/null +++ b/frameworks/Dart/relic/bin/server.dart @@ -0,0 +1,70 @@ +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 new file mode 100644 index 00000000000..a473d37b055 --- /dev/null +++ b/frameworks/Dart/relic/pubspec.yaml @@ -0,0 +1,7 @@ +name: relicbenchmark +description: A benchmark of pkg:relic +environment: + sdk: ^3.8.0 + +dependencies: + relic: ^0.7.0 diff --git a/frameworks/Dart/relic/relic.dockerfile b/frameworks/Dart/relic/relic.dockerfile new file mode 100644 index 00000000000..1671de7d052 --- /dev/null +++ b/frameworks/Dart/relic/relic.dockerfile @@ -0,0 +1,14 @@ + +FROM dart:3.9 AS builder + +COPY . /app +WORKDIR /app +RUN mkdir build +RUN dart compile exe ./bin/server.dart -o build/server + +FROM scratch +COPY --from=builder /runtime/ / +COPY --from=builder /app/build /bin + +EXPOSE 8080 +CMD ["server"] diff --git a/frameworks/Dart/shelf/.dockerignore b/frameworks/Dart/shelf/.dockerignore new file mode 100644 index 00000000000..6a6cc8727a7 --- /dev/null +++ b/frameworks/Dart/shelf/.dockerignore @@ -0,0 +1,9 @@ +# From https://hub.docker.com/_/dart +.dockerignore +Dockerfile +build/ +.dart_tool/ +.git/ +.github/ +.gitignore +.packages diff --git a/frameworks/Dart/shelf/.gitignore b/frameworks/Dart/shelf/.gitignore new file mode 100644 index 00000000000..27fe9f77a4b --- /dev/null +++ b/frameworks/Dart/shelf/.gitignore @@ -0,0 +1,5 @@ +# https://dart.dev/guides/libraries/private-files +# Created by `dart pub` +.dart_tool/ +*.lock +!bin diff --git a/frameworks/Dart/shelf/README.md b/frameworks/Dart/shelf/README.md new file mode 100644 index 00000000000..90820f340dd --- /dev/null +++ b/frameworks/Dart/shelf/README.md @@ -0,0 +1,23 @@ +# Shelf Benchmarking Test + +### Test Type Implementation Source Code + +- [JSON](server.dart) +- [PLAINTEXT](server.dart) + +## Important Libraries + +The tests were run with: + +- [pkg:shelf](https://pub.dev/packages/shelf) +- [Dart](https://dart.dev/) + +## Test URLs + +### JSON + +http://localhost:8080/json + +### PLAINTEXT + +http://localhost:8080/plaintext diff --git a/frameworks/Dart/shelf/benchmark_config.json b/frameworks/Dart/shelf/benchmark_config.json new file mode 100644 index 00000000000..29200587d0c --- /dev/null +++ b/frameworks/Dart/shelf/benchmark_config.json @@ -0,0 +1,26 @@ +{ + "framework": "shelf", + "tests": [ + { + "default": { + "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", + "notes": "", + "versus": "None" + } + } + ] +} diff --git a/frameworks/Dart/shelf/bin/server.dart b/frameworks/Dart/shelf/bin/server.dart new file mode 100755 index 00000000000..e3c3b71ca64 --- /dev/null +++ b/frameworks/Dart/shelf/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/shelf/pubspec.yaml b/frameworks/Dart/shelf/pubspec.yaml new file mode 100644 index 00000000000..c41cff1b872 --- /dev/null +++ b/frameworks/Dart/shelf/pubspec.yaml @@ -0,0 +1,7 @@ +name: shelfbenchmark +description: A benchmark of pkg:shelf +environment: + sdk: ^3.8.0 + +dependencies: + shelf: ^1.0.0 diff --git a/frameworks/Dart/shelf/shelf.dockerfile b/frameworks/Dart/shelf/shelf.dockerfile new file mode 100644 index 00000000000..812b7e959ee --- /dev/null +++ b/frameworks/Dart/shelf/shelf.dockerfile @@ -0,0 +1,14 @@ + +FROM dart:3.8 AS builder + +COPY . /app +WORKDIR /app +RUN mkdir build +RUN dart compile exe ./bin/server.dart -o build/server + +FROM scratch +COPY --from=builder /runtime/ / +COPY --from=builder /app/build /bin + +EXPOSE 8080 +CMD ["server"] diff --git a/frameworks/Elixir/phoenix/benchmark_config.json b/frameworks/Elixir/phoenix/benchmark_config.json index 9af25b9fbdc..2286bd85fbd 100644 --- a/frameworks/Elixir/phoenix/benchmark_config.json +++ b/frameworks/Elixir/phoenix/benchmark_config.json @@ -2,30 +2,6 @@ "framework": "phoenix", "tests": [{ "default": { - "json_url": "/json", - "db_url": "/db", - "query_url": "/queries?queries=", - "fortune_url": "/fortunes", - "plaintext_url": "/plaintext", - "update_url": "/updates?queries=", - "cached_query_url": "/cached-queries?count=", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "Postgres", - "framework": "Phoenix", - "language": "Elixir", - "flavor": "None", - "orm": "full", - "platform": "beam", - "webserver": "cowboy", - "os": "Linux", - "database_os": "Linux", - "display_name": "Phoenix", - "notes": "", - "versus": "" - }, - "bandit": { "json_url": "/json", "db_url": "/db", "query_url": "/queries?queries=", @@ -45,9 +21,8 @@ "webserver": "bandit", "os": "Linux", "database_os": "Linux", - "display_name": "Phoenix-Bandit", - "notes": "", - "versus": "default" + "display_name": "Phoenix", + "notes": "" } }] } diff --git a/frameworks/Elixir/phoenix/config/bandit.exs b/frameworks/Elixir/phoenix/config/bandit.exs deleted file mode 100644 index ccaf648c115..00000000000 --- a/frameworks/Elixir/phoenix/config/bandit.exs +++ /dev/null @@ -1,43 +0,0 @@ -import Config - -config :hello, HelloWeb.Endpoint, - adapter: Bandit.PhoenixAdapter, - http: [port: 8080, ip: {0, 0, 0, 0}], - cache_static_lookup: false, - check_orgin: false, - debug_errors: false, - code_reloader: false, - server: true - - -config :hello, Hello.Repo, - username: "benchmarkdbuser", - password: "benchmarkdbpass", - database: "hello_world", - hostname: "tfb-database", - pool_size: 40, - queue_target: 5000, - log: false - -config :phoenix, :logger, false - -config :logger, - compile_time_purge_matching: [ - [level_lower_than: :error] - ], - level: :error, - backends: [] - -# ## SSL Support -# -# To get SSL working, you will need to add the `https` key -# to the previous section: -# -# config:hello, Hello.Endpoint, -# ... -# https: [port: 443, -# keyfile: System.get_env("SOME_APP_SSL_KEY_PATH"), -# certfile: System.get_env("SOME_APP_SSL_CERT_PATH")] -# -# Where those two env variables point to a file on -# disk for the key and cert. diff --git a/frameworks/Elixir/phoenix/config/config.exs b/frameworks/Elixir/phoenix/config/config.exs index be5688f535b..e464e49d164 100755 --- a/frameworks/Elixir/phoenix/config/config.exs +++ b/frameworks/Elixir/phoenix/config/config.exs @@ -18,6 +18,14 @@ config :hello, HelloWeb.Endpoint, debug_errors: false, secret_key_base: "Z18ZjzZslFpKd8HB41IljqMavPiOKVF9y1DIQ+S2Ytg7Op0EIauwJgd7mtRStssx" +# Configure cache for world entities +config :hello, Hello.WorldCache, + gc_interval: :timer.hours(1), + max_size: 1_000_000, + allocated_memory: 100_000_000, + gc_cleanup_min_timeout: :timer.seconds(30), + gc_cleanup_max_timeout: :timer.minutes(30) + # Configures Elixir's Logger config :logger, :console, format: "$time $metadata[$level] $message\n", diff --git a/frameworks/Elixir/phoenix/config/dev.exs b/frameworks/Elixir/phoenix/config/dev.exs index fef1a0e3888..ad06286bc58 100644 --- a/frameworks/Elixir/phoenix/config/dev.exs +++ b/frameworks/Elixir/phoenix/config/dev.exs @@ -1,13 +1,15 @@ import Config -# For development, we disable any cache and enable -# debugging and code reloading. -# -# The watchers configuration can be used to run external -# watchers to your application. For example, we use it -# with brunch.io to recompile .js and .css sources. config :hello, HelloWeb.Endpoint, - http: [port: 8080], + adapter: Bandit.PhoenixAdapter, + http: [ + port: 4000, + ip: {0, 0, 0, 0}, + http_options: [ + compress: false, + log_protocol_errors: :verbose + ], + ], debug_errors: true, code_reloader: true, cache_static_lookup: false @@ -23,10 +25,10 @@ config :hello, HelloWeb.Endpoint, ] config :hello, Hello.Repo, - username: "benchmarkdbuser", - password: "benchmarkdbpass", + username: "postgres", + password: "postgres", database: "hello_world", - hostname: "tfb-database" + hostname: "localhost" # Do not include metadata nor timestamps in development logs config :logger, :console, format: "[$level] $message\n" diff --git a/frameworks/Elixir/phoenix/config/prod.exs b/frameworks/Elixir/phoenix/config/prod.exs index 853a5ea247d..e2c578f4656 100755 --- a/frameworks/Elixir/phoenix/config/prod.exs +++ b/frameworks/Elixir/phoenix/config/prod.exs @@ -1,9 +1,19 @@ import Config config :hello, HelloWeb.Endpoint, - url: [host: "0.0.0.0"], - http: [port: 8080, protocol_options: [max_keepalive: :infinity], backlog: 8096], - cache_static_lookup: false, + adapter: Bandit.PhoenixAdapter, + http: [ + port: 8080, + ip: {0, 0, 0, 0}, + http_options: [ + compress: false, + log_protocol_errors: false + ], + thousand_island_options: [ + transport_options: [ backlog: 8192 ] + ], + ], + compress: false, check_origin: false, debug_errors: false, code_reloader: false, @@ -14,7 +24,8 @@ config :hello, Hello.Repo, password: "benchmarkdbpass", database: "hello_world", hostname: "tfb-database", - pool_size: 40, + pool_count: 56, + pool_size: 15, queue_target: 5000, log: false @@ -26,17 +37,3 @@ config :logger, ], level: :error, backends: [] - -# ## SSL Support -# -# To get SSL working, you will need to add the `https` key -# to the previous section: -# -# config:hello, Hello.Endpoint, -# ... -# https: [port: 443, -# keyfile: System.get_env("SOME_APP_SSL_KEY_PATH"), -# certfile: System.get_env("SOME_APP_SSL_CERT_PATH")] -# -# Where those two env variables point to a file on -# disk for the key and cert. diff --git a/frameworks/Elixir/phoenix/lib/hello/application.ex b/frameworks/Elixir/phoenix/lib/hello/application.ex index 58fed15fc63..49f1ef8ba03 100644 --- a/frameworks/Elixir/phoenix/lib/hello/application.ex +++ b/frameworks/Elixir/phoenix/lib/hello/application.ex @@ -6,7 +6,7 @@ defmodule Hello.Application do def start(_type, _args) do children = [ Hello.Repo, - {Hello.Cache, []}, + {Hello.WorldCache, []}, HelloWeb.Endpoint ] diff --git a/frameworks/Elixir/phoenix/lib/hello/cache.ex b/frameworks/Elixir/phoenix/lib/hello/cache.ex deleted file mode 100644 index 0f051a3fb72..00000000000 --- a/frameworks/Elixir/phoenix/lib/hello/cache.ex +++ /dev/null @@ -1,5 +0,0 @@ -defmodule Hello.Cache do - use Nebulex.Cache, - otp_app: :hello, - adapter: Nebulex.Adapters.Local -end diff --git a/frameworks/Elixir/phoenix/lib/hello/world_cache.ex b/frameworks/Elixir/phoenix/lib/hello/world_cache.ex new file mode 100644 index 00000000000..e6cde7ab58e --- /dev/null +++ b/frameworks/Elixir/phoenix/lib/hello/world_cache.ex @@ -0,0 +1,31 @@ +defmodule Hello.WorldCache do + use Nebulex.Cache, + otp_app: :hello, + adapter: Nebulex.Adapters.Local + + alias Hello.Models.World + alias Hello.Repo + + def seed do + if not __MODULE__.has_key?(:seeded) do + World + |> Repo.all() + |> Enum.into([], &{&1.id, &1}) + |> __MODULE__.put_all() + + __MODULE__.put(:seeded, true) + end + end + + def fetch(id) do + case __MODULE__.get(id) do + nil -> + world = Repo.get(World, id) + :ok = __MODULE__.put(id, world) + world + + world -> + world + end + end +end diff --git a/frameworks/Elixir/phoenix/lib/hello_web.ex b/frameworks/Elixir/phoenix/lib/hello_web.ex index 78062f969be..e3411588296 100644 --- a/frameworks/Elixir/phoenix/lib/hello_web.ex +++ b/frameworks/Elixir/phoenix/lib/hello_web.ex @@ -29,7 +29,6 @@ defmodule HelloWeb do log: false import Plug.Conn - import HelloWeb.Gettext unquote(verified_routes()) end @@ -39,8 +38,6 @@ defmodule HelloWeb do quote do use Phoenix.Component - import HelloWeb.Gettext - # Routes generation with the ~p sigil unquote(verified_routes()) end @@ -62,9 +59,7 @@ defmodule HelloWeb do defp html_helpers do quote do # Use all HTML functionality (forms, tags, etc) - use Phoenix.HTML - # Core UI Components and translation - import HelloWeb.Gettext + import Phoenix.HTML # Routes generation with the ~p sigil unquote(verified_routes()) @@ -97,8 +92,8 @@ defmodule HelloWeb do end @doc """ - When used, dispatch to the appropriate controller/view/etc. - """ + When used, dispatch to the appropriate controller/view/etc. + """ defmacro __using__(which) when is_atom(which) do apply(__MODULE__, which, []) end diff --git a/frameworks/Elixir/phoenix/lib/hello_web/controllers/page_controller.ex b/frameworks/Elixir/phoenix/lib/hello_web/controllers/page_controller.ex index a44c5edf099..fe03f3337c1 100644 --- a/frameworks/Elixir/phoenix/lib/hello_web/controllers/page_controller.ex +++ b/frameworks/Elixir/phoenix/lib/hello_web/controllers/page_controller.ex @@ -1,13 +1,15 @@ defmodule HelloWeb.PageController do - alias Hello.Models.{Fortune, World} - use HelloWeb, :controller + alias Hello.Models.Fortune + alias Hello.Models.World alias Hello.Repo - alias Hello.Cache + alias Hello.WorldCache @random_max 10_000 + plug :accepts, ~w(html json) when action == :fortunes + def index(conn, _params) do json(conn, %{"TE Benchmarks\n" => "Started"}) end @@ -24,13 +26,12 @@ defmodule HelloWeb.PageController do end def queries(conn, params) do - :rand.seed(:exsp) - worlds = - Stream.repeatedly(&random_id/0) - |> Stream.uniq() - |> Stream.map(fn idx -> Repo.get(World, idx) end) - |> Enum.take(size(params["queries"])) + Repo.checkout(fn -> + params["queries"] + |> random_ids_sample() + |> Enum.map(&Repo.get(World, &1)) + end) json(conn, worlds) end @@ -41,71 +42,74 @@ defmodule HelloWeb.PageController do message: "Additional fortune added at request time." } - fortunes = [additional_fortune | Repo.all(Fortune)] + fortunes = + [additional_fortune | Repo.all(Fortune)] + |> Enum.sort(fn a, b -> a.message < b.message end) - render(conn, :fortunes, - fortunes: Enum.sort(fortunes, fn f1, f2 -> f1.message < f2.message end) - ) + render(conn, :fortunes, fortunes: fortunes) end def updates(conn, params) do - :rand.seed(:exsp) - - worlds = - Stream.repeatedly(&random_id/0) - |> Stream.uniq() - |> Stream.map(fn idx -> Repo.get(World, idx) end) - |> Stream.map(fn world -> %{id: world.id, randomnumber: :rand.uniform(@random_max)} end) - |> Enum.take(size(params["queries"])) + world_updates = + Repo.checkout(fn -> + params["queries"] + |> random_ids_sample() + |> Enum.sort() + # + # If this is not sorted it will intermittently generate: + # + # FAIL for http://tfb-server:8080/updates/20 + # Only 20470 executed queries in the database out of roughly 20480 expected. + # + |> Enum.map(fn id -> + world = Repo.get(World, id) + %{id: world.id, randomnumber: :rand.uniform(@random_max)} + end) + end) Repo.insert_all( World, - worlds, + world_updates, on_conflict: {:replace_all_except, [:id]}, conflict_target: [:id], returning: false ) - json(conn, worlds) + json(conn, world_updates) end def plaintext(conn, _params) do - text(conn, "Hello, World!") + conn + |> put_resp_header("content-type", "text/plain") + |> send_resp(200, "Hello, World!") end def cached(conn, params) do - :rand.seed(:exsp) + WorldCache.seed() worlds = - Stream.repeatedly(&random_id/0) - |> Stream.uniq() - |> Stream.map(&get_cached_world/1) - |> Enum.take(size(params["count"])) + params["count"] + |> random_ids_sample() + |> Enum.map(&WorldCache.fetch(&1)) json(conn, worlds) end - defp get_cached_world(idx) do - case Cache.get(idx) do - nil -> - world = Repo.get(World, idx) - :ok = Cache.put(idx, world) - world - - world -> - world - end - end - defp random_id() do :rand.uniform(@random_max) end - defp size(nil), do: 1 - defp size(""), do: 1 + defp random_ids_sample(count) do + # Use the fastest rand algorithm + :rand.seed(:exsp) + + Stream.repeatedly(&random_id/0) + |> Stream.uniq() + |> Enum.take(size(count)) + end - defp size(queries) when is_bitstring(queries) do - case Integer.parse(queries) do + defp size(param_count) when is_bitstring(param_count) do + case Integer.parse(param_count) do {count, _} -> max(1, min(500, count)) _ -> 1 end diff --git a/frameworks/Elixir/phoenix/lib/hello_web/controllers/page_html/fortunes.html.eex b/frameworks/Elixir/phoenix/lib/hello_web/controllers/page_html/fortunes.html.heex similarity index 100% rename from frameworks/Elixir/phoenix/lib/hello_web/controllers/page_html/fortunes.html.eex rename to frameworks/Elixir/phoenix/lib/hello_web/controllers/page_html/fortunes.html.heex diff --git a/frameworks/Elixir/phoenix/lib/hello_web/endpoint.ex b/frameworks/Elixir/phoenix/lib/hello_web/endpoint.ex index f709d00a2e8..a764bbf653e 100644 --- a/frameworks/Elixir/phoenix/lib/hello_web/endpoint.ex +++ b/frameworks/Elixir/phoenix/lib/hello_web/endpoint.ex @@ -20,4 +20,3 @@ defmodule HelloWeb.Endpoint do plug HelloWeb.HeadersPlug plug HelloWeb.Router end - diff --git a/frameworks/Elixir/phoenix/lib/hello_web/gettext.ex b/frameworks/Elixir/phoenix/lib/hello_web/gettext.ex deleted file mode 100644 index a5bacc56875..00000000000 --- a/frameworks/Elixir/phoenix/lib/hello_web/gettext.ex +++ /dev/null @@ -1,24 +0,0 @@ -defmodule HelloWeb.Gettext do - @moduledoc """ - A module providing Internationalization with a gettext-based API. - - By using [Gettext](https://hexdocs.pm/gettext), - your module gains a set of macros for translations, for example: - - import HelloWeb.Gettext - - # Simple translation - gettext("Here is the string to translate") - - # Plural translation - ngettext("Here is the string to translate", - "Here are the strings to translate", - 3) - - # Domain-based translation - dgettext("errors", "Here is the error message to translate") - - See the [Gettext Docs](https://hexdocs.pm/gettext) for detailed usage. - """ - use Gettext, otp_app: :hello -end diff --git a/frameworks/Elixir/phoenix/lib/hello_web/router.ex b/frameworks/Elixir/phoenix/lib/hello_web/router.ex index 1634f3403fd..7e3caed3b8f 100755 --- a/frameworks/Elixir/phoenix/lib/hello_web/router.ex +++ b/frameworks/Elixir/phoenix/lib/hello_web/router.ex @@ -1,13 +1,7 @@ defmodule HelloWeb.Router do use HelloWeb, :router - pipeline :browser do - plug :accepts, ~w(html json) - end - scope "/", HelloWeb do - pipe_through [:browser] - get "/json", PageController, :_json get "/db", PageController, :db get "/queries", PageController, :queries diff --git a/frameworks/Elixir/phoenix/mix.exs b/frameworks/Elixir/phoenix/mix.exs index fa48c24784d..8e2e600c889 100755 --- a/frameworks/Elixir/phoenix/mix.exs +++ b/frameworks/Elixir/phoenix/mix.exs @@ -4,8 +4,8 @@ defmodule Hello.Mixfile do def project do [ app: :hello, - version: "0.1.0", - elixir: "~> 1.14", + version: "1.1.1", + elixir: "~> 1.17", elixirc_paths: elixirc_paths(Mix.env()), start_permanent: Mix.env() == :prod, deps: deps() @@ -29,17 +29,15 @@ defmodule Hello.Mixfile do # Type `mix help deps` for examples and options defp deps do [ - {:bandit, "~> 1.0.0-pre.5"}, - {:gettext, "~> 0.20"}, - {:ecto_sql, "~> 3.7"}, + {:bandit, "~> 1.6.1"}, + {:ecto_sql, "~> 3.10"}, {:jason, "~> 1.2"}, {:phoenix, "~> 1.7"}, - {:phoenix_ecto, "~> 4.4"}, - {:phoenix_html, "~> 3.2"}, {:phoenix_live_view, "~> 0.18"}, - {:plug_cowboy, "~> 2.5"}, - {:postgrex, "~> 0.15"}, - {:nebulex, "~> 2.4"} + {:phoenix_ecto, "~> 4.4"}, + {:phoenix_html, "~> 4.1"}, + {:postgrex, ">= 0.0.0"}, + {:nebulex, "~> 2.6"} ] end end diff --git a/frameworks/Elixir/phoenix/mix.lock b/frameworks/Elixir/phoenix/mix.lock index 415edcb0107..5fd905d6784 100644 --- a/frameworks/Elixir/phoenix/mix.lock +++ b/frameworks/Elixir/phoenix/mix.lock @@ -1,32 +1,25 @@ %{ - "bandit": {:hex, :bandit, "1.0.0-pre.5", "94b668f987a3b63f53123d2bdef1aaab73439eb02fcef7eb99032038206cab54", [:mix], [{:hpax, "~> 0.1.1", [hex: :hpax, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:thousand_island, "~> 1.0-pre", [hex: :thousand_island, repo: "hexpm", optional: false]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "686da83f0c2cabd68cc221067ab43bc50af88c3e7fc8ef824a0b7039a978e383"}, - "castore": {:hex, :castore, "1.0.2", "0c6292ecf3e3f20b7c88408f00096337c4bfd99bd46cc2fe63413ddbe45b3573", [:mix], [], "hexpm", "40b2dd2836199203df8500e4a270f10fc006cc95adc8a319e148dc3077391d96"}, - "cowboy": {:hex, :cowboy, "2.10.0", "ff9ffeff91dae4ae270dd975642997afe2a1179d94b1887863e43f681a203e26", [:make, :rebar3], [{:cowlib, "2.12.1", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "3afdccb7183cc6f143cb14d3cf51fa00e53db9ec80cdcd525482f5e99bc41d6b"}, - "cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"}, - "cowlib": {:hex, :cowlib, "2.12.1", "a9fa9a625f1d2025fe6b462cb865881329b5caff8f1854d1cbc9f9533f00e1e1", [:make, :rebar3], [], "hexpm", "163b73f6367a7341b33c794c4e88e7dbfe6498ac42dcd69ef44c5bc5507c8db0"}, - "db_connection": {:hex, :db_connection, "2.5.0", "bb6d4f30d35ded97b29fe80d8bd6f928a1912ca1ff110831edcd238a1973652c", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c92d5ba26cd69ead1ff7582dbb860adeedfff39774105a4f1c92cbb654b55aa2"}, - "decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"}, - "ecto": {:hex, :ecto, "3.10.1", "c6757101880e90acc6125b095853176a02da8f1afe056f91f1f90b80c9389822", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d2ac4255f1601bdf7ac74c0ed971102c6829dc158719b94bd30041bbad77f87a"}, - "ecto_sql": {:hex, :ecto_sql, "3.10.1", "6ea6b3036a0b0ca94c2a02613fd9f742614b5cfe494c41af2e6571bb034dd94c", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.10.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16.0 or ~> 0.17.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "f6a25bdbbd695f12c8171eaff0851fa4c8e72eec1e98c7364402dda9ce11c56b"}, - "expo": {:hex, :expo, "0.4.1", "1c61d18a5df197dfda38861673d392e642649a9cef7694d2f97a587b2cfb319b", [:mix], [], "hexpm", "2ff7ba7a798c8c543c12550fa0e2cbc81b95d4974c65855d8d15ba7b37a1ce47"}, - "gettext": {:hex, :gettext, "0.22.2", "6bfca374de34ecc913a28ba391ca184d88d77810a3e427afa8454a71a51341ac", [:mix], [{:expo, "~> 0.4.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "8a2d389673aea82d7eae387e6a2ccc12660610080ae7beb19452cfdc1ec30f60"}, - "hpax": {:hex, :hpax, "0.1.2", "09a75600d9d8bbd064cdd741f21fc06fc1f4cf3d0fcc335e5aa19be1a7235c84", [:mix], [], "hexpm", "2c87843d5a23f5f16748ebe77969880e29809580efdaccd615cd3bed628a8c13"}, - "jason": {:hex, :jason, "1.4.0", "e855647bc964a44e2f67df589ccf49105ae039d4179db7f6271dfd3843dc27e6", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "79a3791085b2a0f743ca04cec0f7be26443738779d09302e01318f97bdb82121"}, - "mime": {:hex, :mime, "2.0.5", "dc34c8efd439abe6ae0343edbb8556f4d63f178594894720607772a041b04b02", [:mix], [], "hexpm", "da0d64a365c45bc9935cc5c8a7fc5e49a0e0f9932a761c55d6c52b142780a05c"}, - "nebulex": {:hex, :nebulex, "2.5.1", "8ffbde30643e76d6cec712281ca68ab05f73170de9e758a39bc7e4e6987f608f", [:mix], [{:decorator, "~> 1.4", [hex: :decorator, repo: "hexpm", optional: true]}, {:shards, "~> 1.1", [hex: :shards, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "8d0d3800d98c68ee19b229b7fe35fac0192ab5963a573612cf74a388e083bccf"}, - "phoenix": {:hex, :phoenix, "1.7.3", "4d8eca2c020c9ed81a28e7a8c60e0a4f6f9f7f6e12eb91dfd01301eac07424c1", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.4", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "6b1bc308758f95ecf3e0d795389440a2ca88a903e0fda1f921c780918c16d640"}, - "phoenix_ecto": {:hex, :phoenix_ecto, "4.4.2", "b21bd01fdeffcfe2fab49e4942aa938b6d3e89e93a480d4aee58085560a0bc0d", [:mix], [{:ecto, "~> 3.5", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "70242edd4601d50b69273b057ecf7b684644c19ee750989fd555625ae4ce8f5d"}, - "phoenix_html": {:hex, :phoenix_html, "3.3.1", "4788757e804a30baac6b3fc9695bf5562465dd3f1da8eb8460ad5b404d9a2178", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "bed1906edd4906a15fd7b412b85b05e521e1f67c9a85418c55999277e553d0d3"}, - "phoenix_live_view": {:hex, :phoenix_live_view, "0.19.0", "de5643d03e3cdf5ff19cd45b5d14543a3b1ad8551d529f6b24246e88a6c6f1b8", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a650b6f814c4f386314b98f1aebf92f8652649166612f84ef2e60a20894addfa"}, - "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.2", "a4950b63ace57720b0fc1c6da083c53346b36f99021de89595cc4f026288ff51", [:mix], [], "hexpm", "45741676a94c71f9afdfed9d22d49b6856c026ff504db04e3dc03a1d86f8201c"}, - "phoenix_template": {:hex, :phoenix_template, "1.0.1", "85f79e3ad1b0180abb43f9725973e3b8c2c3354a87245f91431eec60553ed3ef", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "157dc078f6226334c91cb32c1865bf3911686f8bcd6bcff86736f6253e6993ee"}, - "plug": {:hex, :plug, "1.14.2", "cff7d4ec45b4ae176a227acd94a7ab536d9b37b942c8e8fa6dfc0fff98ff4d80", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "842fc50187e13cf4ac3b253d47d9474ed6c296a8732752835ce4a86acdf68d13"}, - "plug_cowboy": {:hex, :plug_cowboy, "2.6.1", "9a3bbfceeb65eff5f39dab529e5cd79137ac36e913c02067dba3963a26efe9b2", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "de36e1a21f451a18b790f37765db198075c25875c64834bcc82d90b309eb6613"}, - "plug_crypto": {:hex, :plug_crypto, "1.2.5", "918772575e48e81e455818229bf719d4ab4181fcbf7f85b68a35620f78d89ced", [:mix], [], "hexpm", "26549a1d6345e2172eb1c233866756ae44a9609bd33ee6f99147ab3fd87fd842"}, - "postgrex": {:hex, :postgrex, "0.17.1", "01c29fd1205940ee55f7addb8f1dc25618ca63a8817e56fac4f6846fc2cddcbe", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "14b057b488e73be2beee508fb1955d8db90d6485c6466428fe9ccf1d6692a555"}, - "ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"}, - "telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"}, - "thousand_island": {:hex, :thousand_island, "1.0.0-pre.3", "67b31809769736031b240339fa5096a6e491b7d7ec5e0e37ee80cab10e8712a9", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "75602046418b2510aac3c968b2941778187fe88256010116834903b806d77f53"}, - "websock": {:hex, :websock, "0.5.1", "c496036ce95bc26d08ba086b2a827b212c67e7cabaa1c06473cd26b40ed8cf10", [:mix], [], "hexpm", "b9f785108b81cd457b06e5f5dabe5f65453d86a99118b2c0a515e1e296dc2d2c"}, - "websock_adapter": {:hex, :websock_adapter, "0.5.1", "292e6c56724e3457e808e525af0e9bcfa088cc7b9c798218e78658c7f9b85066", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "8e2e1544bfde5f9d0442f9cec2f5235398b224f75c9e06b60557debf64248ec1"}, + "bandit": {:hex, :bandit, "1.6.1", "9e01b93d72ddc21d8c576a704949e86ee6cde7d11270a1d3073787876527a48f", [:mix], [{:hpax, "~> 1.0", [hex: :hpax, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:thousand_island, "~> 1.0", [hex: :thousand_island, repo: "hexpm", optional: false]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "5a904bf010ea24b67979835e0507688e31ac873d4ffc8ed0e5413e8d77455031"}, + "castore": {:hex, :castore, "1.0.10", "43bbeeac820f16c89f79721af1b3e092399b3a1ecc8df1a472738fd853574911", [:mix], [], "hexpm", "1b0b7ea14d889d9ea21202c43a4fa015eb913021cb535e8ed91946f4b77a8848"}, + "db_connection": {:hex, :db_connection, "2.7.0", "b99faa9291bb09892c7da373bb82cba59aefa9b36300f6145c5f201c7adf48ec", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dcf08f31b2701f857dfc787fbad78223d61a32204f217f15e881dd93e4bdd3ff"}, + "decimal": {:hex, :decimal, "2.2.0", "df3d06bb9517e302b1bd265c1e7f16cda51547ad9d99892049340841f3e15836", [:mix], [], "hexpm", "af8daf87384b51b7e611fb1a1f2c4d4876b65ef968fa8bd3adf44cff401c7f21"}, + "ecto": {:hex, :ecto, "3.12.5", "4a312960ce612e17337e7cefcf9be45b95a3be6b36b6f94dfb3d8c361d631866", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "6eb18e80bef8bb57e17f5a7f068a1719fbda384d40fc37acb8eb8aeca493b6ea"}, + "ecto_sql": {:hex, :ecto_sql, "3.12.1", "c0d0d60e85d9ff4631f12bafa454bc392ce8b9ec83531a412c12a0d415a3a4d0", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.12", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.7", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.19 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "aff5b958a899762c5f09028c847569f7dfb9cc9d63bdb8133bff8a5546de6bf5"}, + "hpax": {:hex, :hpax, "1.0.1", "c857057f89e8bd71d97d9042e009df2a42705d6d690d54eca84c8b29af0787b0", [:mix], [], "hexpm", "4e2d5a4f76ae1e3048f35ae7adb1641c36265510a2d4638157fbcb53dda38445"}, + "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, + "mime": {:hex, :mime, "2.0.6", "8f18486773d9b15f95f4f4f1e39b710045fa1de891fada4516559967276e4dc2", [:mix], [], "hexpm", "c9945363a6b26d747389aac3643f8e0e09d30499a138ad64fe8fd1d13d9b153e"}, + "nebulex": {:hex, :nebulex, "2.6.4", "4b00706e0e676474783d988962abf74614480e13c0a32645acb89bb32b660e09", [:mix], [{:decorator, "~> 1.4", [hex: :decorator, repo: "hexpm", optional: true]}, {:shards, "~> 1.1", [hex: :shards, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "25bdabf3fb86035c8151bba60bda20f80f96ae0261db7bd4090878ff63b03581"}, + "phoenix": {:hex, :phoenix, "1.7.17", "2fcdceecc6fb90bec26fab008f96abbd0fd93bc9956ec7985e5892cf545152ca", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.7", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "50e8ad537f3f7b0efb1509b2f75b5c918f697be6a45d48e49a30d3b7c0e464c9"}, + "phoenix_ecto": {:hex, :phoenix_ecto, "4.6.3", "f686701b0499a07f2e3b122d84d52ff8a31f5def386e03706c916f6feddf69ef", [:mix], [{:ecto, "~> 3.5", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.1", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "909502956916a657a197f94cc1206d9a65247538de8a5e186f7537c895d95764"}, + "phoenix_html": {:hex, :phoenix_html, "4.1.1", "4c064fd3873d12ebb1388425a8f2a19348cef56e7289e1998e2d2fa758aa982e", [:mix], [], "hexpm", "f2f2df5a72bc9a2f510b21497fd7d2b86d932ec0598f0210fed4114adc546c6f"}, + "phoenix_live_view": {:hex, :phoenix_live_view, "0.20.17", "f396bbdaf4ba227b82251eb75ac0afa6b3da5e509bc0d030206374237dfc9450", [:mix], [{:floki, "~> 0.36", [hex: :floki, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.15", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a61d741ffb78c85fdbca0de084da6a48f8ceb5261a79165b5a0b59e5f65ce98b"}, + "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.3", "3168d78ba41835aecad272d5e8cd51aa87a7ac9eb836eabc42f6e57538e3731d", [:mix], [], "hexpm", "bba06bc1dcfd8cb086759f0edc94a8ba2bc8896d5331a1e2c2902bf8e36ee502"}, + "phoenix_template": {:hex, :phoenix_template, "1.0.4", "e2092c132f3b5e5b2d49c96695342eb36d0ed514c5b252a77048d5969330d639", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "2c0c81f0e5c6753faf5cca2f229c9709919aba34fab866d3bc05060c9c444206"}, + "plug": {:hex, :plug, "1.16.1", "40c74619c12f82736d2214557dedec2e9762029b2438d6d175c5074c933edc9d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a13ff6b9006b03d7e33874945b2755253841b238c34071ed85b0e86057f8cddc"}, + "plug_crypto": {:hex, :plug_crypto, "2.1.0", "f44309c2b06d249c27c8d3f65cfe08158ade08418cf540fd4f72d4d6863abb7b", [:mix], [], "hexpm", "131216a4b030b8f8ce0f26038bc4421ae60e4bb95c5cf5395e1421437824c4fa"}, + "postgrex": {:hex, :postgrex, "0.19.3", "a0bda6e3bc75ec07fca5b0a89bffd242ca209a4822a9533e7d3e84ee80707e19", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "d31c28053655b78f47f948c85bb1cf86a9c1f8ead346ba1aa0d0df017fa05b61"}, + "telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"}, + "thousand_island": {:hex, :thousand_island, "1.3.7", "1da7598c0f4f5f50562c097a3f8af308ded48cd35139f0e6f17d9443e4d0c9c5", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "0139335079953de41d381a6134d8b618d53d084f558c734f2662d1a72818dd12"}, + "websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"}, + "websock_adapter": {:hex, :websock_adapter, "0.5.8", "3b97dc94e407e2d1fc666b2fb9acf6be81a1798a2602294aac000260a7c4a47d", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "315b9a1865552212b5f35140ad194e67ce31af45bcee443d4ecb96b5fd3f3782"}, } diff --git a/frameworks/Elixir/phoenix/phoenix-bandit.dockerfile b/frameworks/Elixir/phoenix/phoenix-bandit.dockerfile deleted file mode 100644 index 103350fc6db..00000000000 --- a/frameworks/Elixir/phoenix/phoenix-bandit.dockerfile +++ /dev/null @@ -1,39 +0,0 @@ -ARG ELIXIR="1.14.5" -ARG ERLANG="26.0" -ARG ALPINE="3.17.3" - -ARG BUILDER_IMAGE="hexpm/elixir:${ELIXIR}-erlang-${ERLANG}-alpine-${ALPINE}" -ARG RUNNER_IMAGE="alpine:${ALPINE}" - -FROM ${BUILDER_IMAGE} AS builder - -ARG MIX_ENV="bandit" - -RUN mix local.hex --force && \ - mix local.rebar --force - -COPY mix.exs mix.lock ./ -RUN mix deps.get --force --only prod - -COPY config ./config - -RUN mix deps.compile - -COPY priv ./priv -COPY lib ./lib - -COPY rel ./rel -RUN mix release --force --path /export - -# start a new build stage so that the final image will only contain -# the compiled release and other runtime necessities -FROM ${RUNNER_IMAGE} - -RUN apk add --no-cache libstdc++ openssl ncurses-libs - -COPY --from=builder /export /opt - -EXPOSE 8080 - -ENTRYPOINT ["/opt/bin/hello"] -CMD ["start"] diff --git a/frameworks/Elixir/phoenix/phoenix.dockerfile b/frameworks/Elixir/phoenix/phoenix.dockerfile index c9e0d7701b2..4de857bbec4 100644 --- a/frameworks/Elixir/phoenix/phoenix.dockerfile +++ b/frameworks/Elixir/phoenix/phoenix.dockerfile @@ -1,6 +1,6 @@ -ARG ELIXIR="1.14.5" -ARG ERLANG="26.0" -ARG ALPINE="3.17.3" +ARG ELIXIR="1.17.2" +ARG ERLANG="27.0.1" +ARG ALPINE="3.19.3" ARG BUILDER_IMAGE="hexpm/elixir:${ELIXIR}-erlang-${ERLANG}-alpine-${ALPINE}" ARG RUNNER_IMAGE="alpine:${ALPINE}" @@ -9,6 +9,8 @@ FROM ${BUILDER_IMAGE} AS builder ARG MIX_ENV="prod" +RUN apk add --no-cache git + RUN mix local.hex --force && \ mix local.rebar --force diff --git a/frameworks/Elixir/plug/elixir-plug-ecto.dockerfile b/frameworks/Elixir/plug/elixir-plug-ecto.dockerfile index a674dd80178..c943ba48991 100644 --- a/frameworks/Elixir/plug/elixir-plug-ecto.dockerfile +++ b/frameworks/Elixir/plug/elixir-plug-ecto.dockerfile @@ -1,6 +1,6 @@ -ARG ELIXIR="1.14.2" -ARG ERLANG="25.1.2" -ARG ALPINE="3.16.2" +ARG ELIXIR="1.17.2" +ARG ERLANG="27.0.1" +ARG ALPINE="3.19.3" ARG BUILDER_IMAGE="hexpm/elixir:${ELIXIR}-erlang-${ERLANG}-alpine-${ALPINE}" ARG RUNNER_IMAGE="alpine:${ALPINE}" diff --git a/frameworks/Elixir/plug/lib/framework_benchmarks/handlers/cached-world.ex b/frameworks/Elixir/plug/lib/framework_benchmarks/handlers/cached-world.ex index c80b71053e7..60b441557c5 100644 --- a/frameworks/Elixir/plug/lib/framework_benchmarks/handlers/cached-world.ex +++ b/frameworks/Elixir/plug/lib/framework_benchmarks/handlers/cached-world.ex @@ -11,10 +11,10 @@ defmodule FrameworkBenchmarks.Handlers.CachedWorld do :rand.uniform(10_000) end) - {:ok, json} = + json = ids |> Enum.map(&FrameworkBenchmarks.CachedWorld.get/1) - |> Jason.encode() + |> Jason.encode_to_iodata!() conn |> Plug.Conn.put_resp_content_type("application/json") diff --git a/frameworks/Elixir/plug/lib/framework_benchmarks/handlers/db.ex b/frameworks/Elixir/plug/lib/framework_benchmarks/handlers/db.ex index b1abba5dd8b..101b7e5f8fd 100644 --- a/frameworks/Elixir/plug/lib/framework_benchmarks/handlers/db.ex +++ b/frameworks/Elixir/plug/lib/framework_benchmarks/handlers/db.ex @@ -5,11 +5,9 @@ defmodule FrameworkBenchmarks.Handlers.DB do def handle(conn) do id = :rand.uniform(10_000) - {:ok, json} = + json = FrameworkBenchmarks.Repo.get(FrameworkBenchmarks.Models.World, id) - |> Map.from_struct() - |> Map.drop([:__meta__]) - |> Jason.encode() + |> Jason.encode_to_iodata!() conn |> Plug.Conn.put_resp_content_type("application/json") diff --git a/frameworks/Elixir/plug/lib/framework_benchmarks/handlers/json.ex b/frameworks/Elixir/plug/lib/framework_benchmarks/handlers/json.ex index c013110a6de..3a7ada06cdb 100644 --- a/frameworks/Elixir/plug/lib/framework_benchmarks/handlers/json.ex +++ b/frameworks/Elixir/plug/lib/framework_benchmarks/handlers/json.ex @@ -3,7 +3,7 @@ defmodule FrameworkBenchmarks.Handlers.JSON do This is the handle for the /json route """ def handle(conn) do - {:ok, json} = Jason.encode(%{message: "Hello, World!"}) + json = Jason.encode_to_iodata!(%{message: "Hello, World!"}) conn |> Plug.Conn.put_resp_content_type("application/json") diff --git a/frameworks/Elixir/plug/lib/framework_benchmarks/handlers/query.ex b/frameworks/Elixir/plug/lib/framework_benchmarks/handlers/query.ex index b4e83026a82..6ad2af9061a 100644 --- a/frameworks/Elixir/plug/lib/framework_benchmarks/handlers/query.ex +++ b/frameworks/Elixir/plug/lib/framework_benchmarks/handlers/query.ex @@ -5,7 +5,7 @@ defmodule FrameworkBenchmarks.Handlers.Query do def handle(conn) do number_of_queries = FrameworkBenchmarks.Handlers.Helpers.parse_queries(conn, "queries") - records = + json = 1..number_of_queries |> Enum.map(fn _ -> :rand.uniform(10_000) @@ -15,16 +15,8 @@ defmodule FrameworkBenchmarks.Handlers.Query do FrameworkBenchmarks.Repo.get(FrameworkBenchmarks.Models.World, &1) end) ) - |> Enum.map(&Task.await(&1)) - - {:ok, json} = - records - |> Enum.map(fn record -> - record - |> Map.from_struct() - |> Map.drop([:__meta__]) - end) - |> Jason.encode() + |> Enum.map(&Task.await(&1, :infinity)) + |> Jason.encode_to_iodata!() conn |> Plug.Conn.put_resp_content_type("application/json") diff --git a/frameworks/Elixir/plug/lib/framework_benchmarks/handlers/update.ex b/frameworks/Elixir/plug/lib/framework_benchmarks/handlers/update.ex index d06744adfde..0b5ad54c4b8 100644 --- a/frameworks/Elixir/plug/lib/framework_benchmarks/handlers/update.ex +++ b/frameworks/Elixir/plug/lib/framework_benchmarks/handlers/update.ex @@ -22,7 +22,7 @@ defmodule FrameworkBenchmarks.Handlers.Update do :rand.uniform(10_000) end) - records = + json = ids |> Enum.map( &Task.async(fn -> @@ -38,16 +38,8 @@ defmodule FrameworkBenchmarks.Handlers.Update do |> FrameworkBenchmarks.Repo.update!() end) ) - |> Enum.map(&Task.await(&1)) - - {:ok, json} = - records - |> Enum.map(fn record -> - record - |> Map.from_struct() - |> Map.drop([:__meta__]) - end) - |> Jason.encode() + |> Enum.map(&Task.await(&1, :infinity)) + |> Jason.encode_to_iodata!() conn |> Plug.Conn.put_resp_content_type("application/json") diff --git a/frameworks/Elixir/plug/lib/framework_benchmarks/models/world.ex b/frameworks/Elixir/plug/lib/framework_benchmarks/models/world.ex index 549d8415a9e..d3db33611c1 100644 --- a/frameworks/Elixir/plug/lib/framework_benchmarks/models/world.ex +++ b/frameworks/Elixir/plug/lib/framework_benchmarks/models/world.ex @@ -1,6 +1,7 @@ defmodule FrameworkBenchmarks.Models.World do use Ecto.Schema + @derive {Jason.Encoder, only: [:id, :randomnumber]} schema "world" do field(:randomnumber, :integer) end diff --git a/frameworks/Elixir/plug/mix.exs b/frameworks/Elixir/plug/mix.exs index 1660a684b65..dcb29917a46 100644 --- a/frameworks/Elixir/plug/mix.exs +++ b/frameworks/Elixir/plug/mix.exs @@ -4,8 +4,8 @@ defmodule FrameworkBenchmarks.MixProject do def project do [ app: :framework_benchmarks, - version: "1.1.0", - elixir: "~> 1.14", + version: "1.1.1", + elixir: "~> 1.17", start_permanent: Mix.env() == :prod, deps: deps() ] @@ -24,10 +24,10 @@ defmodule FrameworkBenchmarks.MixProject do [ {:plug_cowboy, "~> 2.5"}, {:jason, "~> 1.4"}, - {:ecto_sql, "~> 3.8"}, - {:postgrex, "~> 0.16"}, - {:cachex, "~> 3.4"}, - {:phoenix_html, "~> 3.2"} + {:ecto_sql, "~> 3.10"}, + {:postgrex, ">= 0.0.0"}, + {:cachex, "~> 3.6"}, + {:phoenix_html, "~> 4.1"} ] end end diff --git a/frameworks/Elixir/plug/mix.lock b/frameworks/Elixir/plug/mix.lock index 324fedc25f8..fcc35f892b8 100644 --- a/frameworks/Elixir/plug/mix.lock +++ b/frameworks/Elixir/plug/mix.lock @@ -1,27 +1,23 @@ %{ "cachex": {:hex, :cachex, "3.6.0", "14a1bfbeee060dd9bec25a5b6f4e4691e3670ebda28c8ba2884b12fe30b36bf8", [:mix], [{:eternal, "~> 1.2", [hex: :eternal, repo: "hexpm", optional: false]}, {:jumper, "~> 1.0", [hex: :jumper, repo: "hexpm", optional: false]}, {:sleeplocks, "~> 1.1", [hex: :sleeplocks, repo: "hexpm", optional: false]}, {:unsafe, "~> 1.0", [hex: :unsafe, repo: "hexpm", optional: false]}], "hexpm", "ebf24e373883bc8e0c8d894a63bbe102ae13d918f790121f5cfe6e485cc8e2e2"}, - "connection": {:hex, :connection, "1.1.0", "ff2a49c4b75b6fb3e674bfc5536451607270aac754ffd1bdfe175abe4a6d7a68", [:mix], [], "hexpm", "722c1eb0a418fbe91ba7bd59a47e28008a189d47e37e0e7bb85585a016b2869c"}, - "cowboy": {:hex, :cowboy, "2.10.0", "ff9ffeff91dae4ae270dd975642997afe2a1179d94b1887863e43f681a203e26", [:make, :rebar3], [{:cowlib, "2.12.1", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "3afdccb7183cc6f143cb14d3cf51fa00e53db9ec80cdcd525482f5e99bc41d6b"}, + "cowboy": {:hex, :cowboy, "2.12.0", "f276d521a1ff88b2b9b4c54d0e753da6c66dd7be6c9fca3d9418b561828a3731", [:make, :rebar3], [{:cowlib, "2.13.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "8a7abe6d183372ceb21caa2709bec928ab2b72e18a3911aa1771639bef82651e"}, "cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"}, - "cowlib": {:hex, :cowlib, "2.12.1", "a9fa9a625f1d2025fe6b462cb865881329b5caff8f1854d1cbc9f9533f00e1e1", [:make, :rebar3], [], "hexpm", "163b73f6367a7341b33c794c4e88e7dbfe6498ac42dcd69ef44c5bc5507c8db0"}, - "db_connection": {:hex, :db_connection, "2.5.0", "bb6d4f30d35ded97b29fe80d8bd6f928a1912ca1ff110831edcd238a1973652c", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c92d5ba26cd69ead1ff7582dbb860adeedfff39774105a4f1c92cbb654b55aa2"}, + "cowlib": {:hex, :cowlib, "2.13.0", "db8f7505d8332d98ef50a3ef34b34c1afddec7506e4ee4dd4a3a266285d282ca", [:make, :rebar3], [], "hexpm", "e1e1284dc3fc030a64b1ad0d8382ae7e99da46c3246b815318a4b848873800a4"}, + "db_connection": {:hex, :db_connection, "2.7.0", "b99faa9291bb09892c7da373bb82cba59aefa9b36300f6145c5f201c7adf48ec", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dcf08f31b2701f857dfc787fbad78223d61a32204f217f15e881dd93e4bdd3ff"}, "decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"}, - "ecto": {:hex, :ecto, "3.10.1", "c6757101880e90acc6125b095853176a02da8f1afe056f91f1f90b80c9389822", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d2ac4255f1601bdf7ac74c0ed971102c6829dc158719b94bd30041bbad77f87a"}, - "ecto_sql": {:hex, :ecto_sql, "3.10.1", "6ea6b3036a0b0ca94c2a02613fd9f742614b5cfe494c41af2e6571bb034dd94c", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.10.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16.0 or ~> 0.17.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "f6a25bdbbd695f12c8171eaff0851fa4c8e72eec1e98c7364402dda9ce11c56b"}, - "eljiffy": {:hex, :eljiffy, "1.3.0", "7e584be454c5ec3fc3ae472eedb4cb2185e9ed6cd863df383ef601de3f3b27fd", [:mix], [{:jiffy, "~> 1.0", [hex: :jiffy, repo: "hexpm", optional: false]}], "hexpm", "90420512d60fb45bc9c09221b4d89cc539c9bfefc1c62f24cb3e2cb13acf2215"}, + "ecto": {:hex, :ecto, "3.11.2", "e1d26be989db350a633667c5cda9c3d115ae779b66da567c68c80cfb26a8c9ee", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3c38bca2c6f8d8023f2145326cc8a80100c3ffe4dcbd9842ff867f7fc6156c65"}, + "ecto_sql": {:hex, :ecto_sql, "3.11.3", "4eb7348ff8101fbc4e6bbc5a4404a24fecbe73a3372d16569526b0cf34ebc195", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.11.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "e5f36e3d736b99c7fee3e631333b8394ade4bafe9d96d35669fca2d81c2be928"}, "eternal": {:hex, :eternal, "1.2.2", "d1641c86368de99375b98d183042dd6c2b234262b8d08dfd72b9eeaafc2a1abd", [:mix], [], "hexpm", "2c9fe32b9c3726703ba5e1d43a1d255a4f3f2d8f8f9bc19f094c7cb1a7a9e782"}, - "jason": {:hex, :jason, "1.4.0", "e855647bc964a44e2f67df589ccf49105ae039d4179db7f6271dfd3843dc27e6", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "79a3791085b2a0f743ca04cec0f7be26443738779d09302e01318f97bdb82121"}, - "jiffy": {:hex, :jiffy, "1.1.1", "aca10f47aa91697bf24ab9582c74e00e8e95474c7ef9f76d4f1a338d0f5de21b", [:rebar3], [], "hexpm", "62e1f0581c3c19c33a725c781dfa88410d8bff1bbafc3885a2552286b4785c4c"}, - "jumper": {:hex, :jumper, "1.0.1", "3c00542ef1a83532b72269fab9f0f0c82bf23a35e27d278bfd9ed0865cecabff", [:mix], [], "hexpm", "318c59078ac220e966d27af3646026db9b5a5e6703cb2aa3e26bcfaba65b7433"}, - "mime": {:hex, :mime, "2.0.5", "dc34c8efd439abe6ae0343edbb8556f4d63f178594894720607772a041b04b02", [:mix], [], "hexpm", "da0d64a365c45bc9935cc5c8a7fc5e49a0e0f9932a761c55d6c52b142780a05c"}, - "phoenix_html": {:hex, :phoenix_html, "3.3.1", "4788757e804a30baac6b3fc9695bf5562465dd3f1da8eb8460ad5b404d9a2178", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "bed1906edd4906a15fd7b412b85b05e521e1f67c9a85418c55999277e553d0d3"}, - "plug": {:hex, :plug, "1.14.2", "cff7d4ec45b4ae176a227acd94a7ab536d9b37b942c8e8fa6dfc0fff98ff4d80", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "842fc50187e13cf4ac3b253d47d9474ed6c296a8732752835ce4a86acdf68d13"}, - "plug_cowboy": {:hex, :plug_cowboy, "2.6.1", "9a3bbfceeb65eff5f39dab529e5cd79137ac36e913c02067dba3963a26efe9b2", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "de36e1a21f451a18b790f37765db198075c25875c64834bcc82d90b309eb6613"}, - "plug_crypto": {:hex, :plug_crypto, "1.2.5", "918772575e48e81e455818229bf719d4ab4181fcbf7f85b68a35620f78d89ced", [:mix], [], "hexpm", "26549a1d6345e2172eb1c233866756ae44a9609bd33ee6f99147ab3fd87fd842"}, - "postgrex": {:hex, :postgrex, "0.17.1", "01c29fd1205940ee55f7addb8f1dc25618ca63a8817e56fac4f6846fc2cddcbe", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "14b057b488e73be2beee508fb1955d8db90d6485c6466428fe9ccf1d6692a555"}, + "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, + "jumper": {:hex, :jumper, "1.0.2", "68cdcd84472a00ac596b4e6459a41b3062d4427cbd4f1e8c8793c5b54f1406a7", [:mix], [], "hexpm", "9b7782409021e01ab3c08270e26f36eb62976a38c1aa64b2eaf6348422f165e1"}, + "mime": {:hex, :mime, "2.0.6", "8f18486773d9b15f95f4f4f1e39b710045fa1de891fada4516559967276e4dc2", [:mix], [], "hexpm", "c9945363a6b26d747389aac3643f8e0e09d30499a138ad64fe8fd1d13d9b153e"}, + "phoenix_html": {:hex, :phoenix_html, "4.1.1", "4c064fd3873d12ebb1388425a8f2a19348cef56e7289e1998e2d2fa758aa982e", [:mix], [], "hexpm", "f2f2df5a72bc9a2f510b21497fd7d2b86d932ec0598f0210fed4114adc546c6f"}, + "plug": {:hex, :plug, "1.16.1", "40c74619c12f82736d2214557dedec2e9762029b2438d6d175c5074c933edc9d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a13ff6b9006b03d7e33874945b2755253841b238c34071ed85b0e86057f8cddc"}, + "plug_cowboy": {:hex, :plug_cowboy, "2.7.1", "87677ffe3b765bc96a89be7960f81703223fe2e21efa42c125fcd0127dd9d6b2", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "02dbd5f9ab571b864ae39418db7811618506256f6d13b4a45037e5fe78dc5de3"}, + "plug_crypto": {:hex, :plug_crypto, "2.1.0", "f44309c2b06d249c27c8d3f65cfe08158ade08418cf540fd4f72d4d6863abb7b", [:mix], [], "hexpm", "131216a4b030b8f8ce0f26038bc4421ae60e4bb95c5cf5395e1421437824c4fa"}, + "postgrex": {:hex, :postgrex, "0.19.0", "f7d50e50cb42e0a185f5b9a6095125a9ab7e4abccfbe2ab820ab9aa92b71dbab", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "dba2d2a0a8637defbf2307e8629cb2526388ba7348f67d04ec77a5d6a72ecfae"}, "ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"}, - "sleeplocks": {:hex, :sleeplocks, "1.1.2", "d45aa1c5513da48c888715e3381211c859af34bee9b8290490e10c90bb6ff0ca", [:rebar3], [], "hexpm", "9fe5d048c5b781d6305c1a3a0f40bb3dfc06f49bf40571f3d2d0c57eaa7f59a5"}, + "sleeplocks": {:hex, :sleeplocks, "1.1.3", "96a86460cc33b435c7310dbd27ec82ca2c1f24ae38e34f8edde97f756503441a", [:rebar3], [], "hexpm", "d3b3958552e6eb16f463921e70ae7c767519ef8f5be46d7696cc1ed649421321"}, "telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"}, - "ucol": {:hex, :ucol, "2.0.0", "64f9589d682dac6ca59252e1222e22697784f74addd0b88c5e34d53d267356bb", [:rebar3], [], "hexpm", "b544b88ce034d1d1ab58e093744cbded9a1e8b05006870b4d3865d6cd5066a21"}, - "unsafe": {:hex, :unsafe, "1.0.1", "a27e1874f72ee49312e0a9ec2e0b27924214a05e3ddac90e91727bc76f8613d8", [:mix], [], "hexpm", "6c7729a2d214806450d29766abc2afaa7a2cbecf415be64f36a6691afebb50e5"}, + "unsafe": {:hex, :unsafe, "1.0.2", "23c6be12f6c1605364801f4b47007c0c159497d0446ad378b5cf05f1855c0581", [:mix], [], "hexpm", "b485231683c3ab01a9cd44cb4a79f152c6f3bb87358439c6f68791b85c2df675"}, } diff --git a/frameworks/Erlang/cowboy/benchmark_config.json b/frameworks/Erlang/cowboy/benchmark_config.json index 324b087d481..7c37a4a6864 100644 --- a/frameworks/Erlang/cowboy/benchmark_config.json +++ b/frameworks/Erlang/cowboy/benchmark_config.json @@ -20,6 +20,7 @@ "database_os": "Linux", "display_name": "Cowboy", "notes": "", + "tags": ["broken"], "versus": "" }}] } diff --git a/frameworks/Erlang/elli/benchmark_config.json b/frameworks/Erlang/elli/benchmark_config.json index 2910a94924c..ce58700f3e1 100644 --- a/frameworks/Erlang/elli/benchmark_config.json +++ b/frameworks/Erlang/elli/benchmark_config.json @@ -19,6 +19,7 @@ "database_os": "Linux", "display_name": "elli", "notes": "", + "tags": ["broken"], "versus": "" }}] } diff --git a/frameworks/Erlang/mochiweb/benchmark_config.json b/frameworks/Erlang/mochiweb/benchmark_config.json index 57f8dcbf8a8..e45bfbf83e7 100644 --- a/frameworks/Erlang/mochiweb/benchmark_config.json +++ b/frameworks/Erlang/mochiweb/benchmark_config.json @@ -21,6 +21,7 @@ "database_os": "Linux", "display_name": "mochiweb", "notes": "", + "tags": ["broken"], "versus": "" }}] } diff --git a/frameworks/FSharp/falco/README.md b/frameworks/FSharp/falco/README.md index 3b954590d09..6c534e885d0 100644 --- a/frameworks/FSharp/falco/README.md +++ b/frameworks/FSharp/falco/README.md @@ -1,11 +1,12 @@ # Falco Tests on Linux + This includes tests for plaintext, json, and fortunes HTML serialization. ## Infrastructure Software Versions **Language** -* F# 6.0 +* F# 6.0 (or greater) **Platforms** @@ -18,11 +19,10 @@ This includes tests for plaintext, json, and fortunes HTML serialization. **Web Stack** * [Falco](https://github.com/pimbrouwers/Falco) -* [Donald](https://github.com/pimbrouwers/Donald) * ASP.NET Core ## Paths & Source for Tests -* [Plaintext](src/App/Value.fs): "/plaintext" -* [JSON serialization](src/App/Value.fs): "/json" -* [Fortunes using Donald](src/App/Fortune.fs): "/fortunes" +* [Plaintext](src/App/Program.fs): "/plaintext" +* [JSON serialization](src/App/Program.fs): "/json" +* [Fortunes using Donald](src/App/Program.fs): "/fortunes" diff --git a/frameworks/FSharp/falco/benchmark_config.json b/frameworks/FSharp/falco/benchmark_config.json index 8e77080c1a5..230dbdc8864 100644 --- a/frameworks/FSharp/falco/benchmark_config.json +++ b/frameworks/FSharp/falco/benchmark_config.json @@ -18,7 +18,7 @@ "webserver": "Kestrel", "os": "Linux", "database_os": "Linux", - "display_name": "Falco, Donald", + "display_name": "Falco", "notes": "", "versus": "aspcore" } diff --git a/frameworks/FSharp/falco/falco.dockerfile b/frameworks/FSharp/falco/falco.dockerfile index b0c2d9ec661..54e170d82f9 100644 --- a/frameworks/FSharp/falco/falco.dockerfile +++ b/frameworks/FSharp/falco/falco.dockerfile @@ -1,12 +1,12 @@ -FROM mcr.microsoft.com/dotnet/sdk:7.0.100 AS build +FROM mcr.microsoft.com/dotnet/sdk:9.0.100 AS build WORKDIR /app COPY src/App . RUN dotnet publish -c Release -o out -FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS runtime +FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS runtime # Full PGO -ENV DOTNET_TieredPGO 1 -ENV DOTNET_TC_QuickJitForLoops 1 +ENV DOTNET_TieredPGO 1 +ENV DOTNET_TC_QuickJitForLoops 1 ENV DOTNET_ReadyToRun 0 ENV ASPNETCORE_URLS http://+:8080 diff --git a/frameworks/FSharp/falco/src/App/App.fsproj b/frameworks/FSharp/falco/src/App/App.fsproj index 00e8bf8f22c..6c7dcff0aba 100644 --- a/frameworks/FSharp/falco/src/App/App.fsproj +++ b/frameworks/FSharp/falco/src/App/App.fsproj @@ -1,7 +1,7 @@  - net7.0 + net9.0 portable App Exe @@ -11,17 +11,13 @@ - - - - - - - + + + diff --git a/frameworks/FSharp/falco/src/App/Fortune.fs b/frameworks/FSharp/falco/src/App/Fortune.fs deleted file mode 100644 index 080a4c0a2b4..00000000000 --- a/frameworks/FSharp/falco/src/App/Fortune.fs +++ /dev/null @@ -1,83 +0,0 @@ -module App.Fortune - -open System.Data -open System.Threading.Tasks -open Donald -open Falco - -type FortuneModel = - { - id : int - message : string - } - -module FortuneModel = - let fromDataReader (rd : IDataReader) = - { - id = rd.GetInt32("id") - message = rd.GetString("message") - } - -module Service = - module ListQuery = - type LoadFortunes = unit -> Task - - let extraFortune = - { - id = 0 - message = "Additional fortune added at request time." - } - - let handle - (loadFortunes : LoadFortunes) = - fun () -> - task { - let! fortunes = loadFortunes () - - return - extraFortune - :: fortunes - |> List.sortBy (fun f -> f.message) - } - - -module Db = - let selectAsync (connection : IDbConnection) : Task = - queryAsync - "SELECT id, message FROM fortune" - [] - FortuneModel.fromDataReader - connection - -module View = - open Falco.Markup - - let index (fortunes : FortuneModel list) = - UI.layout "Fortunes" [ - Elem.table [] [ - yield Elem.tr [] [ - Elem.th [] [ Text.raw "id" ] - Elem.th [] [ Text.raw "message" ] - ] - for fortune in fortunes -> - Elem.tr [] [ - Elem.td [] [ Text.raw (string fortune.id) ] - Elem.td [] [ Text.enc fortune.message] - ] - ] - ] - -let handleIndex : HttpHandler = - fun ctx -> - task { - let connFactory = ctx.GetService() - use conn = createConn connFactory - let selectFortunes = fun () -> Db.selectAsync conn - let! fortunes = () |> Service.ListQuery.handle selectFortunes - - return! - ctx - |> (fortunes - |> View.index - |> Response.ofHtml) - } :> Task diff --git a/frameworks/FSharp/falco/src/App/Program.fs b/frameworks/FSharp/falco/src/App/Program.fs index e91b068ad7e..7d6f19e5584 100644 --- a/frameworks/FSharp/falco/src/App/Program.fs +++ b/frameworks/FSharp/falco/src/App/Program.fs @@ -1,7 +1,13 @@ module Program +open System.Data +open Dapper open Falco -open App +open Falco.Markup +open Falco.Routing +open Microsoft.AspNetCore.Builder +open Microsoft.Extensions.Logging +open Npgsql [] let connectionString = "Server=tfb-database;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;SSL Mode=Disable;Maximum Pool Size=1024;NoResetOnClose=true;Enlist=false;Max Auto Prepare=4;Multiplexing=true;Write Coalescing Buffer Threshold Bytes=1000" @@ -9,16 +15,63 @@ let connectionString = "Server=tfb-database;Database=hello_world;User Id=benchma [] let defaultMsg = "Hello, World!" -type JsonModel = { message : string } +type JsonResponse = + { message : string } + +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) + + let sortedFortunes = + fortunes + |> Seq.sortBy (fun f -> f.message) + + let html = + Elem.html [] [ + Elem.head [] [ + Elem.title [] [ Text.raw "Fortunes" ] + ] + Elem.body [] [ + Elem.table [] [ + yield Elem.tr [] [ + Elem.th [] [ Text.raw "id" ] + Elem.th [] [ Text.raw "message" ] + ] + for fortune in sortedFortunes -> + Elem.tr [] [ + Elem.td [] [ Text.raw (string fortune.id) ] + Elem.td [] [ Text.enc fortune.message] + ] + ] + ] + ] + + return Response.ofHtml html ctx +} [] -let main args = - Host.startWebHost - args - (Server.configure connectionString) - [ - get "/plaintext" (Response.ofPlainText defaultMsg) - get "/json" (Response.ofJson { message = defaultMsg }) - get "/fortunes" Fortune.handleIndex - ] +let main args = + let bldr = WebApplication.CreateBuilder(args) + bldr.Logging.ClearProviders() |> ignore + + let wapp = bldr.Build() + + wapp.UseRouting() + .UseFalco([ + get "/plaintext" (Response.ofPlainText defaultMsg) + get "/json" (Response.ofJson { message = defaultMsg }) + get "/fortunes" (handleFortunes connectionString) + ]) + .Run() 0 \ No newline at end of file diff --git a/frameworks/FSharp/falco/src/App/Server.fs b/frameworks/FSharp/falco/src/App/Server.fs deleted file mode 100644 index dd4125b2230..00000000000 --- a/frameworks/FSharp/falco/src/App/Server.fs +++ /dev/null @@ -1,47 +0,0 @@ -module App.Server - -open System.Data -open Donald -open Falco -open Falco.Host -open Microsoft.AspNetCore.Builder -open Microsoft.AspNetCore.Hosting -open Microsoft.Extensions.DependencyInjection -open Microsoft.Extensions.Logging -open Npgsql - -type ConnectionString = string -type ConfigureLogging = ILoggingBuilder -> unit -type ConfigureServices = DbConnectionFactory -> IServiceCollection -> unit -type ConfigureApp = HttpEndpoint list -> IApplicationBuilder -> unit -type ConfigureServer = ConnectionString -> ConfigureWebHost - -let configure : ConfigureServer = - let configureLogging : ConfigureLogging = - fun log -> - log.ClearProviders() - |> ignore - - let configureServices : ConfigureServices = - fun connectionFactory services -> - services - .AddRouting() - .AddSingleton(connectionFactory) - |> ignore - - let configure : ConfigureApp = - fun endpoints app -> - app.UseRouting() - .UseHttpEndPoints(endpoints) - |> ignore - - fun connectionString endpoints webHost -> - let connectionFactory = - fun () -> new NpgsqlConnection(connectionString) :> IDbConnection - - webHost - .UseKestrel() - .ConfigureLogging(configureLogging) - .ConfigureServices(configureServices connectionFactory) - .Configure(configure endpoints) - |> ignore \ No newline at end of file diff --git a/frameworks/FSharp/falco/src/App/UI.fs b/frameworks/FSharp/falco/src/App/UI.fs deleted file mode 100644 index aa3a4bc85da..00000000000 --- a/frameworks/FSharp/falco/src/App/UI.fs +++ /dev/null @@ -1,11 +0,0 @@ -module App.UI - -open Falco.Markup - -let layout pageTitle content = - Elem.html [] [ - Elem.head [] [ - Elem.title [] [ Text.raw pageTitle ] - ] - Elem.body [] content - ] \ No newline at end of file diff --git a/frameworks/FSharp/frank/src/App/App.fsproj b/frameworks/FSharp/frank/src/App/App.fsproj index ac861c86488..6d5658a653d 100644 --- a/frameworks/FSharp/frank/src/App/App.fsproj +++ b/frameworks/FSharp/frank/src/App/App.fsproj @@ -16,7 +16,7 @@ - + diff --git a/frameworks/FSharp/giraffe/.editorconfig b/frameworks/FSharp/giraffe/.editorconfig new file mode 100644 index 00000000000..e0f001d4808 --- /dev/null +++ b/frameworks/FSharp/giraffe/.editorconfig @@ -0,0 +1,17 @@ +root = true + +[*.{fs,fsi,fsx}] +indent_size = 4 +indent_style = space +max_line_length = 90 +fsharp_space_before_uppercase_invocation = true +fsharp_space_before_member = true +fsharp_space_before_colon = false +fsharp_space_before_semicolon = false +fsharp_multiline_bracket_style = stroustrup +fsharp_newline_between_type_definition_and_members = true +fsharp_align_function_signature_to_indentation = true +fsharp_alternative_long_member_definitions = true +fsharp_multi_line_lambda_closing_newline = true +fsharp_experimental_keep_indent_in_branch = true +fsharp_bar_before_discriminated_union_declaration = true \ No newline at end of file diff --git a/frameworks/FSharp/giraffe/README.md b/frameworks/FSharp/giraffe/README.md index fa4751bbda2..99a2e8898fb 100644 --- a/frameworks/FSharp/giraffe/README.md +++ b/frameworks/FSharp/giraffe/README.md @@ -3,22 +3,22 @@ This application tests Giraffe in 3 modes: - Default: Using Giraffe's Endpoint Routing APIs with the `System.Text.Json` serializer -- Utf8Json: Testing the JSON endpoint with the `Utf8Json` serializer - Newtonsoft: Testing the JSON endpoint with the `NewtonsoftJson` serializer +- FSharpFriendly: Testing the JSON endpoint with the `FSharp.SystemTextJson` serializer ## Infrastructure Software Versions **Language** -* F# 8.0 +* F# 9.0 **Platforms** -* .NET 6 (Windows and Linux) +* .NET 9 (Windows and Linux) **Web Servers** -* [Kestrel](https://github.com/aspnet/KestrelHttpServer) +* [Kestrel](https://github.com/dotnet/aspnetcore/tree/main/src/Servers/Kestrel) **Web Stack** @@ -27,9 +27,8 @@ This application tests Giraffe in 3 modes: ## Paths & Source for Tests -All source code is inside `Program.fs`. - App listens for a single command line argument to pick the desired JSON implementation: - - `system`: `System.Text.Json` - - `newtonsoft`: `Newtonsoft.Json` +- `system`: `System.Text.Json` +- `newtonsoft`: `Newtonsoft.Json` +- `fsharpfriendly`: `FSharp.SystemTextJson` diff --git a/frameworks/FSharp/giraffe/benchmark_config.json b/frameworks/FSharp/giraffe/benchmark_config.json index 4384822a751..cc2e70a748f 100644 --- a/frameworks/FSharp/giraffe/benchmark_config.json +++ b/frameworks/FSharp/giraffe/benchmark_config.json @@ -5,6 +5,9 @@ "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", @@ -39,6 +42,46 @@ "display_name": "Giraffe, NewtonsoftJson", "notes": "", "versus": "aspcore" + }, + "fsharp-systemtextjson": { + "json_url": "/json", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "None", + "framework": "Giraffe", + "language": "F#", + "orm": "Raw", + "platform": ".NET", + "flavor": "CoreCLR", + "webserver": "Kestrel", + "os": "Linux", + "database_os": "Linux", + "display_name": "Giraffe, FSharp.SystemTextJson", + "notes": "", + "versus": "aspcore" + }, + "chiseled": { + "plaintext_url": "/plaintext", + "json_url": "/json", + "db_url": "/db", + "query_url": "/queries?queries=", + "fortune_url": "/fortunes", + "port": 8080, + "approach": "Realistic", + "classification": "fullstack", + "database": "Postgres", + "framework": "giraffe", + "language": "F#", + "orm": "micro", + "platform": ".NET", + "flavor": "CoreCLR", + "webserver": "Kestrel", + "os": "Linux", + "database_os": "Linux", + "display_name": "Giraffe Chiseled, Default with Dapper", + "notes": "", + "versus": "aspcore" } } ] diff --git a/frameworks/FSharp/giraffe/config.toml b/frameworks/FSharp/giraffe/config.toml index 15122b9ddba..ada171349cb 100644 --- a/frameworks/FSharp/giraffe/config.toml +++ b/frameworks/FSharp/giraffe/config.toml @@ -2,9 +2,12 @@ name = "giraffe" [main] -urls.plaintext = "/plaintext" urls.json = "/json" +urls.db = "/db" +urls.query = "/queries?queries=" urls.fortune = "/fortunes" +urls.update = "/updates?queries=" +urls.plaintext = "/plaintext" approach = "Realistic" classification = "fullstack" database = "Postgres" @@ -26,3 +29,31 @@ orm = "Raw" platform = ".NET" webserver = "Kestrel" versus = "aspcore" + +[fsharp-systemtextjson] +urls.json = "/json" +approach = "Realistic" +classification = "Micro" +database = "None" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = ".NET" +webserver = "Kestrel" +versus = "aspcore" + +[chiseled] +urls.plaintext = "/plaintext" +urls.json = "/json" +urls.db = "/db" +urls.query = "/queries?queries=" +urls.fortune = "/fortunes" +approach = "Realistic" +classification = "fullstack" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "micro" +platform = ".NET" +webserver = "Kestrel" +versus = "aspcore" \ No newline at end of file diff --git a/frameworks/FSharp/giraffe/giraffe-chiseled.dockerfile b/frameworks/FSharp/giraffe/giraffe-chiseled.dockerfile new file mode 100644 index 00000000000..490513ee85c --- /dev/null +++ b/frameworks/FSharp/giraffe/giraffe-chiseled.dockerfile @@ -0,0 +1,19 @@ +FROM mcr.microsoft.com/dotnet/sdk:9.0.306 AS build +WORKDIR /app +COPY src/App . +RUN dotnet publish -c Release -o out + +FROM mcr.microsoft.com/dotnet/aspnet:9.0-noble-chiseled AS runtime +ENV ASPNETCORE_URLS http://+:8080 + +# Full PGO +ENV DOTNET_TieredPGO 1 +ENV DOTNET_TC_QuickJitForLoops 1 +ENV DOTNET_ReadyToRun 0 + +WORKDIR /app +COPY --from=build /app/out ./ + +EXPOSE 8080 + +ENTRYPOINT ["dotnet", "App.dll", "system"] diff --git a/frameworks/FSharp/giraffe/giraffe-fsharp-systemtextjson.dockerfile b/frameworks/FSharp/giraffe/giraffe-fsharp-systemtextjson.dockerfile new file mode 100644 index 00000000000..cf377fa97ce --- /dev/null +++ b/frameworks/FSharp/giraffe/giraffe-fsharp-systemtextjson.dockerfile @@ -0,0 +1,19 @@ +FROM mcr.microsoft.com/dotnet/sdk:9.0.306 AS build +WORKDIR /app +COPY src/App . +RUN dotnet publish -c Release -o out + +FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS runtime +ENV ASPNETCORE_URLS http://+:8080 + +# Full PGO +ENV DOTNET_TieredPGO 1 +ENV DOTNET_TC_QuickJitForLoops 1 +ENV DOTNET_ReadyToRun 0 + +WORKDIR /app +COPY --from=build /app/out ./ + +EXPOSE 8080 + +ENTRYPOINT ["dotnet", "App.dll", "fsharpfriendly"] diff --git a/frameworks/FSharp/giraffe/giraffe-newtonsoft.dockerfile b/frameworks/FSharp/giraffe/giraffe-newtonsoft.dockerfile index b22de354452..61cc3d1ec71 100644 --- a/frameworks/FSharp/giraffe/giraffe-newtonsoft.dockerfile +++ b/frameworks/FSharp/giraffe/giraffe-newtonsoft.dockerfile @@ -1,9 +1,9 @@ -FROM mcr.microsoft.com/dotnet/sdk:8.0.100 AS build +FROM mcr.microsoft.com/dotnet/sdk:9.0.306 AS build WORKDIR /app COPY src/App . RUN dotnet publish -c Release -o out -FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime +FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS runtime ENV ASPNETCORE_URLS http://+:8080 # Full PGO diff --git a/frameworks/FSharp/giraffe/giraffe.dockerfile b/frameworks/FSharp/giraffe/giraffe.dockerfile index b63044e65c2..6ae0606f20b 100644 --- a/frameworks/FSharp/giraffe/giraffe.dockerfile +++ b/frameworks/FSharp/giraffe/giraffe.dockerfile @@ -1,9 +1,9 @@ -FROM mcr.microsoft.com/dotnet/sdk:8.0.100 AS build +FROM mcr.microsoft.com/dotnet/sdk:9.0.306 AS build WORKDIR /app COPY src/App . RUN dotnet publish -c Release -o out -FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime +FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS runtime ENV ASPNETCORE_URLS http://+:8080 # Full PGO diff --git a/frameworks/FSharp/giraffe/src/App/App.fsproj b/frameworks/FSharp/giraffe/src/App/App.fsproj index bbdd52ee3af..ef58a0c3618 100644 --- a/frameworks/FSharp/giraffe/src/App/App.fsproj +++ b/frameworks/FSharp/giraffe/src/App/App.fsproj @@ -1,19 +1,21 @@ - - - - net8.0 - false - - - - - - - - - - - - - - + + + + net9.0 + false + + + + + + + + + + + + + + + + diff --git a/frameworks/FSharp/giraffe/src/App/Newtonsoft.fs b/frameworks/FSharp/giraffe/src/App/Newtonsoft.fs new file mode 100644 index 00000000000..6090323e37b --- /dev/null +++ b/frameworks/FSharp/giraffe/src/App/Newtonsoft.fs @@ -0,0 +1,60 @@ +module NewtonsoftJson + +open System.IO +open System.Text +open System.Threading.Tasks +open Microsoft.IO +open Newtonsoft.Json +open Newtonsoft.Json.Serialization +open Giraffe + +type Serializer + (settings: JsonSerializerSettings, rmsManager: RecyclableMemoryStreamManager) + = + let serializer = JsonSerializer.Create settings + let utf8EncodingWithoutBom = UTF8Encoding (false) + + static member DefaultSettings = + JsonSerializerSettings ( + ContractResolver = CamelCasePropertyNamesContractResolver () + ) + + interface Json.ISerializer with + member __.SerializeToString (x: 'T) = + JsonConvert.SerializeObject (x, settings) + + member __.SerializeToBytes (x: 'T) = + JsonConvert.SerializeObject (x, settings) |> Encoding.UTF8.GetBytes + + member __.SerializeToStreamAsync (x: 'T) (stream: Stream) = + task { + use memoryStream = + rmsManager.GetStream ("giraffe-json-serialize-to-stream") + + use streamWriter = new StreamWriter (memoryStream, utf8EncodingWithoutBom) + + use jsonTextWriter = new JsonTextWriter (streamWriter) + serializer.Serialize (jsonTextWriter, x) + jsonTextWriter.Flush () + memoryStream.Seek (0L, SeekOrigin.Begin) |> ignore + do! memoryStream.CopyToAsync (stream, 65536) + } + :> Task + + member __.Deserialize<'T> (json: string) = + JsonConvert.DeserializeObject<'T> (json, settings) + + member __.Deserialize<'T> (bytes: byte array) = + let json = Encoding.UTF8.GetString bytes + JsonConvert.DeserializeObject<'T> (json, settings) + + member __.DeserializeAsync<'T> (stream: Stream) = + task { + use memoryStream = rmsManager.GetStream ("giraffe-json-deserialize") + + do! stream.CopyToAsync (memoryStream) + memoryStream.Seek (0L, SeekOrigin.Begin) |> ignore + use streamReader = new StreamReader (memoryStream) + use jsonTextReader = new JsonTextReader (streamReader) + return serializer.Deserialize<'T> (jsonTextReader) + } diff --git a/frameworks/FSharp/giraffe/src/App/Program.fs b/frameworks/FSharp/giraffe/src/App/Program.fs index ce8514699cd..f7d62db7d33 100644 --- a/frameworks/FSharp/giraffe/src/App/Program.fs +++ b/frameworks/FSharp/giraffe/src/App/Program.fs @@ -1,144 +1,321 @@ -namespace App - -[] -module Common = - open System - open System.Collections.Generic - - [] - type Fortune = - { - id : int - message : string - } - - [] - let ConnectionString = "Server=tfb-database;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;SSL Mode=Disable;Maximum Pool Size=1024;NoResetOnClose=true;Enlist=false;Max Auto Prepare=4;Multiplexing=true;Write Coalescing Buffer Threshold Bytes=1000" - - type JsonMode = - | System - | Newtonsoft - - let FortuneComparer = - { - new IComparer with - member __.Compare (a, b) = - String.CompareOrdinal(a.message, b.message) - } - -[] -module HtmlViews = - open Giraffe.ViewEngine - - let private fortunesHead = - head [] [ - title [] [ rawText "Fortunes" ] - ] - - let private layout (content: XmlNode list) = - html [] [ - fortunesHead - body [] content - ] - - let private fortunesTableHeader = - tr [] [ - th [] [ rawText "id" ] - th [] [ rawText "message" ] - ] - - let fortunes (fortunes: Fortune seq) = - [ - table [] [ - yield fortunesTableHeader - for f in fortunes -> - tr [] [ - td [] [ rawText <| string f.id ] - td [] [ encodedText <| f.message ] - ] - ] - ] |> layout - -[] -module HttpHandlers = - open Giraffe - open Giraffe.EndpointRouting - open Giraffe.ViewEngine - open Dapper - open Npgsql - - let private extra = - { - id = 0 - message = "Additional fortune added at request time." - } - - let private fortunes : HttpHandler = - fun _ ctx -> - task { - use conn = new NpgsqlConnection(ConnectionString) - let! data = conn.QueryAsync("SELECT id, message FROM fortune") - - let view = - let xs = data.AsList() - xs.Add extra - xs.Sort FortuneComparer - HtmlViews.fortunes xs - - let bytes = RenderView.AsBytes.htmlDocument view - - ctx.SetContentType "text/html;charset=utf-8" - return! ctx.WriteBytesAsync bytes - } - - let endpoints : Endpoint list = - [ - route "/plaintext" (text "Hello, World!") - route "/json" (json {| message = "Hello, World!" |}) - route "/fortunes" fortunes - ] - - -module Main = - open Microsoft.AspNetCore.Builder - open Microsoft.AspNetCore.Hosting - open Microsoft.Extensions.DependencyInjection - open Giraffe - open Giraffe.EndpointRouting - open Microsoft.Extensions.Hosting - open Microsoft.Extensions.Logging - - [] - let main args = - let jsonMode = - match args with - | [| "newtonsoft" |] -> Newtonsoft - | _ -> System - - printfn $"Running with %A{jsonMode} JSON serializer" - - let jsonSerializer = - match jsonMode with - | System -> - SystemTextJson.Serializer(SystemTextJson.Serializer.DefaultOptions) - :> Json.ISerializer - | Newtonsoft -> - NewtonsoftJson.Serializer(NewtonsoftJson.Serializer.DefaultSettings) - :> Json.ISerializer - - let builder = WebApplication.CreateBuilder(args) - - builder.Services - .AddSingleton(jsonSerializer) - .AddGiraffe() |> ignore - - builder.Logging.ClearProviders() |> ignore - - let app = builder.Build() - - app.UseRouting() - .UseGiraffe HttpHandlers.endpoints |> ignore - - app.Run() - - 0 \ No newline at end of file +namespace App + +[] +module Common = + open System + open System.Collections.Generic + + [] + type Fortune = { id: int; message: string } + + [] + type World = { id: int; randomNumber: int } + + [] + let ConnectionString = + """ + Server=tfb-database; + Database=hello_world; + User Id=benchmarkdbuser; + Password=benchmarkdbpass; + Maximum Pool Size=1024; + NoResetOnClose=true; + Enlist=false; + Max Auto Prepare=4 + """ + + [] + let MultiplexedConnectionString = ConnectionString + ";Multiplexing=true" + + [] + type JsonMode = + | System + | Newtonsoft + | FSharpFriendly + + let FortuneComparer = + { new IComparer with + member __.Compare (a, b) = + String.CompareOrdinal (a.message, b.message) + } + + type RandomUtil() = + let rnd = System.Random () + let min = 1 + let max = 10_000 + + member _.Next () = rnd.Next (min, max) + + // Cache SQL strings for bulk updates to avoid rebuilding on every request + // This module generates and caches SQL UPDATE statements that use PostgreSQL's + // VALUES clause to update multiple rows in a single statement. + module BatchUpdateSql = + let private cache = Array.zeroCreate 501 + + let get (count: int) = + match cache.[count] with + | null -> + let lastIndex = count - 1 + + // Build the VALUES clause: (@Id_0, @Rn_0), (@Id_1, @Rn_1), ... + // Each pair represents (id, new_randomnumber) for one row + let valueClauses = + List.init lastIndex (fun i -> sprintf "(@Id_%d, @Rn_%d), " i i) + |> String.concat "" + + // The final SQL uses a CTE-like VALUES construct to update multiple rows: + // UPDATE world SET randomnumber = temp.randomnumber + // FROM (VALUES ...) AS temp(id, randomnumber) + // WHERE temp.id = world.id + let sql = + sprintf + """ + UPDATE world + SET randomnumber = temp.randomnumber + FROM (VALUES %s(@Id_%d, @Rn_%d) ORDER BY 1) + AS temp(id, randomnumber) + WHERE temp.id = world.id + """ + valueClauses + lastIndex + lastIndex + + cache.[count] <- sql + sql + | sql -> sql + +[] +module HtmlViews = + open Giraffe.ViewEngine + + let private fortunesHead = head [] [ title [] [ rawText "Fortunes" ] ] + + let private layout (content: XmlNode list) = + html [] [ fortunesHead; body [] content ] + + let private fortunesTableHeader = + tr [] [ th [] [ rawText "id" ]; th [] [ rawText "message" ] ] + + let fortunes (fortunes: Fortune seq) = + [ + table [] [ + yield fortunesTableHeader + for f in fortunes -> + tr [] [ + td [] [ rawText <| string f.id ] + td [] [ encodedText <| f.message ] + ] + ] + ] + |> layout + +[] +module HttpHandlers = + open Giraffe + open Giraffe.EndpointRouting + open Giraffe.ViewEngine + open Dapper + open Npgsql + + let private extra = { + id = 0 + message = "Additional fortune added at request time." + } + + let fortunes: HttpHandler = + fun _ ctx -> + task { + let dataSource = ctx.GetService () + use conn = dataSource.CreateConnection () + do! conn.OpenAsync () + + let! data = conn.QueryAsync ("SELECT id, message FROM fortune") + + let view = + let xs = data.AsList () + xs.Add extra + xs.Sort FortuneComparer + HtmlViews.fortunes xs + + let bytes = RenderView.AsBytes.htmlDocument view + + ctx.SetContentType "text/html;charset=utf-8" + return! ctx.WriteBytesAsync bytes + } + + let db: HttpHandler = + fun _ ctx -> + task { + let rnd = ctx.GetService () + let dataSource = ctx.GetService () + use conn = dataSource.CreateConnection () + do! conn.OpenAsync () + + let! data = + conn.QuerySingleAsync ( + "SELECT id, randomnumber FROM world WHERE id = @Id", + {| Id = rnd.Next () |} + ) + + return! ctx.WriteJsonAsync data + } + + let queries: HttpHandler = + fun _ ctx -> + task { + let queryParam = + ctx.TryGetQueryStringValue "queries" + |> Option.map (fun value -> + match System.Int32.TryParse value with + | true, intValue -> + if intValue < 1 then 1 + elif intValue > 500 then 500 + else intValue + | false, _ -> 1 + ) + |> Option.defaultValue 1 + + let rnd = ctx.GetService () + let dataSource = ctx.GetService () + + use conn = dataSource.CreateConnection () + do! conn.OpenAsync () + + // Read all rows sequentially + let results = Array.zeroCreate queryParam + + for i in 0 .. queryParam - 1 do + let! world = + conn.QuerySingleAsync ( + "SELECT id, randomnumber FROM world WHERE id = @Id", + {| Id = rnd.Next () |} + ) + + results.[i] <- world + + return! ctx.WriteJsonAsync results + } + + let updates: HttpHandler = + fun _ ctx -> + task { + let queryParam = + ctx.TryGetQueryStringValue "queries" + |> Option.map (fun value -> + match System.Int32.TryParse value with + | true, intValue -> + if intValue < 1 then 1 + elif intValue > 500 then 500 + else intValue + | false, _ -> 1 + ) + |> Option.defaultValue 1 + + let rnd = ctx.GetService () + + // Use multiplexed connection for updates (more efficient for sequential ops) + use conn = new NpgsqlConnection (MultiplexedConnectionString) + do! conn.OpenAsync () + + // Read all rows sequentially + let readResults = Array.zeroCreate queryParam + + for i in 0 .. queryParam - 1 do + let! world = + conn.QuerySingleAsync ( + "SELECT id, randomnumber FROM world WHERE id = @Id", + {| Id = rnd.Next () |} + ) + + readResults.[i] <- world + + // Update random numbers functionally + let updatedData = + readResults + |> Array.map (fun data -> { data with randomNumber = rnd.Next () }) + + // Build bulk update parameters functionally + // We use a single UPDATE statement with a VALUES clause to update all rows at once. + // + // Example SQL for 2 rows: + // UPDATE world SET randomnumber = temp.randomnumber + // FROM (VALUES (@Id_0, @Rn_0), (@Id_1, @Rn_1) ORDER BY 1) AS temp(id, randomnumber) + // WHERE temp.id = world.id + let updateParams = + updatedData + |> Array.mapi (fun i data -> [ + sprintf "@Id_%d" i, box data.id // Parameter for the id + sprintf "@Rn_%d" i, box data.randomNumber // Parameter for the new random number + ]) + |> Array.collect List.toArray // Flatten the list of parameter pairs + |> dict // Convert to dictionary for Dapper + + // Execute bulk update using Dapper + let sql = BatchUpdateSql.get queryParam + let! _ = conn.ExecuteAsync (sql, updateParams) + + return! ctx.WriteJsonAsync updatedData + } + + let endpoints: Endpoint list = [ + route "/json" (json {| message = "Hello, World!" |}) + route "/db" db + route "/queries" queries + route "/fortunes" fortunes + route "/updates" updates + route "/plaintext" (text "Hello, World!") + ] + + +module Main = + open Microsoft.AspNetCore.Builder + open Microsoft.Extensions.DependencyInjection + open Giraffe + open Giraffe.EndpointRouting + open Microsoft.Extensions.Hosting + open Microsoft.Extensions.Logging + open System.Text.Json + open Newtonsoft.Json + open Npgsql + + [] + let main args = + let jsonMode = + match args with + | [| "newtonsoft" |] -> Newtonsoft + | [| "fsharpfriendly" |] -> FSharpFriendly + | _ -> System + + printfn $"Running with %A{jsonMode} JSON serializer" + + let jsonSerializer = + match jsonMode with + | System -> Json.Serializer JsonSerializerOptions.Default :> Json.ISerializer + | Newtonsoft -> + NewtonsoftJson.Serializer ( + JsonSerializerSettings (), + Microsoft.IO.RecyclableMemoryStreamManager () + ) + :> Json.ISerializer + | FSharpFriendly -> Json.FsharpFriendlySerializer () :> Json.ISerializer + + let builder = WebApplication.CreateBuilder (args) + + let rnd = RandomUtil () + + builder.Services + .AddSingleton(jsonSerializer) + .AddSingleton(rnd) + .AddSingleton(NpgsqlDataSource.Create (ConnectionString)) + .AddGiraffe () + |> ignore + + builder.Logging.ClearProviders () |> ignore + + let app = builder.Build () + + app.UseRouting().UseGiraffe HttpHandlers.endpoints |> ignore + + app.Run () + + 0 diff --git a/frameworks/FSharp/oxpecker/.gitignore b/frameworks/FSharp/oxpecker/.gitignore new file mode 100644 index 00000000000..2ad42ca00cf --- /dev/null +++ b/frameworks/FSharp/oxpecker/.gitignore @@ -0,0 +1,360 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*[.json, .xml, .info] + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd \ No newline at end of file diff --git a/frameworks/FSharp/oxpecker/README.md b/frameworks/FSharp/oxpecker/README.md new file mode 100644 index 00000000000..6ac388b2d50 --- /dev/null +++ b/frameworks/FSharp/oxpecker/README.md @@ -0,0 +1,23 @@ +# Oxpecker Tests on Linux +This includes tests for plaintext, json, fortunes, single query, mutliple queries and data updates. + +## Infrastructure Software Versions + +**Language** + +* F# 10.0 + +**Platforms** + +* .NET Core (Windows and Linux) + +**Web Servers** + +* [Kestrel](https://github.com/dotnet/aspnetcore/tree/main/src/Servers/Kestrel) + +**Web Stack** + +* [Oxpecker](https://github.com/Lanayx/Oxpecker) +* [Npgsql](https://github.com/npgsql/npgsql) +* [SpanJson](https://github.com/Tornhoof/SpanJson) +* ASP.NET Core \ No newline at end of file diff --git a/frameworks/FSharp/oxpecker/benchmark_config.json b/frameworks/FSharp/oxpecker/benchmark_config.json new file mode 100644 index 00000000000..562c9514420 --- /dev/null +++ b/frameworks/FSharp/oxpecker/benchmark_config.json @@ -0,0 +1,30 @@ +{ + "framework": "oxpecker", + "tests": [ + { + "default": { + "plaintext_url": "/plaintext", + "json_url": "/json", + "fortune_url": "/fortunes", + "db_url": "/db", + "query_url": "/queries/", + "update_url": "/updates/", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "Postgres", + "framework": "Oxpecker", + "language": "F#", + "orm": "Raw", + "platform": ".NET", + "flavor": "CoreCLR", + "webserver": "Kestrel", + "os": "Linux", + "database_os": "Linux", + "display_name": "Oxpecker", + "notes": "", + "versus": "aspnetcore" + } + } + ] +} diff --git a/frameworks/FSharp/oxpecker/config.toml b/frameworks/FSharp/oxpecker/config.toml new file mode 100644 index 00000000000..75e7f904754 --- /dev/null +++ b/frameworks/FSharp/oxpecker/config.toml @@ -0,0 +1,19 @@ +[framework] +name = "oxpecker" + +[main] +urls.plaintext = "/plaintext" +urls.json = "/json" +urls.fortune = "/fortunes" +urls.db = "/db" +urls.query = "/queries/" +urls.update = "/updates/" +approach = "Realistic" +classification = "fullstack" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = ".NET" +webserver = "Kestrel" +versus = "aspnetcore" \ No newline at end of file diff --git a/frameworks/FSharp/oxpecker/oxpecker.dockerfile b/frameworks/FSharp/oxpecker/oxpecker.dockerfile new file mode 100644 index 00000000000..480ed2e3dd8 --- /dev/null +++ b/frameworks/FSharp/oxpecker/oxpecker.dockerfile @@ -0,0 +1,20 @@ +FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build +WORKDIR /app +COPY src/App . +RUN dotnet publish -c Release -o out + +FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS runtime + +ENV DOTNET_GCDynamicAdaptationMode=0 +ENV DOTNET_ReadyToRun 0 +ENV DOTNET_HillClimbing_Disable=1 +ENV ASPNETCORE_hostBuilder__reloadConfigOnChange false + +ENV URLS http://+:8080 + +WORKDIR /app +COPY --from=build /app/out ./ + +EXPOSE 8080 + +ENTRYPOINT ["dotnet", "App.dll"] \ No newline at end of file diff --git a/frameworks/FSharp/oxpecker/src/App/App.fsproj b/frameworks/FSharp/oxpecker/src/App/App.fsproj new file mode 100644 index 00000000000..c19d5d614ac --- /dev/null +++ b/frameworks/FSharp/oxpecker/src/App/App.fsproj @@ -0,0 +1,22 @@ + + + + net10.0 + false + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/frameworks/FSharp/oxpecker/src/App/Common.fs b/frameworks/FSharp/oxpecker/src/App/Common.fs new file mode 100644 index 00000000000..d8b3e407d74 --- /dev/null +++ b/frameworks/FSharp/oxpecker/src/App/Common.fs @@ -0,0 +1,36 @@ +namespace App + +open System +open System.Collections.Generic + +[] +module Common = + + [] + [] + type JsonMessage = { + message: string + } + + [] + type Fortune = { + id: int + message: string + } + + [] + [] + type World = { + id: int + randomnumber: int + } + + [] + let ConnectionString = "Server=tfb-database;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;Maximum Pool Size=1024;NoResetOnClose=true;Enlist=false;Max Auto Prepare=4" + [] + let MultiplexedConnectionString = ConnectionString + ";Multiplexing=true" + + let FortuneComparer = { + new IComparer with + member self.Compare(a,b) = String.CompareOrdinal(a.message, b.message) + } diff --git a/frameworks/FSharp/oxpecker/src/App/Db.fs b/frameworks/FSharp/oxpecker/src/App/Db.fs new file mode 100644 index 00000000000..e4466dc08c8 --- /dev/null +++ b/frameworks/FSharp/oxpecker/src/App/Db.fs @@ -0,0 +1,116 @@ +namespace App + +open System +open System.Data +open Microsoft.Extensions.ObjectPool +open Npgsql + + +[] +module Db = + let loadFortunes () = + let result = ResizeArray() + task { + use db = new NpgsqlConnection(ConnectionString) + use cmd = db.CreateCommand(CommandText = "SELECT id, message FROM fortune") + do! db.OpenAsync() + use! rdr = cmd.ExecuteReaderAsync(CommandBehavior.CloseConnection) + while! rdr.ReadAsync() do + result.Add { id = rdr.GetInt32(0); message = rdr.GetString(1) } + return result + } + + let private createReadCommand (connection: NpgsqlConnection) = + let cmd = connection.CreateCommand( + CommandText = "SELECT id, randomnumber FROM world WHERE id = @Id" + ) + let id = NpgsqlParameter( + ParameterName = "@Id", + DbType = DbType.Int32, + TypedValue = Random.Shared.Next(1, 10001) + ) + cmd.Parameters.Add(id) |> ignore + struct(cmd, id) + + let private readSingleRow (cmd: NpgsqlCommand) = + task { + use! rdr = cmd.ExecuteReaderAsync(CommandBehavior.SingleRow) + let! _ = rdr.ReadAsync() + return { id = rdr.GetInt32(0); randomnumber = rdr.GetInt32(1) } + } + + let loadSingleRow () = + task { + use db = new NpgsqlConnection(ConnectionString) + let struct(cmd', _) = createReadCommand db + use cmd = cmd' + do! db.OpenAsync() + return! readSingleRow cmd + } + + let private readMultipleRows (count: int) (conn: NpgsqlConnection) = + let result = Array.zeroCreate count + task { + let struct(cmd', idParam) = createReadCommand conn + use cmd = cmd' + for i in 0..result.Length-1 do + let! row = readSingleRow cmd + result[i] <- row + idParam.TypedValue <- Random.Shared.Next(1, 10001) + return result + } + + let loadMultipleRows (count: int) = + task { + use db = new NpgsqlConnection(ConnectionString) + do! db.OpenAsync() + return! readMultipleRows count db + } + + let private maxBatch = 500 + let private queries = Array.zeroCreate (maxBatch + 1) + let private stringBuilderPool = DefaultObjectPoolProvider().CreateStringBuilderPool() + let private batchUpdateString batchSize = + match queries[batchSize] with + | null -> + let lastIndex = batchSize - 1 + let sb = stringBuilderPool.Get() + sb.Append("UPDATE world SET randomNumber = temp.randomNumber FROM (VALUES ") |> ignore + for i in 0..lastIndex-1 do + sb.AppendFormat("(@Id_{0}, @Rn_{0}), ", i) |> ignore + sb.AppendFormat("(@Id_{0}, @Rn_{0}) ORDER BY 1) AS temp(id, randomNumber) WHERE temp.id = world.id", lastIndex) |> ignore + let result = sb.ToString() + stringBuilderPool.Return(sb) + queries[batchSize] <- result + result + | q -> + q + + // fill cache + let _ = [| 0..maxBatch |] |> Array.map batchUpdateString + + let private paramNames = + seq { 0..maxBatch*2 } + |> Seq.map (fun i -> struct($"@Rn_{i}", $"@Id_{i}")) + |> Seq.toArray + + let private generateParameters (results: World[]) (command: NpgsqlCommand) = + for i in 0..results.Length-1 do + let randomNumber = Random.Shared.Next(1, 10001) + let struct(rnParamName, idParamName) = paramNames[i] + command.Parameters.Add(NpgsqlParameter( + ParameterName = rnParamName, DbType = DbType.Int32, TypedValue = randomNumber)) |> ignore + command.Parameters.Add(NpgsqlParameter( + ParameterName = idParamName, DbType = DbType.Int32, TypedValue = results[i].id)) |> ignore + results[i] <- { results[i] with randomnumber = randomNumber } + + let doMultipleUpdates (count: int) = + task { + use conn = new NpgsqlConnection(MultiplexedConnectionString) + do! conn.OpenAsync() + let! results = readMultipleRows count conn + use cmd = conn.CreateCommand(CommandText = batchUpdateString count) + do generateParameters results cmd + let! _ = cmd.ExecuteNonQueryAsync() + return results + } diff --git a/frameworks/FSharp/oxpecker/src/App/Program.fs b/frameworks/FSharp/oxpecker/src/App/Program.fs new file mode 100644 index 00000000000..ce301a87b89 --- /dev/null +++ b/frameworks/FSharp/oxpecker/src/App/Program.fs @@ -0,0 +1,121 @@ +namespace App + +open System +open Oxpecker + +[] +module HttpHandlers = + open System.Text + open Microsoft.AspNetCore.Http + open SpanJson + open Oxpecker.ViewEngine + + let private extra = + { + id = 0 + message = "Additional fortune added at request time." + } + + let private fortunesHeadAndTail = + (fun (content: HtmlElement) -> + html() { + head() { + title() { "Fortunes" } + } + body() { + table() { + tr() { + th() { "id" } + th() { "message" } + } + content + } + } + } :> HtmlElement + ) |> RenderHelpers.prerender + + let rec private renderFortunes (ctx: HttpContext) (data: ResizeArray) = + data.Add extra + data.Sort FortuneComparer + RenderHelpers.CombinedElement(fortunesHeadAndTail, data) + |> ctx.WriteHtmlViewChunked + + let fortunes : EndpointHandler = + fun ctx -> + task { + let! dbFortunes = loadFortunes () + return! renderFortunes ctx dbFortunes + } + + let singleQuery : EndpointHandler = + fun ctx -> + task { + let! result = loadSingleRow() + return! ctx.WriteJsonChunked result + } + + let private parseQueries (ctx: HttpContext) = + match ctx.TryGetRouteValue("count") with + | Some q -> + match Int32.TryParse q with + | true, q when q > 1 -> if q < 500 then q else 500 + | _, _ -> 1 + | _ -> 1 + + let multipleQueries : EndpointHandler = + fun ctx -> + let count = parseQueries ctx + task { + let! results = loadMultipleRows count + return! ctx.WriteJsonChunked results + } + + let multipleUpdates : EndpointHandler = + fun ctx -> + let count = parseQueries ctx + task { + let! results = doMultipleUpdates count + return! ctx.WriteJsonChunked results + } + + let utf8Const (s: string): EndpointHandler = + let result = s |> Encoding.UTF8.GetBytes + fun ctx -> + ctx.SetContentType("text/plain") + ctx.WriteBytes(result) + + let jsonSimple value : EndpointHandler = + fun ctx -> + ctx.SetContentType("application/json") + JsonSerializer.Generic.Utf8.SerializeAsync<_>(value, stream = ctx.Response.Body).AsTask() + + let endpoints = + [| + route "/plaintext" <| utf8Const "Hello, World!" + route "/json" <| jsonSimple { message = "Hello, World!" } + route "/fortunes" fortunes + route "/db" singleQuery + route "/queries/{count?}" multipleQueries + route "/updates/{count?}" multipleUpdates + |] + +module Main = + open Microsoft.AspNetCore.Builder + open Microsoft.Extensions.DependencyInjection + open Microsoft.Extensions.Hosting + open Microsoft.Extensions.Logging + + [] + let main args = + let builder = WebApplication.CreateBuilder(args) + builder.Services + .AddRouting() + .AddOxpecker() |> ignore + builder.Logging + .ClearProviders() |> ignore + let app = builder.Build() + app + .UseRouting() + .UseOxpecker(HttpHandlers.endpoints) |> ignore + app.Run() + 0 \ No newline at end of file diff --git a/frameworks/FSharp/oxpecker/src/App/RenderHelpers.fs b/frameworks/FSharp/oxpecker/src/App/RenderHelpers.fs new file mode 100644 index 00000000000..7a94b2552ba --- /dev/null +++ b/frameworks/FSharp/oxpecker/src/App/RenderHelpers.fs @@ -0,0 +1,35 @@ +module RenderHelpers + + open System.Text + open App + open Oxpecker.ViewEngine + + type HeadAndTail = + { + Head: string + Tail: string + } + + [] + type CombinedElement(ht: HeadAndTail, fortunesData: ResizeArray) = + interface HtmlElement with + member this.Render(sb) = + sb.Append(ht.Head) |> ignore + for fortune in fortunesData do + (tr() { + td() { raw <| string fortune.id } + td() { fortune.message } + }).Render(sb) + sb.Append(ht.Tail) |> ignore + + let prerender (view: HtmlElement -> HtmlElement) = + let sb = StringBuilder() + let mutable head = "" + let fakeHole = + { new HtmlElement with + member this.Render(sb) = + head <- sb.ToString() + sb.Clear() |> ignore } + let readyView = view fakeHole + readyView.Render(sb) + { Head = head; Tail = sb.ToString() } \ No newline at end of file diff --git a/frameworks/FSharp/zebra/src/App/App.fsproj b/frameworks/FSharp/zebra/src/App/App.fsproj index 87f9f551340..84fb27f39d0 100644 --- a/frameworks/FSharp/zebra/src/App/App.fsproj +++ b/frameworks/FSharp/zebra/src/App/App.fsproj @@ -9,10 +9,10 @@ - - + + - + diff --git a/frameworks/FSharp/zebra/zebra-simple.dockerfile b/frameworks/FSharp/zebra/zebra-simple.dockerfile index b02a6c8977f..b36a831dd89 100644 --- a/frameworks/FSharp/zebra/zebra-simple.dockerfile +++ b/frameworks/FSharp/zebra/zebra-simple.dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/dotnet/sdk:8.0.100 AS build +FROM mcr.microsoft.com/dotnet/sdk:8.0.204 AS build WORKDIR /app COPY src/App . RUN dotnet publish -c Release -o out diff --git a/frameworks/FSharp/zebra/zebra.dockerfile b/frameworks/FSharp/zebra/zebra.dockerfile index a43c8eb1c5c..42fd7f53ee9 100644 --- a/frameworks/FSharp/zebra/zebra.dockerfile +++ b/frameworks/FSharp/zebra/zebra.dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/dotnet/sdk:8.0.100 AS build +FROM mcr.microsoft.com/dotnet/sdk:8.0.204 AS build WORKDIR /app COPY src/App . RUN dotnet publish -c Release -o out diff --git a/frameworks/Go/aah/README.md b/frameworks/Go/aah/README.md deleted file mode 100644 index d154da40489..00000000000 --- a/frameworks/Go/aah/README.md +++ /dev/null @@ -1,26 +0,0 @@ -

- -

Benchmark Application

-

aah - A secure, flexible, rapid Go web framework

-

- -Visit official website https://aahframework.org to learn more about `aah` framework. - -### Test URLs - - * http://localhost:8080/json - * http://localhost:8080/plaintext - -### Test URLs - w/ MySQL Datasource - - * http://localhost:8080/db - * http://localhost:8080/db/queries?count=[1-500] - * http://localhost:8080/db/fortunes - * http://localhost:8080/db/updates?count=[1-500] - -### Test URLs - w/ PostgreSQL Datasource - - * http://localhost:8080/pg-db - * http://localhost:8080/pg-db/queries?count=[1-500] - * http://localhost:8080/pg-db/fortunes - * http://localhost:8080/pg-db/updates?count=[1-500] diff --git a/frameworks/Go/aah/aah-mysql.dockerfile b/frameworks/Go/aah/aah-mysql.dockerfile deleted file mode 100644 index 626642cecd8..00000000000 --- a/frameworks/Go/aah/aah-mysql.dockerfile +++ /dev/null @@ -1,22 +0,0 @@ -FROM golang:1.14 - -RUN apt-get update -yqq - -ADD ./ /aah -WORKDIR /aah - -ENV GOPATH /aah -ENV PATH ${GOPATH}/bin:${PATH} -ENV GO111MODULE on - -RUN curl -sL https://aahframework.org/install-cli | bash -s v0.13.3 - -WORKDIR /aah/src/benchmark - -RUN aah --version -RUN mkdir -p views/common -RUN aah build --single - -EXPOSE 8080 - -CMD build/bin/benchmark run --envprofile bm_mysql diff --git a/frameworks/Go/aah/aah-postgresql.dockerfile b/frameworks/Go/aah/aah-postgresql.dockerfile deleted file mode 100644 index 37e3f352549..00000000000 --- a/frameworks/Go/aah/aah-postgresql.dockerfile +++ /dev/null @@ -1,22 +0,0 @@ -FROM golang:1.14 - -RUN apt-get update -yqq - -ADD ./ /aah -WORKDIR /aah - -ENV GOPATH /aah -ENV PATH ${GOPATH}/bin:${PATH} -ENV GO111MODULE on - -RUN curl -sL https://aahframework.org/install-cli | bash -s v0.13.3 - -WORKDIR /aah/src/benchmark - -RUN aah --version -RUN mkdir -p views/common -RUN aah build --single - -EXPOSE 8080 - -CMD build/bin/benchmark run --envprofile bm_postgresql diff --git a/frameworks/Go/aah/aah.dockerfile b/frameworks/Go/aah/aah.dockerfile deleted file mode 100644 index 7d813662574..00000000000 --- a/frameworks/Go/aah/aah.dockerfile +++ /dev/null @@ -1,22 +0,0 @@ -FROM golang:1.14 - -RUN apt-get update -yqq - -ADD ./ /aah -WORKDIR /aah - -ENV GOPATH /aah -ENV PATH ${GOPATH}/bin:${PATH} -ENV GO111MODULE on - -RUN curl -sL https://aahframework.org/install-cli | bash -s v0.13.3 - -WORKDIR /aah/src/benchmark - -RUN aah --version -RUN mkdir -p views/common -RUN aah build --single - -EXPOSE 8080 - -CMD build/bin/benchmark run --envprofile bm_default diff --git a/frameworks/Go/aah/benchmark_config.json b/frameworks/Go/aah/benchmark_config.json deleted file mode 100644 index 1f3fef2ed34..00000000000 --- a/frameworks/Go/aah/benchmark_config.json +++ /dev/null @@ -1,73 +0,0 @@ -{ - "framework": "aah", - "tests": [{ - "default": { - "json_url": "/json", - "plaintext_url": "/plaintext", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "MySQL", - "framework": "aah", - "language": "Go", - "flavor": "None", - "orm": "Raw", - "platform": "None", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "aah", - "notes": "", - "versus": "go", - "tags": ["broken"] - }, - "mysql": { - "dockerfile": "aah.dockerfile", - "docker_cmd": "build/bin/benchmark run --envprofile bm_mysql", - "db_url": "/db", - "query_url": "/db/queries?count=", - "fortune_url": "/db/fortunes", - "update_url": "/db/updates?count=", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "MySQL", - "framework": "aah", - "language": "Go", - "flavor": "None", - "orm": "Raw", - "platform": "None", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "aah-mysql", - "notes": "", - "versus": "go", - "tags": ["broken"] - }, - "postgresql": { - "dockerfile": "aah.dockerfile", - "docker_cmd": "build/bin/benchmark run --envprofile bm_postgresql", - "db_url": "/pg-db", - "query_url": "/pg-db/queries?count=", - "fortune_url": "/pg-db/fortunes", - "update_url": "/pg-db/updates?count=", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "Postgres", - "framework": "aah", - "language": "Go", - "flavor": "None", - "orm": "Raw", - "platform": "None", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "aah-postgresql", - "notes": "", - "versus": "go", - "tags": ["broken"] - } - }] -} diff --git a/frameworks/Go/aah/config.toml b/frameworks/Go/aah/config.toml deleted file mode 100644 index 72075e170a8..00000000000 --- a/frameworks/Go/aah/config.toml +++ /dev/null @@ -1,47 +0,0 @@ -[framework] -name = "aah" - -[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" - -[postgresql] -urls.db = "/pg-db" -urls.query = "/pg-db/queries?count=" -urls.update = "/pg-db/updates?count=" -urls.fortune = "/pg-db/fortunes" -approach = "Realistic" -classification = "Fullstack" -database = "Postgres" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "None" -webserver = "None" -versus = "go" -dockerfile = "aah.dockerfile" - -[mysql] -urls.db = "/db" -urls.query = "/db/queries?count=" -urls.update = "/db/updates?count=" -urls.fortune = "/db/fortunes" -approach = "Realistic" -classification = "Fullstack" -database = "MySQL" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "None" -webserver = "None" -versus = "go" -dockerfile = "aah.dockerfile" diff --git a/frameworks/Go/aah/src/benchmark/aah.project b/frameworks/Go/aah/src/benchmark/aah.project deleted file mode 100644 index b204a8b7be2..00000000000 --- a/frameworks/Go/aah/src/benchmark/aah.project +++ /dev/null @@ -1,43 +0,0 @@ -######################################## -# benchmark - aah framework project -# -# Note: Add it to version control -######################################## - -# Build section is used during aah application compile and build command. -build { - # Application binary name - # Default value is `name` attribute value from `aah.conf` - #binary_name = "benchmark" - - # Used as fallback if - # - `git commit sha` or - # - `AAH_APP_VERSION` environment value is not available. - version = "0.0.1" - - # If application is missing any dependencies in `build import path` - # during a compile and build, aah CLI will try to get dependencies - # using 'go get '. - # Default value is `false`. - #dep_get = true - - # Log level is used for aah CLI tool logging. - # Default value is `info`. - #log_level = "info" - - flags = ["-i"] - - ldflags = "" - - tags = "" - - # AST excludes is used for `aah.Context` inspection and generating aah - # application main Go file. Valid exclude patterns - # refer: https://golang.org/pkg/path/filepath/#Match - ast_excludes = ["*_test.go", ".*", "*.bak", "*.tmp", "vendor"] - - # Packing excludes is used to exclude file/directory during aah application - # build archive. Valid exclude patterns - # refer: https://golang.org/pkg/path/filepath/#Match - excludes = ["*.go", "*_test.go", ".*", "*.bak", "*.tmp", "vendor", "app", "build", "tests", "logs"] -} diff --git a/frameworks/Go/aah/src/benchmark/app/controllers/app.go b/frameworks/Go/aah/src/benchmark/app/controllers/app.go deleted file mode 100644 index 307961eff1b..00000000000 --- a/frameworks/Go/aah/src/benchmark/app/controllers/app.go +++ /dev/null @@ -1,122 +0,0 @@ -package controllers - -import ( - "strconv" - - "benchmark/app/models" - - "aahframe.work" -) - -const helloWorldString = "Hello, World!" - -// AppController struct application controller -type AppController struct { - *aah.Context -} - -// Plaintext method is for `/plaintext` test. -func (c *AppController) Plaintext() { - c.Reply().Text(helloWorldString) -} - -// JSON method is for `/json` test. -func (c *AppController) JSON() { - c.Reply().JSON(models.Message{Message: helloWorldString}) -} - -//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ -// MySQL DB based implementation -//___________________________________________________________________________ - -// World returns one world record randomly for `/db` test. -func (c *AppController) World() { - world := new(models.World) - if err := models.MySQLFetchRandomWorld(world); err != nil { - c.Reply().InternalServerError().Text(err.Error()) - return - } - c.Reply().JSON(world) -} - -// Worlds returns one world record randomly for `/db/queries` test. -func (c *AppController) Worlds() { - c.handleResult(models.MySQLRandomWorlds(c.getCount())) -} - -// UpdateWorlds updates record and returns those records for `/db/updates` test. -func (c *AppController) UpdateWorlds() { - c.handleResult(models.MySQLUpdateRandomWorlds(c.getCount())) -} - -// Fortunes method is for `/db/fortunes` test. -func (c *AppController) Fortunes() { - fortunes, err := models.MySQLFortunes() - if err != nil { - c.Reply().InternalServerError().Text(err.Error()) - return - } - - c.Reply().HTML(aah.Data{ - "Fortunes": fortunes, - }) -} - -//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ -// PostgreSQL DB based implementation -//___________________________________________________________________________ - -// PGWorld returns one world record randomly for `/pg-db` test. -func (c *AppController) PGWorld() { - world := new(models.World) - if err := models.PGFetchRandomWorld(world); err != nil { - c.Reply().InternalServerError().Text(err.Error()) - return - } - c.Reply().JSON(world) -} - -// PGWorlds returns one world record randomly for `/pg-db/queries` test. -func (c *AppController) PGWorlds() { - c.handleResult(models.PGRandomWorlds(c.getCount())) -} - -// PGUpdateWorlds updates record and returns those records for `/pg-db/updates` test. -func (c *AppController) PGUpdateWorlds() { - c.handleResult(models.PGUpdateRandomWorlds(c.getCount())) -} - -// PGFortunes method is for `/pg-db/fortunes` test. -func (c *AppController) PGFortunes() { - fortunes, err := models.PGFortunes() - if err != nil { - c.Reply().InternalServerError().Text(err.Error()) - return - } - - c.Reply().HTMLf("fortunes.html", aah.Data{ - "Fortunes": fortunes, - }) -} - -//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ -// Unexported methods -//___________________________________________________________________________ - -func (c *AppController) getCount() int { - cnt, err := strconv.Atoi(c.Req.QueryValue("count")) - if err != nil || cnt < 1 { - cnt = 1 - } else if cnt > 500 { - cnt = 500 - } - return cnt -} - -func (c *AppController) handleResult(worlds []models.World, err error) { - if err != nil { - c.Reply().InternalServerError().Text(err.Error()) - return - } - c.Reply().JSON(worlds) -} diff --git a/frameworks/Go/aah/src/benchmark/app/db/mysql.go b/frameworks/Go/aah/src/benchmark/app/db/mysql.go deleted file mode 100644 index 65c7aaf2501..00000000000 --- a/frameworks/Go/aah/src/benchmark/app/db/mysql.go +++ /dev/null @@ -1,63 +0,0 @@ -package db - -import ( - "database/sql" - "runtime" - - "aahframe.work" - - // mysql driver - _ "github.com/go-sql-driver/mysql" -) - -// MySQL database connection and prepared statements -var ( - MySQL *sql.DB - MSworldSelectStmt *sql.Stmt - MSworldUpdateStmt *sql.Stmt - MSfortuneSelectStmt *sql.Stmt - - mysqlMaxConnCount = runtime.NumCPU() * 2 -) - -// InitMySQLDatabase initializes the Database. -func InitMySQLDatabase(_ *aah.Event) { - app := aah.App() - if !app.IsEnvProfile("bm_mysql") { - return - } - - cfg := app.Config() - var err error - MySQL, err = sql.Open( - cfg.StringDefault("datasource.benchmark.mysql.driver", "mysql"), - cfg.StringDefault("datasource.benchmark.mysql.url", ""), - ) - if err != nil { - app.Log().Fatal(err) - } - - if err = MySQL.Ping(); err != nil { - app.Log().Fatal(err) - } - - MySQL.SetMaxIdleConns(mysqlMaxConnCount) - MySQL.SetMaxOpenConns(mysqlMaxConnCount) - - if MSworldSelectStmt, err = MySQL.Prepare("SELECT id, randomNumber FROM World WHERE id = ?"); err != nil { - app.Log().Fatal(err) - } - if MSworldUpdateStmt, err = MySQL.Prepare("UPDATE World SET randomNumber = ? WHERE id = ?"); err != nil { - app.Log().Fatal(err) - } - if MSfortuneSelectStmt, err = MySQL.Prepare("SELECT id, message FROM Fortune"); err != nil { - app.Log().Fatal(err) - } -} - -// CloseMySQLDatabase initializes the Database. -func CloseMySQLDatabase(_ *aah.Event) { - if MySQL != nil { - _ = MySQL.Close() - } -} diff --git a/frameworks/Go/aah/src/benchmark/app/db/postgresql.go b/frameworks/Go/aah/src/benchmark/app/db/postgresql.go deleted file mode 100644 index b05561c97c9..00000000000 --- a/frameworks/Go/aah/src/benchmark/app/db/postgresql.go +++ /dev/null @@ -1,66 +0,0 @@ -package db - -import ( - "runtime" - - "aahframe.work" - - "github.com/jackc/pgx" -) - -// PostgreSQL database connection and statements -var ( - PostgreSQL *pgx.ConnPool - PGWorldSelectStmt *pgx.PreparedStatement - PGWorldUpdateStmt *pgx.PreparedStatement - PGFortuneSelectStmt *pgx.PreparedStatement - - postgresqlMaxConnCount = runtime.NumCPU() * 4 -) - -// InitPostgreSQLDatabase initializes the Database. -func InitPostgreSQLDatabase(_ *aah.Event) { - app := aah.App() - if !app.IsEnvProfile("bm_postgresql") { - return - } - - cfg := app.Config() - config := pgx.ConnPoolConfig{ - ConnConfig: pgx.ConnConfig{ - Host: cfg.StringDefault("datasource.benchmark.postgresql.host", ""), - Port: uint16(cfg.IntDefault("datasource.benchmark.postgresql.port", 5432)), - User: cfg.StringDefault("datasource.benchmark.postgresql.user", ""), - Password: cfg.StringDefault("datasource.benchmark.postgresql.password", ""), - Database: cfg.StringDefault("datasource.benchmark.postgresql.dbname", ""), - }, - MaxConnections: postgresqlMaxConnCount, - } - - config.AfterConnect = func(conn *pgx.Conn) error { - var err error - if PGWorldSelectStmt, err = conn.Prepare("worldSelectStmt", "SELECT id, randomNumber FROM World WHERE id = $1"); err != nil { - app.Log().Fatal(err) - } - if PGWorldUpdateStmt, err = conn.Prepare("worldUpdateStmt", "UPDATE World SET randomNumber = $1 WHERE id = $2"); err != nil { - app.Log().Fatal(err) - } - if PGFortuneSelectStmt, err = conn.Prepare("fortuneSelectStmt", "SELECT id, message FROM Fortune"); err != nil { - app.Log().Fatal(err) - } - return nil - } - - var err error - PostgreSQL, err = pgx.NewConnPool(config) - if err != nil { - app.Log().Fatal(err) - } -} - -// ClosePostgreSQLDatabase initializes the Database. -func ClosePostgreSQLDatabase(_ *aah.Event) { - if PostgreSQL != nil { - PostgreSQL.Close() - } -} diff --git a/frameworks/Go/aah/src/benchmark/app/init.go b/frameworks/Go/aah/src/benchmark/app/init.go deleted file mode 100644 index a4e59ed3ac7..00000000000 --- a/frameworks/Go/aah/src/benchmark/app/init.go +++ /dev/null @@ -1,28 +0,0 @@ -// aah application initialization - configuration, server extensions, middleware's, etc. -// Customize it per application use case. - -package main - -import ( - "benchmark/app/db" - - "aahframe.work" -) - -func init() { - app := aah.App() - - app.OnStart(db.InitMySQLDatabase) - app.OnStart(db.InitPostgreSQLDatabase) - app.OnStart(func(_ *aah.Event) { - app.SecurityManager().AntiCSRF.Enabled = false - }) - - app.OnPostShutdown(db.CloseMySQLDatabase) - app.OnPostShutdown(db.ClosePostgreSQLDatabase) - - app.HTTPEngine().Middlewares( - aah.RouteMiddleware, - aah.ActionMiddleware, - ) -} diff --git a/frameworks/Go/aah/src/benchmark/app/models/models.go b/frameworks/Go/aah/src/benchmark/app/models/models.go deleted file mode 100644 index 1c79d855228..00000000000 --- a/frameworks/Go/aah/src/benchmark/app/models/models.go +++ /dev/null @@ -1,188 +0,0 @@ -package models - -import ( - "fmt" - "math/rand" - "sort" - - "benchmark/app/db" -) - -var worldRowCount = 10000 - -type ( - // Message is used for JSON reply. - Message struct { - Message string `json:"message"` - } - - // World is used for database operation. - World struct { - ID uint16 `json:"id"` - RandomNumber uint16 `json:"randomNumber"` - } - - // Fortune is used for database and reply. - Fortune struct { - ID uint16 `json:"id"` - Message string `json:"message"` - } - - // Fortunes slice - Fortunes []*Fortune -) - -//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ -// MySQL DB based implementation -//___________________________________________________________________________ - -// MySQLFetchRandomWorld method returns one world record info. -func MySQLFetchRandomWorld(w *World) error { - err := db.MSworldSelectStmt.QueryRow(randomWorldNum()).Scan(&w.ID, &w.RandomNumber) - return err -} - -// MySQLRandomWorlds method returns world record from db randomly. -func MySQLRandomWorlds(count int) ([]World, error) { - worlds := make([]World, count) - var err error - for i := 0; i < count; i++ { - w := &worlds[i] - if err = MySQLFetchRandomWorld(w); err != nil { - return nil, err - } - } - return worlds, nil -} - -// MySQLUpdateRandomWorlds method updates random world records. -func MySQLUpdateRandomWorlds(count int) ([]World, error) { - worlds := make([]World, count) - var err error - for i := 0; i < count; i++ { - w := &worlds[i] - if err = MySQLFetchRandomWorld(w); err != nil { - return nil, err - } - - w.RandomNumber = uint16(randomWorldNum()) - if _, err = db.MSworldUpdateStmt.Exec(w.RandomNumber, w.ID); err != nil { - return nil, err - } - } - return worlds, nil -} - -// MySQLFortunes method returns fortunes records -func MySQLFortunes() (Fortunes, error) { - rows, err := db.MSfortuneSelectStmt.Query() - if err != nil { - return nil, err - } - - fortunes := make(Fortunes, 0) - for rows.Next() { - var fortune Fortune - if err = rows.Scan(&fortune.ID, &fortune.Message); err != nil { - return nil, err - } - fortunes = append(fortunes, &fortune) - } - _ = rows.Close() - - fortunes = append(fortunes, &Fortune{Message: "Additional fortune added at request time."}) - sortFortunesByMessage(fortunes) - return fortunes, nil -} - -//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ -// PostgreSQL DB based implementation -//___________________________________________________________________________ - -// PGFetchRandomWorld method returns one world record info. -func PGFetchRandomWorld(w *World) error { - return db.PostgreSQL.QueryRow("worldSelectStmt", randomWorldNum()).Scan(&w.ID, &w.RandomNumber) -} - -// PGRandomWorlds method returns world record from db randomly. -func PGRandomWorlds(count int) ([]World, error) { - worlds := make([]World, count) - var err error - for i := 0; i < count; i++ { - w := &worlds[i] - if err = PGFetchRandomWorld(w); err != nil { - return nil, err - } - } - return worlds, nil -} - -// PGUpdateRandomWorlds method updates random world records. -func PGUpdateRandomWorlds(count int) ([]World, error) { - worlds := make([]World, count) - var err error - for i := 0; i < count; i++ { - w := &worlds[i] - if err = PGFetchRandomWorld(w); err != nil { - return nil, err - } - w.RandomNumber = uint16(randomWorldNum()) - } - - // sorting is required for insert deadlock prevention. - sortWorldsByID(worlds) - - txn, err := db.PostgreSQL.Begin() - if err != nil { - return nil, fmt.Errorf("Error starting transaction: %s", err) - } - for i := 0; i < count; i++ { - w := &worlds[i] - if _, err = txn.Exec("worldUpdateStmt", w.RandomNumber, w.ID); err != nil { - return nil, fmt.Errorf("Error updating world row %d: %s", i, err) - } - } - if err = txn.Commit(); err != nil { - return nil, fmt.Errorf("Error when commiting world rows: %s", err) - } - - return worlds, nil -} - -// PGFortunes method returns fortunes records -func PGFortunes() (Fortunes, error) { - rows, err := db.PostgreSQL.Query("fortuneSelectStmt") - if err != nil { - return nil, err - } - - fortunes := make(Fortunes, 0) - for rows.Next() { - var fortune Fortune - if err = rows.Scan(&fortune.ID, &fortune.Message); err != nil { - return nil, err - } - fortunes = append(fortunes, &fortune) - } - rows.Close() - - fortunes = append(fortunes, &Fortune{Message: "Additional fortune added at request time."}) - sortFortunesByMessage(fortunes) - return fortunes, nil -} - -//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ -// Unexported methods -//___________________________________________________________________________ - -func randomWorldNum() int { - return rand.Intn(worldRowCount) + 1 -} - -func sortFortunesByMessage(fortunes Fortunes) { - sort.Slice(fortunes, func(i, j int) bool { return fortunes[i].Message < fortunes[j].Message }) -} - -func sortWorldsByID(worlds []World) { - sort.Slice(worlds, func(i, j int) bool { return worlds[i].ID < worlds[j].ID }) -} diff --git a/frameworks/Go/aah/src/benchmark/config/aah.conf b/frameworks/Go/aah/src/benchmark/config/aah.conf deleted file mode 100644 index df619ec86da..00000000000 --- a/frameworks/Go/aah/src/benchmark/config/aah.conf +++ /dev/null @@ -1,50 +0,0 @@ -# ----------------------------------------------------------------------------- -# benchmark - aah Application Configuration -# -# Refer documentation to explore and customize the configurations. -# Doc: https://docs.aahframework.org/app-config.html -# ----------------------------------------------------------------------------- - -name = "benchmark" -desc = "aah framework web application" -type = "web" - -server { - header = "aah" -} - -request { - id { - enable = false - } -} - -render { - default = "html" - gzip { - enable = false - } -} - -cache { - static { - default_cache_control = "public, max-age=31536000" - } -} - -view { - engine = "go" - ext = ".html" - delimiters = "{{.}}" -} - -include "./security.conf" - -env { - active = "bm_default" - - # ------------------------------------------------- - # Including Environment profile configurations - # ------------------------------------------------- - include "./env/*.conf" -} diff --git a/frameworks/Go/aah/src/benchmark/config/env/bm-default.conf b/frameworks/Go/aah/src/benchmark/config/env/bm-default.conf deleted file mode 100644 index 3ba63c7af53..00000000000 --- a/frameworks/Go/aah/src/benchmark/config/env/bm-default.conf +++ /dev/null @@ -1,12 +0,0 @@ -# --------------------------------- -# Default Benchmark profile -# --------------------------------- - -bm_default { - - log { - receiver = "console" - level = "error" - } - -} \ No newline at end of file diff --git a/frameworks/Go/aah/src/benchmark/config/env/bm-mysql.conf b/frameworks/Go/aah/src/benchmark/config/env/bm-mysql.conf deleted file mode 100644 index e76817b6487..00000000000 --- a/frameworks/Go/aah/src/benchmark/config/env/bm-mysql.conf +++ /dev/null @@ -1,21 +0,0 @@ -# --------------------------------- -# MySQL Benchmark profile -# --------------------------------- - -bm_mysql { - - log { - receiver = "console" - level = "error" - } - - datasource { - benchmark { - mysql { - driver = "mysql" - url = "benchmarkdbuser:benchmarkdbpass@tcp(tfb-database:3306)/hello_world" - } - } - } - -} \ No newline at end of file diff --git a/frameworks/Go/aah/src/benchmark/config/env/bm-postgresql.conf b/frameworks/Go/aah/src/benchmark/config/env/bm-postgresql.conf deleted file mode 100644 index d5706d3d181..00000000000 --- a/frameworks/Go/aah/src/benchmark/config/env/bm-postgresql.conf +++ /dev/null @@ -1,24 +0,0 @@ -# --------------------------------- -# PostgreSQL Benchmark profile -# --------------------------------- - -bm_postgresql { - - log { - receiver = "console" - level = "error" - } - - datasource { - benchmark { - postgresql { - host = "tfb-database" - port = 5432 - dbname = "hello_world" - user = "benchmarkdbuser" - password = "benchmarkdbpass" - } - } - } - -} \ No newline at end of file diff --git a/frameworks/Go/aah/src/benchmark/config/routes.conf b/frameworks/Go/aah/src/benchmark/config/routes.conf deleted file mode 100644 index e4624897820..00000000000 --- a/frameworks/Go/aah/src/benchmark/config/routes.conf +++ /dev/null @@ -1,76 +0,0 @@ -# ----------------------------------------------------------------------------- -# benchmark - Application Routes Configuration -# -# Refer documentation to explore and configure routes. -# Doc: https://docs.aahframework.org/routing.html -# ----------------------------------------------------------------------------- - -domains { - - localhost { - name = "benchmark routes" - host = "localhost" - - routes { - - json { - path = "/json" - controller = "AppController" - action = "JSON" - } - - plaintext { - path = "/plaintext" - controller = "AppController" - action = "Plaintext" - } - - # For MySQL datasource - db { - path = "/db" - controller = "AppController" - action = "World" - - routes { - dbs { - path = "/queries" - action = "Worlds" - } - fortunes { - path = "/fortunes" - action = "Fortunes" - } - updates { - path = "/updates" - action = "UpdateWorlds" - } - } - } - - # For PostgreSQL datasource - pg_db { - path = "/pg-db" - controller = "AppController" - action = "PGWorld" - - routes { - pg_dbs { - path = "/queries" - action = "PGWorlds" - } - pg_fortunes { - path = "/fortunes" - action = "PGFortunes" - } - pg_updates { - path = "/updates" - action = "PGUpdateWorlds" - } - } - } - - } # end - routes - - } # end - localhost - -} # end - domains diff --git a/frameworks/Go/aah/src/benchmark/config/security.conf b/frameworks/Go/aah/src/benchmark/config/security.conf deleted file mode 100644 index c81a5160d35..00000000000 --- a/frameworks/Go/aah/src/benchmark/config/security.conf +++ /dev/null @@ -1,12 +0,0 @@ -# ----------------------------------------------------------------------------- -# benchmark - Application Security Configuration -# -# Refer documentation to explore and customize the configurations. -# Doc: https://docs.aahframework.org/security-config.html -# ----------------------------------------------------------------------------- - -security { - http_header { - enable = false - } -} diff --git a/frameworks/Go/aah/src/benchmark/go.mod b/frameworks/Go/aah/src/benchmark/go.mod deleted file mode 100644 index 26910164c0d..00000000000 --- a/frameworks/Go/aah/src/benchmark/go.mod +++ /dev/null @@ -1,33 +0,0 @@ -module benchmark - -require ( - aahframe.work v0.12.4 - github.com/go-sql-driver/mysql v1.4.1 - github.com/jackc/pgx v3.3.0+incompatible -) - -require ( - cloud.google.com/go v0.30.0 // indirect - github.com/cockroachdb/apd v1.1.0 // indirect - github.com/go-aah/forge v0.8.0 // indirect - github.com/go-playground/locales v0.12.1 // indirect - github.com/go-playground/universal-translator v0.16.0 // indirect - github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee // indirect - github.com/gobwas/pool v0.2.0 // indirect - github.com/gobwas/ws v1.0.0 // indirect - github.com/golang/protobuf v1.3.1 // indirect - github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 // indirect - github.com/lib/pq v1.10.7 // indirect - github.com/pkg/errors v0.8.1 // indirect - github.com/satori/go.uuid v1.2.0 // indirect - github.com/shopspring/decimal v1.3.1 // indirect - github.com/urfave/cli v1.20.0 // indirect - golang.org/x/crypto v0.14.0 // indirect - golang.org/x/net v0.17.0 // indirect - golang.org/x/oauth2 v0.0.0-20181003184128-c57b0facaced // indirect - golang.org/x/sys v0.13.0 // indirect - golang.org/x/text v0.13.0 // indirect - google.golang.org/appengine v1.6.7 // indirect - gopkg.in/go-playground/assert.v1 v1.2.1 // indirect - gopkg.in/go-playground/validator.v9 v9.21.0 // indirect -) diff --git a/frameworks/Go/aah/src/benchmark/go.sum b/frameworks/Go/aah/src/benchmark/go.sum deleted file mode 100644 index 0a70faaf940..00000000000 --- a/frameworks/Go/aah/src/benchmark/go.sum +++ /dev/null @@ -1,66 +0,0 @@ -aahframe.work v0.12.4 h1:Hcp1EP7T8Y+qh1ukFjTqXjImqKxyk03nuvACm81OTfU= -aahframe.work v0.12.4/go.mod h1:Ogn3OQKcq9W59XSAZzPqk4g2PpFH9h2Px1PFPnoGmvs= -cloud.google.com/go v0.30.0 h1:xKvyLgk56d0nksWq49J0UyGEeUIicTl4+UBiX1NPX9g= -cloud.google.com/go v0.30.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= -github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= -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/go-aah/forge v0.8.0 h1:sk4Z523B9ay3JQF4At97U7kecB5yTIm0J2UM/qRVXbQ= -github.com/go-aah/forge v0.8.0/go.mod h1:+pz2ywtYKCMzKtHa2kyKIOBw2XhQpj+dgch/vMGWyqo= -github.com/go-playground/locales v0.12.1 h1:2FITxuFt/xuCNP1Acdhv62OzaCiviiE4kotfhkmOqEc= -github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM= -github.com/go-playground/universal-translator v0.16.0 h1:X++omBR/4cE2MNg91AoC3rmGrCjJ8eAeUP/K/EKx4DM= -github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY= -github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= -github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0= -github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= -github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8= -github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= -github.com/gobwas/ws v1.0.0 h1:1WdyfgUcImUfVBvYbsW2krIsnko+1QU2t45soaF8v1M= -github.com/gobwas/ws v1.0.0/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= -github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 h1:vr3AYkKovP8uR8AvSGGUK1IDqRa5lAAvEkZG1LKaCRc= -github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ= -github.com/jackc/pgx v3.3.0+incompatible h1:Wa90/+qsITBAPkAZjiByeIGHFcj3Ztu+VzrrIpHjL90= -github.com/jackc/pgx v3.3.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= -github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= -github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -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/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= -github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= -github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= -github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw= -github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= -golang.org/x/crypto v0.0.0-20181012144002-a92615f3c490/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= -golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/oauth2 v0.0.0-20181003184128-c57b0facaced h1:4oqSq7eft7MdPKBGQK11X9WYUxmj6ZLgGTqYIbY1kyw= -golang.org/x/oauth2 v0.0.0-20181003184128-c57b0facaced/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM= -gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= -gopkg.in/go-playground/validator.v9 v9.21.0 h1:wSDJGBpQBYC1wLpVnGHLmshm2JicoSNdrb38Zj+8yHI= -gopkg.in/go-playground/validator.v9 v9.21.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= diff --git a/frameworks/Go/aah/src/benchmark/views/layouts/master.html b/frameworks/Go/aah/src/benchmark/views/layouts/master.html deleted file mode 100644 index f06a329b50e..00000000000 --- a/frameworks/Go/aah/src/benchmark/views/layouts/master.html +++ /dev/null @@ -1,7 +0,0 @@ - - -{{ template "title" . }} - -{{ template "body" . }} - - diff --git a/frameworks/Go/aah/src/benchmark/views/pages/app/fortunes.html b/frameworks/Go/aah/src/benchmark/views/pages/app/fortunes.html deleted file mode 100644 index afe58dcc0af..00000000000 --- a/frameworks/Go/aah/src/benchmark/views/pages/app/fortunes.html +++ /dev/null @@ -1,10 +0,0 @@ -{{ define "title" -}}Fortunes{{- end }} - -{{ define "body" -}} - - -{{- range .Fortunes }} - -{{- end }} -
idmessage
{{ .ID }}{{ .Message }}
-{{- end }} diff --git a/frameworks/Go/atreugo/atreugo-prefork.dockerfile b/frameworks/Go/atreugo/atreugo-prefork.dockerfile index 40cc16b1797..2f930396493 100644 --- a/frameworks/Go/atreugo/atreugo-prefork.dockerfile +++ b/frameworks/Go/atreugo/atreugo-prefork.dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/golang:1.19 +FROM docker.io/golang:1.24.2 WORKDIR /atreugo diff --git a/frameworks/Go/atreugo/atreugo.dockerfile b/frameworks/Go/atreugo/atreugo.dockerfile index 22f114ee7a4..3a6db2415fd 100644 --- a/frameworks/Go/atreugo/atreugo.dockerfile +++ b/frameworks/Go/atreugo/atreugo.dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/golang:1.19 +FROM docker.io/golang:1.24.2 WORKDIR /atreugo diff --git a/frameworks/Go/atreugo/src/go.mod b/frameworks/Go/atreugo/src/go.mod index 68c2acb94fe..01fb51e3d5c 100644 --- a/frameworks/Go/atreugo/src/go.mod +++ b/frameworks/Go/atreugo/src/go.mod @@ -1,34 +1,27 @@ module atreugo/src -go 1.19 +go 1.24.0 + +toolchain go1.24.1 require ( - github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c - github.com/jackc/pgx/v5 v5.0.4 - github.com/mailru/easyjson v0.7.7 - github.com/savsgio/atreugo/v11 v11.9.7 - github.com/valyala/quicktemplate v1.7.0 + github.com/jackc/pgx/v5 v5.7.4 + github.com/savsgio/atreugo/v11 v11.13.2 + github.com/valyala/quicktemplate v1.8.0 ) require ( - github.com/andybalholm/brotli v1.0.4 // indirect - github.com/fasthttp/router v1.4.12 // indirect - github.com/jackc/chunkreader/v2 v2.0.1 // indirect - github.com/jackc/pgconn v1.13.0 // indirect - github.com/jackc/pgio v1.0.0 // indirect + github.com/andybalholm/brotli v1.1.1 // indirect + github.com/fasthttp/router v1.5.4 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect - github.com/jackc/pgproto3/v2 v2.3.1 // indirect - github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect - github.com/jackc/pgtype v1.12.0 // indirect - github.com/jackc/puddle v1.3.0 // indirect - github.com/jackc/puddle/v2 v2.0.0 // indirect - github.com/josharian/intern v1.0.0 // indirect - github.com/klauspost/compress v1.15.10 // indirect - github.com/savsgio/gotils v0.0.0-20220530130905-52f3993e8d6d // 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/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/fasthttp v1.40.0 // indirect - github.com/valyala/tcplisten v1.0.0 // indirect - golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 // indirect - golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41 // indirect - golang.org/x/text v0.3.8 // 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/atreugo/src/go.sum b/frameworks/Go/atreugo/src/go.sum index f30a89a3d8d..87b06ac2495 100644 --- a/frameworks/Go/atreugo/src/go.sum +++ b/frameworks/Go/atreugo/src/go.sum @@ -1,234 +1,50 @@ -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= -github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= -github.com/andybalholm/brotli v1.0.3/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= -github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY= -github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA= +github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA= github.com/atreugo/mock v0.0.0-20200601091009-13c275b330b0 h1:IVqe9WnancrkICl5HqEfGjrnkQ4+VsU5fodcuFVoG/A= github.com/atreugo/mock v0.0.0-20200601091009-13c275b330b0/go.mod h1:HTHAc8RoZXMVTr6wZQN7Jjm3mYMnbfkqqKdnQgSoe9o= -github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= -github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= -github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= 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/fasthttp/router v1.4.12 h1:QEgK+UKARaC1bAzJgnIhdUMay6nwp+YFq6VGPlyKN1o= -github.com/fasthttp/router v1.4.12/go.mod h1:41Qdc4Z4T2pWVVtATHCnoUnOtxdBoeKEYJTXhHwbxCQ= -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-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= -github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= -github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= -github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= -github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= -github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= -github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE= -github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s= -github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= -github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= -github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= -github.com/jackc/pgconn v1.13.0 h1:3L1XMNV2Zvca/8BYhzcRFS70Lr0WlDg16Di6SFGAbys= -github.com/jackc/pgconn v1.13.0/go.mod h1:AnowpAqO4CMIIJNZl2VJp+KrkAZciAkhEl0W0JIobpI= -github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= -github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= -github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= -github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c= -github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc= -github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak= +github.com/fasthttp/router v1.5.4 h1:oxdThbBwQgsDIYZ3wR1IavsNl6ZS9WdjKukeMikOnC8= +github.com/fasthttp/router v1.5.4/go.mod h1:3/hysWq6cky7dTfzaaEPZGdptwjwx0qzTgFCKEWRjgc= 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/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= -github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA= -github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg= -github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= -github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= -github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.3.1 h1:nwj7qwf0S+Q7ISFfBndqeLwSwxs+4DPsbRFjECT1Y4Y= -github.com/jackc/pgproto3/v2 v2.3.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg= -github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= -github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= -github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= -github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= -github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= -github.com/jackc/pgtype v1.12.0 h1:Dlq8Qvcch7kiehm8wPGIW0W3KsCCHJnRacKW0UM8n5w= -github.com/jackc/pgtype v1.12.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= -github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= -github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= -github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= -github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c h1:Dznn52SgVIVst9UyOT9brctYUgxs+CvVfPaC3jKrA50= -github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= -github.com/jackc/pgx/v4 v4.17.2 h1:0Ut0rpeKwvIVbMQ1KbMBU4h6wxehBI535LK6Flheh8E= -github.com/jackc/pgx/v4 v4.17.2/go.mod h1:lcxIZN44yMIrWI78a5CpucdD14hX0SBDbNRvjDBItsw= -github.com/jackc/pgx/v5 v5.0.4 h1:r5O6y84qHX/z/HZV40JBdx2obsHz7/uRj5b+CcYEdeY= -github.com/jackc/pgx/v5 v5.0.4/go.mod h1:U0ynklHtgg43fue9Ly30w3OCSTDPlXjig9ghrNGaguQ= -github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.3.0 h1:eHK/5clGOatcjX3oWGBO/MpxpbHzSwud5EWTSCI+MX0= -github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle/v2 v2.0.0 h1:Kwk/AlLigcnZsDssc3Zun1dk1tAtQNPaBBxBHWn0Mjc= -github.com/jackc/puddle/v2 v2.0.0/go.mod h1:itE7ZJY8xnoo0JqJEpSMprN0f+NQkMCuEV/N9j8h0oc= -github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= -github.com/klauspost/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.15.10 h1:Ai8UzuomSCDw90e1qNMtb15msBXsNpH6gzkkENQNcJo= -github.com/klauspost/compress v1.15.10/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8= -github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= -github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +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/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.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -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= -github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/savsgio/atreugo/v11 v11.9.7 h1:nzd/0G0bkvja7e5/wEb27K/7pXlRcSDmE70WR3Fx9MI= -github.com/savsgio/atreugo/v11 v11.9.7/go.mod h1:bziyB6t8H3YQ7mdCUX0ZVFTXo/7ANslmVbfRFM+pJOQ= -github.com/savsgio/gotils v0.0.0-20220530130905-52f3993e8d6d h1:Q+gqLBOPkFGHyCJxXMRqtUgUbTjI8/Ze8vu8GGyNFwo= -github.com/savsgio/gotils v0.0.0-20220530130905-52f3993e8d6d/go.mod h1:Gy+0tqhJvgGlqnTF8CVGP0AaGRjwBtXs/a5PA0Y3+A4= -github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= -github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= -github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= -github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/savsgio/atreugo/v11 v11.13.2 h1:F1XHN2slrHKokg3ESLS6O2+hvlKqPJcBRuhJBEFJbn8= +github.com/savsgio/atreugo/v11 v11.13.2/go.mod h1:PloaYuHYZpXc7vkxXbMmqqorLlGZVAI4KFzVrynx5qo= +github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38 h1:D0vL7YNisV2yqE55+q0lFuGse6U8lxlg7fYTctlT5Gc= +github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38/go.mod h1:sM7Mt7uEoCeFSCBM+qBrqvEo+/9vdmj19wzp3yzUhmg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +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.30.0/go.mod h1:2rsYD01CKFrjjsvFxx75KlEUNpWNBY9JWD3K/7o2Cus= -github.com/valyala/fasthttp v1.40.0 h1:CRq/00MfruPGFLTQKY8b+8SfdK60TxNztjRMnH0t1Yc= -github.com/valyala/fasthttp v1.40.0/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I= -github.com/valyala/quicktemplate v1.7.0 h1:LUPTJmlVcb46OOUY3IeD9DojFpAVbsG+5WFTcjMJzCM= -github.com/valyala/quicktemplate v1.7.0/go.mod h1:sqKJnoaOF88V07vkO+9FL8fb9uZg/VPSJnLYn+LmLk8= -github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= -github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= -github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= -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= -go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= -go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= -go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= -golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM= -golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41 h1:ohgcoMbSofXygzo6AD2I1kz3BFmW1QArPYTtwEM3UXc= -golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -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= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +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.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/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 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= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= diff --git a/frameworks/Go/chi/chi-gojay-prefork.dockerfile b/frameworks/Go/chi/chi-gojay-prefork.dockerfile index 2403792062f..9381a8601b2 100644 --- a/frameworks/Go/chi/chi-gojay-prefork.dockerfile +++ b/frameworks/Go/chi/chi-gojay-prefork.dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/golang:1.19 +FROM docker.io/golang:1.24.2 ADD ./src/chi-gojay /chi WORKDIR /chi diff --git a/frameworks/Go/chi/chi-gojay.dockerfile b/frameworks/Go/chi/chi-gojay.dockerfile index 4f4e2ccf72d..05a5eb524dd 100644 --- a/frameworks/Go/chi/chi-gojay.dockerfile +++ b/frameworks/Go/chi/chi-gojay.dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/golang:1.19 +FROM docker.io/golang:1.24.2 ADD ./src/chi-gojay /chi WORKDIR /chi diff --git a/frameworks/Go/chi/chi-prefork.dockerfile b/frameworks/Go/chi/chi-prefork.dockerfile index a516efa3726..5a86cae27bf 100644 --- a/frameworks/Go/chi/chi-prefork.dockerfile +++ b/frameworks/Go/chi/chi-prefork.dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/golang:1.19 +FROM docker.io/golang:1.24.2 ADD ./src/chi /chi WORKDIR /chi diff --git a/frameworks/Go/chi/chi-scratch.dockerfile b/frameworks/Go/chi/chi-scratch.dockerfile index 63f9b7ac031..baad2c7b074 100644 --- a/frameworks/Go/chi/chi-scratch.dockerfile +++ b/frameworks/Go/chi/chi-scratch.dockerfile @@ -1,13 +1,12 @@ # build layer -FROM docker.io/golang:1.19-alpine as builder +FROM docker.io/golang:1.24.2-alpine as builder ADD ./src/chi /chi WORKDIR /chi RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GOAMD64=v3 \ - go build -ldflags="-w -s" -o server - -RUN apk --no-cache add --update ca-certificates + go build -ldflags="-w -s" -o server && \ + apk --no-cache add --update ca-certificates # release layer FROM scratch diff --git a/frameworks/Go/chi/chi-sjson-prefork.dockerfile b/frameworks/Go/chi/chi-sjson-prefork.dockerfile index 1e6e7029c01..dc949b5f137 100644 --- a/frameworks/Go/chi/chi-sjson-prefork.dockerfile +++ b/frameworks/Go/chi/chi-sjson-prefork.dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/golang:1.19 +FROM docker.io/golang:1.24.2 ADD ./src/chi-sjson /chi WORKDIR /chi diff --git a/frameworks/Go/chi/chi-sjson.dockerfile b/frameworks/Go/chi/chi-sjson.dockerfile index 6af99dc4011..6942fb43636 100644 --- a/frameworks/Go/chi/chi-sjson.dockerfile +++ b/frameworks/Go/chi/chi-sjson.dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/golang:1.19 +FROM docker.io/golang:1.24.2 ADD ./src/chi-sjson /chi WORKDIR /chi diff --git a/frameworks/Go/chi/chi.dockerfile b/frameworks/Go/chi/chi.dockerfile index 205c2bdf7d5..2378ae07c9e 100644 --- a/frameworks/Go/chi/chi.dockerfile +++ b/frameworks/Go/chi/chi.dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/golang:1.19 +FROM docker.io/golang:1.24.2 ADD ./src/chi /chi WORKDIR /chi diff --git a/frameworks/Go/chi/src/chi-gojay/go.mod b/frameworks/Go/chi/src/chi-gojay/go.mod index 8521c5e7b7f..24337489ee9 100644 --- a/frameworks/Go/chi/src/chi-gojay/go.mod +++ b/frameworks/Go/chi/src/chi-gojay/go.mod @@ -1,8 +1,10 @@ module chi/server -go 1.19 +go 1.23.1 require ( - github.com/go-chi/chi/v5 v5.0.7 - github.com/go-sql-driver/mysql v1.6.0 + github.com/go-chi/chi/v5 v5.2.1 + github.com/go-sql-driver/mysql v1.9.1 ) + +require filippo.io/edwards25519 v1.1.0 // indirect diff --git a/frameworks/Go/chi/src/chi-gojay/go.sum b/frameworks/Go/chi/src/chi-gojay/go.sum index 68a8dd38f73..383118b55e6 100644 --- a/frameworks/Go/chi/src/chi-gojay/go.sum +++ b/frameworks/Go/chi/src/chi-gojay/go.sum @@ -1,4 +1,6 @@ -github.com/go-chi/chi/v5 v5.0.7 h1:rDTPXLDHGATaeHvVlLcR4Qe0zftYethFucbjVQ1PxU8= -github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= -github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= -github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/go-chi/chi/v5 v5.2.1 h1:KOIHODQj58PmL80G2Eak4WdvUzjSJSm0vG72crDCqb8= +github.com/go-chi/chi/v5 v5.2.1/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops= +github.com/go-sql-driver/mysql v1.9.1 h1:FrjNGn/BsJQjVRuSa8CBrM5BWA9BWoXXat3KrtSb/iI= +github.com/go-sql-driver/mysql v1.9.1/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU= diff --git a/frameworks/Go/chi/src/chi-sjson/go.mod b/frameworks/Go/chi/src/chi-sjson/go.mod index 8521c5e7b7f..6c250386303 100644 --- a/frameworks/Go/chi/src/chi-sjson/go.mod +++ b/frameworks/Go/chi/src/chi-sjson/go.mod @@ -1,8 +1,10 @@ module chi/server -go 1.19 +go 1.23.1 require ( - github.com/go-chi/chi/v5 v5.0.7 - github.com/go-sql-driver/mysql v1.6.0 + github.com/go-chi/chi/v5 v5.2.2 + github.com/go-sql-driver/mysql v1.9.1 ) + +require filippo.io/edwards25519 v1.1.0 // indirect diff --git a/frameworks/Go/chi/src/chi-sjson/go.sum b/frameworks/Go/chi/src/chi-sjson/go.sum index 68a8dd38f73..f5cb6c06e7f 100644 --- a/frameworks/Go/chi/src/chi-sjson/go.sum +++ b/frameworks/Go/chi/src/chi-sjson/go.sum @@ -1,4 +1,6 @@ -github.com/go-chi/chi/v5 v5.0.7 h1:rDTPXLDHGATaeHvVlLcR4Qe0zftYethFucbjVQ1PxU8= -github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= -github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= -github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/go-chi/chi/v5 v5.2.2 h1:CMwsvRVTbXVytCk1Wd72Zy1LAsAh9GxMmSNWLHCG618= +github.com/go-chi/chi/v5 v5.2.2/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops= +github.com/go-sql-driver/mysql v1.9.1 h1:FrjNGn/BsJQjVRuSa8CBrM5BWA9BWoXXat3KrtSb/iI= +github.com/go-sql-driver/mysql v1.9.1/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU= diff --git a/frameworks/Go/chi/src/chi/go.mod b/frameworks/Go/chi/src/chi/go.mod index 829aae200bd..e2fd954ff4b 100644 --- a/frameworks/Go/chi/src/chi/go.mod +++ b/frameworks/Go/chi/src/chi/go.mod @@ -1,11 +1,14 @@ module chi/server -go 1.19 +go 1.23.1 require ( - github.com/go-chi/chi/v5 v5.0.7 - github.com/go-sql-driver/mysql v1.6.0 - github.com/mailru/easyjson v0.7.7 + github.com/go-chi/chi/v5 v5.2.1 + github.com/go-sql-driver/mysql v1.9.1 + github.com/mailru/easyjson v0.9.0 ) -require github.com/josharian/intern v1.0.0 // indirect +require ( + filippo.io/edwards25519 v1.1.0 // indirect + github.com/josharian/intern v1.0.0 // indirect +) diff --git a/frameworks/Go/chi/src/chi/go.sum b/frameworks/Go/chi/src/chi/go.sum index f18160ebd73..cac59f89c15 100644 --- a/frameworks/Go/chi/src/chi/go.sum +++ b/frameworks/Go/chi/src/chi/go.sum @@ -1,8 +1,10 @@ -github.com/go-chi/chi/v5 v5.0.7 h1:rDTPXLDHGATaeHvVlLcR4Qe0zftYethFucbjVQ1PxU8= -github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= -github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= -github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/go-chi/chi/v5 v5.2.1 h1:KOIHODQj58PmL80G2Eak4WdvUzjSJSm0vG72crDCqb8= +github.com/go-chi/chi/v5 v5.2.1/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops= +github.com/go-sql-driver/mysql v1.9.1 h1:FrjNGn/BsJQjVRuSa8CBrM5BWA9BWoXXat3KrtSb/iI= +github.com/go-sql-driver/mysql v1.9.1/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= +github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= diff --git a/frameworks/Go/clevergo/README.md b/frameworks/Go/clevergo/README.md deleted file mode 100755 index 6587302c373..00000000000 --- a/frameworks/Go/clevergo/README.md +++ /dev/null @@ -1,12 +0,0 @@ -# [CleverGo](https://github.com/clevergo/clevergo) Benchmarking Test - -[CleverGo](https://github.com/clevergo/clevergo) is a lightweight, feature rich and high performance web framework writing in Go. - -## Test URLs - -http://localhost:8080/json -http://localhost:8080/plaintext -http://localhost:8080/db -http://localhost:8080/query?queries= -http://localhost:8080/update?queries= -http://localhost:8080/fortunes diff --git a/frameworks/Go/clevergo/benchmark_config.json b/frameworks/Go/clevergo/benchmark_config.json deleted file mode 100755 index fdd62b07751..00000000000 --- a/frameworks/Go/clevergo/benchmark_config.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "framework": "clevergo", - "tests": [ - { - "default": { - "json_url": "/json", - "plaintext_url": "/plaintext", - "db_url": "/db", - "query_url": "/queries?n=", - "fortune_url": "/fortunes", - "update_url": "/updates?n=", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "mysql", - "framework": "CleverGo", - "language": "Go", - "flavor": "None", - "orm": "Raw", - "platform": "None", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "CleverGo", - "notes": "", - "versus": "go" - } - } - ] -} diff --git a/frameworks/Go/clevergo/clevergo.dockerfile b/frameworks/Go/clevergo/clevergo.dockerfile deleted file mode 100644 index 38f766b256d..00000000000 --- a/frameworks/Go/clevergo/clevergo.dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM docker.io/golang:1.19 - -ADD ./ /clevergo -WORKDIR /clevergo - -RUN GOAMD64=v3 go build -o app main.go - -EXPOSE 8080 - -CMD ./app diff --git a/frameworks/Go/clevergo/config.toml b/frameworks/Go/clevergo/config.toml deleted file mode 100644 index cd48ff7609a..00000000000 --- a/frameworks/Go/clevergo/config.toml +++ /dev/null @@ -1,19 +0,0 @@ -[framework] -name = "clevergo" - -[main] -urls.plaintext = "/plaintext" -urls.json = "/json" -urls.db = "/db" -urls.query = "/queries?n=" -urls.update = "/updates?n=" -urls.fortune = "/fortunes" -approach = "Realistic" -classification = "Micro" -database = "mysql" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "None" -webserver = "None" -versus = "go" diff --git a/frameworks/Go/clevergo/go.mod b/frameworks/Go/clevergo/go.mod deleted file mode 100644 index b6b39a0d8b6..00000000000 --- a/frameworks/Go/clevergo/go.mod +++ /dev/null @@ -1,10 +0,0 @@ -module clevergo/app - -go 1.19 - -require ( - clevergo.tech/clevergo v0.6.0 - github.com/go-sql-driver/mysql v1.6.0 -) - -require clevergo.tech/log v0.3.0 // indirect diff --git a/frameworks/Go/clevergo/go.sum b/frameworks/Go/clevergo/go.sum deleted file mode 100644 index 59a8f1efa51..00000000000 --- a/frameworks/Go/clevergo/go.sum +++ /dev/null @@ -1,21 +0,0 @@ -clevergo.tech/clevergo v0.6.0 h1:smn2Kch2YhmRgU1fh3KAxaXHtmMBfZ1r2dPxxnSuFbI= -clevergo.tech/clevergo v0.6.0/go.mod h1:DKjcOs3CrayCTcm5j7gDht2p9u/zakSKClz9cObvO3E= -clevergo.tech/log v0.3.0 h1:9ryDHGeOD3BUSUuJEW3be8QtdnjjavoBkknoRCA7dp8= -clevergo.tech/log v0.3.0/go.mod h1:61sruy0OB79q5JJlxlyi+6eZzVf/bxbUbXnL0KIzsVw= -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/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= -github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -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.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/frameworks/Go/clevergo/main.go b/frameworks/Go/clevergo/main.go deleted file mode 100644 index 0b3d9819f3a..00000000000 --- a/frameworks/Go/clevergo/main.go +++ /dev/null @@ -1,218 +0,0 @@ -package main - -import ( - "database/sql" - "html/template" - "log" - "math/rand" - "net/http" - "runtime" - "sort" - "strconv" - - "clevergo.tech/clevergo" - _ "github.com/go-sql-driver/mysql" -) - -type Fortune struct { - ID uint16 `json:"id"` - Message string `json:"message"` -} - -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 FortunesByMessage struct { - Fortunes -} - -func (f FortunesByMessage) Less(i, j int) bool { - return f.Fortunes[i].Message < f.Fortunes[j].Message -} - -var ( - // Template - fortuneHTML = ` - - - Fortunes - - - - - - - - {{range .}} - - - - - {{end}} -
idmessage
{{ .ID }}{{ .Message }}
- -` - fortuneTmpl = template.Must(template.New("fortune").Parse(fortuneHTML)) - - // Database - db *sql.DB - dbDSN = "benchmarkdbuser:benchmarkdbpass@tcp(tfb-database:3306)/hello_world" - worldSelect = "SELECT id, randomNumber FROM World WHERE id = ?" - worldUpdate = "UPDATE World SET randomNumber = ? WHERE id = ?" - fortuneSelect = "SELECT id, message FROM Fortune" - worldSelectStmt *sql.Stmt - worldUpdateStmt *sql.Stmt - fortuneSelectStmt *sql.Stmt - worldRowCount = 10000 - maxConnections = 256 - - helloWorld = "Hello, World!" -) - -func init() { - runtime.GOMAXPROCS(runtime.NumCPU()) -} - -func initialize() (err error) { - db, err = sql.Open("mysql", dbDSN) - if err != nil { - log.Fatalf("Error opening database: %v", err) - } - db.SetMaxIdleConns(maxConnections) - db.SetMaxOpenConns(maxConnections) - worldSelectStmt, err = db.Prepare(worldSelect) - if err != nil { - log.Fatal(err) - } - worldUpdateStmt, err = db.Prepare(worldUpdate) - if err != nil { - log.Fatal(err) - } - fortuneSelectStmt, err = db.Prepare(fortuneSelect) - if err != nil { - log.Fatal(err) - } - - return -} - -func main() { - if err := initialize(); err != nil { - log.Fatal(err) - } - - app := clevergo.Pure() - app.Use(clevergo.ServerHeader("CleverGo")) - app.Get("/plaintext", plaintextHandler) - app.Get("/json", jsonHandler) - app.Get("/db", dbHandler) - app.Get("/queries", queriesHandler) - app.Get("/fortunes", fortunesHandler) - app.Get("/updates", updateHandler) - log.Println(app.Run(":8080")) -} - -func dbHandler(c *clevergo.Context) error { - world := new(World) - if err := fetchRandomWorld(world); err != nil { - return err - } - return c.JSON(http.StatusOK, world) -} - -func getQueryCount(q string) int { - n, err := strconv.Atoi(q) - if err != nil || n < 1 { - return 1 - } - if n > 500 { - return 500 - } - return n -} - -type World struct { - ID uint16 `json:"id"` - RandomNumber uint16 `json:"randomNumber"` -} - -func fetchRandomWorld(w *World) error { - n := randomWorldNum() - return worldSelectStmt.QueryRow(n).Scan(&w.ID, &w.RandomNumber) -} - -func randomWorldNum() int { - return rand.Intn(worldRowCount) + 1 -} - -func queriesHandler(c *clevergo.Context) error { - n := getQueryCount(c.QueryParam("n")) - worlds := make([]World, n) - for i := 0; i < n; i++ { - if err := fetchRandomWorld(&worlds[i]); err != nil { - return err - } - } - - return c.JSON(http.StatusOK, worlds) -} - -func fortunesHandler(c *clevergo.Context) error { - rows, err := fortuneSelectStmt.Query() - if err != nil { - return err - } - defer rows.Close() - - fortunes := make(Fortunes, 0) - for rows.Next() { // Fetch rows - f := new(Fortune) - if err := rows.Scan(&f.ID, &f.Message); err != nil { - return err - } - fortunes = append(fortunes, f) - } - fortunes = append(fortunes, &Fortune{Message: "Additional fortune added at request time."}) - sort.Sort(FortunesByMessage{fortunes}) - - return fortuneTmpl.Execute(c.Response, fortunes) -} - -func updateHandler(c *clevergo.Context) error { - n := getQueryCount(c.QueryParam("n")) - worlds := make([]World, n) - for i := 0; i < n; i++ { - // Fetch and modify - w := &worlds[i] - if err := fetchRandomWorld(&worlds[i]); err != nil { - return err - } - w.RandomNumber = uint16(randomWorldNum()) - - // Update - if _, err := worldUpdateStmt.Exec(w.RandomNumber, w.ID); err != nil { - return err - } - } - - return c.JSON(http.StatusOK, worlds) -} - -func plaintextHandler(c *clevergo.Context) error { - return c.String(http.StatusOK, helloWorld) -} - -type Message struct { - Message string `json:"message"` -} - -func jsonHandler(c *clevergo.Context) error { - return c.JSON(http.StatusOK, Message{"Hello, World!"}) -} diff --git a/frameworks/Go/echo/echo.dockerfile b/frameworks/Go/echo/echo.dockerfile index ccc8c0186d2..ccb80b19211 100644 --- a/frameworks/Go/echo/echo.dockerfile +++ b/frameworks/Go/echo/echo.dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/golang:1.19 +FROM docker.io/golang:1.24.2 ADD ./src /echo WORKDIR /echo diff --git a/frameworks/Go/echo/src/go.mod b/frameworks/Go/echo/src/go.mod index 29ed5d97b1e..53560874b16 100644 --- a/frameworks/Go/echo/src/go.mod +++ b/frameworks/Go/echo/src/go.mod @@ -1,20 +1,26 @@ module echo/app -go 1.19 +go 1.23.0 + +toolchain go1.24.1 require ( - github.com/labstack/echo/v4 v4.9.0 - github.com/lib/pq v1.10.7 + github.com/jackc/pgx/v5 v5.7.4 + github.com/labstack/echo/v4 v4.13.3 ) require ( - github.com/labstack/gommon v0.3.1 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.16 // 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/labstack/gommon v0.4.2 // indirect + github.com/mattn/go-colorable v0.1.14 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/fasttemplate v1.2.1 // indirect - golang.org/x/crypto v0.14.0 // indirect - golang.org/x/net v0.17.0 // indirect - golang.org/x/sys v0.13.0 // indirect - golang.org/x/text v0.13.0 // indirect + github.com/valyala/fasttemplate v1.2.2 // indirect + golang.org/x/crypto v0.36.0 // indirect + golang.org/x/net v0.38.0 // indirect + golang.org/x/sync v0.12.0 // indirect + golang.org/x/sys v0.31.0 // indirect + golang.org/x/text v0.23.0 // indirect ) diff --git a/frameworks/Go/echo/src/go.sum b/frameworks/Go/echo/src/go.sum index 320ff5c30de..d818aa63045 100644 --- a/frameworks/Go/echo/src/go.sum +++ b/frameworks/Go/echo/src/go.sum @@ -1,40 +1,45 @@ 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/labstack/echo/v4 v4.9.0 h1:wPOF1CE6gvt/kmbMR4dGzWvHMPT+sAEUJOwOTtvITVY= -github.com/labstack/echo/v4 v4.9.0/go.mod h1:xkCDAdFCIf8jsFQ5NnbK7oqaF/yU1A1X20Ltm0OvSks= -github.com/labstack/gommon v0.3.1 h1:OomWaJXm7xR6L1HmEtGyQf26TEn7V6X88mktX9kee9o= -github.com/labstack/gommon v0.3.1/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= -github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= -github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +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/labstack/echo/v4 v4.13.3 h1:pwhpCPrTl5qry5HRdM5FwdXnhXSLSY+WE+YQSeCaafY= +github.com/labstack/echo/v4 v4.13.3/go.mod h1:o90YNEeQWjDozo584l7AwhJMHN0bOC4tAfg+Xox9q5g= +github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0= +github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU= +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/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.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +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.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 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/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4= -github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= -golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= +github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= +golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= +golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= +golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= +golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= +golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= +golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= +golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= +golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= 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.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/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/echo/src/main.go b/frameworks/Go/echo/src/main.go index ed999f215c0..4642ee2f5b1 100644 --- a/frameworks/Go/echo/src/main.go +++ b/frameworks/Go/echo/src/main.go @@ -1,9 +1,11 @@ package main import ( - "database/sql" + "context" "encoding/json" "fmt" + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgxpool" "html/template" "io" "log" @@ -13,7 +15,6 @@ import ( "strconv" "github.com/labstack/echo/v4" - _ "github.com/lib/pq" ) type ( @@ -79,10 +80,7 @@ const ( var ( // Database - db *sql.DB - worldSelectStmt *sql.Stmt - worldUpdateStmt *sql.Stmt - fortuneSelectStmt *sql.Stmt + db *pgxpool.Pool // Template Template = &StdTemplate{ @@ -120,8 +118,9 @@ func (h *handler) json() echo.HandlerFunc { // Test 2: Single database query func (h *handler) db() echo.HandlerFunc { return func(c echo.Context) error { + ctx := c.Request().Context() world := new(World) - if err := fetchRandomWorld(world); err != nil { + if err := fetchRandomWorld(ctx, world); err != nil { return err } @@ -134,10 +133,11 @@ func (h *handler) db() echo.HandlerFunc { // Test 3: Multiple database queries func (h *handler) queries() echo.HandlerFunc { return func(c echo.Context) error { + ctx := c.Request().Context() n := getQueryCount(c.QueryParam("n")) worlds := make([]World, n) for i := 0; i < n; i++ { - if err := fetchRandomWorld(&worlds[i]); err != nil { + if err := fetchRandomWorld(ctx, &worlds[i]); err != nil { return err } } @@ -151,7 +151,8 @@ func (h *handler) queries() echo.HandlerFunc { // Test 4: Fortunes func (h *handler) fortunes() echo.HandlerFunc { return func(c echo.Context) error { - rows, err := fortuneSelectStmt.Query() + ctx := c.Request().Context() + rows, err := db.Query(ctx, fortuneSelect) if err != nil { return fmt.Errorf("Error preparing statement: %v", err) } @@ -172,18 +173,19 @@ func (h *handler) fortunes() echo.HandlerFunc { // Test 5: Database updates func (h *handler) updates() echo.HandlerFunc { return func(c echo.Context) error { + ctx := c.Request().Context() n := getQueryCount(c.QueryParam("n")) worlds := make([]World, n) for i := 0; i < n; i++ { // Fetch and modify w := &worlds[i] - if err := fetchRandomWorld(&worlds[i]); err != nil { + if err := fetchRandomWorld(ctx, &worlds[i]); err != nil { return err } w.RandomNumber = uint16(randomWorldNum()) // Update - if _, err := worldUpdateStmt.Exec(w.RandomNumber, w.ID); err != nil { + if _, err := db.Exec(ctx, worldUpdate, w.RandomNumber, w.ID); err != nil { return fmt.Errorf("Error updating world row: %v", err) } } @@ -221,9 +223,9 @@ func (h *handler) plaintext() echo.HandlerFunc { } } -func fetchRandomWorld(w *World) error { +func fetchRandomWorld(ctx context.Context, w *World) error { n := randomWorldNum() - return worldSelectStmt.QueryRow(n).Scan(&w.ID, &w.RandomNumber) + return db.QueryRow(ctx, worldSelect, n).Scan(&w.ID, &w.RandomNumber) } func randomWorldNum() int { @@ -241,7 +243,7 @@ func getQueryCount(q string) int { return n } -func fetchFortunes(rows *sql.Rows) (Fortunes, error) { +func fetchFortunes(rows pgx.Rows) (Fortunes, error) { fortunes := make(Fortunes, 0) for rows.Next() { // Fetch rows f := new(Fortune) @@ -267,24 +269,17 @@ func InitPostgres() { host := "tfb-database" var err error - db, err = sql.Open("postgres", fmt.Sprintf(connectionString, host)) - if err != nil { - log.Fatalf("Error opening database: %v", err) - } - db.SetMaxIdleConns(maxConnections) - db.SetMaxOpenConns(maxConnections) - worldSelectStmt, err = db.Prepare(worldSelect) + dbCfg, err := pgxpool.ParseConfig(fmt.Sprintf(connectionString, host)) if err != nil { - log.Fatal(err) + log.Fatalf("Error reading database connection string: %v", err) } - worldUpdateStmt, err = db.Prepare(worldUpdate) - if err != nil { - log.Fatal(err) - } - fortuneSelectStmt, err = db.Prepare(fortuneSelect) + dbCfg.MaxConns = maxConnections + dbCfg.MinConns = maxConnections + + db, err = pgxpool.NewWithConfig(context.Background(), dbCfg) if err != nil { - log.Fatal(err) + log.Fatalf("Error opening database: %v", err) } } diff --git a/frameworks/Go/evio/README.md b/frameworks/Go/evio/README.md deleted file mode 100644 index 1d147be1529..00000000000 --- a/frameworks/Go/evio/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# [evio](https://github.com/tidwall/evio) (GoLang) Benchmarking Test - -This is the go portion of a [benchmarking test suite](https://www.techempower.com/benchmarks/) comparing a variety of web development platforms. - -"Golang Evio" - -## Test URLs - - http://localhost:8080/plaintext diff --git a/frameworks/Go/evio/benchmark_config.json b/frameworks/Go/evio/benchmark_config.json deleted file mode 100644 index 6c4d3495911..00000000000 --- a/frameworks/Go/evio/benchmark_config.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "framework": "evio", - "tests": [{ - "default": { - "plaintext_url": "/plaintext", - "port": 8080, - "approach": "Realistic", - "classification": "Platform", - "database": "None", - "framework": "evio", - "language": "Go", - "flavor": "None", - "orm": "Raw", - "platform": "None", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "Evio", - "notes": "", - "versus": "go" - }, - "stdlib": { - "plaintext_url": "/plaintext", - "port": 8080, - "approach": "Realistic", - "classification": "Platform", - "database": "None", - "framework": "evio", - "language": "Go", - "flavor": "None", - "orm": "Raw", - "platform": "None", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "Evio", - "notes": "", - "versus": "go" - } - }] -} \ No newline at end of file diff --git a/frameworks/Go/evio/config.toml b/frameworks/Go/evio/config.toml deleted file mode 100644 index 82b63effc16..00000000000 --- a/frameworks/Go/evio/config.toml +++ /dev/null @@ -1,26 +0,0 @@ -[framework] -name = "evio" - -[main] -urls.plaintext = "/plaintext" -approach = "Realistic" -classification = "Platform" -database = "None" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "None" -webserver = "None" -versus = "go" - -[stdlib] -urls.plaintext = "/plaintext" -approach = "Realistic" -classification = "Platform" -database = "None" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "None" -webserver = "None" -versus = "go" diff --git a/frameworks/Go/evio/evio-stdlib.dockerfile b/frameworks/Go/evio/evio-stdlib.dockerfile deleted file mode 100644 index 941bc78797b..00000000000 --- a/frameworks/Go/evio/evio-stdlib.dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM docker.io/golang:1.19 - -WORKDIR /evio - -COPY ./src /evio - -RUN GOAMD64=v3 go build -ldflags="-s -w" -o app . - -EXPOSE 8080 - -CMD ./app -stdlib diff --git a/frameworks/Go/evio/evio.dockerfile b/frameworks/Go/evio/evio.dockerfile deleted file mode 100644 index b8fa848ac18..00000000000 --- a/frameworks/Go/evio/evio.dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM docker.io/golang:1.19 - -WORKDIR /evio - -COPY ./src /evio - -RUN GOAMD64=v3 go build -ldflags="-s -w" -o app . - -EXPOSE 8080 - -CMD ./app diff --git a/frameworks/Go/evio/src/go.mod b/frameworks/Go/evio/src/go.mod deleted file mode 100644 index f7858c6290a..00000000000 --- a/frameworks/Go/evio/src/go.mod +++ /dev/null @@ -1,7 +0,0 @@ -module evio/app - -go 1.19 - -require github.com/tidwall/evio v1.0.8 - -require github.com/kavu/go_reuseport v1.5.0 // indirect diff --git a/frameworks/Go/evio/src/go.sum b/frameworks/Go/evio/src/go.sum deleted file mode 100644 index a23d6dc0c9e..00000000000 --- a/frameworks/Go/evio/src/go.sum +++ /dev/null @@ -1,4 +0,0 @@ -github.com/kavu/go_reuseport v1.5.0 h1:UNuiY2OblcqAtVDE8Gsg1kZz8zbBWg907sP1ceBV+bk= -github.com/kavu/go_reuseport v1.5.0/go.mod h1:CG8Ee7ceMFSMnx/xr25Vm0qXaj2Z4i5PWoUx+JZ5/CU= -github.com/tidwall/evio v1.0.8 h1:+M7lh83rL4KwEObDGtXP3J1wE5utH80LeaAhrKCGVfE= -github.com/tidwall/evio v1.0.8/go.mod h1:MJhRp4iVVqx/n/5mJk77oKmSABVhC7yYykcJiKaFYYw= diff --git a/frameworks/Go/evio/src/main.go b/frameworks/Go/evio/src/main.go deleted file mode 100644 index c24aa24aea8..00000000000 --- a/frameworks/Go/evio/src/main.go +++ /dev/null @@ -1,225 +0,0 @@ -// Copyright 2017 Joshua J Baker. All rights reserved. -// Use of this source code is governed by an MIT-style -// license that can be found in the LICENSE file. - -package main - -import ( - "flag" - "fmt" - "log" - "strconv" - "strings" - "time" - - "github.com/tidwall/evio" -) - -var res string - -type request struct { - proto, method string - path, query string - head, body string - remoteAddr string -} - -func main() { - var port int - var loops int - var unixsocket string - var stdlib bool - - flag.StringVar(&unixsocket, "unixsocket", "", "unix socket") - flag.IntVar(&port, "port", 8080, "server port") - flag.BoolVar(&stdlib, "stdlib", false, "use stdlib") - flag.IntVar(&loops, "loops", -1, "num loops") - flag.Parse() - - res = "Hello, World!" - - var events evio.Events - events.NumLoops = loops - - events.Serving = func(srv evio.Server) (action evio.Action) { - log.Printf("http server started on port %d (loops: %d)", port, srv.NumLoops) - if unixsocket != "" { - log.Printf("http server started at %s", unixsocket) - } - if stdlib { - log.Printf("http server is using stdlib") - } - return - } - - events.Opened = func(c evio.Conn) (out []byte, opts evio.Options, action evio.Action) { - c.SetContext(&evio.InputStream{}) - return - } - - events.Closed = func(c evio.Conn, err error) (action evio.Action) { - return - } - - events.Data = func(c evio.Conn, in []byte) (out []byte, action evio.Action) { - if in == nil { - return - } - is := c.Context().(*evio.InputStream) - data := is.Begin(in) - - // buf := bufio.NewReader(bytes.NewReader(data)) - // req, err := http.ReadRequest(buf) - // if err != nil { - // log.Println(err) - // is.End(data) - // return - // } - // t := &http.Response{ - // Status: "200 OK", - // StatusCode: 200, - // Proto: "HTTP/1.1", - // ProtoMajor: 1, - // ProtoMinor: 1, - // Body: ioutil.NopCloser(bytes.NewBufferString(res)), - // ContentLength: int64(len(res)), - // Request: req, - // Header: make(http.Header, 0), - // } - // resp := bytes.NewBuffer(nil) - // t.Write(resp) - // out = resp.Bytes() - - // process the pipeline - var req request - for { - leftover, err := parsereq(data, &req) - if err != nil { - // bad thing happened - out = appendresp(out, "500 Error", "", err.Error()+"\n") - action = evio.Close - break - } else if len(leftover) == len(data) { - // request not ready, yet - break - } - // handle the request - req.remoteAddr = c.RemoteAddr().String() - out = appendhandle(out, &req) - data = leftover - } - is.End(data) - return - } - var ssuf string - if stdlib { - ssuf = "-net" - } - // We at least want the single http address. - addrs := []string{fmt.Sprintf("tcp"+ssuf+"://:%d", port)} - if unixsocket != "" { - addrs = append(addrs, fmt.Sprintf("unix"+ssuf+"://%s", unixsocket)) - } - // Start serving! - log.Fatal(evio.Serve(events, addrs...)) -} - -// appendhandle handles the incoming request and appends the response to -// the provided bytes, which is then returned to the caller. -func appendhandle(b []byte, req *request) []byte { - return appendresp(b, "200 OK", "", res) -} - -// appendresp will append a valid http response to the provide bytes. -// The status param should be the code plus text such as "200 OK". -// The head parameter should be a series of lines ending with "\r\n" or empty. -func appendresp(b []byte, status, head, body string) []byte { - b = append(b, "HTTP/1.1"...) - b = append(b, ' ') - b = append(b, status...) - b = append(b, '\r', '\n') - b = append(b, "Server: evio\r\n"...) - b = append(b, "Content-Type: text/plain\r\n"...) - b = append(b, "Date: "...) - b = time.Now().AppendFormat(b, "Mon, 02 Jan 2006 15:04:05 GMT") - b = append(b, '\r', '\n') - if len(body) > 0 { - b = append(b, "Content-Length: "...) - b = strconv.AppendInt(b, int64(len(body)), 10) - b = append(b, '\r', '\n') - } - b = append(b, head...) - b = append(b, '\r', '\n') - if len(body) > 0 { - b = append(b, body...) - } - return b -} - -// parsereq is a very simple http request parser. This operation -// waits for the entire payload to be buffered before returning a -// valid request. -func parsereq(data []byte, req *request) (leftover []byte, err error) { - sdata := string(data) - var i, s int - var top string - var clen int - var q = -1 - // method, path, proto line - for ; i < len(sdata); i++ { - if sdata[i] == ' ' { - req.method = sdata[s:i] - for i, s = i+1, i+1; i < len(sdata); i++ { - if sdata[i] == '?' && q == -1 { - q = i - s - } else if sdata[i] == ' ' { - if q != -1 { - req.path = sdata[s:q] - req.query = req.path[q+1 : i] - } else { - req.path = sdata[s:i] - } - for i, s = i+1, i+1; i < len(sdata); i++ { - if sdata[i] == '\n' && sdata[i-1] == '\r' { - req.proto = sdata[s:i] - i, s = i+1, i+1 - break - } - } - break - } - } - break - } - } - if req.proto == "" { - return data, fmt.Errorf("malformed request") - } - top = sdata[:s] - for ; i < len(sdata); i++ { - if i > 1 && sdata[i] == '\n' && sdata[i-1] == '\r' { - line := sdata[s : i-1] - s = i + 1 - if line == "" { - req.head = sdata[len(top)+2 : i+1] - i++ - if clen > 0 { - if len(sdata[i:]) < clen { - break - } - req.body = sdata[i : i+clen] - i += clen - } - return data[i:], nil - } - if strings.HasPrefix(line, "Content-Length:") { - n, err := strconv.ParseInt(strings.TrimSpace(line[len("Content-Length:"):]), 10, 64) - if err == nil { - clen = int(n) - } - } - } - } - // not enough data - return data, nil -} diff --git a/frameworks/Go/fasthttp/fasthttp-prefork.dockerfile b/frameworks/Go/fasthttp/fasthttp-prefork.dockerfile index 168ead214b6..01cbcf4a4ed 100644 --- a/frameworks/Go/fasthttp/fasthttp-prefork.dockerfile +++ b/frameworks/Go/fasthttp/fasthttp-prefork.dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/golang:1.19 +FROM docker.io/golang:1.24.2 WORKDIR /fasthttp diff --git a/frameworks/Go/fasthttp/fasthttp.dockerfile b/frameworks/Go/fasthttp/fasthttp.dockerfile index 0fb465487ba..b7b74b0a7ab 100644 --- a/frameworks/Go/fasthttp/fasthttp.dockerfile +++ b/frameworks/Go/fasthttp/fasthttp.dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/golang:1.19 +FROM docker.io/golang:1.24.2 WORKDIR /fasthttp diff --git a/frameworks/Go/fasthttp/src/go.mod b/frameworks/Go/fasthttp/src/go.mod index c02732cecb8..b7f1bc305c5 100644 --- a/frameworks/Go/fasthttp/src/go.mod +++ b/frameworks/Go/fasthttp/src/go.mod @@ -1,28 +1,29 @@ module fasthttp/app -go 1.19 +go 1.23.0 + +toolchain go1.24.1 require ( - github.com/jackc/pgx/v4 v4.17.2 - github.com/savsgio/gotils v0.0.0-20220530130905-52f3993e8d6d - github.com/valyala/fasthttp v1.40.0 - github.com/valyala/quicktemplate v1.7.0 + github.com/jackc/pgx/v4 v4.18.3 + github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38 + github.com/valyala/fasthttp v1.60.0 + github.com/valyala/quicktemplate v1.8.0 ) require ( - github.com/andybalholm/brotli v1.0.4 // indirect + github.com/andybalholm/brotli v1.1.1 // indirect github.com/jackc/chunkreader/v2 v2.0.1 // indirect - github.com/jackc/pgconn v1.13.0 // indirect + github.com/jackc/pgconn v1.14.3 // indirect github.com/jackc/pgio v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect - github.com/jackc/pgproto3/v2 v2.3.1 // indirect - github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect - github.com/jackc/pgtype v1.12.0 // indirect + github.com/jackc/pgproto3/v2 v2.3.3 // indirect + github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect + github.com/jackc/pgtype v1.14.4 // indirect github.com/jackc/puddle v1.3.0 // indirect - github.com/klauspost/compress v1.15.10 // indirect + github.com/klauspost/compress v1.18.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/tcplisten v1.0.0 // indirect - golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 // indirect - golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41 // indirect - golang.org/x/text v0.3.8 // indirect + golang.org/x/crypto v0.36.0 // indirect + golang.org/x/sys v0.31.0 // indirect + golang.org/x/text v0.23.0 // indirect ) diff --git a/frameworks/Go/fasthttp/src/go.sum b/frameworks/Go/fasthttp/src/go.sum index 6511752d850..b99b3205212 100644 --- a/frameworks/Go/fasthttp/src/go.sum +++ b/frameworks/Go/fasthttp/src/go.sum @@ -1,9 +1,7 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= -github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= -github.com/andybalholm/brotli v1.0.3/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= -github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY= -github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA= +github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA= github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= @@ -17,9 +15,7 @@ github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= @@ -30,8 +26,8 @@ github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsU github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= -github.com/jackc/pgconn v1.13.0 h1:3L1XMNV2Zvca/8BYhzcRFS70Lr0WlDg16Di6SFGAbys= -github.com/jackc/pgconn v1.13.0/go.mod h1:AnowpAqO4CMIIJNZl2VJp+KrkAZciAkhEl0W0JIobpI= +github.com/jackc/pgconn v1.14.3 h1:bVoTr12EGANZz66nZPkMInAV/KHD2TxH9npjXXgiB3w= +github.com/jackc/pgconn v1.14.3/go.mod h1:RZbme4uasqzybK2RK5c65VsHxoyaml09lx3tXOcO/VM= github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= @@ -47,33 +43,34 @@ github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvW github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.3.1 h1:nwj7qwf0S+Q7ISFfBndqeLwSwxs+4DPsbRFjECT1Y4Y= -github.com/jackc/pgproto3/v2 v2.3.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg= +github.com/jackc/pgproto3/v2 v2.3.3 h1:1HLSx5H+tXR9pW3in3zaztoEwQYRC9SQaYUHjTSUOag= +github.com/jackc/pgproto3/v2 v2.3.3/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +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/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= -github.com/jackc/pgtype v1.12.0 h1:Dlq8Qvcch7kiehm8wPGIW0W3KsCCHJnRacKW0UM8n5w= -github.com/jackc/pgtype v1.12.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= +github.com/jackc/pgtype v1.14.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= +github.com/jackc/pgtype v1.14.4 h1:fKuNiCumbKTAIxQwXfB/nsrnkEI6bPJrrSiMKgbJ2j8= +github.com/jackc/pgtype v1.14.4/go.mod h1:aKeozOde08iifGosdJpz9MBZonJOUJxqNpPBcMJTlVA= github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= -github.com/jackc/pgx/v4 v4.17.2 h1:0Ut0rpeKwvIVbMQ1KbMBU4h6wxehBI535LK6Flheh8E= -github.com/jackc/pgx/v4 v4.17.2/go.mod h1:lcxIZN44yMIrWI78a5CpucdD14hX0SBDbNRvjDBItsw= +github.com/jackc/pgx/v4 v4.18.2/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw= +github.com/jackc/pgx/v4 v4.18.3 h1:dE2/TrEsGX3RBprb3qryqSV9Y60iZN1C6i8IrmW9/BA= +github.com/jackc/pgx/v4 v4.18.3/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw= github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.3.0 h1:eHK/5clGOatcjX3oWGBO/MpxpbHzSwud5EWTSCI+MX0= github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= -github.com/klauspost/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.15.10 h1:Ai8UzuomSCDw90e1qNMtb15msBXsNpH6gzkkENQNcJo= -github.com/klauspost/compress v1.15.10/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= +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/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -99,8 +96,8 @@ 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= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/savsgio/gotils v0.0.0-20220530130905-52f3993e8d6d h1:Q+gqLBOPkFGHyCJxXMRqtUgUbTjI8/Ze8vu8GGyNFwo= -github.com/savsgio/gotils v0.0.0-20220530130905-52f3993e8d6d/go.mod h1:Gy+0tqhJvgGlqnTF8CVGP0AaGRjwBtXs/a5PA0Y3+A4= +github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38 h1:D0vL7YNisV2yqE55+q0lFuGse6U8lxlg7fYTctlT5Gc= +github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38/go.mod h1:sM7Mt7uEoCeFSCBM+qBrqvEo+/9vdmj19wzp3yzUhmg= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= @@ -110,23 +107,25 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +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.30.0/go.mod h1:2rsYD01CKFrjjsvFxx75KlEUNpWNBY9JWD3K/7o2Cus= -github.com/valyala/fasthttp v1.40.0 h1:CRq/00MfruPGFLTQKY8b+8SfdK60TxNztjRMnH0t1Yc= -github.com/valyala/fasthttp v1.40.0/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I= -github.com/valyala/quicktemplate v1.7.0 h1:LUPTJmlVcb46OOUY3IeD9DojFpAVbsG+5WFTcjMJzCM= -github.com/valyala/quicktemplate v1.7.0/go.mod h1:sqKJnoaOF88V07vkO+9FL8fb9uZg/VPSJnLYn+LmLk8= -github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= -github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= +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= +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.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= @@ -146,25 +145,30 @@ golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM= -golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.20.0/go.mod h1:Xwo95rrVNIoSMx9wa1JroENMToLWn3RNVrTBpLHgZPQ= +golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= +golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -176,24 +180,31 @@ golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41 h1:ohgcoMbSofXygzo6AD2I1kz3BFmW1QArPYTtwEM3UXc= -golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.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/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= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= +golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -201,7 +212,10 @@ golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/frameworks/Go/fiber/fiber-prefork.dockerfile b/frameworks/Go/fiber/fiber-prefork.dockerfile index 85acc26ef6b..13e45eb4cba 100644 --- a/frameworks/Go/fiber/fiber-prefork.dockerfile +++ b/frameworks/Go/fiber/fiber-prefork.dockerfile @@ -1,14 +1,18 @@ -FROM docker.io/golang:1.20 +FROM golang:1.24.2-alpine as builder WORKDIR /fiber COPY ./src /fiber -RUN go mod download +RUN go mod download && \ + go generate -x ./templates && \ + GOAMD64=v3 go build -ldflags="-s -w" -o app . -RUN go generate -x ./templates +FROM alpine:latest -RUN GOAMD64=v3 go build -ldflags="-s -w" -o app . +WORKDIR /fiber + +COPY --from=builder /fiber/app . EXPOSE 8080 diff --git a/frameworks/Go/fiber/fiber.dockerfile b/frameworks/Go/fiber/fiber.dockerfile index 37f02a59405..fc82a07891c 100644 --- a/frameworks/Go/fiber/fiber.dockerfile +++ b/frameworks/Go/fiber/fiber.dockerfile @@ -1,14 +1,18 @@ -FROM docker.io/golang:1.20 +FROM golang:1.24.2-alpine as builder WORKDIR /fiber COPY ./src /fiber -RUN go mod download +RUN go mod download && \ + go generate -x ./templates && \ + GOAMD64=v3 go build -ldflags="-s -w" -o app . -RUN go generate -x ./templates +FROM alpine:latest -RUN GOAMD64=v3 go build -ldflags="-s -w" -o app . +WORKDIR /fiber + +COPY --from=builder /fiber/app . EXPOSE 8080 diff --git a/frameworks/Go/fiber/src/go.mod b/frameworks/Go/fiber/src/go.mod index cc77f3409c8..6e1dcc6247f 100644 --- a/frameworks/Go/fiber/src/go.mod +++ b/frameworks/Go/fiber/src/go.mod @@ -1,31 +1,31 @@ module fiber/app -go 1.19 +go 1.24.0 + +toolchain go1.24.1 require ( - github.com/goccy/go-json v0.10.0 - github.com/gofiber/fiber/v2 v2.50.0 - github.com/jackc/pgx/v5 v5.2.0 - github.com/valyala/quicktemplate v1.7.0 + 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.0.5 // indirect - github.com/google/uuid v1.3.1 // indirect + 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-20200714003250-2b9c44734f2b // indirect - github.com/jackc/puddle/v2 v2.1.2 // indirect - github.com/klauspost/compress v1.16.7 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.19 // indirect - github.com/mattn/go-runewidth v0.0.15 // indirect - github.com/rivo/uniseg v0.2.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.50.0 // indirect - github.com/valyala/tcplisten v1.0.0 // indirect - go.uber.org/atomic v1.10.0 // indirect - golang.org/x/crypto v0.7.0 // indirect - golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.13.0 // indirect - golang.org/x/text v0.8.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 index 8781721ebb7..bbb70d60f3f 100644 --- a/frameworks/Go/fiber/src/go.sum +++ b/frameworks/Go/fiber/src/go.sum @@ -1,74 +1,58 @@ -github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= -github.com/andybalholm/brotli v1.0.3/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= -github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= -github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +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/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA= -github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= -github.com/gofiber/fiber/v2 v2.50.0 h1:ia0JaB+uw3GpNSCR5nvC5dsaxXjRU5OEu36aytx+zGw= -github.com/gofiber/fiber/v2 v2.50.0/go.mod h1:21eytvay9Is7S6z+OgPi7c7n4++tnClWmhpimVHMimw= -github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= -github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +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-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg= -github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= -github.com/jackc/pgx/v5 v5.2.0 h1:NdPpngX0Y6z6XDFKqmFQaE+bCtkqzvQIOt1wvBlAqs8= -github.com/jackc/pgx/v5 v5.2.0/go.mod h1:Ptn7zmohNsWEsdxRawMzk3gaKma2obW+NWTnKa0S4nk= -github.com/jackc/puddle/v2 v2.1.2 h1:0f7vaaXINONKTsxYDn4otOAiJanX/BMeAtY//BXqzlg= -github.com/jackc/puddle/v2 v2.1.2/go.mod h1:2lpufsF5mRHO6SuZkm0fNYxM6SWHfvyFj62KwNzgels= -github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= -github.com/klauspost/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= -github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= -github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +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 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= 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.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +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.30.0/go.mod h1:2rsYD01CKFrjjsvFxx75KlEUNpWNBY9JWD3K/7o2Cus= -github.com/valyala/fasthttp v1.50.0 h1:H7fweIlBm0rXLs2q0XbalvJ6r0CUPFWK3/bB4N13e9M= -github.com/valyala/fasthttp v1.50.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA= -github.com/valyala/quicktemplate v1.7.0 h1:LUPTJmlVcb46OOUY3IeD9DojFpAVbsG+5WFTcjMJzCM= -github.com/valyala/quicktemplate v1.7.0/go.mod h1:sqKJnoaOF88V07vkO+9FL8fb9uZg/VPSJnLYn+LmLk8= -github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= -github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= -go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= -go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= -golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= -golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +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.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +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.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +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_test.go b/frameworks/Go/fiber/src/server_test.go index 84ec001a54c..3fcb783d8bb 100644 --- a/frameworks/Go/fiber/src/server_test.go +++ b/frameworks/Go/fiber/src/server_test.go @@ -1,8 +1,7 @@ package main import ( - "encoding/json" - "io/ioutil" + "io" "net/http" "net/http/httptest" "testing" @@ -37,7 +36,7 @@ func Benchmark_Plaintext(b *testing.B) { utils.AssertEqual(b, nil, err, "app.Test(req)") utils.AssertEqual(b, 200, resp.StatusCode, "Status code") utils.AssertEqual(b, fiber.MIMETextPlainCharsetUTF8, resp.Header.Get("Content-Type")) - body, _ := ioutil.ReadAll(resp.Body) + body, _ := io.ReadAll(resp.Body) utils.AssertEqual(b, helloworldRaw, body) } @@ -66,6 +65,6 @@ func Benchmark_JSON(b *testing.B) { utils.AssertEqual(b, nil, err, "app.Test(req)") utils.AssertEqual(b, 200, resp.StatusCode, "Status code") utils.AssertEqual(b, fiber.MIMEApplicationJSON, resp.Header.Get("Content-Type")) - body, _ := ioutil.ReadAll(resp.Body) + body, _ := io.ReadAll(resp.Body) utils.AssertEqual(b, `{"message":"Hello, World!"}`, string(body)) } diff --git a/frameworks/Go/gearbox/README.md b/frameworks/Go/gearbox/README.md deleted file mode 100644 index b96364ebace..00000000000 --- a/frameworks/Go/gearbox/README.md +++ /dev/null @@ -1,18 +0,0 @@ -

- - - -

- -

- gearbox ⚙️is a web framework for building micro services written in Go with a focus on high performance. It's built on fasthttp which is up to 10x faster than net/http -

- -## Test URLs -* http://localhost:8080/json -* http://localhost:8080/db -* http://localhost:8080/queries?queries=[1-500] -* http://localhost:8080/cached-worlds?count=[1-500] -* http://localhost:8080/fortune -* http://localhost:8080/update?queries=[1-500] -* http://localhost:8080/plaintext diff --git a/frameworks/Go/gearbox/benchmark_config.json b/frameworks/Go/gearbox/benchmark_config.json deleted file mode 100644 index d8b77581c08..00000000000 --- a/frameworks/Go/gearbox/benchmark_config.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "framework": "gearbox", - "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": "gearbox", - "language": "Go", - "flavor": "None", - "orm": "Raw", - "platform": "None", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "Gearbox", - "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": "gearbox", - "language": "Go", - "flavor": "None", - "orm": "Raw", - "platform": "None", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "Gearbox prefork", - "notes": "", - "versus": "go" - } - } - ] -} \ No newline at end of file diff --git a/frameworks/Go/gearbox/config.toml b/frameworks/Go/gearbox/config.toml deleted file mode 100644 index fdbd00e15e6..00000000000 --- a/frameworks/Go/gearbox/config.toml +++ /dev/null @@ -1,38 +0,0 @@ -[framework] -name = "gearbox" - -[main] -urls.plaintext = "/plaintext" -urls.json = "/json" -urls.db = "/db" -urls.query = "/queries?q=" -urls.update = "/update?q=" -urls.fortune = "/fortunes" -urls.cached_query = "/cached-worlds?q=" -approach = "Realistic" -classification = "Platform" -database = "Postgres" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "None" -webserver = "None" -versus = "go" - -[prefork] -urls.plaintext = "/plaintext" -urls.json = "/json" -urls.db = "/db" -urls.query = "/queries?q=" -urls.update = "/update?q=" -urls.fortune = "/fortunes" -urls.cached_query = "/cached-worlds?q=" -approach = "Realistic" -classification = "Platform" -database = "Postgres" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "None" -webserver = "None" -versus = "go" diff --git a/frameworks/Go/gearbox/gearbox-prefork.dockerfile b/frameworks/Go/gearbox/gearbox-prefork.dockerfile deleted file mode 100644 index c7863feabf7..00000000000 --- a/frameworks/Go/gearbox/gearbox-prefork.dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM docker.io/golang:1.19 - -WORKDIR /gearbox - -COPY ./src /gearbox - -RUN go generate -x ./templates - -RUN GOAMD64=v3 go build -ldflags="-s -w" -o app . - -EXPOSE 8080 - -CMD ./app -prefork diff --git a/frameworks/Go/gearbox/gearbox.dockerfile b/frameworks/Go/gearbox/gearbox.dockerfile deleted file mode 100644 index 8a78ce290a5..00000000000 --- a/frameworks/Go/gearbox/gearbox.dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM docker.io/golang:1.19 - -WORKDIR /gearbox - -COPY ./src /gearbox - -RUN go generate -x ./templates - -RUN GOAMD64=v3 go build -ldflags="-s -w" -o app . - -EXPOSE 8080 - -CMD ./app diff --git a/frameworks/Go/gearbox/src/go.mod b/frameworks/Go/gearbox/src/go.mod deleted file mode 100644 index f2a5cc6785b..00000000000 --- a/frameworks/Go/gearbox/src/go.mod +++ /dev/null @@ -1,31 +0,0 @@ -module gearbox/app - -go 1.19 - -require ( - github.com/gogearbox/gearbox v1.2.4 - github.com/jackc/pgx/v4 v4.17.2 - github.com/valyala/quicktemplate v1.7.0 -) - -require ( - github.com/andybalholm/brotli v1.0.4 // indirect - github.com/jackc/chunkreader/v2 v2.0.1 // indirect - github.com/jackc/pgconn v1.13.0 // indirect - github.com/jackc/pgio v1.0.0 // indirect - github.com/jackc/pgpassfile v1.0.0 // indirect - github.com/jackc/pgproto3/v2 v2.3.1 // indirect - github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect - github.com/jackc/pgtype v1.12.0 // indirect - github.com/jackc/puddle v1.3.0 // indirect - github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.15.10 // indirect - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/fasthttp v1.40.0 // indirect - github.com/valyala/tcplisten v1.0.0 // indirect - golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 // indirect - golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41 // indirect - golang.org/x/text v0.3.8 // indirect -) diff --git a/frameworks/Go/gearbox/src/go.sum b/frameworks/Go/gearbox/src/go.sum deleted file mode 100644 index 9f9e9083572..00000000000 --- a/frameworks/Go/gearbox/src/go.sum +++ /dev/null @@ -1,226 +0,0 @@ -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= -github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= -github.com/andybalholm/brotli v1.0.3/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= -github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY= -github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= -github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= -github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= -github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= -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/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-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= -github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/gogearbox/gearbox v1.2.4 h1:h7GNxGRltV63UCGl0smFWKAhScMkFlc5dCZi9k/fFqo= -github.com/gogearbox/gearbox v1.2.4/go.mod h1:IIUyEDzcMVjnA8bkUM7etHHrgzVj70naUDlE2QZk/QU= -github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= -github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= -github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= -github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= -github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= -github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE= -github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s= -github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= -github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= -github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= -github.com/jackc/pgconn v1.13.0 h1:3L1XMNV2Zvca/8BYhzcRFS70Lr0WlDg16Di6SFGAbys= -github.com/jackc/pgconn v1.13.0/go.mod h1:AnowpAqO4CMIIJNZl2VJp+KrkAZciAkhEl0W0JIobpI= -github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= -github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= -github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= -github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c= -github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc= -github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak= -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/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= -github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA= -github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg= -github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= -github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= -github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.3.1 h1:nwj7qwf0S+Q7ISFfBndqeLwSwxs+4DPsbRFjECT1Y4Y= -github.com/jackc/pgproto3/v2 v2.3.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg= -github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= -github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= -github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= -github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= -github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= -github.com/jackc/pgtype v1.12.0 h1:Dlq8Qvcch7kiehm8wPGIW0W3KsCCHJnRacKW0UM8n5w= -github.com/jackc/pgtype v1.12.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= -github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= -github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= -github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= -github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= -github.com/jackc/pgx/v4 v4.17.2 h1:0Ut0rpeKwvIVbMQ1KbMBU4h6wxehBI535LK6Flheh8E= -github.com/jackc/pgx/v4 v4.17.2/go.mod h1:lcxIZN44yMIrWI78a5CpucdD14hX0SBDbNRvjDBItsw= -github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.3.0 h1:eHK/5clGOatcjX3oWGBO/MpxpbHzSwud5EWTSCI+MX0= -github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= -github.com/klauspost/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.15.10 h1:Ai8UzuomSCDw90e1qNMtb15msBXsNpH6gzkkENQNcJo= -github.com/klauspost/compress v1.15.10/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8= -github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= -github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -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.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -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= -github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= -github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= -github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= -github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -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.30.0/go.mod h1:2rsYD01CKFrjjsvFxx75KlEUNpWNBY9JWD3K/7o2Cus= -github.com/valyala/fasthttp v1.31.0/go.mod h1:2rsYD01CKFrjjsvFxx75KlEUNpWNBY9JWD3K/7o2Cus= -github.com/valyala/fasthttp v1.40.0 h1:CRq/00MfruPGFLTQKY8b+8SfdK60TxNztjRMnH0t1Yc= -github.com/valyala/fasthttp v1.40.0/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I= -github.com/valyala/quicktemplate v1.7.0 h1:LUPTJmlVcb46OOUY3IeD9DojFpAVbsG+5WFTcjMJzCM= -github.com/valyala/quicktemplate v1.7.0/go.mod h1:sqKJnoaOF88V07vkO+9FL8fb9uZg/VPSJnLYn+LmLk8= -github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= -github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= -github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= -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= -go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= -go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= -go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= -golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM= -golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41 h1:ohgcoMbSofXygzo6AD2I1kz3BFmW1QArPYTtwEM3UXc= -golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -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= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -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= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= diff --git a/frameworks/Go/gearbox/src/main.go b/frameworks/Go/gearbox/src/main.go deleted file mode 100644 index 5e933cf4421..00000000000 --- a/frameworks/Go/gearbox/src/main.go +++ /dev/null @@ -1,289 +0,0 @@ -package main - -import ( - "context" - "fmt" - "math/rand" - "os" - "runtime" - "sort" - "strconv" - "sync" - - "gearbox/app/templates" - - "github.com/gogearbox/gearbox" - pgx "github.com/jackc/pgx/v4" - "github.com/jackc/pgx/v4/pgxpool" -) - -var ( - child bool - 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" - contentType = "Content-Type" - contentTypeHTML = "text/html; charset=utf-8" -) - -func hasArgument(arg string) bool { - for i := range os.Args[1:] { - if os.Args[1:][i] == arg { - return true - } - } - return false -} - -func main() { - initDatabase() - - settings := &gearbox.Settings{ - ServerName: "go", - DisableHeaderNormalizing: true, - } - - if hasArgument("-prefork") { - settings.Prefork = true - } - if hasArgument("-prefork-child") { - child = true - } - - gb := gearbox.New(settings) - gb.Get("/plaintext", plaintextHandler) - gb.Get("/json", jsonHandler) - gb.Get("/db", dbHandler) - gb.Get("/update", updateHandler) - gb.Get("/queries", queriesHandler) - gb.Get("/fortunes", templateHandler) - gb.Get("/cached-worlds", cachedHandler) - gb.Start(":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() - if maxConn == 0 { - maxConn = 8 - } - if child { - maxConn = maxConn - } else { - maxConn = maxConn * 4 - } - - var err error - db, err = pgxpool.Connect(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(ctx gearbox.Context) { - m := AcquireJSON() - m.Message = helloworld - ctx.SendJSON(&m) - ReleaseJSON(m) -} - -// dbHandler : -func dbHandler(ctx gearbox.Context) { - w := AcquireWorld() - db.QueryRow(context.Background(), worldselectsql, RandomWorld()).Scan(&w.ID, &w.RandomNumber) - ctx.SendJSON(&w) - ReleaseWorld(w) -} - -// Frameworks/Go/fasthttp/src/server-postgresql/server.go#104 -func templateHandler(ctx gearbox.Context) { - 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 - }) - - ctx.Set(contentType, contentTypeHTML) - - templates.WriteFortunePage(ctx.Context(), fortunes) -} - -// queriesHandler : -func queriesHandler(ctx gearbox.Context) { - n := QueriesCount(ctx) - worlds := AcquireWorlds()[:n] - for i := 0; i < n; i++ { - w := &worlds[i] - db.QueryRow(context.Background(), worldselectsql, RandomWorld()).Scan(&w.ID, &w.RandomNumber) - } - ctx.SendJSON(&worlds) - ReleaseWorlds(worlds) -} - -// updateHandler : -func updateHandler(ctx gearbox.Context) { - n := QueriesCount(ctx) - 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() - ctx.SendJSON(&worlds) - ReleaseWorlds(worlds) -} - -var helloworldRaw = []byte("Hello, World!") - -// plaintextHandler : -func plaintextHandler(ctx gearbox.Context) { - ctx.SendBytes(helloworldRaw) -} - -// cachedHandler : -func cachedHandler(ctx gearbox.Context) { - n := QueriesCount(ctx) - worlds := AcquireWorlds()[:n] - for i := 0; i < n; i++ { - worlds[i] = cachedWorlds[RandomWorld()-1] - } - ctx.SendJSON(&worlds) - ReleaseWorlds(worlds) -} - -// RandomWorld : -func RandomWorld() int { - return rand.Intn(worldcount) + 1 -} - -// QueriesCount : -func QueriesCount(ctx gearbox.Context) int { - n, _ := strconv.Atoi(ctx.Query(queryparam)) - if n < 1 { - n = 1 - } else if n > 500 { - n = 500 - } - return n -} diff --git a/frameworks/Go/gin/gin-gorm.dockerfile b/frameworks/Go/gin/gin-gorm.dockerfile index dee2eceff93..665b4849c1c 100644 --- a/frameworks/Go/gin/gin-gorm.dockerfile +++ b/frameworks/Go/gin/gin-gorm.dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/golang:1.20-bullseye as build-env +FROM docker.io/golang:1.24.2 as build-env WORKDIR /src/ COPY ./gin-gorm /src/ diff --git a/frameworks/Go/gin/gin-gorm/go.mod b/frameworks/Go/gin/gin-gorm/go.mod index ff15c7e28ec..1660edbccf5 100644 --- a/frameworks/Go/gin/gin-gorm/go.mod +++ b/frameworks/Go/gin/gin-gorm/go.mod @@ -1,51 +1,49 @@ module gin-gorm/app -go 1.19 +go 1.24.0 + +toolchain go1.24.1 require ( - github.com/gin-gonic/gin v1.9.1 - gorm.io/driver/postgres v1.3.10 - gorm.io/gorm v1.23.9 + github.com/gin-gonic/gin v1.10.0 + gorm.io/driver/postgres v1.5.11 + gorm.io/gorm v1.25.12 ) require ( - github.com/bytedance/sonic v1.9.1 // indirect - github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect - github.com/gabriel-vasile/mimetype v1.4.2 // indirect - github.com/gin-contrib/sse v0.1.0 // indirect + github.com/bytedance/sonic v1.13.2 // indirect + github.com/bytedance/sonic/loader v0.2.4 // indirect + github.com/cloudwego/base64x v0.1.5 // indirect + github.com/gabriel-vasile/mimetype v1.4.8 // indirect + github.com/gin-contrib/sse v1.0.0 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.14.0 // indirect - github.com/goccy/go-json v0.10.2 // indirect - github.com/gofrs/uuid v4.3.0+incompatible // indirect + github.com/go-playground/validator/v10 v10.26.0 // indirect + github.com/goccy/go-json v0.10.5 // indirect github.com/google/go-cmp v0.5.9 // indirect - github.com/jackc/chunkreader/v2 v2.0.1 // indirect - github.com/jackc/pgconn v1.13.0 // indirect - github.com/jackc/pgio v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect - github.com/jackc/pgproto3/v2 v2.3.1 // indirect - github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect - github.com/jackc/pgtype v1.12.0 // indirect - github.com/jackc/pgx/v4 v4.17.2 // indirect + github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect + github.com/jackc/pgx/v5 v5.7.4 // indirect + github.com/jackc/puddle/v2 v2.2.2 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/cpuid/v2 v2.2.4 // indirect - github.com/leodido/go-urn v1.2.4 // indirect - github.com/lib/pq v1.10.7 // indirect - github.com/mattn/go-isatty v0.0.19 // indirect + github.com/klauspost/cpuid/v2 v2.2.10 // indirect + github.com/kr/text v0.1.0 // indirect + github.com/leodido/go-urn v1.4.0 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/pelletier/go-toml/v2 v2.0.8 // indirect - github.com/pkg/errors v0.9.1 // indirect - github.com/shopspring/decimal v1.3.1 // indirect + github.com/pelletier/go-toml/v2 v2.2.3 // indirect + github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect - github.com/ugorji/go/codec v1.2.11 // indirect - golang.org/x/arch v0.3.0 // indirect - golang.org/x/crypto v0.14.0 // indirect - golang.org/x/net v0.17.0 // indirect - golang.org/x/sys v0.13.0 // indirect - golang.org/x/text v0.13.0 // indirect - google.golang.org/protobuf v1.30.0 // indirect + github.com/ugorji/go/codec v1.2.12 // indirect + golang.org/x/arch v0.15.0 // indirect + golang.org/x/crypto v0.45.0 // indirect + golang.org/x/net v0.47.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 + google.golang.org/protobuf v1.36.6 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/frameworks/Go/gin/gin-gorm/go.sum b/frameworks/Go/gin/gin-gorm/go.sum index 04c15d31cc6..79a5ba8e1a4 100644 --- a/frameworks/Go/gin/gin-gorm/go.sum +++ b/frameworks/Go/gin/gin-gorm/go.sum @@ -1,267 +1,110 @@ -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc= -github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= -github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= -github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= -github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= -github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= -github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= -github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= -github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= -github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= -github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/bytedance/sonic v1.13.2 h1:8/H1FempDZqC4VqjptGo14QQlJx8VdZJegxs6wwfqpQ= +github.com/bytedance/sonic v1.13.2/go.mod h1:o68xyaF9u2gvVBuGHPlUVCy+ZfmNNO5ETf1+KgkJhz4= +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/cloudwego/base64x v0.1.5 h1:XPciSp1xaq2VCSt6lF0phncD4koWyULpl5bUxbfCyP4= +github.com/cloudwego/base64x v0.1.5/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= +github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= 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/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= -github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= -github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= -github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= -github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= -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/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM= +github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8= +github.com/gin-contrib/sse v1.0.0 h1:y3bT1mUWUxDpW4JLQg/HnTqV4rozuW4tC9eFKTxYI9E= +github.com/gin-contrib/sse v1.0.0/go.mod h1:zNuFdwarAygJBht0NTKiSi3jRf6RbqeILZ9Sp6Slhe0= +github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= +github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= -github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= -github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= -github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/gofrs/uuid v4.3.0+incompatible h1:CaSVZxm5B+7o45rtab4jC2G37WGYX1zQfuU2i6DSvnc= -github.com/gofrs/uuid v4.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc/iMaVtFbr3Sw2k= +github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo= +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/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= -github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= -github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= -github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= -github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= -github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE= -github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s= -github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= -github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= -github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= -github.com/jackc/pgconn v1.13.0 h1:3L1XMNV2Zvca/8BYhzcRFS70Lr0WlDg16Di6SFGAbys= -github.com/jackc/pgconn v1.13.0/go.mod h1:AnowpAqO4CMIIJNZl2VJp+KrkAZciAkhEl0W0JIobpI= -github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= -github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= -github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= -github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c= -github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc= -github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak= 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/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= -github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA= -github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg= -github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= -github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= -github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.3.1 h1:nwj7qwf0S+Q7ISFfBndqeLwSwxs+4DPsbRFjECT1Y4Y= -github.com/jackc/pgproto3/v2 v2.3.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg= -github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= -github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= -github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= -github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= -github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= -github.com/jackc/pgtype v1.12.0 h1:Dlq8Qvcch7kiehm8wPGIW0W3KsCCHJnRacKW0UM8n5w= -github.com/jackc/pgtype v1.12.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= -github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= -github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= -github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= -github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= -github.com/jackc/pgx/v4 v4.17.2 h1:0Ut0rpeKwvIVbMQ1KbMBU4h6wxehBI535LK6Flheh8E= -github.com/jackc/pgx/v4 v4.17.2/go.mod h1:lcxIZN44yMIrWI78a5CpucdD14hX0SBDbNRvjDBItsw= -github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +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/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= -github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= -github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= +github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= -github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= -github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= -github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= -github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +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/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= -github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= +github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= 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.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -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= -github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= -github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= -github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= -github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= -github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 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.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= -github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +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/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/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= -github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= -github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= -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= -go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= -go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= -go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= -golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= -golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= -golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= +github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +golang.org/x/arch v0.15.0 h1:QtOrQd0bTUnhNVNndMpLHNWrDmYzZ2KDqSrEymqInZw= +golang.org/x/arch v0.15.0/go.mod h1:JmwW7aLIoRUKgaTzhkiEFxvcEiQGyOg9BMonBJUS7EE= +golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= +golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= +golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= +golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= +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.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -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/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +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= +google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +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= -gorm.io/driver/postgres v1.3.10 h1:Fsd+pQpFMGlGxxVMUPJhNo8gG8B1lKtk8QQ4/VZZAJw= -gorm.io/driver/postgres v1.3.10/go.mod h1:whNfh5WhhHs96honoLjBAMwJGYEuA3m1hvgUbNXhPCw= -gorm.io/gorm v1.23.7/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= -gorm.io/gorm v1.23.9 h1:NSHG021i+MCznokeXR3udGaNyFyBQJW8MbjrJMVCfGw= -gorm.io/gorm v1.23.9/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= +gorm.io/driver/postgres v1.5.11 h1:ubBVAfbKEUld/twyKZ0IYn9rSQh448EdelLYk9Mv314= +gorm.io/driver/postgres v1.5.11/go.mod h1:DX3GReXH+3FPWGrrgffdvCk3DQ1dwDPdmbenSkweRGI= +gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8= +gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ= +nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= diff --git a/frameworks/Go/gin/gin-scratch.dockerfile b/frameworks/Go/gin/gin-scratch.dockerfile index 997e4c236ee..859a0b13b79 100644 --- a/frameworks/Go/gin/gin-scratch.dockerfile +++ b/frameworks/Go/gin/gin-scratch.dockerfile @@ -1,5 +1,5 @@ # build layer -FROM docker.io/golang:1.19-alpine as builder +FROM docker.io/golang:1.24.2-alpine as builder WORKDIR /gin COPY ./gin-std /gin diff --git a/frameworks/Go/gin/gin-src/go.mod b/frameworks/Go/gin/gin-src/go.mod index df6aca92639..35027ca96d1 100644 --- a/frameworks/Go/gin/gin-src/go.mod +++ b/frameworks/Go/gin/gin-src/go.mod @@ -1,35 +1,39 @@ module gin -go 1.19 +go 1.23.0 + +toolchain go1.24.1 require ( - github.com/gin-gonic/gin v1.9.1 - github.com/go-sql-driver/mysql v1.6.0 + github.com/gin-gonic/gin v1.10.0 + github.com/go-sql-driver/mysql v1.9.1 ) require ( - github.com/bytedance/sonic v1.9.1 // indirect - github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect - github.com/gabriel-vasile/mimetype v1.4.2 // indirect - github.com/gin-contrib/sse v0.1.0 // indirect + filippo.io/edwards25519 v1.1.0 // indirect + github.com/bytedance/sonic v1.13.2 // indirect + github.com/bytedance/sonic/loader v0.2.4 // indirect + github.com/cloudwego/base64x v0.1.5 // indirect + github.com/gabriel-vasile/mimetype v1.4.8 // indirect + github.com/gin-contrib/sse v1.0.0 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.14.0 // indirect - github.com/goccy/go-json v0.10.2 // indirect + github.com/go-playground/validator/v10 v10.26.0 // indirect + github.com/goccy/go-json v0.10.5 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/cpuid/v2 v2.2.4 // indirect - github.com/leodido/go-urn v1.2.4 // indirect - github.com/mattn/go-isatty v0.0.19 // indirect + github.com/klauspost/cpuid/v2 v2.2.10 // indirect + github.com/leodido/go-urn v1.4.0 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/pelletier/go-toml/v2 v2.0.8 // indirect + github.com/pelletier/go-toml/v2 v2.2.3 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect - github.com/ugorji/go/codec v1.2.11 // indirect - golang.org/x/arch v0.3.0 // indirect - golang.org/x/crypto v0.14.0 // indirect - golang.org/x/net v0.17.0 // indirect - golang.org/x/sys v0.13.0 // indirect - golang.org/x/text v0.13.0 // indirect - google.golang.org/protobuf v1.30.0 // indirect + github.com/ugorji/go/codec v1.2.12 // 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/text v0.23.0 // indirect + google.golang.org/protobuf v1.36.6 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/frameworks/Go/gin/gin-src/go.sum b/frameworks/Go/gin/gin-src/go.sum index 956d69bbd6b..c7fbc425b01 100644 --- a/frameworks/Go/gin/gin-src/go.sum +++ b/frameworks/Go/gin/gin-src/go.sum @@ -1,87 +1,90 @@ -github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= -github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= -github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= -github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= -github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= -github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/bytedance/sonic v1.13.2 h1:8/H1FempDZqC4VqjptGo14QQlJx8VdZJegxs6wwfqpQ= +github.com/bytedance/sonic v1.13.2/go.mod h1:o68xyaF9u2gvVBuGHPlUVCy+ZfmNNO5ETf1+KgkJhz4= +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/cloudwego/base64x v0.1.5 h1:XPciSp1xaq2VCSt6lF0phncD4koWyULpl5bUxbfCyP4= +github.com/cloudwego/base64x v0.1.5/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= +github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= 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/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= -github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= -github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= -github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= -github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= +github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM= +github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8= +github.com/gin-contrib/sse v1.0.0 h1:y3bT1mUWUxDpW4JLQg/HnTqV4rozuW4tC9eFKTxYI9E= +github.com/gin-contrib/sse v1.0.0/go.mod h1:zNuFdwarAygJBht0NTKiSi3jRf6RbqeILZ9Sp6Slhe0= +github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= +github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= -github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= -github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= -github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= -github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= -github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc/iMaVtFbr3Sw2k= +github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo= +github.com/go-sql-driver/mysql v1.9.1 h1:FrjNGn/BsJQjVRuSa8CBrM5BWA9BWoXXat3KrtSb/iI= +github.com/go-sql-driver/mysql v1.9.1/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU= +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/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= -github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= -github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= -github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= +github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +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/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= -github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= +github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= +github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= 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/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= 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.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.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= -github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +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/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/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= -github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= -golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= -golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= -golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= -golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= +github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +golang.org/x/arch v0.15.0 h1:QtOrQd0bTUnhNVNndMpLHNWrDmYzZ2KDqSrEymqInZw= +golang.org/x/arch v0.15.0/go.mod h1:JmwW7aLIoRUKgaTzhkiEFxvcEiQGyOg9BMonBJUS7EE= +golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= +golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= +golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= +golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= +golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= +golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 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= -rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= +nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= diff --git a/frameworks/Go/gin/gin-src/hello.go b/frameworks/Go/gin/gin-src/hello.go index 88328c39e4b..4b15c438838 100644 --- a/frameworks/Go/gin/gin-src/hello.go +++ b/frameworks/Go/gin/gin-src/hello.go @@ -99,6 +99,7 @@ func fortunes(c *gin.Context) { c.AbortWithError(500, err) return } + defer rows.Close() // Ensure rows are closed fortunes := make(Fortunes, 0) for rows.Next() { //Fetch rows diff --git a/frameworks/Go/gin/gin-std/go.mod b/frameworks/Go/gin/gin-std/go.mod index b15771ce3cf..0706138f01d 100644 --- a/frameworks/Go/gin/gin-std/go.mod +++ b/frameworks/Go/gin/gin-std/go.mod @@ -1,36 +1,40 @@ module gin-std/server -go 1.19 +go 1.23.0 + +toolchain go1.24.1 require ( - github.com/gin-gonic/gin v1.9.1 - github.com/go-sql-driver/mysql v1.6.0 + github.com/gin-gonic/gin v1.10.0 + github.com/go-sql-driver/mysql v1.9.1 ) require ( - github.com/bytedance/sonic v1.9.1 // indirect - github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect - github.com/gabriel-vasile/mimetype v1.4.2 // indirect - github.com/gin-contrib/sse v0.1.0 // indirect + filippo.io/edwards25519 v1.1.0 // indirect + github.com/bytedance/sonic v1.13.2 // indirect + github.com/bytedance/sonic/loader v0.2.4 // indirect + github.com/cloudwego/base64x v0.1.5 // indirect + github.com/gabriel-vasile/mimetype v1.4.8 // indirect + github.com/gin-contrib/sse v1.0.0 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.14.0 // indirect - github.com/goccy/go-json v0.10.2 // indirect + github.com/go-playground/validator/v10 v10.26.0 // indirect + github.com/goccy/go-json v0.10.5 // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/cpuid/v2 v2.2.4 // indirect - github.com/leodido/go-urn v1.2.4 // indirect - github.com/mattn/go-isatty v0.0.19 // indirect + github.com/klauspost/cpuid/v2 v2.2.10 // indirect + github.com/leodido/go-urn v1.4.0 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/pelletier/go-toml/v2 v2.0.8 // indirect + github.com/pelletier/go-toml/v2 v2.2.3 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect - github.com/ugorji/go/codec v1.2.11 // indirect - golang.org/x/arch v0.3.0 // indirect - golang.org/x/crypto v0.14.0 // indirect - golang.org/x/net v0.17.0 // indirect - golang.org/x/sys v0.13.0 // indirect - golang.org/x/text v0.13.0 // indirect - google.golang.org/protobuf v1.30.0 // indirect + github.com/ugorji/go/codec v1.2.12 // 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/text v0.23.0 // indirect + google.golang.org/protobuf v1.36.6 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/frameworks/Go/gin/gin-std/go.sum b/frameworks/Go/gin/gin-std/go.sum index d7c446e32e5..101235e7c85 100644 --- a/frameworks/Go/gin/gin-std/go.sum +++ b/frameworks/Go/gin/gin-std/go.sum @@ -1,87 +1,88 @@ -github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= -github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= -github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= -github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= -github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= -github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/bytedance/sonic v1.13.2 h1:8/H1FempDZqC4VqjptGo14QQlJx8VdZJegxs6wwfqpQ= +github.com/bytedance/sonic v1.13.2/go.mod h1:o68xyaF9u2gvVBuGHPlUVCy+ZfmNNO5ETf1+KgkJhz4= +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/cloudwego/base64x v0.1.5 h1:XPciSp1xaq2VCSt6lF0phncD4koWyULpl5bUxbfCyP4= +github.com/cloudwego/base64x v0.1.5/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= +github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= 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/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= -github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= -github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= -github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= -github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= +github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM= +github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8= +github.com/gin-contrib/sse v1.0.0 h1:y3bT1mUWUxDpW4JLQg/HnTqV4rozuW4tC9eFKTxYI9E= +github.com/gin-contrib/sse v1.0.0/go.mod h1:zNuFdwarAygJBht0NTKiSi3jRf6RbqeILZ9Sp6Slhe0= +github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= +github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= -github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= -github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= -github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= -github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= -github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc/iMaVtFbr3Sw2k= +github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo= +github.com/go-sql-driver/mysql v1.9.1 h1:FrjNGn/BsJQjVRuSa8CBrM5BWA9BWoXXat3KrtSb/iI= +github.com/go-sql-driver/mysql v1.9.1/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU= +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/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= -github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= -github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= -github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= +github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +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/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= -github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= +github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= +github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= 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/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= 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.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.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= -github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +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/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/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= -github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= -golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= -golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= -golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= -golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= +github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +golang.org/x/arch v0.15.0 h1:QtOrQd0bTUnhNVNndMpLHNWrDmYzZ2KDqSrEymqInZw= +golang.org/x/arch v0.15.0/go.mod h1:JmwW7aLIoRUKgaTzhkiEFxvcEiQGyOg9BMonBJUS7EE= +golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= +golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= +golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= +golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= +golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= +golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= +google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 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= -rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= +nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= diff --git a/frameworks/Go/gin/gin-std/main.go b/frameworks/Go/gin/gin-std/main.go index 43065bc9b22..390d7e13f3b 100644 --- a/frameworks/Go/gin/gin-std/main.go +++ b/frameworks/Go/gin/gin-std/main.go @@ -99,6 +99,7 @@ func fortunes(c *gin.Context) { c.AbortWithError(500, err) return } + defer rows.Close() // Ensure rows are closed fortunes := make(Fortunes, 0) for rows.Next() { //Fetch rows diff --git a/frameworks/Go/gin/gin.dockerfile b/frameworks/Go/gin/gin.dockerfile index b0f145a8448..b814898ae18 100644 --- a/frameworks/Go/gin/gin.dockerfile +++ b/frameworks/Go/gin/gin.dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/golang:1.19 +FROM docker.io/golang:1.24.2 WORKDIR /gin COPY ./gin-std /gin diff --git a/frameworks/Go/gnet/benchmark_config.json b/frameworks/Go/gnet/benchmark_config.json index 484ec41b8ff..1ff8439be6d 100644 --- a/frameworks/Go/gnet/benchmark_config.json +++ b/frameworks/Go/gnet/benchmark_config.json @@ -20,4 +20,4 @@ "versus": "go" } }] -} \ No newline at end of file +} diff --git a/frameworks/Go/gnet/gnet.dockerfile b/frameworks/Go/gnet/gnet.dockerfile index 2b060d96acd..4786d869d72 100644 --- a/frameworks/Go/gnet/gnet.dockerfile +++ b/frameworks/Go/gnet/gnet.dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/golang:1.19 +FROM docker.io/golang:1.24.2 WORKDIR /gnet diff --git a/frameworks/Go/gnet/src/go.mod b/frameworks/Go/gnet/src/go.mod index bc59a7c9cfd..567d3bf13c2 100644 --- a/frameworks/Go/gnet/src/go.mod +++ b/frameworks/Go/gnet/src/go.mod @@ -1,17 +1,19 @@ module gnet -go 1.19 +go 1.23.1 require ( - github.com/panjf2000/gnet/v2 v2.1.2 - go.uber.org/multierr v1.8.0 // indirect - golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41 // indirect + github.com/evanphx/wildcat v0.0.0-20141114174135-e7012f664567 + github.com/panjf2000/gnet/v2 v2.7.2 ) require ( - github.com/josharian/intern v1.0.0 // indirect - github.com/mailru/easyjson v0.7.7 // indirect - go.uber.org/atomic v1.10.0 // indirect - go.uber.org/zap v1.23.0 // indirect - gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect + github.com/panjf2000/ants/v2 v2.11.2 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/vektra/errors v0.0.0-20140903201135-c64d83aba85a // indirect + go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap v1.27.0 // indirect + golang.org/x/sync v0.12.0 // indirect + golang.org/x/sys v0.31.0 // indirect + gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect ) diff --git a/frameworks/Go/gnet/src/go.sum b/frameworks/Go/gnet/src/go.sum index f9f9c868493..d754f38b357 100644 --- a/frameworks/Go/gnet/src/go.sum +++ b/frameworks/Go/gnet/src/go.sum @@ -1,82 +1,30 @@ -github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= -github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -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/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/panjf2000/ants/v2 v2.4.8 h1:JgTbolX6K6RreZ4+bfctI0Ifs+3mrE5BIHudQxUDQ9k= -github.com/panjf2000/ants/v2 v2.4.8/go.mod h1:f6F0NZVFsGCp5A7QW/Zj/m92atWwOkY0OIhFxRNFr4A= -github.com/panjf2000/gnet/v2 v2.1.2 h1:WJ/PkbfV6G0wcGOng2pyCwv8oadKiqtP8p+38smN7ao= -github.com/panjf2000/gnet/v2 v2.1.2/go.mod h1:unWr2B4jF0DQPJH3GsXBGQiDcAamM6+Pf5FiK705kc4= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/evanphx/wildcat v0.0.0-20141114174135-e7012f664567 h1:7+oQw6YjB/kk9x27AEC7DMXudqERHD583hZpno18lRw= +github.com/evanphx/wildcat v0.0.0-20141114174135-e7012f664567/go.mod h1:XNGflD53X+hfdCAt1NGeBUgiUpe9QmweW/zI1gV26Zw= +github.com/panjf2000/ants/v2 v2.11.2 h1:AVGpMSePxUNpcLaBO34xuIgM1ZdKOiGnpxLXixLi5Jo= +github.com/panjf2000/ants/v2 v2.11.2/go.mod h1:8u92CYMUc6gyvTIw8Ru7Mt7+/ESnJahz5EVtqfrilek= +github.com/panjf2000/gnet/v2 v2.7.2 h1:c+QhXBKi/Qfdi4fh8ju6xiShGQHS1lHSEk6euFzJaIk= +github.com/panjf2000/gnet/v2 v2.7.2/go.mod h1:PIMw/8ILZsN/4K11bqDtSE1rEVPoFtjFlc0Q4edkncA= 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.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +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/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= -go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= -go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= -go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= -go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= -go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= -go.uber.org/zap v1.23.0 h1:OjGQ5KQDEUawVHxNwQgPpiypGHOxo2mNZsOqTak4fFY= -go.uber.org/zap v1.23.0/go.mod h1:D+nX8jyLsMHMYrln8A0rJjFt/T/9/bGgIhAqxv5URuY= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220224120231-95c6836cb0e7/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41 h1:ohgcoMbSofXygzo6AD2I1kz3BFmW1QArPYTtwEM3UXc= -golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= -gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +github.com/vektra/errors v0.0.0-20140903201135-c64d83aba85a h1:lUVfiMMY/te9icPKBqOKkBIMZNxSpM90dxokDeCcfBg= +github.com/vektra/errors v0.0.0-20140903201135-c64d83aba85a/go.mod h1:KUxJS71XlMs+ztT+RzsLRoWUQRUpECo/+Rb0EBk8/Wc= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= +golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= +golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= 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/gnet/src/main.go b/frameworks/Go/gnet/src/main.go index 88f1fba167c..125e12ac10b 100644 --- a/frameworks/Go/gnet/src/main.go +++ b/frameworks/Go/gnet/src/main.go @@ -7,9 +7,11 @@ import ( "fmt" "log" "runtime" + "strconv" "sync/atomic" "time" + "github.com/evanphx/wildcat" "github.com/panjf2000/gnet/v2" ) @@ -22,30 +24,68 @@ type httpServer struct { } type httpCodec struct { - delimiter []byte - buf []byte + parser *wildcat.HTTPParser + contentLength int + buf []byte } -func (hc *httpCodec) appendResponse() { - hc.buf = append(hc.buf, "HTTP/1.1 200 OK\r\nServer: gnet\r\nContent-Type: text/plain\r\nDate: "...) - //hc.buf = time.Now().AppendFormat(hc.buf, "Mon, 02 Jan 2006 15:04:05 GMT") - hc.buf = append(hc.buf, NowTimeFormat()...) - hc.buf = append(hc.buf, "\r\nContent-Length: 13\r\n\r\nHello, World!"...) -} - -var errCRLFNotFound = errors.New("CRLF not found") +var CRLF = []byte("\r\n\r\n") func (hc *httpCodec) parse(data []byte) (int, error) { - if idx := bytes.Index(data, hc.delimiter); idx != -1 { + // Perform a legit HTTP request parsing. + bodyOffset, err := hc.parser.Parse(data) + if err != nil { + return 0, err + } + + // First check if the Content-Length header is present. + contentLength := hc.getContentLength() + if contentLength > -1 { + return bodyOffset + contentLength, nil + } + + // If the Content-Length header is not found, + // we need to find the end of the body section. + if idx := bytes.Index(data, CRLF); idx != -1 { return idx + 4, nil } - return -1, errCRLFNotFound + + return 0, errors.New("invalid http request") +} + +var contentLengthKey = []byte("Content-Length") + +func (hc *httpCodec) getContentLength() int { + if hc.contentLength != -1 { + return hc.contentLength + } + + val := hc.parser.FindHeader(contentLengthKey) + if val != nil { + i, err := strconv.ParseInt(string(val), 10, 0) + if err == nil { + hc.contentLength = int(i) + } + } + + return hc.contentLength +} + +func (hc *httpCodec) resetParser() { + hc.contentLength = -1 } func (hc *httpCodec) reset() { + hc.resetParser() hc.buf = hc.buf[:0] } +func (hc *httpCodec) appendResponse() { + hc.buf = append(hc.buf, "HTTP/1.1 200 OK\r\nServer: gnet\r\nContent-Type: text/plain\r\nDate: "...) + hc.buf = append(hc.buf, NowTimeFormat()...) + hc.buf = append(hc.buf, "\r\nContent-Length: 13\r\n\r\nHello, World!"...) +} + func (hs *httpServer) OnBoot(eng gnet.Engine) gnet.Action { hs.eng = eng log.Printf("echo server with multi-core=%t is listening on %s\n", hs.multicore, hs.addr) @@ -53,18 +93,20 @@ func (hs *httpServer) OnBoot(eng gnet.Engine) gnet.Action { } func (hs *httpServer) OnOpen(c gnet.Conn) ([]byte, gnet.Action) { - c.SetContext(&httpCodec{delimiter: []byte("\r\n\r\n")}) + c.SetContext(&httpCodec{parser: wildcat.NewHTTPParser()}) return nil, gnet.None } func (hs *httpServer) OnTraffic(c gnet.Conn) gnet.Action { - buf, _ := c.Next(-1) hc := c.Context().(*httpCodec) + buf, _ := c.Next(-1) + pipeline: nextOffset, err := hc.parse(buf) if err != nil { goto response } + hc.resetParser() hc.appendResponse() buf = buf[nextOffset:] if len(buf) > 0 { diff --git a/frameworks/Go/go-faster/README.md b/frameworks/Go/go-faster/README.md new file mode 100644 index 00000000000..4e2f3475b87 --- /dev/null +++ b/frameworks/Go/go-faster/README.md @@ -0,0 +1,16 @@ +# [go-faster](https://github.com/go-faster) (Go) Benchmarking Test + +The [go-faster/hx][hx] is a low-level http package for Go, simplified fork of [fasthttp][fasthttp]. +The [go-faster/jx][jx] is a low-level json package for Go. +The [ogen][ogen] project is a fast OpenAPI v3 implementation for Go. + +[go-faster]: https://github.com/go-faster +[hx]: https://github.com/go-faster/hx +[jx]: https://github.com/go-faster/jx +[ogen]: https://github.com/ogen-go +[fasthttp]: https://github.com/valyala/fasthttp + +## Test URLs + + http://localhost:8080/plaintext + http://localhost:8080/json diff --git a/frameworks/Go/go-faster/benchmark_config.json b/frameworks/Go/go-faster/benchmark_config.json new file mode 100644 index 00000000000..67ccf198078 --- /dev/null +++ b/frameworks/Go/go-faster/benchmark_config.json @@ -0,0 +1,24 @@ +{ + "framework": "go-faster", + "tests": [{ + "default": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Platform", + "database": "None", + "framework": "go-faster", + "language": "Go", + "flavor": "None", + "orm": "Raw", + "platform": "None", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "go-faster", + "notes": "", + "versus": "go" + } + }] +} diff --git a/frameworks/Go/go-faster/config.toml b/frameworks/Go/go-faster/config.toml new file mode 100644 index 00000000000..775da34271c --- /dev/null +++ b/frameworks/Go/go-faster/config.toml @@ -0,0 +1,15 @@ +[framework] +name = "go-faster" + +[main] +urls.plaintext = "/plaintext" +urls.json = "/json" +approach = "Realistic" +classification = "Platform" +database = "None" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "None" +webserver = "None" +versus = "go" diff --git a/frameworks/Go/go-faster/go-faster.dockerfile b/frameworks/Go/go-faster/go-faster.dockerfile new file mode 100644 index 00000000000..32f40e082a8 --- /dev/null +++ b/frameworks/Go/go-faster/go-faster.dockerfile @@ -0,0 +1,8 @@ +FROM docker.io/golang:1.25.0 + +WORKDIR /go-faster +COPY ./src /go-faster +RUN make build + +EXPOSE 8080 +CMD ["./go-faster-techempower"] diff --git a/frameworks/Go/go-faster/src/.gitignore b/frameworks/Go/go-faster/src/.gitignore new file mode 100644 index 00000000000..d9beb2c6bf8 --- /dev/null +++ b/frameworks/Go/go-faster/src/.gitignore @@ -0,0 +1 @@ +/go-faster-techempower diff --git a/frameworks/Go/go-faster/src/Makefile b/frameworks/Go/go-faster/src/Makefile new file mode 100644 index 00000000000..e4988315f8b --- /dev/null +++ b/frameworks/Go/go-faster/src/Makefile @@ -0,0 +1,2 @@ +build: + GOAMD64=v3 go build -ldflags="-s -w" -o go-faster-techempower . diff --git a/frameworks/Go/go-faster/src/go.mod b/frameworks/Go/go-faster/src/go.mod new file mode 100644 index 00000000000..4b1d09314e8 --- /dev/null +++ b/frameworks/Go/go-faster/src/go.mod @@ -0,0 +1,36 @@ +module go-faster/app + +go 1.24.0 + +toolchain go1.25.0 + +require ( + github.com/go-faster/errors v0.7.1 + github.com/go-faster/hx v0.4.0 + github.com/go-faster/jx v1.1.0 + github.com/ogen-go/ogen v1.14.0 +) + +tool github.com/ogen-go/ogen/cmd/jschemagen + +require ( + github.com/dlclark/regexp2 v1.11.5 // indirect + github.com/fatih/color v1.18.0 // indirect + github.com/ghodss/yaml v1.0.0 // indirect + github.com/go-faster/yaml v0.4.6 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/segmentio/asm v1.2.0 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap v1.27.0 // indirect + golang.org/x/exp v0.0.0-20230725093048-515e97ebf090 // indirect + golang.org/x/mod v0.24.0 // indirect + golang.org/x/net v0.40.0 // indirect + golang.org/x/sync v0.17.0 // indirect + golang.org/x/sys v0.33.0 // indirect + golang.org/x/text v0.25.0 // indirect + golang.org/x/tools v0.33.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect +) diff --git a/frameworks/Go/go-faster/src/go.sum b/frameworks/Go/go-faster/src/go.sum new file mode 100644 index 00000000000..2c90e39872f --- /dev/null +++ b/frameworks/Go/go-faster/src/go.sum @@ -0,0 +1,68 @@ +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/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ= +github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= +github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= +github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-faster/errors v0.7.1 h1:MkJTnDoEdi9pDabt1dpWf7AA8/BaSYZqibYyhZ20AYg= +github.com/go-faster/errors v0.7.1/go.mod h1:5ySTjWFiphBs07IKuiL69nxdfd5+fzh1u7FPGZP2quo= +github.com/go-faster/hx v0.4.0 h1:HQHQJWjRX6OrOq5Eym+iUEuQQ3fE204LzTSxkGmqc/o= +github.com/go-faster/hx v0.4.0/go.mod h1:T+v3cOtXcUkJrFH9iBrKCK8gV77tU2RVC9UKaAZ1wLI= +github.com/go-faster/jx v1.1.0 h1:ZsW3wD+snOdmTDy9eIVgQdjUpXRRV4rqW8NS3t+20bg= +github.com/go-faster/jx v1.1.0/go.mod h1:vKDNikrKoyUmpzaJ0OkIkRQClNHFX/nF3dnTJZb3skg= +github.com/go-faster/yaml v0.4.6 h1:lOK/EhI04gCpPgPhgt0bChS6bvw7G3WwI8xxVe0sw9I= +github.com/go-faster/yaml v0.4.6/go.mod h1:390dRIvV4zbnO7qC9FGo6YYutc+wyyUSHBgbXL52eXk= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +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/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +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.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +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/ogen-go/ogen v1.14.0 h1:TU1Nj4z9UBsAfTkf+IhuNNp7igdFQKqkk9+6/y4XuWg= +github.com/ogen-go/ogen v1.14.0/go.mod h1:Iw1vkqkx6SU7I9th5ceP+fVPJ6Wge4e3kAVzAxJEpPE= +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/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= +github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= +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= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +golang.org/x/exp v0.0.0-20230725093048-515e97ebf090 h1:Di6/M8l0O2lCLc6VVRWhgCiApHV8MnQurBnFSHsQtNY= +golang.org/x/exp v0.0.0-20230725093048-515e97ebf090/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= +golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU= +golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= +golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= +golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= +golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= +golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= +golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4= +golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= +golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc= +golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +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/go-faster/src/main.go b/frameworks/Go/go-faster/src/main.go new file mode 100644 index 00000000000..9d596209d9d --- /dev/null +++ b/frameworks/Go/go-faster/src/main.go @@ -0,0 +1,50 @@ +package main + +import ( + "context" + "flag" + "log/slog" + "net/http" + + "github.com/go-faster/hx" +) + +//go:generate go tool jschemagen -target message.go -typename Message message.schema.json + +func main() { + var arg struct { + Workers int + Addr string + Mode string + } + flag.StringVar(&arg.Addr, "addr", ":8080", "listen address") + flag.IntVar(&arg.Workers, "j", 1024, "count of workers") + flag.Parse() + + slog.Info("starting server", + slog.String("addr", arg.Addr), + slog.Int("workers", arg.Workers), + ) + + s := &hx.Server{ + Workers: arg.Workers, + Name: "hx", + Handler: func(ctx *hx.Ctx) { + switch string(ctx.Request.URI().Path()) { + case "/plaintext": + ctx.Response.Header.Add("Content-Type", "text/plain") + ctx.Response.AppendBodyString("Hello, World!") + case "/json": + ctx.Response.Header.Add("Content-Type", "application/json") + msg := Message{Message: "Hello, World!"} + ctx.JSON.Encode(msg) + ctx.Response.AppendBody(ctx.JSON.Encoder.Bytes()) + default: + ctx.Response.SetStatusCode(http.StatusNotFound) + } + }, + } + if err := s.ListenAndServe(context.Background(), arg.Addr); err != nil { + slog.Error("Failed to start server", slog.Any("err", err)) + } +} diff --git a/frameworks/Go/go-faster/src/message.encoder.go b/frameworks/Go/go-faster/src/message.encoder.go new file mode 100644 index 00000000000..51fbf69b2db --- /dev/null +++ b/frameworks/Go/go-faster/src/message.encoder.go @@ -0,0 +1,7 @@ +package main + +import "github.com/go-faster/jx" + +func (m Message) JSONEncode(e *jx.Encoder) { + m.Encode(e) +} diff --git a/frameworks/Go/go-faster/src/message.go b/frameworks/Go/go-faster/src/message.go new file mode 100644 index 00000000000..acbbddc43af --- /dev/null +++ b/frameworks/Go/go-faster/src/message.go @@ -0,0 +1,123 @@ +// Code generated by ogen, DO NOT EDIT. + +package main + +import ( + "math/bits" + "strconv" + + "github.com/go-faster/errors" + "github.com/go-faster/jx" + + "github.com/ogen-go/ogen/validate" +) + +type Message struct { + Message string `json:"message"` +} + +// GetMessage returns the value of Message. +func (s *Message) GetMessage() string { + return s.Message +} + +// SetMessage sets the value of Message. +func (s *Message) SetMessage(val string) { + s.Message = val +} + +// Encode implements json.Marshaler. +func (s *Message) Encode(e *jx.Encoder) { + e.ObjStart() + s.encodeFields(e) + e.ObjEnd() +} + +// encodeFields encodes fields. +func (s *Message) encodeFields(e *jx.Encoder) { + { + e.FieldStart("message") + e.Str(s.Message) + } +} + +var jsonFieldsNameOfMessage = [1]string{ + 0: "message", +} + +// Decode decodes Message from json. +func (s *Message) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode Message to nil") + } + var requiredBitSet [1]uint8 + + if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { + switch string(k) { + case "message": + requiredBitSet[0] |= 1 << 0 + if err := func() error { + v, err := d.Str() + s.Message = string(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"message\"") + } + default: + return errors.Errorf("unexpected field %q", k) + } + return nil + }); err != nil { + return errors.Wrap(err, "decode Message") + } + // Validate required fields. + var failures []validate.FieldError + for i, mask := range [1]uint8{ + 0b00000001, + } { + if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { + // Mask only required fields and check equality to mask using XOR. + // + // If XOR result is not zero, result is not equal to expected, so some fields are missed. + // Bits of fields which would be set are actually bits of missed fields. + missed := bits.OnesCount8(result) + for bitN := 0; bitN < missed; bitN++ { + bitIdx := bits.TrailingZeros8(result) + fieldIdx := i*8 + bitIdx + var name string + if fieldIdx < len(jsonFieldsNameOfMessage) { + name = jsonFieldsNameOfMessage[fieldIdx] + } else { + name = strconv.Itoa(fieldIdx) + } + failures = append(failures, validate.FieldError{ + Name: name, + Error: validate.ErrFieldRequired, + }) + // Reset bit. + result &^= 1 << bitIdx + } + } + } + if len(failures) > 0 { + return &validate.Error{Fields: failures} + } + + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s *Message) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *Message) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} diff --git a/frameworks/Go/go-faster/src/message.schema.json b/frameworks/Go/go-faster/src/message.schema.json new file mode 100644 index 00000000000..f4e5c81a095 --- /dev/null +++ b/frameworks/Go/go-faster/src/message.schema.json @@ -0,0 +1,11 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "message": { + "type": "string" + } + }, + "required": ["message"], + "additionalProperties": false +} \ No newline at end of file diff --git a/frameworks/Go/go-std/go-mgo-prefork.dockerfile b/frameworks/Go/go-std/go-mgo-prefork.dockerfile index b72c35635db..f340258c824 100644 --- a/frameworks/Go/go-std/go-mgo-prefork.dockerfile +++ b/frameworks/Go/go-std/go-mgo-prefork.dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/golang:1.19 +FROM docker.io/golang:1.24.2 WORKDIR /go-std diff --git a/frameworks/Go/go-std/go-mgo.dockerfile b/frameworks/Go/go-std/go-mgo.dockerfile index dc3460db891..05a4806f81a 100644 --- a/frameworks/Go/go-std/go-mgo.dockerfile +++ b/frameworks/Go/go-std/go-mgo.dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/golang:1.19 +FROM docker.io/golang:1.24.2 WORKDIR /go-std diff --git a/frameworks/Go/go-std/go-my-prefork.dockerfile b/frameworks/Go/go-std/go-my-prefork.dockerfile index 13e6cc93bed..763cf2f55ed 100644 --- a/frameworks/Go/go-std/go-my-prefork.dockerfile +++ b/frameworks/Go/go-std/go-my-prefork.dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/golang:1.19 +FROM docker.io/golang:1.24.2 WORKDIR /go-std diff --git a/frameworks/Go/go-std/go-my.dockerfile b/frameworks/Go/go-std/go-my.dockerfile index d456038999f..14d06b09885 100644 --- a/frameworks/Go/go-std/go-my.dockerfile +++ b/frameworks/Go/go-std/go-my.dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/golang:1.19 +FROM docker.io/golang:1.24.2 WORKDIR /go-std diff --git a/frameworks/Go/go-std/go-pgx-easyjson.dockerfile b/frameworks/Go/go-std/go-pgx-easyjson.dockerfile index 6f790e15990..21608a57ace 100644 --- a/frameworks/Go/go-std/go-pgx-easyjson.dockerfile +++ b/frameworks/Go/go-std/go-pgx-easyjson.dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/golang:1.19 +FROM docker.io/golang:1.24.2 WORKDIR /go-std diff --git a/frameworks/Go/go-std/go-pgx-prefork-easyjson.dockerfile b/frameworks/Go/go-std/go-pgx-prefork-easyjson.dockerfile index 3da0370bffd..e1640ae49e0 100644 --- a/frameworks/Go/go-std/go-pgx-prefork-easyjson.dockerfile +++ b/frameworks/Go/go-std/go-pgx-prefork-easyjson.dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/golang:1.19 +FROM docker.io/golang:1.24.2 WORKDIR /go-std diff --git a/frameworks/Go/go-std/go-pgx-prefork-quicktemplate.dockerfile b/frameworks/Go/go-std/go-pgx-prefork-quicktemplate.dockerfile index 2745a7fc93e..765f771efcd 100644 --- a/frameworks/Go/go-std/go-pgx-prefork-quicktemplate.dockerfile +++ b/frameworks/Go/go-std/go-pgx-prefork-quicktemplate.dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/golang:1.19 +FROM docker.io/golang:1.24.2 WORKDIR /go-std diff --git a/frameworks/Go/go-std/go-pgx-prefork.dockerfile b/frameworks/Go/go-std/go-pgx-prefork.dockerfile index 2745a7fc93e..765f771efcd 100644 --- a/frameworks/Go/go-std/go-pgx-prefork.dockerfile +++ b/frameworks/Go/go-std/go-pgx-prefork.dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/golang:1.19 +FROM docker.io/golang:1.24.2 WORKDIR /go-std diff --git a/frameworks/Go/go-std/go-pgx-quicktemplate.dockerfile b/frameworks/Go/go-std/go-pgx-quicktemplate.dockerfile index efad70a7bfb..fd754e6c9e3 100644 --- a/frameworks/Go/go-std/go-pgx-quicktemplate.dockerfile +++ b/frameworks/Go/go-std/go-pgx-quicktemplate.dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/golang:1.19 +FROM docker.io/golang:1.24.2 WORKDIR /go-std diff --git a/frameworks/Go/go-std/go-pgx.dockerfile b/frameworks/Go/go-std/go-pgx.dockerfile index efad70a7bfb..fd754e6c9e3 100644 --- a/frameworks/Go/go-std/go-pgx.dockerfile +++ b/frameworks/Go/go-std/go-pgx.dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/golang:1.19 +FROM docker.io/golang:1.24.2 WORKDIR /go-std diff --git a/frameworks/Go/go-std/go.dockerfile b/frameworks/Go/go-std/go.dockerfile index cb38aec3676..8b361d8de97 100644 --- a/frameworks/Go/go-std/go.dockerfile +++ b/frameworks/Go/go-std/go.dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/golang:1.19 +FROM docker.io/golang:1.24.2 WORKDIR /go-std diff --git a/frameworks/Go/go-std/src/go.mod b/frameworks/Go/go-std/src/go.mod index ad635fe7e0f..5b0257bab2c 100644 --- a/frameworks/Go/go-std/src/go.mod +++ b/frameworks/Go/go-std/src/go.mod @@ -1,16 +1,19 @@ module go-std/app -go 1.19 +go 1.23.0 + +toolchain go1.24.1 require ( - github.com/go-sql-driver/mysql v1.6.0 + github.com/go-sql-driver/mysql v1.9.1 github.com/jackc/pgx v3.6.2+incompatible - github.com/mailru/easyjson v0.7.7 - github.com/valyala/quicktemplate v1.7.0 + github.com/mailru/easyjson v0.9.0 + github.com/valyala/quicktemplate v1.8.0 gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 ) require ( + filippo.io/edwards25519 v1.1.0 // indirect github.com/cockroachdb/apd v1.1.0 // indirect github.com/gofrs/uuid v4.3.0+incompatible // indirect github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 // indirect @@ -21,8 +24,8 @@ require ( github.com/rogpeppe/go-internal v1.9.0 // indirect github.com/shopspring/decimal v1.3.1 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect - golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 // indirect - golang.org/x/text v0.3.8 // indirect + golang.org/x/crypto v0.36.0 // indirect + golang.org/x/text v0.23.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v2 v2.4.0 // indirect ) diff --git a/frameworks/Go/go-std/src/go.sum b/frameworks/Go/go-std/src/go.sum index afe042667a2..43b561e4d10 100644 --- a/frameworks/Go/go-std/src/go.sum +++ b/frameworks/Go/go-std/src/go.sum @@ -1,21 +1,18 @@ -github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= -github.com/andybalholm/brotli v1.0.3/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= -github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-sql-driver/mysql v1.9.1 h1:FrjNGn/BsJQjVRuSa8CBrM5BWA9BWoXXat3KrtSb/iI= +github.com/go-sql-driver/mysql v1.9.1/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU= github.com/gofrs/uuid v4.3.0+incompatible h1:CaSVZxm5B+7o45rtab4jC2G37WGYX1zQfuU2i6DSvnc= github.com/gofrs/uuid v4.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 h1:vr3AYkKovP8uR8AvSGGUK1IDqRa5lAAvEkZG1LKaCRc= github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ= github.com/jackc/pgx v3.6.2+incompatible h1:2zP5OD7kiyR3xzRYMhOcXVvkDZsImVXfj+yIyTQf3/o= github.com/jackc/pgx v3.6.2+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= -github.com/klauspost/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= @@ -26,8 +23,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= +github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= @@ -37,24 +34,12 @@ github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5g github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= 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.30.0/go.mod h1:2rsYD01CKFrjjsvFxx75KlEUNpWNBY9JWD3K/7o2Cus= -github.com/valyala/quicktemplate v1.7.0 h1:LUPTJmlVcb46OOUY3IeD9DojFpAVbsG+5WFTcjMJzCM= -github.com/valyala/quicktemplate v1.7.0/go.mod h1:sqKJnoaOF88V07vkO+9FL8fb9uZg/VPSJnLYn+LmLk8= -github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= -golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= -golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM= -golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +github.com/valyala/quicktemplate v1.8.0 h1:zU0tjbIqTRgKQzFY1L42zq0qR3eh4WoQQdIdqCysW5k= +github.com/valyala/quicktemplate v1.8.0/go.mod h1:qIqW8/igXt8fdrUln5kOSb+KWMaJ4Y8QUsfd1k6L2jM= +golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= +golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= +golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= +golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= diff --git a/frameworks/Go/goframe/goframe.dockerfile b/frameworks/Go/goframe/goframe.dockerfile index 5f68f2a8b9e..8a1252fa7c7 100644 --- a/frameworks/Go/goframe/goframe.dockerfile +++ b/frameworks/Go/goframe/goframe.dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/golang:1.19 +FROM docker.io/golang:1.24.2 ADD ./src /goframe WORKDIR /goframe diff --git a/frameworks/Go/goframe/src/go.mod b/frameworks/Go/goframe/src/go.mod index a14d0d3b7cd..ee265ecc7d0 100644 --- a/frameworks/Go/goframe/src/go.mod +++ b/frameworks/Go/goframe/src/go.mod @@ -1,50 +1,55 @@ module goframe/app -go 1.19 +go 1.23.0 + +toolchain go1.24.1 require ( - github.com/bytedance/sonic v1.4.0 - github.com/gogf/gf/v2 v2.1.4 - github.com/jackc/pgx/v4 v4.17.2 - github.com/valyala/quicktemplate v1.7.0 + github.com/bytedance/sonic v1.13.2 + github.com/gogf/gf/v2 v2.9.0 + github.com/jackc/pgx/v4 v4.18.3 + github.com/valyala/quicktemplate v1.8.0 ) require ( - github.com/BurntSushi/toml v1.1.0 // indirect - github.com/cespare/xxhash/v2 v2.1.2 // indirect - github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06 // indirect - github.com/clbanning/mxj/v2 v2.5.5 // indirect - github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect - github.com/fatih/color v1.13.0 // indirect - github.com/fsnotify/fsnotify v1.5.4 // indirect - github.com/go-logr/logr v1.2.3 // indirect + github.com/BurntSushi/toml v1.5.0 // indirect + github.com/bytedance/sonic/loader v0.2.4 // 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/stdr v1.2.2 // indirect - github.com/go-redis/redis/v8 v8.11.5 // indirect - github.com/gorilla/websocket v1.5.0 // indirect - github.com/grokify/html-strip-tags-go v0.0.1 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/gorilla/websocket v1.5.3 // indirect + github.com/grokify/html-strip-tags-go v0.1.0 // indirect github.com/jackc/chunkreader/v2 v2.0.1 // indirect - github.com/jackc/pgconn v1.13.0 // indirect + github.com/jackc/pgconn v1.14.3 // indirect github.com/jackc/pgio v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect - github.com/jackc/pgproto3/v2 v2.3.1 // indirect - github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect - github.com/jackc/pgtype v1.12.0 // indirect + github.com/jackc/pgproto3/v2 v2.3.3 // indirect + github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect + github.com/jackc/pgtype v1.14.4 // indirect github.com/jackc/puddle v1.3.0 // indirect - github.com/klauspost/cpuid/v2 v2.0.9 // indirect - github.com/magiconair/properties v1.8.6 // indirect - github.com/mattn/go-colorable v0.1.9 // indirect - github.com/mattn/go-isatty v0.0.14 // indirect - github.com/mattn/go-runewidth v0.0.9 // indirect + github.com/klauspost/cpuid/v2 v2.2.10 // indirect + github.com/magiconair/properties v1.8.9 // 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/olekukonko/tablewriter v0.0.5 // indirect + 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/otel v1.7.0 // indirect - go.opentelemetry.io/otel/sdk v1.7.0 // indirect - go.opentelemetry.io/otel/trace v1.7.0 // indirect - golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect - golang.org/x/crypto v0.14.0 // indirect - golang.org/x/net v0.17.0 // indirect - golang.org/x/sys v0.13.0 // indirect - golang.org/x/text v0.13.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 + 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/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 a103d1f9e04..50336211cdc 100644 --- a/frameworks/Go/goframe/src/go.sum +++ b/frameworks/Go/goframe/src/go.sum @@ -1,20 +1,17 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I= -github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg= +github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= -github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= -github.com/andybalholm/brotli v1.0.3/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= -github.com/bytedance/sonic v1.4.0 h1:d6vgPhwgHfpmEiz/9Fzea9fGzWY7RO1TQEySBiRwDLY= -github.com/bytedance/sonic v1.4.0/go.mod h1:V973WhNhGmvHxW6nQmsHEfHaoU9F3zTF+93rH03hcUQ= -github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= -github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06 h1:1sDoSuDPWzhkdzNVxCxtIaKiAe96ESVPv8coGwc1gZ4= -github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/clbanning/mxj/v2 v2.5.5 h1:oT81vUeEiQQ/DcHbzSytRngP6Ky9O+L+0Bw0zSJag9E= -github.com/clbanning/mxj/v2 v2.5.5/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= +github.com/bytedance/sonic v1.13.2 h1:8/H1FempDZqC4VqjptGo14QQlJx8VdZJegxs6wwfqpQ= +github.com/bytedance/sonic v1.13.2/go.mod h1:o68xyaF9u2gvVBuGHPlUVCy+ZfmNNO5ETf1+KgkJhz4= +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/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= +github.com/cloudwego/base64x v0.1.5/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= +github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= @@ -23,56 +20,33 @@ github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7Do 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/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= -github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= -github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= -github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= -github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= +github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= +github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= +github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= +github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= +github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= +github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= 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.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= -github.com/go-logr/logr v1.2.3/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/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= -github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -github.com/goccy/go-json v0.9.4 h1:L8MLKG2mvVXiQu07qB6hmfqeSYQdOnqPot2GhsIwIaI= -github.com/goccy/go-json v0.9.4/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/gogf/gf/v2 v2.1.4 h1:zebl7kahNnU+0o7hcLx81svcTdp5fYdW9ZnZagXyLt4= -github.com/gogf/gf/v2 v2.1.4/go.mod h1:thvkyb43RWUu/m05sRm4CbH9r7t7/FrW2M56L9Ystwk= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= -github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/gogf/gf/v2 v2.9.0 h1:semN5Q5qGjDQEv4620VzxcJzJlSD07gmyJ9Sy9zfbHk= +github.com/gogf/gf/v2 v2.9.0/go.mod h1:sWGQw+pLILtuHmbOxoe0D+0DdaXxbleT57axOLH2vKI= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/grokify/html-strip-tags-go v0.0.1 h1:0fThFwLbW7P/kOiTBs03FsJSV9RM2M/Q/MOnCQxKMo0= -github.com/grokify/html-strip-tags-go v0.0.1/go.mod h1:2Su6romC5/1VXOQMaWL2yb618ARB8iVo6/DR99A6d78= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +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/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= +github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4= +github.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc= github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= @@ -83,8 +57,8 @@ github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsU github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= -github.com/jackc/pgconn v1.13.0 h1:3L1XMNV2Zvca/8BYhzcRFS70Lr0WlDg16Di6SFGAbys= -github.com/jackc/pgconn v1.13.0/go.mod h1:AnowpAqO4CMIIJNZl2VJp+KrkAZciAkhEl0W0JIobpI= +github.com/jackc/pgconn v1.14.3 h1:bVoTr12EGANZz66nZPkMInAV/KHD2TxH9npjXXgiB3w= +github.com/jackc/pgconn v1.14.3/go.mod h1:RZbme4uasqzybK2RK5c65VsHxoyaml09lx3tXOcO/VM= github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= @@ -100,85 +74,77 @@ github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvW github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.3.1 h1:nwj7qwf0S+Q7ISFfBndqeLwSwxs+4DPsbRFjECT1Y4Y= -github.com/jackc/pgproto3/v2 v2.3.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg= +github.com/jackc/pgproto3/v2 v2.3.3 h1:1HLSx5H+tXR9pW3in3zaztoEwQYRC9SQaYUHjTSUOag= +github.com/jackc/pgproto3/v2 v2.3.3/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +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/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= -github.com/jackc/pgtype v1.12.0 h1:Dlq8Qvcch7kiehm8wPGIW0W3KsCCHJnRacKW0UM8n5w= -github.com/jackc/pgtype v1.12.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= +github.com/jackc/pgtype v1.14.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= +github.com/jackc/pgtype v1.14.4 h1:fKuNiCumbKTAIxQwXfB/nsrnkEI6bPJrrSiMKgbJ2j8= +github.com/jackc/pgtype v1.14.4/go.mod h1:aKeozOde08iifGosdJpz9MBZonJOUJxqNpPBcMJTlVA= github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= -github.com/jackc/pgx/v4 v4.17.2 h1:0Ut0rpeKwvIVbMQ1KbMBU4h6wxehBI535LK6Flheh8E= -github.com/jackc/pgx/v4 v4.17.2/go.mod h1:lcxIZN44yMIrWI78a5CpucdD14hX0SBDbNRvjDBItsw= +github.com/jackc/pgx/v4 v4.18.2/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw= +github.com/jackc/pgx/v4 v4.18.3 h1:dE2/TrEsGX3RBprb3qryqSV9Y60iZN1C6i8IrmW9/BA= +github.com/jackc/pgx/v4 v4.18.3/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw= github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.3.0 h1:eHK/5clGOatcjX3oWGBO/MpxpbHzSwud5EWTSCI+MX0= github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= -github.com/klauspost/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= +github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8= github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= -github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM= +github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.9 h1:sqDoxXbdeALODt0DAeJCVp38ps9ZogZEAXjus69YV3U= -github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +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.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= +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.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= -github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +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/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= -github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= -github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= -github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= -github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 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/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/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= @@ -192,44 +158,41 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/tidwall/gjson v1.12.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= -github.com/tidwall/gjson v1.13.0 h1:3TFY9yxOQShrvmjdM76K+jc66zJeT6D3/VFFYCGQf7M= -github.com/tidwall/gjson v1.13.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= -github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= -github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= -github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= -github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= -github.com/tidwall/sjson v1.2.4 h1:cuiLzLnaMeBhRmEv00Lpk3tkYrcxpmbU81tAY4Dw0tc= -github.com/tidwall/sjson v1.2.4/go.mod h1:098SZ494YoMWPmMO6ct4dcFnqxwj9r/gF0Etp19pSNM= +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/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= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.30.0/go.mod h1:2rsYD01CKFrjjsvFxx75KlEUNpWNBY9JWD3K/7o2Cus= -github.com/valyala/quicktemplate v1.7.0 h1:LUPTJmlVcb46OOUY3IeD9DojFpAVbsG+5WFTcjMJzCM= -github.com/valyala/quicktemplate v1.7.0/go.mod h1:sqKJnoaOF88V07vkO+9FL8fb9uZg/VPSJnLYn+LmLk8= -github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/valyala/quicktemplate v1.8.0 h1:zU0tjbIqTRgKQzFY1L42zq0qR3eh4WoQQdIdqCysW5k= +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/otel v1.7.0 h1:Z2lA3Tdch0iDcrhJXDIlC94XE+bxok1F9B+4Lz/lGsM= -go.opentelemetry.io/otel v1.7.0/go.mod h1:5BdUoMIz5WEs0vt0CUEMtSSaTSHBBVwrhnz7+nrD5xk= -go.opentelemetry.io/otel/sdk v1.7.0 h1:4OmStpcKVOfvDOgCt7UriAPtKolwIhxpnSNI/yK+1B0= -go.opentelemetry.io/otel/sdk v1.7.0/go.mod h1:uTEOTwaqIVuTGiJN7ii13Ibp75wJmYUDe374q6cZwUU= -go.opentelemetry.io/otel/trace v1.7.0 h1:O37Iogk1lEkMRXewVtZ1BBTVn5JEp8GrJvP92bJqC6o= -go.opentelemetry.io/otel/trace v1.7.0/go.mod h1:fzLSB9nqR2eXzxPXb2JW9IKE+ScyXA48yyE4TNvoHqU= +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.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= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= @@ -237,8 +200,8 @@ go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9E go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= -golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU= -golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.15.0 h1:QtOrQd0bTUnhNVNndMpLHNWrDmYzZ2KDqSrEymqInZw= +golang.org/x/arch v0.15.0/go.mod h1:JmwW7aLIoRUKgaTzhkiEFxvcEiQGyOg9BMonBJUS7EE= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -246,75 +209,69 @@ golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.20.0/go.mod h1:Xwo95rrVNIoSMx9wa1JroENMToLWn3RNVrTBpLHgZPQ= +golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= +golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= +golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +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/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= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8-0.20211105212822-18b340fc7af2/go.mod h1:EFNZuWvGYxIRUEX+K8UmCFwYmZjqcrnq15ZuVldZkZ0= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= +golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -324,38 +281,22 @@ golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/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/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/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= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= +nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= diff --git a/frameworks/Go/goji/goji.dockerfile b/frameworks/Go/goji/goji.dockerfile index 6da1e062bdb..8d23a8d14e8 100644 --- a/frameworks/Go/goji/goji.dockerfile +++ b/frameworks/Go/goji/goji.dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/golang:1.19 +FROM docker.io/golang:1.24.2 ADD ./src /goji WORKDIR /goji diff --git a/frameworks/Go/goji/src/go.mod b/frameworks/Go/goji/src/go.mod index 1eb8744a13e..04fe1ba3336 100644 --- a/frameworks/Go/goji/src/go.mod +++ b/frameworks/Go/goji/src/go.mod @@ -1,8 +1,12 @@ module server -go 1.19 +go 1.21.0 + +toolchain go1.24.1 require ( - github.com/go-sql-driver/mysql v1.6.0 + github.com/go-sql-driver/mysql v1.9.1 github.com/zenazn/goji v1.0.1 ) + +require filippo.io/edwards25519 v1.1.0 // indirect diff --git a/frameworks/Go/goji/src/go.sum b/frameworks/Go/goji/src/go.sum index e4e91956bb5..4637fbf3f4a 100644 --- a/frameworks/Go/goji/src/go.sum +++ b/frameworks/Go/goji/src/go.sum @@ -1,4 +1,6 @@ -github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= -github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/go-sql-driver/mysql v1.9.1 h1:FrjNGn/BsJQjVRuSa8CBrM5BWA9BWoXXat3KrtSb/iI= +github.com/go-sql-driver/mysql v1.9.1/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU= github.com/zenazn/goji v1.0.1 h1:4lbD8Mx2h7IvloP7r2C0D6ltZP6Ufip8Hn0wmSK5LR8= github.com/zenazn/goji v1.0.1/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= diff --git a/frameworks/Go/goravel/README.md b/frameworks/Go/goravel/README.md new file mode 100644 index 00000000000..f9b0d413503 --- /dev/null +++ b/frameworks/Go/goravel/README.md @@ -0,0 +1,44 @@ +# Goravel Benchmarking Test + +[Goravel](https://www.goravel.dev/) is a web application framework with complete functions and excellent scalability. As a starting scaffolding to help Gopher quickly build their own applications. + +The framework's design is consistent with [Laravel](https://github.com/laravel/laravel), simplifying the learning curve for PHPers. Kudos to Laravel! + +### Test Type Implementation Source Code + +* [JSON](src/gin/app/http/controllers/test_controller.go) +* [PLAINTEXT](src/gin/app/http/controllers/test_controller.go) +* [DB](src/gin/app/http/controllers/test_controller.go) +* [QUERY](src/gin/app/http/controllers/test_controller.go) +* [CACHED QUERY](src/gin/app/http/controllers/test_controller.go) +* [UPDATE](src/gin/app/http/controllers/test_controller.go) +* [FORTUNES](src/gin/app/http/controllers/test_controller.go) + +## Test URLs +### JSON + +http://localhost:8080/json + +### PLAINTEXT + +http://localhost:8080/plaintext + +### DB + +http://localhost:8080/db + +### QUERY + +http://localhost:8080/query?q= + +### CACHED QUERY + +http://localhost:8080/cached_query?q= + +### UPDATE + +http://localhost:8080/update?q= + +### FORTUNES + +http://localhost:8080/fortunes diff --git a/frameworks/Go/goravel/benchmark_config.json b/frameworks/Go/goravel/benchmark_config.json new file mode 100644 index 00000000000..5be71f6fdbe --- /dev/null +++ b/frameworks/Go/goravel/benchmark_config.json @@ -0,0 +1,56 @@ +{ + "framework": "goravel", + "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": "Fullstack", + "database": "postgres", + "framework": "goravel", + "language": "Go", + "flavor": "None", + "orm": "Full", + "platform": "None", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "Goravel Gin", + "notes": "", + "versus": "go" + }, + "fiber": { + "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": "Fullstack", + "database": "postgres", + "framework": "goravel", + "language": "Go", + "flavor": "None", + "orm": "Full", + "platform": "None", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "Goravel Fiber", + "notes": "", + "tags": ["broken"], + "versus": "go" + } + } + ] +} diff --git a/frameworks/Go/goravel/goravel-fiber.dockerfile b/frameworks/Go/goravel/goravel-fiber.dockerfile new file mode 100644 index 00000000000..91d583dface --- /dev/null +++ b/frameworks/Go/goravel/goravel-fiber.dockerfile @@ -0,0 +1,21 @@ +FROM golang:1.22-alpine + +ENV GO111MODULE=on \ + CGO_ENABLED=0 \ + GOAMD64=v3 \ + GOARCH="amd64" \ + GOOS=linux + +WORKDIR /go/goravel + +COPY ./src/fiber /go/goravel + +RUN go mod tidy + +RUN go generate -x ./templates + +RUN go build -ldflags '-s -w --extldflags "-static"' -o /go/goravel/main + +EXPOSE 8080 + +CMD /go/goravel/main diff --git a/frameworks/Go/goravel/goravel.dockerfile b/frameworks/Go/goravel/goravel.dockerfile new file mode 100644 index 00000000000..2000cbbcf35 --- /dev/null +++ b/frameworks/Go/goravel/goravel.dockerfile @@ -0,0 +1,19 @@ +FROM golang:1.22-alpine + +ENV GO111MODULE=on \ + CGO_ENABLED=0 \ + GOAMD64=v3 \ + GOARCH="amd64" \ + GOOS=linux + +WORKDIR /go/goravel + +COPY ./src/gin /go/goravel + +RUN go mod tidy + +RUN go build -tags="sonic avx" -ldflags '-s -w --extldflags "-static"' -o /go/goravel/main + +EXPOSE 8080 + +CMD /go/goravel/main diff --git a/frameworks/Go/goravel/src/fiber/.env b/frameworks/Go/goravel/src/fiber/.env new file mode 100644 index 00000000000..9ceb9e63dc9 --- /dev/null +++ b/frameworks/Go/goravel/src/fiber/.env @@ -0,0 +1 @@ +APP_KEY=abcdefghijklmnopqrstuvwxyz123456 \ No newline at end of file diff --git a/frameworks/Go/goravel/src/fiber/app/http/controllers/test_controller.go b/frameworks/Go/goravel/src/fiber/app/http/controllers/test_controller.go new file mode 100644 index 00000000000..c433f221e7b --- /dev/null +++ b/frameworks/Go/goravel/src/fiber/app/http/controllers/test_controller.go @@ -0,0 +1,126 @@ +package controllers + +import ( + "math/rand/v2" + "sort" + + "github.com/goravel/framework/contracts/http" + "github.com/goravel/framework/facades" + + "goravel/templates" +) + +type TestController struct{} + +func NewTestController() *TestController { + initCache() + return &TestController{} +} + +func (r *TestController) Plaintext(ctx http.Context) http.Response { + Plaintext(ctx, helloworld) + return nil +} + +func (r *TestController) JSON(ctx http.Context) http.Response { + message := acquireMessage() + message.Message = helloworld + + JSON(ctx, &message) + releaseMessage(message) + return nil +} + +func (r *TestController) DB(ctx http.Context) http.Response { + world := acquireWorld() + + world.ID = r.getRand() + _ = facades.Orm().Query().Find(&world) + + JSON(ctx, &world) + releaseWorld(world) + return nil +} + +func (r *TestController) Queries(ctx http.Context) http.Response { + n := r.getN(ctx) + worlds := acquireWorlds()[:n] + + for i := 0; i < n; i++ { + worlds[i].ID = r.getRand() + _ = facades.Orm().Query().Find(&worlds[i]) + } + + JSON(ctx, &worlds) + releaseWorlds(worlds) + return nil +} + +func (r *TestController) Update(ctx http.Context) http.Response { + n := r.getN(ctx) + worlds := acquireWorlds()[:n] + + for i := 0; i < n; i++ { + worlds[i].ID = r.getRand() + _ = facades.Orm().Query().Find(&worlds[i]) + } + + // sorting is required for insert deadlock prevention. + sort.Slice(worlds, func(i, j int) bool { + return worlds[i].ID < worlds[j].ID + }) + + tx, _ := facades.Orm().Query().Begin() + for i := 0; i < n; i++ { + worlds[i].RandomNumber = r.getRand() + _ = tx.Save(&worlds[i]) + } + _ = tx.Commit() + + JSON(ctx, &worlds) + releaseWorlds(worlds) + return nil +} + +func (r *TestController) Fortunes(ctx http.Context) http.Response { + fortunes := make([]templates.Fortune, 0) + _ = facades.Orm().Query().Table("Fortune").Get(&fortunes) + + 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 + }) + + HTML(ctx) + templates.WriteFortunePage(ctx.Response().Writer(), fortunes) + return nil +} + +func (r *TestController) CacheQueries(ctx http.Context) http.Response { + n := r.getN(ctx) + worlds := acquireWorlds()[:n] + cached := facades.Cache().Get("worlds").(Worlds) + + for i := 0; i < n; i++ { + worlds[i] = cached[r.getRand()-1] + } + + JSON(ctx, &worlds) + releaseWorlds(worlds) + return nil +} + +func (r *TestController) getN(ctx http.Context) int { + n := ctx.Request().QueryInt(queryparam) + if n < 1 { + n = 1 + } else if n > 500 { + n = 500 + } + + return n +} + +func (r *TestController) getRand() int32 { + return rand.Int32N(worldcount) + 1 +} diff --git a/frameworks/Go/goravel/src/fiber/app/http/controllers/utils.go b/frameworks/Go/goravel/src/fiber/app/http/controllers/utils.go new file mode 100644 index 00000000000..b125edad3f3 --- /dev/null +++ b/frameworks/Go/goravel/src/fiber/app/http/controllers/utils.go @@ -0,0 +1,107 @@ +package controllers + +import ( + "fmt" + "sync" + "unsafe" + + "github.com/bytedance/sonic" + "github.com/goravel/framework/contracts/http" + "github.com/goravel/framework/facades" + + "goravel/app/models" +) + +const ( + queryparam = "q" + helloworld = "Hello, World!" + worldcount = 10000 + contentTypePlain = "text/plain; charset=utf-8" + contentTypeHtml = "text/html; charset=utf-8" + contentTypeJson = "application/json" +) + +type Message struct { + Message string `json:"message"` +} + +type Worlds []models.World + +var messagePool = sync.Pool{ + New: func() any { + return new(Message) + }, +} + +var worldPool = sync.Pool{ + New: func() any { + return new(models.World) + }, +} + +var worldsPool = sync.Pool{ + New: func() any { + return make(Worlds, 0, 500) + }, +} + +func acquireMessage() *Message { + return messagePool.Get().(*Message) +} + +func releaseMessage(m *Message) { + m.Message = "" + messagePool.Put(m) +} + +func acquireWorld() *models.World { + return worldPool.Get().(*models.World) +} + +func releaseWorld(w *models.World) { + w.ID = 0 + w.RandomNumber = 0 + worldPool.Put(w) +} + +func acquireWorlds() Worlds { + return worldsPool.Get().(Worlds) +} + +func releaseWorlds(w Worlds) { + w = w[:0] + worldsPool.Put(w) +} + +func str2bytes(s string) []byte { + return unsafe.Slice(unsafe.StringData(s), len(s)) +} + +func initCache() { + worlds := acquireWorlds() + defer releaseWorlds(worlds) + + if err := facades.Orm().Query().Get(&worlds); err != nil { + panic(fmt.Sprintf("Failed to init cached Worlds: %v", err)) + } + + facades.Cache().Forever("worlds", worlds) +} + +func JSON(ctx http.Context, data any) { + ctx.Response().Header("Server", "Goravel") + ctx.Response().Header("Content-Type", contentTypeJson) + bytes, _ := sonic.Marshal(data) + _, _ = ctx.Response().Writer().Write(bytes) +} + +func Plaintext(ctx http.Context, data string) { + ctx.Response().Header("Server", "Goravel") + ctx.Response().Header("Content-Type", contentTypePlain) + _, _ = ctx.Response().Writer().Write(str2bytes(data)) +} + +func HTML(ctx http.Context) { + ctx.Response().Header("Server", "Goravel") + ctx.Response().Header("Content-Type", contentTypeHtml) +} diff --git a/frameworks/Go/goravel/src/fiber/app/models/world.go b/frameworks/Go/goravel/src/fiber/app/models/world.go new file mode 100644 index 00000000000..da724366273 --- /dev/null +++ b/frameworks/Go/goravel/src/fiber/app/models/world.go @@ -0,0 +1,10 @@ +package models + +type World struct { + ID int32 `gorm:"primaryKey" json:"id"` + RandomNumber int32 `gorm:"column:randomnumber" json:"randomNumber"` +} + +func (r *World) TableName() string { + return "World" +} diff --git a/frameworks/Go/goravel/src/fiber/app/providers/route_service_provider.go b/frameworks/Go/goravel/src/fiber/app/providers/route_service_provider.go new file mode 100644 index 00000000000..2e96015a24f --- /dev/null +++ b/frameworks/Go/goravel/src/fiber/app/providers/route_service_provider.go @@ -0,0 +1,16 @@ +package providers + +import ( + "github.com/goravel/framework/contracts/foundation" + + "goravel/routes" +) + +type RouteServiceProvider struct{} + +func (receiver *RouteServiceProvider) Register(app foundation.Application) { +} + +func (receiver *RouteServiceProvider) Boot(app foundation.Application) { + routes.Web() +} diff --git a/frameworks/Go/goravel/src/fiber/config/app.go b/frameworks/Go/goravel/src/fiber/config/app.go new file mode 100644 index 00000000000..3ab05123159 --- /dev/null +++ b/frameworks/Go/goravel/src/fiber/config/app.go @@ -0,0 +1,40 @@ +package config + +import ( + "github.com/goravel/fiber" + "github.com/goravel/framework/cache" + "github.com/goravel/framework/console" + "github.com/goravel/framework/contracts/foundation" + "github.com/goravel/framework/database" + "github.com/goravel/framework/facades" + "github.com/goravel/framework/http" + "github.com/goravel/framework/log" + "github.com/goravel/framework/route" + "github.com/goravel/framework/validation" + + "goravel/app/providers" +) + +// Boot Start all init methods of the current folder to bootstrap all config. +func Boot() {} + +func init() { + config := facades.Config() + config.Add("app", map[string]any{ + "name": "Goravel", + "env": "production", + "debug": false, + "key": config.Env("APP_KEY", ""), + "providers": []foundation.ServiceProvider{ + &log.ServiceProvider{}, + &console.ServiceProvider{}, + &database.ServiceProvider{}, + &cache.ServiceProvider{}, + &http.ServiceProvider{}, + &route.ServiceProvider{}, + &validation.ServiceProvider{}, + &providers.RouteServiceProvider{}, + &fiber.ServiceProvider{}, + }, + }) +} diff --git a/frameworks/Go/goravel/src/fiber/config/cache.go b/frameworks/Go/goravel/src/fiber/config/cache.go new file mode 100644 index 00000000000..3c638243c2c --- /dev/null +++ b/frameworks/Go/goravel/src/fiber/config/cache.go @@ -0,0 +1,18 @@ +package config + +import ( + "github.com/goravel/framework/facades" +) + +func init() { + config := facades.Config() + config.Add("cache", map[string]any{ + "default": "memory", + "stores": map[string]any{ + "memory": map[string]any{ + "driver": "memory", + }, + }, + "prefix": "goravel_cache", + }) +} diff --git a/frameworks/Go/goravel/src/fiber/config/database.go b/frameworks/Go/goravel/src/fiber/config/database.go new file mode 100644 index 00000000000..e1b1eb3272a --- /dev/null +++ b/frameworks/Go/goravel/src/fiber/config/database.go @@ -0,0 +1,32 @@ +package config + +import ( + "github.com/goravel/framework/facades" +) + +func init() { + config := facades.Config() + config.Add("database", map[string]any{ + "default": "postgresql", + "connections": map[string]any{ + "postgresql": map[string]any{ + "driver": "postgresql", + "host": config.Env("DB_HOST", "tfb-database"), + "port": config.Env("DB_PORT", 5432), + "database": config.Env("DB_DATABASE", "hello_world"), + "username": config.Env("DB_USERNAME", "benchmarkdbuser"), + "password": config.Env("DB_PASSWORD", "benchmarkdbpass"), + "sslmode": "disable", + "timezone": "UTC", + "prefix": "", + "singular": true, + }, + }, + "pool": map[string]any{ + "max_idle_conns": 100, + "max_open_conns": 2000, + "conn_max_idletime": 3600, + "conn_max_lifetime": 3600, + }, + }) +} diff --git a/frameworks/Go/goravel/src/fiber/config/http.go b/frameworks/Go/goravel/src/fiber/config/http.go new file mode 100644 index 00000000000..3d48d689691 --- /dev/null +++ b/frameworks/Go/goravel/src/fiber/config/http.go @@ -0,0 +1,26 @@ +package config + +import ( + fiberfacades "github.com/goravel/fiber/facades" + "github.com/goravel/framework/contracts/route" + "github.com/goravel/framework/facades" +) + +func init() { + config := facades.Config() + config.Add("http", map[string]any{ + "default": "fiber", + "drivers": map[string]any{ + "fiber": map[string]any{ + "prefork": true, + "body_limit": 4096, + "header_limit": 4096, + "route": func() (route.Route, error) { + return fiberfacades.Route("fiber"), nil + }, + }, + }, + "host": "", + "port": "8080", + }) +} diff --git a/frameworks/Go/goravel/src/fiber/config/json.go b/frameworks/Go/goravel/src/fiber/config/json.go new file mode 100644 index 00000000000..2b2e1af3f80 --- /dev/null +++ b/frameworks/Go/goravel/src/fiber/config/json.go @@ -0,0 +1,31 @@ +package config + +import ( + "github.com/bytedance/sonic" + "github.com/goravel/framework/contracts/foundation" + "github.com/goravel/framework/facades" +) + +func init() { + facades.App().SetJson(NewJson()) +} + +type Json struct { + marshal func(any) ([]byte, error) + unmarshal func([]byte, any) error +} + +func NewJson() foundation.Json { + return &Json{ + marshal: sonic.Marshal, + unmarshal: sonic.Unmarshal, + } +} + +func (j *Json) Marshal(v any) ([]byte, error) { + return j.marshal(v) +} + +func (j *Json) Unmarshal(data []byte, v any) error { + return j.unmarshal(data, v) +} diff --git a/frameworks/Go/goravel/src/fiber/go.mod b/frameworks/Go/goravel/src/fiber/go.mod new file mode 100644 index 00000000000..e0ee741ee37 --- /dev/null +++ b/frameworks/Go/goravel/src/fiber/go.mod @@ -0,0 +1,193 @@ +module goravel + +go 1.24.0 + +toolchain go1.24.1 + +require ( + github.com/bytedance/sonic v1.11.9 + github.com/goravel/fiber v1.2.1 + github.com/goravel/framework v1.14.1 + github.com/valyala/quicktemplate v1.7.0 +) + +require ( + atomicgo.dev/cursor v0.2.0 // indirect + atomicgo.dev/keyboard v0.2.9 // indirect + atomicgo.dev/schedule v0.1.0 // indirect + cloud.google.com/go v0.112.1 // indirect + cloud.google.com/go/compute v1.25.1 // indirect + 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 + 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 + github.com/Azure/go-autorest/logger v0.2.1 // indirect + github.com/Azure/go-autorest/tracing v0.6.0 // indirect + github.com/RichardKnop/logging v0.0.0-20190827224416-1a693bdd4fae // indirect + github.com/RichardKnop/machinery/v2 v2.0.13 // indirect + github.com/andybalholm/brotli v1.1.0 // indirect + github.com/atotto/clipboard v0.1.4 // indirect + github.com/aws/aws-sdk-go v1.49.6 // indirect + github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect + github.com/bytedance/sonic/loader v0.1.1 // indirect + github.com/catppuccin/go v0.2.0 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/charmbracelet/bubbles v0.18.0 // indirect + github.com/charmbracelet/bubbletea v0.26.3 // indirect + github.com/charmbracelet/huh v0.4.2 // indirect + github.com/charmbracelet/huh/spinner v0.0.0-20240508140610-13957916abf0 // indirect + github.com/charmbracelet/lipgloss v0.11.0 // indirect + github.com/charmbracelet/x/ansi v0.1.1 // indirect + github.com/charmbracelet/x/exp/strings v0.0.0-20240524151031-ff83003bf67a // indirect + github.com/charmbracelet/x/input v0.1.1 // indirect + github.com/charmbracelet/x/term v0.1.1 // indirect + github.com/charmbracelet/x/windows v0.1.2 // indirect + github.com/cloudwego/base64x v0.1.4 // indirect + github.com/cloudwego/iasm v0.2.0 // indirect + github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/dustin/go-humanize v1.0.1 // indirect + github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.4 // indirect + github.com/glebarez/go-sqlite v1.22.0 // indirect + github.com/glebarez/sqlite v1.11.0 // indirect + github.com/go-logr/logr v1.4.1 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + 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/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/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 + github.com/golang-module/carbon/v2 v2.3.12 // indirect + github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect + github.com/golang-sql/sqlexp v0.1.0 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/golang/protobuf v1.5.4 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/gomodule/redigo v2.0.0+incompatible // indirect + github.com/google/s2a-go v0.1.7 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/google/wire v0.6.0 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect + github.com/googleapis/gax-go/v2 v2.12.3 // indirect + github.com/gookit/color v1.5.4 // indirect + github.com/gookit/filter v1.2.1 // indirect + github.com/gookit/goutil v0.6.15 // indirect + github.com/gookit/validate v1.5.2 // indirect + github.com/goravel/file-rotatelogs/v2 v2.4.2 // indirect + github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect + github.com/jackc/pgx/v5 v5.5.4 // indirect + github.com/jackc/puddle/v2 v2.2.1 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect + github.com/jmespath/go-jmespath v0.4.0 // indirect + github.com/kelseyhightower/envconfig v1.4.0 // indirect + github.com/klauspost/compress v1.17.9 // indirect + github.com/klauspost/cpuid/v2 v2.2.7 // indirect + github.com/lib/pq v1.10.9 // indirect + github.com/lithammer/fuzzysearch v1.1.8 // indirect + github.com/lucasb-eyer/go-colorful v1.2.0 // indirect + github.com/magiconair/properties v1.8.7 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-localereader v0.0.1 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect + github.com/microsoft/go-mssqldb v1.6.0 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect + github.com/muesli/cancelreader v0.2.2 // indirect + github.com/muesli/termenv v0.15.2 // indirect + github.com/opentracing/opentracing-go v1.2.0 // indirect + github.com/patrickmn/go-cache v2.1.0+incompatible // indirect + github.com/pelletier/go-toml/v2 v2.2.2 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/pterm/pterm v0.12.79 // indirect + github.com/rabbitmq/amqp091-go v1.9.0 // indirect + github.com/redis/go-redis/v9 v9.5.3 // indirect + github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect + github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 // indirect + github.com/rivo/uniseg v0.4.7 // indirect + github.com/robfig/cron/v3 v3.0.1 // indirect + github.com/rogpeppe/go-internal v1.11.0 // indirect + github.com/rotisserie/eris v0.5.4 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/sagikazarmark/locafero v0.4.0 // indirect + github.com/sagikazarmark/slog-shim v0.1.0 // indirect + github.com/savioxavier/termlink v1.3.0 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect + github.com/sourcegraph/conc v0.3.0 // indirect + github.com/spf13/afero v1.11.0 // indirect + github.com/spf13/cast v1.6.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/spf13/viper v1.19.0 // indirect + github.com/stretchr/objx v0.5.2 // indirect + github.com/stretchr/testify v1.9.0 // indirect + github.com/subosito/gotenv v1.6.0 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/urfave/cli/v2 v2.27.2 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasthttp v1.55.0 // indirect + github.com/valyala/tcplisten v1.0.0 // indirect + github.com/xdg-go/pbkdf2 v1.0.0 // indirect + github.com/xdg-go/scram v1.1.1 // indirect + github.com/xdg-go/stringprep v1.0.3 // indirect + github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect + github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 // indirect + github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect + go.mongodb.org/mongo-driver v1.7.5 // indirect + go.opencensus.io v0.24.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect + go.opentelemetry.io/otel v1.24.0 // indirect + go.opentelemetry.io/otel/metric v1.24.0 // indirect + go.opentelemetry.io/otel/trace v1.24.0 // indirect + go.uber.org/atomic v1.11.0 // indirect + go.uber.org/multierr v1.9.0 // indirect + golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect + golang.org/x/crypto v0.45.0 // indirect + golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect + golang.org/x/net v0.47.0 // indirect + golang.org/x/oauth2 v0.18.0 // indirect + golang.org/x/sync v0.18.0 // indirect + golang.org/x/sys v0.38.0 // indirect + golang.org/x/term v0.37.0 // indirect + golang.org/x/text v0.31.0 // indirect + golang.org/x/time v0.5.0 // indirect + google.golang.org/api v0.171.0 // indirect + google.golang.org/appengine v1.6.8 // indirect + google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect + google.golang.org/grpc v1.64.1 // indirect + google.golang.org/protobuf v1.34.1 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + gorm.io/driver/mysql v1.5.6 // indirect + gorm.io/driver/postgres v1.5.7 // indirect + gorm.io/driver/sqlserver v1.5.3 // indirect + gorm.io/gorm v1.25.10 // indirect + gorm.io/plugin/dbresolver v1.5.1 // indirect + modernc.org/libc v1.37.6 // indirect + modernc.org/mathutil v1.6.0 // indirect + modernc.org/memory v1.7.2 // indirect + modernc.org/sqlite v1.28.0 // indirect +) diff --git a/frameworks/Go/goravel/src/fiber/go.sum b/frameworks/Go/goravel/src/fiber/go.sum new file mode 100644 index 00000000000..5e100bb5998 --- /dev/null +++ b/frameworks/Go/goravel/src/fiber/go.sum @@ -0,0 +1,1171 @@ +atomicgo.dev/assert v0.0.2 h1:FiKeMiZSgRrZsPo9qn/7vmr7mCsh5SZyXY4YGYiYwrg= +atomicgo.dev/assert v0.0.2/go.mod h1:ut4NcI3QDdJtlmAxQULOmA13Gz6e2DWbSAS8RUOmNYQ= +atomicgo.dev/cursor v0.2.0 h1:H6XN5alUJ52FZZUkI7AlJbUc1aW38GWZalpYRPpoPOw= +atomicgo.dev/cursor v0.2.0/go.mod h1:Lr4ZJB3U7DfPPOkbH7/6TOtJ4vFGHlgj1nc+n900IpU= +atomicgo.dev/keyboard v0.2.9 h1:tOsIid3nlPLZ3lwgG8KZMp/SFmr7P0ssEN5JUsm78K8= +atomicgo.dev/keyboard v0.2.9/go.mod h1:BC4w9g00XkxH/f1HXhW2sXmJFOCWbKn9xrOunSFtExQ= +atomicgo.dev/schedule v0.1.0 h1:nTthAbhZS5YZmgYbb2+DH8uQIZcTlIrd4eYr3UQxEjs= +atomicgo.dev/schedule v0.1.0/go.mod h1:xeUa3oAkiuHYh8bKiQBRojqAMq3PXXbJujjb0hw8pEU= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= +cloud.google.com/go v0.112.1 h1:uJSeirPke5UNZHIb4SxfZklVSiWWVqW4oXlETwZziwM= +cloud.google.com/go v0.112.1/go.mod h1:+Vbu+Y1UU+I1rjmzeMOb/8RfkKJK2Gyxi1X6jJCZLo4= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/compute v1.25.1 h1:ZRpHJedLtTpKgr3RV1Fx23NuaAEN1Zfx9hw1u4aJdjU= +cloud.google.com/go/compute v1.25.1/go.mod h1:oopOIR53ly6viBYxaDhBfJwzUAxf1zE//uf3IB011ls= +cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/iam v1.1.6 h1:bEa06k05IO4f4uJonbB5iAgKTPpABy1ayxaIZV/GHVc= +cloud.google.com/go/iam v1.1.6/go.mod h1:O0zxdPeGBoFdWW3HWmBxJsk0pfvNM/p/qa82rWOGTwI= +cloud.google.com/go/kms v1.15.7 h1:7caV9K3yIxvlQPAcaFffhlT7d1qpxjB1wHBtjWa13SM= +cloud.google.com/go/kms v1.15.7/go.mod h1:ub54lbsa6tDkUwnu4W7Yt1aAIFLnspgh0kPGToDukeI= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/pubsub v1.10.0/go.mod h1:eNpTrkOy7dCpkNyaSNetMa6udbgecJMd0ZsTJS/cuNo= +cloud.google.com/go/pubsub v1.36.1 h1:dfEPuGCHGbWUhaMCTHUFjfroILEkx55iUmKBZTP5f+Y= +cloud.google.com/go/pubsub v1.36.1/go.mod h1:iYjCa9EzWOoBiTdd4ps7QoMtMln5NwaZQpK1hbRfBDE= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +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= +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= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.1 h1:/iHxaJhsFr0+xVFfbMr5vxz848jyiWuIEDhYq3y5odY= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.1/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0 h1:vcYCAze6p19qBW7MhZybIsqD8sMV8js0NyQM8JDnVtg= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0/go.mod h1:OQeznEEkTZ9OrhHJoDD8ZDq51FHgXjqtP9z6bEwBq9U= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.1.2/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.2.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 h1:sXr+ck84g/ZlZUOZiNELInmMgOsuGwdjjVkEIde0OtY= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.0 h1:yfJe15aSwEQ6Oo6J+gdfdulPNoZ3TEhmbhLIoxZcA+U= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.0/go.mod h1:Q28U+75mpCaSCDowNEmhIo/rmgdkqmkmzI7N6TGR4UY= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v0.8.0 h1:T028gtTPiYt/RMUfs8nVsAL7FDQrfLlrm/NnRG/zcC4= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v0.8.0/go.mod h1:cw4zVQgBby0Z5f2v0itn6se2dDP17nTjbZFXW5uPyHA= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest/adal v0.9.16 h1:P8An8Z9rH1ldbOLdFpxYorgOt2sywL9V24dAwWHPuGc= +github.com/Azure/go-autorest/autorest/adal v0.9.16/go.mod h1:tGMin8I49Yij6AQ+rvV+Xa/zwxYQB5hmsd6DkfAx2+A= +github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/autorest/mocks v0.4.1 h1:K0laFcLE6VLTOwNgSxaGbUcLPuGXlNkbVvq4cW4nIHk= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg= +github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= +github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0/go.mod h1:kgDmCTgBzIEPFElEF+FK0SdjAor06dRq2Go927dnQ6o= +github.com/AzureAD/microsoft-authentication-library-for-go v1.1.0 h1:HCc0+LpPfpCKs6LGGLAhwBARt9632unrVcI6i8s/8os= +github.com/AzureAD/microsoft-authentication-library-for-go v1.1.0/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/MarvinJWendt/testza v0.1.0/go.mod h1:7AxNvlfeHP7Z/hDQ5JtE3OKYT3XFUeLCDE2DQninSqs= +github.com/MarvinJWendt/testza v0.2.1/go.mod h1:God7bhG8n6uQxwdScay+gjm9/LnO4D3kkcZX4hv9Rp8= +github.com/MarvinJWendt/testza v0.2.8/go.mod h1:nwIcjmr0Zz+Rcwfh3/4UhBp7ePKVhuBExvZqnKYWlII= +github.com/MarvinJWendt/testza v0.2.10/go.mod h1:pd+VWsoGUiFtq+hRKSU1Bktnn+DMCSrDrXDpX2bG66k= +github.com/MarvinJWendt/testza v0.2.12/go.mod h1:JOIegYyV7rX+7VZ9r77L/eH6CfJHHzXjB69adAhzZkI= +github.com/MarvinJWendt/testza v0.3.0/go.mod h1:eFcL4I0idjtIx8P9C6KkAuLgATNKpX4/2oUqKc6bF2c= +github.com/MarvinJWendt/testza v0.4.2/go.mod h1:mSdhXiKH8sg/gQehJ63bINcCKp7RtYewEjXsvsVUPbE= +github.com/MarvinJWendt/testza v0.5.2 h1:53KDo64C1z/h/d/stCYCPY69bt/OSwjq5KpFNwi+zB4= +github.com/MarvinJWendt/testza v0.5.2/go.mod h1:xu53QFE5sCdjtMCKk8YMQ2MnymimEctc4n3EjyIYvEY= +github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/RichardKnop/logging v0.0.0-20190827224416-1a693bdd4fae h1:DcFpTQBYQ9Ct2d6sC7ol0/ynxc2pO1cpGUM+f4t5adg= +github.com/RichardKnop/logging v0.0.0-20190827224416-1a693bdd4fae/go.mod h1:rJJ84PyA/Wlmw1hO+xTzV2wsSUon6J5ktg0g8BF2PuU= +github.com/RichardKnop/machinery/v2 v2.0.13 h1:uo9htg+qNBi7UeUK3jcTBl3vTO/vvLKGaOdCOKePl50= +github.com/RichardKnop/machinery/v2 v2.0.13/go.mod h1:Yc2X/QRm9rRfAjB+93NGR+kSUqtnqqs8kME4L+TKKiw= +github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= +github.com/andybalholm/brotli v1.0.3/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= +github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= +github.com/atomicgo/cursor v0.0.1/go.mod h1:cBON2QmmrysudxNBFthvMtN32r3jxVRIvzkUiF/RuIk= +github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= +github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= +github.com/aws/aws-sdk-go v1.34.28/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48= +github.com/aws/aws-sdk-go v1.37.16/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.49.6 h1:yNldzF5kzLBRvKlKz1S0bkvc2+04R1kt13KfBWQBfFA= +github.com/aws/aws-sdk-go v1.49.6/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= +github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= +github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= +github.com/brianvoe/gofakeit/v6 v6.28.0 h1:Xib46XXuQfmlLS2EXRuJpqcw8St6qSZz75OUo0tgAW4= +github.com/brianvoe/gofakeit/v6 v6.28.0/go.mod h1:Xj58BMSnFqcn/fAQeSK+/PLtC5kSb7FJIq4JyGa8vEs= +github.com/bsm/ginkgo/v2 v2.5.0/go.mod h1:AiKlXPm7ItEHNc/2+OkrNG4E0ITzojb9/xWzvQ9XZ9w= +github.com/bsm/ginkgo/v2 v2.7.0/go.mod h1:AiKlXPm7ItEHNc/2+OkrNG4E0ITzojb9/xWzvQ9XZ9w= +github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= +github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= +github.com/bsm/gomega v1.20.0/go.mod h1:JifAceMQ4crZIWYUKrlGcmbN3bqHogVTADMD2ATsbwk= +github.com/bsm/gomega v1.26.0/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= +github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= +github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= +github.com/bytedance/sonic v1.11.9 h1:LFHENlIY/SLzDWverzdOvgMztTxcfcF+cqNsz9pK5zg= +github.com/bytedance/sonic v1.11.9/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4= +github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM= +github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= +github.com/catppuccin/go v0.2.0 h1:ktBeIrIP42b/8FGiScP9sgrWOss3lw0Z5SktRoithGA= +github.com/catppuccin/go v0.2.0/go.mod h1:8IHJuMGaUUjQM82qBrGNBv7LFq6JI3NnQCF6MOlZjpc= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/charmbracelet/bubbles v0.18.0 h1:PYv1A036luoBGroX6VWjQIE9Syf2Wby2oOl/39KLfy0= +github.com/charmbracelet/bubbles v0.18.0/go.mod h1:08qhZhtIwzgrtBjAcJnij1t1H0ZRjwHyGsy6AL11PSw= +github.com/charmbracelet/bubbletea v0.26.3 h1:iXyGvI+FfOWqkB2V07m1DF3xxQijxjY2j8PqiXYqasg= +github.com/charmbracelet/bubbletea v0.26.3/go.mod h1:bpZHfDHTYJC5g+FBK+ptJRCQotRC+Dhh3AoMxa/2+3Q= +github.com/charmbracelet/huh v0.4.2 h1:5wLkwrA58XDAfEZsJzNQlfJ+K8N9+wYwvR5FOM7jXFM= +github.com/charmbracelet/huh v0.4.2/go.mod h1:g9OXBgtY3zRV4ahnVih9bZE+1yGYN+y2C9Q6L2P+WM0= +github.com/charmbracelet/huh/spinner v0.0.0-20240508140610-13957916abf0 h1:79JTuYRirtyCn9ac6rzPt5AQKtBDFc1gKxpw0wBrI+Y= +github.com/charmbracelet/huh/spinner v0.0.0-20240508140610-13957916abf0/go.mod h1:Zxt9FH6togK9kY71pRJGtmyNkJ1eIWdK1gRaXrS/FKA= +github.com/charmbracelet/lipgloss v0.11.0 h1:UoAcbQ6Qml8hDwSWs0Y1cB5TEQuZkDPH/ZqwWWYTG4g= +github.com/charmbracelet/lipgloss v0.11.0/go.mod h1:1UdRTH9gYgpcdNN5oBtjbu/IzNKtzVtb7sqN1t9LNn8= +github.com/charmbracelet/x/ansi v0.1.1 h1:CGAduulr6egay/YVbGc8Hsu8deMg1xZ/bkaXTPi1JDk= +github.com/charmbracelet/x/ansi v0.1.1/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= +github.com/charmbracelet/x/exp/strings v0.0.0-20240524151031-ff83003bf67a h1:lOpqe2UvPmlln41DGoii7wlSZ/q8qGIon5JJ8Biu46I= +github.com/charmbracelet/x/exp/strings v0.0.0-20240524151031-ff83003bf67a/go.mod h1:pBhA0ybfXv6hDjQUZ7hk1lVxBiUbupdw5R31yPUViVQ= +github.com/charmbracelet/x/exp/term v0.0.0-20240524151031-ff83003bf67a h1:k/s6UoOSVynWiw7PlclyGO2VdVs5ZLbMIHiGp4shFZE= +github.com/charmbracelet/x/exp/term v0.0.0-20240524151031-ff83003bf67a/go.mod h1:YBotIGhfoWhHDlnUpJMkjebGV2pdGRCn1Y4/Nk/vVcU= +github.com/charmbracelet/x/input v0.1.1 h1:YDOJaTUKCqtGnq9PHzx3pkkl4pXDOANUHmhH3DqMtM4= +github.com/charmbracelet/x/input v0.1.1/go.mod h1:jvdTVUnNWj/RD6hjC4FsoB0SeZCJ2ZBkiuFP9zXvZI0= +github.com/charmbracelet/x/term v0.1.1 h1:3cosVAiPOig+EV4X9U+3LDgtwwAoEzJjNdwbXDjF6yI= +github.com/charmbracelet/x/term v0.1.1/go.mod h1:wB1fHt5ECsu3mXYusyzcngVWWlu1KKUmmLhfgr/Flxw= +github.com/charmbracelet/x/windows v0.1.2 h1:Iumiwq2G+BRmgoayww/qfcvof7W/3uLoelhxojXlRWg= +github.com/charmbracelet/x/windows v0.1.2/go.mod h1:GLEO/l+lizvFDBPLIOk+49gdX49L9YWMB5t+DZd0jkQ= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= +github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= +github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= +github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= +github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 h1:q2hJAaP1k2wIvVRd/hEHD7lacgqrCPS+k8g1MndzfWY= +github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/dhui/dktest v0.4.1 h1:/w+IWuDXVymg3IrRJCHHOkMK10m9aNVMOyD0X12YVTg= +github.com/dhui/dktest v0.4.1/go.mod h1:DdOqcUpL7vgyP4GlF3X3w7HbSlz8cEQzwewPveYEQbA= +github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko= +github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= +github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= +github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v24.0.9+incompatible h1:HPGzNmwfLZWdxHqK9/II92pyi1EpYKsAqcl4G0Of9v0= +github.com/docker/docker v24.0.9+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4= +github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/gabriel-vasile/mimetype v1.4.4 h1:QjV6pZ7/XZ7ryI2KuyeEDE8wnh7fHP9YnQy+R0LnH8I= +github.com/gabriel-vasile/mimetype v1.4.4/go.mod h1:JwLei5XPtWdGiMFB5Pjle1oEeoSeEuJfJE+TtfvdB/s= +github.com/glebarez/go-sqlite v1.22.0 h1:uAcMJhaA6r3LHMTFgP0SifzgXg46yJkgxqyuyec+ruQ= +github.com/glebarez/go-sqlite v1.22.0/go.mod h1:PlBIdHe0+aUEFn+r2/uthrWq4FxbzugL0L8Li6yQJbc= +github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GMw= +github.com/glebarez/sqlite v1.11.0/go.mod h1:h8/o8j5wiAsqSPoWELDUdJXhjAhsVliSn7bWZjOhrgQ= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +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.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/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-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg= +github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= +github.com/go-redis/redis/v7 v7.4.0 h1:7obg6wUoj05T0EpY0o8B59S9w5yeMWql7sw2kwNW1x4= +github.com/go-redis/redis/v7 v7.4.0/go.mod h1:JDNMw23GTyLNC4GZu9njt15ctBQVn7xjRfnwdHj/Dcg= +github.com/go-redis/redis/v8 v8.11.4/go.mod h1:2Z2wHZXdQpCDXEGzqMockDpNyYvi2l4Pxt6RJr792+w= +github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= +github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= +github.com/go-redsync/redsync/v4 v4.8.1 h1:rq2RvdTI0obznMdxKUWGdmmulo7lS9yCzb8fgDKOlbM= +github.com/go-redsync/redsync/v4 v4.8.1/go.mod h1:LmUAsQuQxhzZAoGY7JS6+dNhNmZyonMZiiEDY9plotM= +github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= +github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= +github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= +github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= +github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY= +github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg= +github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/flect v0.1.0/go.mod h1:d2ehjJqGOH/Kjqcoz+F7jHTBbmDb38yXA598Hb50EGs= +github.com/gobuffalo/flect v0.1.1/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= +github.com/gobuffalo/flect v0.1.3/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= +github.com/gobuffalo/genny v0.0.0-20190329151137-27723ad26ef9/go.mod h1:rWs4Z12d1Zbf19rlsn0nurr75KqhYp52EAGGxTbBhNk= +github.com/gobuffalo/genny v0.0.0-20190403191548-3ca520ef0d9e/go.mod h1:80lIj3kVJWwOrXWWMRzzdhW3DsrdjILVil/SFKBzF28= +github.com/gobuffalo/genny v0.1.0/go.mod h1:XidbUqzak3lHdS//TPu2OgiFB+51Ur5f7CSnXZ/JDvo= +github.com/gobuffalo/genny v0.1.1/go.mod h1:5TExbEyY48pfunL4QSXxlDOmdsD44RRq4mVZ0Ex28Xk= +github.com/gobuffalo/gitgen v0.0.0-20190315122116-cc086187d211/go.mod h1:vEHJk/E9DmhejeLeNt7UVvlSGv3ziL+djtTr3yyzcOw= +github.com/gobuffalo/gogen v0.0.0-20190315121717-8f38393713f5/go.mod h1:V9QVDIxsgKNZs6L2IYiGR8datgMhB577vzTDqypH360= +github.com/gobuffalo/gogen v0.1.0/go.mod h1:8NTelM5qd8RZ15VjQTFkAW6qOMx5wBbW4dSCS3BY8gg= +github.com/gobuffalo/gogen v0.1.1/go.mod h1:y8iBtmHmGc4qa3urIyo1shvOD8JftTtfcKi+71xfDNE= +github.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2/go.mod h1:QdxcLw541hSGtBnhUc4gaNIXRjiDppFGaDqzbrBd3v8= +github.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= +github.com/gobuffalo/mapi v1.0.2/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= +github.com/gobuffalo/packd v0.0.0-20190315124812-a385830c7fc0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= +github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= +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/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/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= +github.com/golang-jwt/jwt/v4 v4.4.3/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo= +github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8= +github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang-migrate/migrate/v4 v4.17.1 h1:4zQ6iqL6t6AiItphxJctQb3cFqWiSpMnX7wLTPnnYO4= +github.com/golang-migrate/migrate/v4 v4.17.1/go.mod h1:m8hinFyWBn0SA4QKHuKh175Pm9wjmxj3S2Mia7dbXzM= +github.com/golang-module/carbon/v2 v2.3.12 h1:VC1DwN1kBwJkh5MjXmTFryjs5g4CWyoM8HAHffZPX/k= +github.com/golang-module/carbon/v2 v2.3.12/go.mod h1:HNsedGzXGuNciZImYP2OMnpiwq/vhIstR/vn45ib5cI= +github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA= +github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= +github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= +github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/gomodule/redigo v1.8.2/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0= +github.com/gomodule/redigo v1.9.2/go.mod h1:KsU3hiK/Ay8U42qpaJk+kuNa3C+spxapWpM+ywhcgtw= +github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0= +github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ= +github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= +github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= +github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +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/google/wire v0.6.0 h1:HBkoIh4BdSxoyo9PveV8giw7ZsaBOvzWKfcg/6MrVwI= +github.com/google/wire v0.6.0/go.mod h1:F4QhpQ9EDIdJ1Mbop/NZBRB+5yrR6qg3BnctaoUk6NA= +github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= +github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gax-go/v2 v2.12.3 h1:5/zPPDvw8Q1SuXjrqrZslrqT7dL/uJT2CQii/cLCKqA= +github.com/googleapis/gax-go/v2 v2.12.3/go.mod h1:AKloxT6GtNbaLm8QTNSidHUVsHYcBHwWRvkNFJUQcS4= +github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ= +github.com/gookit/color v1.5.0/go.mod h1:43aQb+Zerm/BWh2GnrgOQm7ffz7tvQXEKV6BFMl7wAo= +github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0= +github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w= +github.com/gookit/filter v1.2.1 h1:37XivkBm2E5qe1KaGdJ5ZfF5l9NYdGWfLEeQadJD8O4= +github.com/gookit/filter v1.2.1/go.mod h1:rxynQFr793x+XDwnRmJFEb53zDw0Zqx3OD7TXWoR9mQ= +github.com/gookit/goutil v0.6.15 h1:mMQ0ElojNZoyPD0eVROk5QXJPh2uKR4g06slgPDF5Jo= +github.com/gookit/goutil v0.6.15/go.mod h1:qdKdYEHQdEtyH+4fNdQNZfJHhI0jUZzHxQVAV3DaMDY= +github.com/gookit/validate v1.5.2 h1:i5I2OQ7WYHFRPRATGu9QarR9snnNHydvwSuHXaRWAV0= +github.com/gookit/validate v1.5.2/go.mod h1:yuPy2WwDlwGRa06fFJ5XIO8QEwhRnTC2LmxmBa5SE14= +github.com/goravel/fiber v1.2.1 h1:+hVmrxDzbT1bF/9bIgYytnROTgF1u+xgiVGM3N0S1E4= +github.com/goravel/fiber v1.2.1/go.mod h1:DB4QvgQ/WBqgXGs1cemhqAHFvj7jtI/Irk0RhHBWKoQ= +github.com/goravel/file-rotatelogs/v2 v2.4.2 h1:g68AzbePXcm0V2CpUMc9j4qVzcDn7+7aoWSjZ51C0m4= +github.com/goravel/file-rotatelogs/v2 v2.4.2/go.mod h1:23VuSW8cBS4ax5cmbV+5AaiLpq25b8UJ96IhbAkdo8I= +github.com/goravel/framework v1.14.1 h1:VcJvzn1ItFQh/rQZO1EMkxKmzDrww1S+OGz4hjZi3UY= +github.com/goravel/framework v1.14.1/go.mod h1:rScDXGQZdoVfyxemNPmijlz/2a+lWNOa4jTuak5GGVg= +github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= +github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= +github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= +github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +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-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.5.4 h1:Xp2aQS8uXButQdnCMWNmvx6UysWQQC+u1EoizjguY+8= +github.com/jackc/pgx/v5 v5.5.4/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A= +github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= +github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= +github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= +github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo= +github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= +github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs= +github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= +github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= +github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= +github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= +github.com/klauspost/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.0.10/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= +github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= +github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= +github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc h1:RKf14vYWi2ttpEmkA4aQ3j4u9dStX2t4M8UM6qqNsG8= +github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc/go.mod h1:kopuH9ugFRkIXf3YoqHKyrJ9YfUFsckUU9S7B+XP+is= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lithammer/fuzzysearch v1.1.8 h1:/HIuJnjHuXS8bKaiTMeeDlW2/AyIWk2brx1V8LFgLN4= +github.com/lithammer/fuzzysearch v1.1.8/go.mod h1:IdqeyBClc3FFqSzYq/MXESsS4S0FsZ5ajtkr5xPLts4= +github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= +github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= +github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +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-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4= +github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= +github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +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/microsoft/go-mssqldb v1.6.0 h1:mM3gYdVwEPFrlg/Dvr2DNVEgYFG7L42l+dGc67NNNpc= +github.com/microsoft/go-mssqldb v1.6.0/go.mod h1:00mDtPbeQCRGC1HwOOR5K/gr30P1NcEG0vx6Kbv2aJU= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= +github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= +github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= +github.com/montanaflynn/stats v0.7.0/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= +github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI= +github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo= +github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= +github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= +github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo= +github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= +github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= +github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= +github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= +github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= +github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= +github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= +github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= +github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= +github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/pterm/pterm v0.12.27/go.mod h1:PhQ89w4i95rhgE+xedAoqous6K9X+r6aSOI2eFF7DZI= +github.com/pterm/pterm v0.12.29/go.mod h1:WI3qxgvoQFFGKGjGnJR849gU0TsEOvKn5Q8LlY1U7lg= +github.com/pterm/pterm v0.12.30/go.mod h1:MOqLIyMOgmTDz9yorcYbcw+HsgoZo3BQfg2wtl3HEFE= +github.com/pterm/pterm v0.12.31/go.mod h1:32ZAWZVXD7ZfG0s8qqHXePte42kdz8ECtRyEejaWgXU= +github.com/pterm/pterm v0.12.33/go.mod h1:x+h2uL+n7CP/rel9+bImHD5lF3nM9vJj80k9ybiiTTE= +github.com/pterm/pterm v0.12.36/go.mod h1:NjiL09hFhT/vWjQHSj1athJpx6H8cjpHXNAK5bUw8T8= +github.com/pterm/pterm v0.12.40/go.mod h1:ffwPLwlbXxP+rxT0GsgDTzS3y3rmpAO1NMjUkGTYf8s= +github.com/pterm/pterm v0.12.79 h1:lH3yrYMhdpeqX9y5Ep1u7DejyHy7NSQg9qrBjF9dFT4= +github.com/pterm/pterm v0.12.79/go.mod h1:1v/gzOF1N0FsjbgTHZ1wVycRkKiatFvJSJC4IGaQAAo= +github.com/rabbitmq/amqp091-go v1.9.0 h1:qrQtyzB4H8BQgEuJwhmVQqVHB9O4+MNDJCCAcpc3Aoo= +github.com/rabbitmq/amqp091-go v1.9.0/go.mod h1:+jPrT9iY2eLjRaMSRHUhc3z14E/l85kv/f+6luSD3pc= +github.com/redis/go-redis/v9 v9.0.2/go.mod h1:/xDTe9EF1LM61hek62Poq2nzQSGj0xSrEtEHbBQevps= +github.com/redis/go-redis/v9 v9.0.5/go.mod h1:WqMKv5vnQbRuZstUwxQI195wHy+t4PuXDOjzMvcuQHk= +github.com/redis/go-redis/v9 v9.5.3 h1:fOAp1/uJG+ZtcITgZOfYFmTKPE7n4Vclj1wZFgRciUU= +github.com/redis/go-redis/v9 v9.5.3/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 h1:mZHayPoR0lNmnHyvtYjDeq0zlVHn9K/ZXoy17ylucdo= +github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5/go.mod h1:GEXHk5HgEKCvEIIrSpFI3ozzG5xOKA2DVlEX/gGnewM= +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/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= +github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= +github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= +github.com/rotisserie/eris v0.5.4 h1:Il6IvLdAapsMhvuOahHWiBnl1G++Q0/L5UIkI5mARSk= +github.com/rotisserie/eris v0.5.4/go.mod h1:Z/kgYTJiJtocxCbFfvRmO+QejApzG6zpyky9G1A4g9s= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= +github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= +github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= +github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= +github.com/savioxavier/termlink v1.3.0 h1:3Gl4FzQjUyiHzmoEDfmWEhgIwDiJY4poOQHP+k8ReA4= +github.com/savioxavier/termlink v1.3.0/go.mod h1:5T5ePUlWbxCHIwyF8/Ez1qufOoGM89RCg9NvG+3G3gc= +github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= +github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= +github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= +github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= +github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= +github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +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.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stvp/tempredis v0.0.0-20181119212430-b82af8480203 h1:QVqDTf3h2WHt08YuiTGPZLls0Wq99X9bWd0Q5ZSBesM= +github.com/stvp/tempredis v0.0.0-20181119212430-b82af8480203/go.mod h1:oqN97ltKNihBbwlX8dLpwxCl3+HnXKV/R0e+sRLd9C8= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +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/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli/v2 v2.27.2 h1:6e0H+AkS+zDckwPCUrZkKX38mRaau4nL2uipkJpbkcI= +github.com/urfave/cli/v2 v2.27.2/go.mod h1:g0+79LmHHATl7DAcHO99smiR/T7uGLw84w8Y42x+4eM= +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.30.0/go.mod h1:2rsYD01CKFrjjsvFxx75KlEUNpWNBY9JWD3K/7o2Cus= +github.com/valyala/fasthttp v1.55.0 h1:Zkefzgt6a7+bVKHnu/YaYSOPfNYNisSVBo/unVCf8k8= +github.com/valyala/fasthttp v1.55.0/go.mod h1:NkY9JtkrpPKmgwV3HTaS2HWaJss9RSIsRVfcxxoHiOM= +github.com/valyala/quicktemplate v1.7.0 h1:LUPTJmlVcb46OOUY3IeD9DojFpAVbsG+5WFTcjMJzCM= +github.com/valyala/quicktemplate v1.7.0/go.mod h1:sqKJnoaOF88V07vkO+9FL8fb9uZg/VPSJnLYn+LmLk8= +github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= +github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= +github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= +github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= +github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= +github.com/xdg-go/scram v1.1.1 h1:VOMT+81stJgXW3CpHyqHN3AXDYIMsx56mEFrB37Mb/E= +github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= +github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= +github.com/xdg-go/stringprep v1.0.3 h1:kdwGpVNwPFtjs98xCGkHjQtGKh86rDcRZN17QEMCOIs= +github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= +github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= +github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= +github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs= +github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= +github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= +github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 h1:+qGGcbkzsfDQNPPe9UDgpxAWQrhbbBXOYJFQDq/dtJw= +github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913/go.mod h1:4aEEwZQutDLsQv2Deui4iYQ6DWTxR14g6m8Wv88+Xqk= +github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA= +github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.einride.tech/aip v0.66.0 h1:XfV+NQX6L7EOYK11yoHHFtndeaWh3KbD9/cN/6iWEt8= +go.einride.tech/aip v0.66.0/go.mod h1:qAhMsfT7plxBX+Oy7Huol6YUvZ0ZzdUz26yZsQwfl1M= +go.mongodb.org/mongo-driver v1.4.6/go.mod h1:WcMNYLx/IlOxLe6JRJiv2uXuCz6zBLndR4SoGjYphSc= +go.mongodb.org/mongo-driver v1.7.5 h1:ny3p0reEpgsR2cfA5cjgwFZg3Cv/ofFh/8jbhGtz9VI= +go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= +go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= +go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= +go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= +go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= +go.opentelemetry.io/otel/sdk v1.22.0 h1:6coWHw9xw7EfClIC/+O31R8IY3/+EiRFHevmHafB2Gw= +go.opentelemetry.io/otel/sdk v1.22.0/go.mod h1:iu7luyVGYovrRpe2fmj3CVKouQNdTOkxtLzPvPz1DOc= +go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= +go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= +go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= +go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= +go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= +go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= +go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= +golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= +golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA= +golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= +golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210113205817-d3ed898aa8a3/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI= +golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +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.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +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.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +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/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= +golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= +golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= +golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= +golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= +golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= +golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ= +golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.39.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.171.0 h1:w174hnBPqut76FzW5Qaupt7zY8Kql6fiVjgys4f58sU= +google.golang.org/api v0.171.0/go.mod h1:Hnq5AHm4OTMt2BUVjael2CWZFD6vksJdWCWiUAmjC9o= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= +google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210207032614-bba0dbe2a9ea/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY= +google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo= +google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237 h1:RFiFrvy37/mpSpdySBDrUdipW/dHwsRwh3J3+A9VgT4= +google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237/go.mod h1:Z5Iiy3jtmioajWHDGFk7CeugTyHtPvMHA4UTmUkyalE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 h1:NnYq6UN9ReLM9/Y01KWNOWyI5xQ9kbIms5GGJVwS/Yc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.64.1 h1:LKtvyfbX3UGVPFcGqJ9ItpVWW6oN/2XqTxfAnwRRXiA= +google.golang.org/grpc v1.64.1/go.mod h1:hiQF4LFZelK2WKaP6W0L92zGHtiQdZxk8CrSdvyjeP0= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= +google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/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/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/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= +gorm.io/driver/mysql v1.4.3/go.mod h1:sSIebwZAVPiT+27jK9HIwvsqOGKx3YMPmrA3mBJR10c= +gorm.io/driver/mysql v1.5.6 h1:Ld4mkIickM+EliaQZQx3uOJDJHtrd70MxAUqWqlx3Y8= +gorm.io/driver/mysql v1.5.6/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM= +gorm.io/driver/postgres v1.5.7 h1:8ptbNJTDbEmhdr62uReG5BGkdQyeasu/FZHxI0IMGnM= +gorm.io/driver/postgres v1.5.7/go.mod h1:3e019WlBaYI5o5LIdNV+LyxCMNtLOQETBXL2h4chKpA= +gorm.io/driver/sqlserver v1.5.3 h1:rjupPS4PVw+rjJkfvr8jn2lJ8BMhT4UW5FwuJY0P3Z0= +gorm.io/driver/sqlserver v1.5.3/go.mod h1:B+CZ0/7oFJ6tAlefsKoyxdgDCXJKSgwS2bMOQZT0I00= +gorm.io/gorm v1.23.8/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= +gorm.io/gorm v1.25.2/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= +gorm.io/gorm v1.25.7-0.20240204074919-46816ad31dde/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= +gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= +gorm.io/gorm v1.25.10 h1:dQpO+33KalOA+aFYGlK+EfxcI5MbO7EP2yYygwh9h+s= +gorm.io/gorm v1.25.10/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= +gorm.io/plugin/dbresolver v1.5.1 h1:s9Dj9f7r+1rE3nx/Ywzc85nXptUEaeOO0pt27xdopM8= +gorm.io/plugin/dbresolver v1.5.1/go.mod h1:l4Cn87EHLEYuqUncpEeTC2tTJQkjngPSD+lo8hIvcT0= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +modernc.org/libc v1.37.6 h1:orZH3c5wmhIQFTXF+Nt+eeauyd+ZIt2BX6ARe+kD+aw= +modernc.org/libc v1.37.6/go.mod h1:YAXkAZ8ktnkCKaN9sw/UDeUVkGYJ/YquGO4FTi5nmHE= +modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= +modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= +modernc.org/memory v1.7.2 h1:Klh90S215mmH8c9gO98QxQFsY+W451E8AnzjoE2ee1E= +modernc.org/memory v1.7.2/go.mod h1:NO4NVCQy0N7ln+T9ngWqOQfi7ley4vpwvARR+Hjw95E= +modernc.org/sqlite v1.28.0 h1:Zx+LyDDmXczNnEQdvPuEfcFVA2ZPyaD7UCZDjef3BHQ= +modernc.org/sqlite v1.28.0/go.mod h1:Qxpazz0zH8Z1xCFyi5GSL3FzbtZ3fvbjmywNogldEW0= +nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/frameworks/Go/goravel/src/fiber/main.go b/frameworks/Go/goravel/src/fiber/main.go new file mode 100644 index 00000000000..ddd89a4e1a1 --- /dev/null +++ b/frameworks/Go/goravel/src/fiber/main.go @@ -0,0 +1,27 @@ +package main + +import ( + "github.com/goravel/framework/facades" + "github.com/goravel/framework/foundation" + + "goravel/config" +) + +func main() { + app := foundation.NewApplication() + + // Bootstrap the application + app.Boot() + + // Bootstrap the config. + config.Boot() + + // Start HTTP server by facades.Route(). + go func() { + if err := facades.Route().Run(); err != nil { + facades.Log().Errorf("Route run error: %v", err) + } + }() + + select {} +} diff --git a/frameworks/Go/goravel/src/fiber/routes/web.go b/frameworks/Go/goravel/src/fiber/routes/web.go new file mode 100644 index 00000000000..86bfbccc2d4 --- /dev/null +++ b/frameworks/Go/goravel/src/fiber/routes/web.go @@ -0,0 +1,19 @@ +package routes + +import ( + "github.com/goravel/framework/facades" + + "goravel/app/http/controllers" +) + +func Web() { + testController := controllers.NewTestController() + facades.Route().Get("/plaintext", testController.Plaintext) + facades.Route().Get("/json", testController.JSON) + facades.Route().Get("/db", testController.DB) + facades.Route().Get("/queries", testController.Queries) + facades.Route().Get("/update", testController.Update) + facades.Route().Get("/fortunes", testController.Fortunes) + facades.Route().Get("/cached-worlds", testController.CacheQueries) + +} diff --git a/frameworks/Go/gearbox/src/templates/fortune.go b/frameworks/Go/goravel/src/fiber/templates/fortune.go similarity index 100% rename from frameworks/Go/gearbox/src/templates/fortune.go rename to frameworks/Go/goravel/src/fiber/templates/fortune.go diff --git a/frameworks/Go/gearbox/src/templates/fortune.qtpl b/frameworks/Go/goravel/src/fiber/templates/fortune.qtpl similarity index 100% rename from frameworks/Go/gearbox/src/templates/fortune.qtpl rename to frameworks/Go/goravel/src/fiber/templates/fortune.qtpl diff --git a/frameworks/Go/gearbox/src/templates/fortune.qtpl.go b/frameworks/Go/goravel/src/fiber/templates/fortune.qtpl.go similarity index 100% rename from frameworks/Go/gearbox/src/templates/fortune.qtpl.go rename to frameworks/Go/goravel/src/fiber/templates/fortune.qtpl.go diff --git a/frameworks/Go/goravel/src/gin/.env b/frameworks/Go/goravel/src/gin/.env new file mode 100644 index 00000000000..9ceb9e63dc9 --- /dev/null +++ b/frameworks/Go/goravel/src/gin/.env @@ -0,0 +1 @@ +APP_KEY=abcdefghijklmnopqrstuvwxyz123456 \ No newline at end of file diff --git a/frameworks/Go/goravel/src/gin/app/http/controllers/test_controller.go b/frameworks/Go/goravel/src/gin/app/http/controllers/test_controller.go new file mode 100644 index 00000000000..7b68b61daeb --- /dev/null +++ b/frameworks/Go/goravel/src/gin/app/http/controllers/test_controller.go @@ -0,0 +1,129 @@ +package controllers + +import ( + "math/rand/v2" + "sort" + + "github.com/goravel/framework/contracts/http" + "github.com/goravel/framework/facades" + + "goravel/app/models" +) + +type TestController struct{} + +func NewTestController() *TestController { + initCache() + return &TestController{} +} + +func (r *TestController) Plaintext(ctx http.Context) http.Response { + Plaintext(ctx, helloworld) + return nil +} + +func (r *TestController) JSON(ctx http.Context) http.Response { + message := acquireMessage() + message.Message = helloworld + + JSON(ctx, &message) + releaseMessage(message) + return nil +} + +func (r *TestController) DB(ctx http.Context) http.Response { + world := acquireWorld() + + world.ID = r.getRand() + _ = facades.Orm().Query().Find(&world) + + JSON(ctx, &world) + releaseWorld(world) + return nil +} + +func (r *TestController) Queries(ctx http.Context) http.Response { + n := r.getN(ctx) + worlds := acquireWorlds()[:n] + + for i := 0; i < n; i++ { + worlds[i].ID = r.getRand() + _ = facades.Orm().Query().Find(&worlds[i]) + } + + JSON(ctx, &worlds) + releaseWorlds(worlds) + return nil +} + +func (r *TestController) Update(ctx http.Context) http.Response { + n := r.getN(ctx) + worlds := acquireWorlds()[:n] + + for i := 0; i < n; i++ { + worlds[i].ID = r.getRand() + _ = facades.Orm().Query().Find(&worlds[i]) + } + + // sorting is required for insert deadlock prevention. + sort.Slice(worlds, func(i, j int) bool { + return worlds[i].ID < worlds[j].ID + }) + + tx, _ := facades.Orm().Query().Begin() + for i := 0; i < n; i++ { + worlds[i].RandomNumber = r.getRand() + _ = tx.Save(&worlds[i]) + } + _ = tx.Commit() + + JSON(ctx, &worlds) + releaseWorlds(worlds) + return nil +} + +func (r *TestController) Fortunes(ctx http.Context) http.Response { + fortunes := make([]models.Fortune, 0) + _ = facades.Orm().Query().Get(&fortunes) + fortunes = append(fortunes, models.Fortune{Message: "Additional fortune added at request time."}) + + sort.Slice(fortunes, func(i, j int) bool { + return fortunes[i].Message < fortunes[j].Message + }) + + return ctx.Response(). + Header("Server", "Goravel"). + View(). + Make("fortunes.tmpl", map[string]any{ + "fortunes": fortunes, + }) +} + +func (r *TestController) CacheQueries(ctx http.Context) http.Response { + n := r.getN(ctx) + worlds := acquireWorlds()[:n] + cached := facades.Cache().Get("worlds").(Worlds) + + for i := 0; i < n; i++ { + worlds[i] = cached[r.getRand()-1] + } + + JSON(ctx, &worlds) + releaseWorlds(worlds) + return nil +} + +func (r *TestController) getN(ctx http.Context) int { + n := ctx.Request().QueryInt(queryparam) + if n < 1 { + n = 1 + } else if n > 500 { + n = 500 + } + + return n +} + +func (r *TestController) getRand() int32 { + return rand.Int32N(worldcount) + 1 +} diff --git a/frameworks/Go/goravel/src/gin/app/http/controllers/utils.go b/frameworks/Go/goravel/src/gin/app/http/controllers/utils.go new file mode 100644 index 00000000000..9cac0d34b48 --- /dev/null +++ b/frameworks/Go/goravel/src/gin/app/http/controllers/utils.go @@ -0,0 +1,101 @@ +package controllers + +import ( + "fmt" + "sync" + "unsafe" + + "github.com/bytedance/sonic" + "github.com/goravel/framework/contracts/http" + "github.com/goravel/framework/facades" + + "goravel/app/models" +) + +const ( + queryparam = "q" + helloworld = "Hello, World!" + worldcount = 10000 + contentTypePlain = "text/plain; charset=utf-8" + contentTypeJson = "application/json" +) + +type Message struct { + Message string `json:"message"` +} + +type Worlds []models.World + +var messagePool = sync.Pool{ + New: func() any { + return new(Message) + }, +} + +var worldPool = sync.Pool{ + New: func() any { + return new(models.World) + }, +} + +var worldsPool = sync.Pool{ + New: func() any { + return make(Worlds, 0, 500) + }, +} + +func acquireMessage() *Message { + return messagePool.Get().(*Message) +} + +func releaseMessage(m *Message) { + m.Message = "" + messagePool.Put(m) +} + +func acquireWorld() *models.World { + return worldPool.Get().(*models.World) +} + +func releaseWorld(w *models.World) { + w.ID = 0 + w.RandomNumber = 0 + worldPool.Put(w) +} + +func acquireWorlds() Worlds { + return worldsPool.Get().(Worlds) +} + +func releaseWorlds(w Worlds) { + w = w[:0] + worldsPool.Put(w) +} + +func str2bytes(s string) []byte { + return unsafe.Slice(unsafe.StringData(s), len(s)) +} + +func initCache() { + worlds := acquireWorlds() + defer releaseWorlds(worlds) + + if err := facades.Orm().Query().Get(&worlds); err != nil { + panic(fmt.Sprintf("Failed to init cached Worlds: %v", err)) + } + + facades.Cache().Forever("worlds", worlds) +} + +func JSON(ctx http.Context, data any) { + ctx.Response().Header("Server", "Goravel") + ctx.Response().Header("Content-Type", contentTypeJson) + bytes, _ := sonic.Marshal(data) + _, _ = ctx.Response().Writer().Write(bytes) +} + +func Plaintext(ctx http.Context, data string) { + ctx.Response().Header("Server", "Goravel") + ctx.Response().Header("Content-Type", contentTypePlain) + _, _ = ctx.Response().Writer().Write(str2bytes(data)) +} diff --git a/frameworks/Go/goravel/src/gin/app/models/fortune.go b/frameworks/Go/goravel/src/gin/app/models/fortune.go new file mode 100644 index 00000000000..8e8e1dd21a8 --- /dev/null +++ b/frameworks/Go/goravel/src/gin/app/models/fortune.go @@ -0,0 +1,10 @@ +package models + +type Fortune struct { + ID uint `gorm:"primaryKey" json:"id"` + Message string `gorm:"column:message" json:"message"` +} + +func (r *Fortune) TableName() string { + return "Fortune" +} diff --git a/frameworks/Go/goravel/src/gin/app/models/world.go b/frameworks/Go/goravel/src/gin/app/models/world.go new file mode 100644 index 00000000000..da724366273 --- /dev/null +++ b/frameworks/Go/goravel/src/gin/app/models/world.go @@ -0,0 +1,10 @@ +package models + +type World struct { + ID int32 `gorm:"primaryKey" json:"id"` + RandomNumber int32 `gorm:"column:randomnumber" json:"randomNumber"` +} + +func (r *World) TableName() string { + return "World" +} diff --git a/frameworks/Go/goravel/src/gin/app/providers/route_service_provider.go b/frameworks/Go/goravel/src/gin/app/providers/route_service_provider.go new file mode 100644 index 00000000000..2e96015a24f --- /dev/null +++ b/frameworks/Go/goravel/src/gin/app/providers/route_service_provider.go @@ -0,0 +1,16 @@ +package providers + +import ( + "github.com/goravel/framework/contracts/foundation" + + "goravel/routes" +) + +type RouteServiceProvider struct{} + +func (receiver *RouteServiceProvider) Register(app foundation.Application) { +} + +func (receiver *RouteServiceProvider) Boot(app foundation.Application) { + routes.Web() +} diff --git a/frameworks/Go/goravel/src/gin/config/app.go b/frameworks/Go/goravel/src/gin/config/app.go new file mode 100644 index 00000000000..f6f898c90fd --- /dev/null +++ b/frameworks/Go/goravel/src/gin/config/app.go @@ -0,0 +1,40 @@ +package config + +import ( + "github.com/goravel/framework/cache" + "github.com/goravel/framework/console" + "github.com/goravel/framework/contracts/foundation" + "github.com/goravel/framework/database" + "github.com/goravel/framework/facades" + "github.com/goravel/framework/http" + "github.com/goravel/framework/log" + "github.com/goravel/framework/route" + "github.com/goravel/framework/validation" + "github.com/goravel/gin" + + "goravel/app/providers" +) + +// Boot Start all init methods of the current folder to bootstrap all config. +func Boot() {} + +func init() { + config := facades.Config() + config.Add("app", map[string]any{ + "name": "Goravel", + "env": "production", + "debug": false, + "key": config.Env("APP_KEY", ""), + "providers": []foundation.ServiceProvider{ + &log.ServiceProvider{}, + &console.ServiceProvider{}, + &database.ServiceProvider{}, + &cache.ServiceProvider{}, + &http.ServiceProvider{}, + &route.ServiceProvider{}, + &validation.ServiceProvider{}, + &providers.RouteServiceProvider{}, + &gin.ServiceProvider{}, + }, + }) +} diff --git a/frameworks/Go/goravel/src/gin/config/cache.go b/frameworks/Go/goravel/src/gin/config/cache.go new file mode 100644 index 00000000000..3c638243c2c --- /dev/null +++ b/frameworks/Go/goravel/src/gin/config/cache.go @@ -0,0 +1,18 @@ +package config + +import ( + "github.com/goravel/framework/facades" +) + +func init() { + config := facades.Config() + config.Add("cache", map[string]any{ + "default": "memory", + "stores": map[string]any{ + "memory": map[string]any{ + "driver": "memory", + }, + }, + "prefix": "goravel_cache", + }) +} diff --git a/frameworks/Go/goravel/src/gin/config/database.go b/frameworks/Go/goravel/src/gin/config/database.go new file mode 100644 index 00000000000..e1b1eb3272a --- /dev/null +++ b/frameworks/Go/goravel/src/gin/config/database.go @@ -0,0 +1,32 @@ +package config + +import ( + "github.com/goravel/framework/facades" +) + +func init() { + config := facades.Config() + config.Add("database", map[string]any{ + "default": "postgresql", + "connections": map[string]any{ + "postgresql": map[string]any{ + "driver": "postgresql", + "host": config.Env("DB_HOST", "tfb-database"), + "port": config.Env("DB_PORT", 5432), + "database": config.Env("DB_DATABASE", "hello_world"), + "username": config.Env("DB_USERNAME", "benchmarkdbuser"), + "password": config.Env("DB_PASSWORD", "benchmarkdbpass"), + "sslmode": "disable", + "timezone": "UTC", + "prefix": "", + "singular": true, + }, + }, + "pool": map[string]any{ + "max_idle_conns": 100, + "max_open_conns": 2000, + "conn_max_idletime": 3600, + "conn_max_lifetime": 3600, + }, + }) +} diff --git a/frameworks/Go/goravel/src/gin/config/http.go b/frameworks/Go/goravel/src/gin/config/http.go new file mode 100644 index 00000000000..9d8846ee610 --- /dev/null +++ b/frameworks/Go/goravel/src/gin/config/http.go @@ -0,0 +1,30 @@ +package config + +import ( + "github.com/gin-gonic/gin/render" + "github.com/goravel/framework/contracts/route" + "github.com/goravel/framework/facades" + "github.com/goravel/gin" + ginfacades "github.com/goravel/gin/facades" +) + +func init() { + config := facades.Config() + config.Add("http", map[string]any{ + "default": "gin", + "drivers": map[string]any{ + "gin": map[string]any{ + "body_limit": 4096, + "header_limit": 4096, + "route": func() (route.Route, error) { + return ginfacades.Route("gin"), nil + }, + "template": func() (render.HTMLRender, error) { + return gin.DefaultTemplate() + }, + }, + }, + "host": "", + "port": "8080", + }) +} diff --git a/frameworks/Go/goravel/src/gin/config/json.go b/frameworks/Go/goravel/src/gin/config/json.go new file mode 100644 index 00000000000..2b2e1af3f80 --- /dev/null +++ b/frameworks/Go/goravel/src/gin/config/json.go @@ -0,0 +1,31 @@ +package config + +import ( + "github.com/bytedance/sonic" + "github.com/goravel/framework/contracts/foundation" + "github.com/goravel/framework/facades" +) + +func init() { + facades.App().SetJson(NewJson()) +} + +type Json struct { + marshal func(any) ([]byte, error) + unmarshal func([]byte, any) error +} + +func NewJson() foundation.Json { + return &Json{ + marshal: sonic.Marshal, + unmarshal: sonic.Unmarshal, + } +} + +func (j *Json) Marshal(v any) ([]byte, error) { + return j.marshal(v) +} + +func (j *Json) Unmarshal(data []byte, v any) error { + return j.unmarshal(data, v) +} diff --git a/frameworks/Go/goravel/src/gin/go.mod b/frameworks/Go/goravel/src/gin/go.mod new file mode 100644 index 00000000000..1e61f0b5682 --- /dev/null +++ b/frameworks/Go/goravel/src/gin/go.mod @@ -0,0 +1,194 @@ +module goravel + +go 1.22 + +require ( + github.com/bytedance/sonic v1.11.9 + github.com/gin-gonic/gin v1.10.0 + github.com/goravel/framework v1.14.1 + github.com/goravel/gin v1.2.1 +) + +require ( + atomicgo.dev/cursor v0.2.0 // indirect + atomicgo.dev/keyboard v0.2.9 // indirect + atomicgo.dev/schedule v0.1.0 // indirect + cloud.google.com/go v0.112.1 // indirect + cloud.google.com/go/compute v1.25.1 // indirect + 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 + 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 + github.com/Azure/go-autorest/logger v0.2.1 // indirect + github.com/Azure/go-autorest/tracing v0.6.0 // indirect + github.com/RichardKnop/logging v0.0.0-20190827224416-1a693bdd4fae // indirect + github.com/RichardKnop/machinery/v2 v2.0.13 // indirect + github.com/atotto/clipboard v0.1.4 // indirect + github.com/aws/aws-sdk-go v1.49.6 // indirect + github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect + github.com/bytedance/sonic/loader v0.1.1 // indirect + github.com/catppuccin/go v0.2.0 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/charmbracelet/bubbles v0.18.0 // indirect + github.com/charmbracelet/bubbletea v0.26.3 // indirect + github.com/charmbracelet/huh v0.4.2 // indirect + github.com/charmbracelet/huh/spinner v0.0.0-20240508140610-13957916abf0 // indirect + github.com/charmbracelet/lipgloss v0.11.0 // indirect + github.com/charmbracelet/x/ansi v0.1.1 // indirect + github.com/charmbracelet/x/exp/strings v0.0.0-20240524151031-ff83003bf67a // indirect + github.com/charmbracelet/x/input v0.1.1 // indirect + github.com/charmbracelet/x/term v0.1.1 // indirect + github.com/charmbracelet/x/windows v0.1.2 // indirect + github.com/cloudwego/base64x v0.1.4 // indirect + github.com/cloudwego/iasm v0.2.0 // indirect + github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/dustin/go-humanize v1.0.1 // indirect + github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.4 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect + github.com/glebarez/go-sqlite v1.22.0 // indirect + github.com/glebarez/sqlite v1.11.0 // indirect + github.com/go-logr/logr v1.4.1 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.20.0 // indirect + 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/goccy/go-json v0.10.2 // indirect + github.com/golang-jwt/jwt/v4 v4.5.2 // indirect + github.com/golang-jwt/jwt/v5 v5.2.1 // indirect + github.com/golang-migrate/migrate/v4 v4.17.1 // indirect + github.com/golang-module/carbon/v2 v2.3.12 // indirect + github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect + github.com/golang-sql/sqlexp v0.1.0 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/golang/protobuf v1.5.4 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/gomodule/redigo v2.0.0+incompatible // indirect + github.com/google/s2a-go v0.1.7 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/google/wire v0.6.0 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect + github.com/googleapis/gax-go/v2 v2.12.3 // indirect + github.com/gookit/color v1.5.4 // indirect + github.com/gookit/filter v1.2.1 // indirect + github.com/gookit/goutil v0.6.15 // indirect + github.com/gookit/validate v1.5.2 // indirect + github.com/goravel/file-rotatelogs/v2 v2.4.2 // indirect + github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect + github.com/jackc/pgx/v5 v5.5.4 // indirect + github.com/jackc/puddle/v2 v2.2.1 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect + github.com/jmespath/go-jmespath v0.4.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/kelseyhightower/envconfig v1.4.0 // indirect + github.com/klauspost/compress v1.17.7 // indirect + github.com/klauspost/cpuid/v2 v2.2.8 // indirect + github.com/leodido/go-urn v1.4.0 // indirect + github.com/lib/pq v1.10.9 // indirect + github.com/lithammer/fuzzysearch v1.1.8 // indirect + github.com/lucasb-eyer/go-colorful v1.2.0 // indirect + github.com/magiconair/properties v1.8.7 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-localereader v0.0.1 // indirect + github.com/mattn/go-runewidth v0.0.15 // indirect + github.com/microsoft/go-mssqldb v1.6.0 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect + github.com/muesli/cancelreader v0.2.2 // indirect + github.com/muesli/termenv v0.15.2 // indirect + github.com/opentracing/opentracing-go v1.2.0 // indirect + github.com/patrickmn/go-cache v2.1.0+incompatible // indirect + github.com/pelletier/go-toml/v2 v2.2.2 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/pterm/pterm v0.12.79 // indirect + github.com/rabbitmq/amqp091-go v1.9.0 // indirect + github.com/redis/go-redis/v9 v9.5.5 // indirect + github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect + github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 // indirect + github.com/rivo/uniseg v0.4.7 // indirect + github.com/robfig/cron/v3 v3.0.1 // indirect + github.com/rogpeppe/go-internal v1.11.0 // indirect + github.com/rotisserie/eris v0.5.4 // indirect + github.com/rs/cors v1.11.0 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/sagikazarmark/locafero v0.4.0 // indirect + github.com/sagikazarmark/slog-shim v0.1.0 // indirect + github.com/savioxavier/termlink v1.3.0 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect + github.com/sourcegraph/conc v0.3.0 // indirect + github.com/spf13/afero v1.11.0 // indirect + github.com/spf13/cast v1.6.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/spf13/viper v1.19.0 // indirect + github.com/stretchr/objx v0.5.2 // indirect + github.com/stretchr/testify v1.9.0 // indirect + github.com/subosito/gotenv v1.6.0 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.12 // indirect + github.com/unrolled/secure v1.14.0 // indirect + github.com/urfave/cli/v2 v2.27.2 // indirect + github.com/xdg-go/pbkdf2 v1.0.0 // indirect + github.com/xdg-go/scram v1.1.1 // indirect + github.com/xdg-go/stringprep v1.0.3 // indirect + github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect + github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 // indirect + github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect + go.mongodb.org/mongo-driver v1.7.5 // indirect + go.opencensus.io v0.24.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect + go.opentelemetry.io/otel v1.24.0 // indirect + go.opentelemetry.io/otel/metric v1.24.0 // indirect + go.opentelemetry.io/otel/trace v1.24.0 // indirect + go.uber.org/atomic v1.11.0 // indirect + go.uber.org/multierr v1.9.0 // indirect + golang.org/x/arch v0.8.0 // indirect + golang.org/x/crypto v0.24.0 // indirect + golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect + golang.org/x/net v0.25.0 // indirect + golang.org/x/oauth2 v0.18.0 // indirect + golang.org/x/sync v0.7.0 // indirect + golang.org/x/sys v0.21.0 // indirect + golang.org/x/term v0.21.0 // indirect + golang.org/x/text v0.16.0 // indirect + golang.org/x/time v0.5.0 // indirect + google.golang.org/api v0.171.0 // indirect + google.golang.org/appengine v1.6.8 // indirect + google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect + google.golang.org/grpc v1.64.0 // indirect + google.golang.org/protobuf v1.34.1 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + gorm.io/driver/mysql v1.5.6 // indirect + gorm.io/driver/postgres v1.5.7 // indirect + gorm.io/driver/sqlserver v1.5.3 // indirect + gorm.io/gorm v1.25.10 // indirect + gorm.io/plugin/dbresolver v1.5.1 // indirect + modernc.org/libc v1.37.6 // indirect + modernc.org/mathutil v1.6.0 // indirect + modernc.org/memory v1.7.2 // indirect + modernc.org/sqlite v1.28.0 // indirect +) diff --git a/frameworks/Go/goravel/src/gin/go.sum b/frameworks/Go/goravel/src/gin/go.sum new file mode 100644 index 00000000000..2d7f6ccefad --- /dev/null +++ b/frameworks/Go/goravel/src/gin/go.sum @@ -0,0 +1,1171 @@ +atomicgo.dev/assert v0.0.2 h1:FiKeMiZSgRrZsPo9qn/7vmr7mCsh5SZyXY4YGYiYwrg= +atomicgo.dev/assert v0.0.2/go.mod h1:ut4NcI3QDdJtlmAxQULOmA13Gz6e2DWbSAS8RUOmNYQ= +atomicgo.dev/cursor v0.2.0 h1:H6XN5alUJ52FZZUkI7AlJbUc1aW38GWZalpYRPpoPOw= +atomicgo.dev/cursor v0.2.0/go.mod h1:Lr4ZJB3U7DfPPOkbH7/6TOtJ4vFGHlgj1nc+n900IpU= +atomicgo.dev/keyboard v0.2.9 h1:tOsIid3nlPLZ3lwgG8KZMp/SFmr7P0ssEN5JUsm78K8= +atomicgo.dev/keyboard v0.2.9/go.mod h1:BC4w9g00XkxH/f1HXhW2sXmJFOCWbKn9xrOunSFtExQ= +atomicgo.dev/schedule v0.1.0 h1:nTthAbhZS5YZmgYbb2+DH8uQIZcTlIrd4eYr3UQxEjs= +atomicgo.dev/schedule v0.1.0/go.mod h1:xeUa3oAkiuHYh8bKiQBRojqAMq3PXXbJujjb0hw8pEU= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= +cloud.google.com/go v0.112.1 h1:uJSeirPke5UNZHIb4SxfZklVSiWWVqW4oXlETwZziwM= +cloud.google.com/go v0.112.1/go.mod h1:+Vbu+Y1UU+I1rjmzeMOb/8RfkKJK2Gyxi1X6jJCZLo4= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/compute v1.25.1 h1:ZRpHJedLtTpKgr3RV1Fx23NuaAEN1Zfx9hw1u4aJdjU= +cloud.google.com/go/compute v1.25.1/go.mod h1:oopOIR53ly6viBYxaDhBfJwzUAxf1zE//uf3IB011ls= +cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/iam v1.1.6 h1:bEa06k05IO4f4uJonbB5iAgKTPpABy1ayxaIZV/GHVc= +cloud.google.com/go/iam v1.1.6/go.mod h1:O0zxdPeGBoFdWW3HWmBxJsk0pfvNM/p/qa82rWOGTwI= +cloud.google.com/go/kms v1.15.7 h1:7caV9K3yIxvlQPAcaFffhlT7d1qpxjB1wHBtjWa13SM= +cloud.google.com/go/kms v1.15.7/go.mod h1:ub54lbsa6tDkUwnu4W7Yt1aAIFLnspgh0kPGToDukeI= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/pubsub v1.10.0/go.mod h1:eNpTrkOy7dCpkNyaSNetMa6udbgecJMd0ZsTJS/cuNo= +cloud.google.com/go/pubsub v1.36.1 h1:dfEPuGCHGbWUhaMCTHUFjfroILEkx55iUmKBZTP5f+Y= +cloud.google.com/go/pubsub v1.36.1/go.mod h1:iYjCa9EzWOoBiTdd4ps7QoMtMln5NwaZQpK1hbRfBDE= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +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= +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= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.1 h1:/iHxaJhsFr0+xVFfbMr5vxz848jyiWuIEDhYq3y5odY= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.1/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0 h1:vcYCAze6p19qBW7MhZybIsqD8sMV8js0NyQM8JDnVtg= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0/go.mod h1:OQeznEEkTZ9OrhHJoDD8ZDq51FHgXjqtP9z6bEwBq9U= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.1.2/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.2.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 h1:sXr+ck84g/ZlZUOZiNELInmMgOsuGwdjjVkEIde0OtY= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.0 h1:yfJe15aSwEQ6Oo6J+gdfdulPNoZ3TEhmbhLIoxZcA+U= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.0/go.mod h1:Q28U+75mpCaSCDowNEmhIo/rmgdkqmkmzI7N6TGR4UY= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v0.8.0 h1:T028gtTPiYt/RMUfs8nVsAL7FDQrfLlrm/NnRG/zcC4= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v0.8.0/go.mod h1:cw4zVQgBby0Z5f2v0itn6se2dDP17nTjbZFXW5uPyHA= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest/adal v0.9.16 h1:P8An8Z9rH1ldbOLdFpxYorgOt2sywL9V24dAwWHPuGc= +github.com/Azure/go-autorest/autorest/adal v0.9.16/go.mod h1:tGMin8I49Yij6AQ+rvV+Xa/zwxYQB5hmsd6DkfAx2+A= +github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/autorest/mocks v0.4.1 h1:K0laFcLE6VLTOwNgSxaGbUcLPuGXlNkbVvq4cW4nIHk= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg= +github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= +github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0/go.mod h1:kgDmCTgBzIEPFElEF+FK0SdjAor06dRq2Go927dnQ6o= +github.com/AzureAD/microsoft-authentication-library-for-go v1.1.0 h1:HCc0+LpPfpCKs6LGGLAhwBARt9632unrVcI6i8s/8os= +github.com/AzureAD/microsoft-authentication-library-for-go v1.1.0/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/MarvinJWendt/testza v0.1.0/go.mod h1:7AxNvlfeHP7Z/hDQ5JtE3OKYT3XFUeLCDE2DQninSqs= +github.com/MarvinJWendt/testza v0.2.1/go.mod h1:God7bhG8n6uQxwdScay+gjm9/LnO4D3kkcZX4hv9Rp8= +github.com/MarvinJWendt/testza v0.2.8/go.mod h1:nwIcjmr0Zz+Rcwfh3/4UhBp7ePKVhuBExvZqnKYWlII= +github.com/MarvinJWendt/testza v0.2.10/go.mod h1:pd+VWsoGUiFtq+hRKSU1Bktnn+DMCSrDrXDpX2bG66k= +github.com/MarvinJWendt/testza v0.2.12/go.mod h1:JOIegYyV7rX+7VZ9r77L/eH6CfJHHzXjB69adAhzZkI= +github.com/MarvinJWendt/testza v0.3.0/go.mod h1:eFcL4I0idjtIx8P9C6KkAuLgATNKpX4/2oUqKc6bF2c= +github.com/MarvinJWendt/testza v0.4.2/go.mod h1:mSdhXiKH8sg/gQehJ63bINcCKp7RtYewEjXsvsVUPbE= +github.com/MarvinJWendt/testza v0.5.2 h1:53KDo64C1z/h/d/stCYCPY69bt/OSwjq5KpFNwi+zB4= +github.com/MarvinJWendt/testza v0.5.2/go.mod h1:xu53QFE5sCdjtMCKk8YMQ2MnymimEctc4n3EjyIYvEY= +github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/RichardKnop/logging v0.0.0-20190827224416-1a693bdd4fae h1:DcFpTQBYQ9Ct2d6sC7ol0/ynxc2pO1cpGUM+f4t5adg= +github.com/RichardKnop/logging v0.0.0-20190827224416-1a693bdd4fae/go.mod h1:rJJ84PyA/Wlmw1hO+xTzV2wsSUon6J5ktg0g8BF2PuU= +github.com/RichardKnop/machinery/v2 v2.0.13 h1:uo9htg+qNBi7UeUK3jcTBl3vTO/vvLKGaOdCOKePl50= +github.com/RichardKnop/machinery/v2 v2.0.13/go.mod h1:Yc2X/QRm9rRfAjB+93NGR+kSUqtnqqs8kME4L+TKKiw= +github.com/atomicgo/cursor v0.0.1/go.mod h1:cBON2QmmrysudxNBFthvMtN32r3jxVRIvzkUiF/RuIk= +github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= +github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= +github.com/aws/aws-sdk-go v1.34.28/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48= +github.com/aws/aws-sdk-go v1.37.16/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.49.6 h1:yNldzF5kzLBRvKlKz1S0bkvc2+04R1kt13KfBWQBfFA= +github.com/aws/aws-sdk-go v1.49.6/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= +github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= +github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= +github.com/brianvoe/gofakeit/v6 v6.28.0 h1:Xib46XXuQfmlLS2EXRuJpqcw8St6qSZz75OUo0tgAW4= +github.com/brianvoe/gofakeit/v6 v6.28.0/go.mod h1:Xj58BMSnFqcn/fAQeSK+/PLtC5kSb7FJIq4JyGa8vEs= +github.com/bsm/ginkgo/v2 v2.5.0/go.mod h1:AiKlXPm7ItEHNc/2+OkrNG4E0ITzojb9/xWzvQ9XZ9w= +github.com/bsm/ginkgo/v2 v2.7.0/go.mod h1:AiKlXPm7ItEHNc/2+OkrNG4E0ITzojb9/xWzvQ9XZ9w= +github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= +github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= +github.com/bsm/gomega v1.20.0/go.mod h1:JifAceMQ4crZIWYUKrlGcmbN3bqHogVTADMD2ATsbwk= +github.com/bsm/gomega v1.26.0/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= +github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= +github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= +github.com/bytedance/sonic v1.11.9 h1:LFHENlIY/SLzDWverzdOvgMztTxcfcF+cqNsz9pK5zg= +github.com/bytedance/sonic v1.11.9/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4= +github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM= +github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= +github.com/catppuccin/go v0.2.0 h1:ktBeIrIP42b/8FGiScP9sgrWOss3lw0Z5SktRoithGA= +github.com/catppuccin/go v0.2.0/go.mod h1:8IHJuMGaUUjQM82qBrGNBv7LFq6JI3NnQCF6MOlZjpc= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/charmbracelet/bubbles v0.18.0 h1:PYv1A036luoBGroX6VWjQIE9Syf2Wby2oOl/39KLfy0= +github.com/charmbracelet/bubbles v0.18.0/go.mod h1:08qhZhtIwzgrtBjAcJnij1t1H0ZRjwHyGsy6AL11PSw= +github.com/charmbracelet/bubbletea v0.26.3 h1:iXyGvI+FfOWqkB2V07m1DF3xxQijxjY2j8PqiXYqasg= +github.com/charmbracelet/bubbletea v0.26.3/go.mod h1:bpZHfDHTYJC5g+FBK+ptJRCQotRC+Dhh3AoMxa/2+3Q= +github.com/charmbracelet/huh v0.4.2 h1:5wLkwrA58XDAfEZsJzNQlfJ+K8N9+wYwvR5FOM7jXFM= +github.com/charmbracelet/huh v0.4.2/go.mod h1:g9OXBgtY3zRV4ahnVih9bZE+1yGYN+y2C9Q6L2P+WM0= +github.com/charmbracelet/huh/spinner v0.0.0-20240508140610-13957916abf0 h1:79JTuYRirtyCn9ac6rzPt5AQKtBDFc1gKxpw0wBrI+Y= +github.com/charmbracelet/huh/spinner v0.0.0-20240508140610-13957916abf0/go.mod h1:Zxt9FH6togK9kY71pRJGtmyNkJ1eIWdK1gRaXrS/FKA= +github.com/charmbracelet/lipgloss v0.11.0 h1:UoAcbQ6Qml8hDwSWs0Y1cB5TEQuZkDPH/ZqwWWYTG4g= +github.com/charmbracelet/lipgloss v0.11.0/go.mod h1:1UdRTH9gYgpcdNN5oBtjbu/IzNKtzVtb7sqN1t9LNn8= +github.com/charmbracelet/x/ansi v0.1.1 h1:CGAduulr6egay/YVbGc8Hsu8deMg1xZ/bkaXTPi1JDk= +github.com/charmbracelet/x/ansi v0.1.1/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= +github.com/charmbracelet/x/exp/strings v0.0.0-20240524151031-ff83003bf67a h1:lOpqe2UvPmlln41DGoii7wlSZ/q8qGIon5JJ8Biu46I= +github.com/charmbracelet/x/exp/strings v0.0.0-20240524151031-ff83003bf67a/go.mod h1:pBhA0ybfXv6hDjQUZ7hk1lVxBiUbupdw5R31yPUViVQ= +github.com/charmbracelet/x/exp/term v0.0.0-20240524151031-ff83003bf67a h1:k/s6UoOSVynWiw7PlclyGO2VdVs5ZLbMIHiGp4shFZE= +github.com/charmbracelet/x/exp/term v0.0.0-20240524151031-ff83003bf67a/go.mod h1:YBotIGhfoWhHDlnUpJMkjebGV2pdGRCn1Y4/Nk/vVcU= +github.com/charmbracelet/x/input v0.1.1 h1:YDOJaTUKCqtGnq9PHzx3pkkl4pXDOANUHmhH3DqMtM4= +github.com/charmbracelet/x/input v0.1.1/go.mod h1:jvdTVUnNWj/RD6hjC4FsoB0SeZCJ2ZBkiuFP9zXvZI0= +github.com/charmbracelet/x/term v0.1.1 h1:3cosVAiPOig+EV4X9U+3LDgtwwAoEzJjNdwbXDjF6yI= +github.com/charmbracelet/x/term v0.1.1/go.mod h1:wB1fHt5ECsu3mXYusyzcngVWWlu1KKUmmLhfgr/Flxw= +github.com/charmbracelet/x/windows v0.1.2 h1:Iumiwq2G+BRmgoayww/qfcvof7W/3uLoelhxojXlRWg= +github.com/charmbracelet/x/windows v0.1.2/go.mod h1:GLEO/l+lizvFDBPLIOk+49gdX49L9YWMB5t+DZd0jkQ= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= +github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= +github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= +github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= +github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 h1:q2hJAaP1k2wIvVRd/hEHD7lacgqrCPS+k8g1MndzfWY= +github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/dhui/dktest v0.4.1 h1:/w+IWuDXVymg3IrRJCHHOkMK10m9aNVMOyD0X12YVTg= +github.com/dhui/dktest v0.4.1/go.mod h1:DdOqcUpL7vgyP4GlF3X3w7HbSlz8cEQzwewPveYEQbA= +github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko= +github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= +github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= +github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v24.0.9+incompatible h1:HPGzNmwfLZWdxHqK9/II92pyi1EpYKsAqcl4G0Of9v0= +github.com/docker/docker v24.0.9+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4= +github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/gabriel-vasile/mimetype v1.4.4 h1:QjV6pZ7/XZ7ryI2KuyeEDE8wnh7fHP9YnQy+R0LnH8I= +github.com/gabriel-vasile/mimetype v1.4.4/go.mod h1:JwLei5XPtWdGiMFB5Pjle1oEeoSeEuJfJE+TtfvdB/s= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= +github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= +github.com/glebarez/go-sqlite v1.22.0 h1:uAcMJhaA6r3LHMTFgP0SifzgXg46yJkgxqyuyec+ruQ= +github.com/glebarez/go-sqlite v1.22.0/go.mod h1:PlBIdHe0+aUEFn+r2/uthrWq4FxbzugL0L8Li6yQJbc= +github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GMw= +github.com/glebarez/sqlite v1.11.0/go.mod h1:h8/o8j5wiAsqSPoWELDUdJXhjAhsVliSn7bWZjOhrgQ= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +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.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/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-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8= +github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= +github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg= +github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= +github.com/go-redis/redis/v7 v7.4.0 h1:7obg6wUoj05T0EpY0o8B59S9w5yeMWql7sw2kwNW1x4= +github.com/go-redis/redis/v7 v7.4.0/go.mod h1:JDNMw23GTyLNC4GZu9njt15ctBQVn7xjRfnwdHj/Dcg= +github.com/go-redis/redis/v8 v8.11.4/go.mod h1:2Z2wHZXdQpCDXEGzqMockDpNyYvi2l4Pxt6RJr792+w= +github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= +github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= +github.com/go-redsync/redsync/v4 v4.8.1 h1:rq2RvdTI0obznMdxKUWGdmmulo7lS9yCzb8fgDKOlbM= +github.com/go-redsync/redsync/v4 v4.8.1/go.mod h1:LmUAsQuQxhzZAoGY7JS6+dNhNmZyonMZiiEDY9plotM= +github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= +github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= +github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= +github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= +github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY= +github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg= +github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/flect v0.1.0/go.mod h1:d2ehjJqGOH/Kjqcoz+F7jHTBbmDb38yXA598Hb50EGs= +github.com/gobuffalo/flect v0.1.1/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= +github.com/gobuffalo/flect v0.1.3/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= +github.com/gobuffalo/genny v0.0.0-20190329151137-27723ad26ef9/go.mod h1:rWs4Z12d1Zbf19rlsn0nurr75KqhYp52EAGGxTbBhNk= +github.com/gobuffalo/genny v0.0.0-20190403191548-3ca520ef0d9e/go.mod h1:80lIj3kVJWwOrXWWMRzzdhW3DsrdjILVil/SFKBzF28= +github.com/gobuffalo/genny v0.1.0/go.mod h1:XidbUqzak3lHdS//TPu2OgiFB+51Ur5f7CSnXZ/JDvo= +github.com/gobuffalo/genny v0.1.1/go.mod h1:5TExbEyY48pfunL4QSXxlDOmdsD44RRq4mVZ0Ex28Xk= +github.com/gobuffalo/gitgen v0.0.0-20190315122116-cc086187d211/go.mod h1:vEHJk/E9DmhejeLeNt7UVvlSGv3ziL+djtTr3yyzcOw= +github.com/gobuffalo/gogen v0.0.0-20190315121717-8f38393713f5/go.mod h1:V9QVDIxsgKNZs6L2IYiGR8datgMhB577vzTDqypH360= +github.com/gobuffalo/gogen v0.1.0/go.mod h1:8NTelM5qd8RZ15VjQTFkAW6qOMx5wBbW4dSCS3BY8gg= +github.com/gobuffalo/gogen v0.1.1/go.mod h1:y8iBtmHmGc4qa3urIyo1shvOD8JftTtfcKi+71xfDNE= +github.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2/go.mod h1:QdxcLw541hSGtBnhUc4gaNIXRjiDppFGaDqzbrBd3v8= +github.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= +github.com/gobuffalo/mapi v1.0.2/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= +github.com/gobuffalo/packd v0.0.0-20190315124812-a385830c7fc0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= +github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= +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/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= +github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +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= +github.com/golang-jwt/jwt/v4 v4.4.3/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI= +github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= +github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang-migrate/migrate/v4 v4.17.1 h1:4zQ6iqL6t6AiItphxJctQb3cFqWiSpMnX7wLTPnnYO4= +github.com/golang-migrate/migrate/v4 v4.17.1/go.mod h1:m8hinFyWBn0SA4QKHuKh175Pm9wjmxj3S2Mia7dbXzM= +github.com/golang-module/carbon/v2 v2.3.12 h1:VC1DwN1kBwJkh5MjXmTFryjs5g4CWyoM8HAHffZPX/k= +github.com/golang-module/carbon/v2 v2.3.12/go.mod h1:HNsedGzXGuNciZImYP2OMnpiwq/vhIstR/vn45ib5cI= +github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA= +github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= +github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= +github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/gomodule/redigo v1.8.2/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0= +github.com/gomodule/redigo v1.9.2/go.mod h1:KsU3hiK/Ay8U42qpaJk+kuNa3C+spxapWpM+ywhcgtw= +github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0= +github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ= +github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= +github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= +github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +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/google/wire v0.6.0 h1:HBkoIh4BdSxoyo9PveV8giw7ZsaBOvzWKfcg/6MrVwI= +github.com/google/wire v0.6.0/go.mod h1:F4QhpQ9EDIdJ1Mbop/NZBRB+5yrR6qg3BnctaoUk6NA= +github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= +github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gax-go/v2 v2.12.3 h1:5/zPPDvw8Q1SuXjrqrZslrqT7dL/uJT2CQii/cLCKqA= +github.com/googleapis/gax-go/v2 v2.12.3/go.mod h1:AKloxT6GtNbaLm8QTNSidHUVsHYcBHwWRvkNFJUQcS4= +github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ= +github.com/gookit/color v1.5.0/go.mod h1:43aQb+Zerm/BWh2GnrgOQm7ffz7tvQXEKV6BFMl7wAo= +github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0= +github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w= +github.com/gookit/filter v1.2.1 h1:37XivkBm2E5qe1KaGdJ5ZfF5l9NYdGWfLEeQadJD8O4= +github.com/gookit/filter v1.2.1/go.mod h1:rxynQFr793x+XDwnRmJFEb53zDw0Zqx3OD7TXWoR9mQ= +github.com/gookit/goutil v0.6.15 h1:mMQ0ElojNZoyPD0eVROk5QXJPh2uKR4g06slgPDF5Jo= +github.com/gookit/goutil v0.6.15/go.mod h1:qdKdYEHQdEtyH+4fNdQNZfJHhI0jUZzHxQVAV3DaMDY= +github.com/gookit/validate v1.5.2 h1:i5I2OQ7WYHFRPRATGu9QarR9snnNHydvwSuHXaRWAV0= +github.com/gookit/validate v1.5.2/go.mod h1:yuPy2WwDlwGRa06fFJ5XIO8QEwhRnTC2LmxmBa5SE14= +github.com/goravel/file-rotatelogs/v2 v2.4.2 h1:g68AzbePXcm0V2CpUMc9j4qVzcDn7+7aoWSjZ51C0m4= +github.com/goravel/file-rotatelogs/v2 v2.4.2/go.mod h1:23VuSW8cBS4ax5cmbV+5AaiLpq25b8UJ96IhbAkdo8I= +github.com/goravel/framework v1.14.1 h1:VcJvzn1ItFQh/rQZO1EMkxKmzDrww1S+OGz4hjZi3UY= +github.com/goravel/framework v1.14.1/go.mod h1:rScDXGQZdoVfyxemNPmijlz/2a+lWNOa4jTuak5GGVg= +github.com/goravel/gin v1.2.1 h1:lnQX3NKUEaSx8x7AAJpoeVkXgi+MVQ9FXy4QywHQElo= +github.com/goravel/gin v1.2.1/go.mod h1:Qt3NJysg/eoxXL4y/swwFUcfcIT7XG+xb0rWChweZfY= +github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= +github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= +github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= +github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +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-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.5.4 h1:Xp2aQS8uXButQdnCMWNmvx6UysWQQC+u1EoizjguY+8= +github.com/jackc/pgx/v5 v5.5.4/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A= +github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= +github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= +github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= +github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo= +github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= +github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs= +github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= +github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= +github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= +github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.17.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLAKQQg= +github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.0.10/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= +github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= +github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM= +github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc h1:RKf14vYWi2ttpEmkA4aQ3j4u9dStX2t4M8UM6qqNsG8= +github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc/go.mod h1:kopuH9ugFRkIXf3YoqHKyrJ9YfUFsckUU9S7B+XP+is= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lithammer/fuzzysearch v1.1.8 h1:/HIuJnjHuXS8bKaiTMeeDlW2/AyIWk2brx1V8LFgLN4= +github.com/lithammer/fuzzysearch v1.1.8/go.mod h1:IdqeyBClc3FFqSzYq/MXESsS4S0FsZ5ajtkr5xPLts4= +github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= +github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= +github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= +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-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4= +github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= +github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= +github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/microsoft/go-mssqldb v1.6.0 h1:mM3gYdVwEPFrlg/Dvr2DNVEgYFG7L42l+dGc67NNNpc= +github.com/microsoft/go-mssqldb v1.6.0/go.mod h1:00mDtPbeQCRGC1HwOOR5K/gr30P1NcEG0vx6Kbv2aJU= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= +github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= +github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= +github.com/montanaflynn/stats v0.7.0/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= +github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI= +github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo= +github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= +github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= +github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo= +github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= +github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= +github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= +github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= +github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= +github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= +github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= +github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= +github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= +github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/pterm/pterm v0.12.27/go.mod h1:PhQ89w4i95rhgE+xedAoqous6K9X+r6aSOI2eFF7DZI= +github.com/pterm/pterm v0.12.29/go.mod h1:WI3qxgvoQFFGKGjGnJR849gU0TsEOvKn5Q8LlY1U7lg= +github.com/pterm/pterm v0.12.30/go.mod h1:MOqLIyMOgmTDz9yorcYbcw+HsgoZo3BQfg2wtl3HEFE= +github.com/pterm/pterm v0.12.31/go.mod h1:32ZAWZVXD7ZfG0s8qqHXePte42kdz8ECtRyEejaWgXU= +github.com/pterm/pterm v0.12.33/go.mod h1:x+h2uL+n7CP/rel9+bImHD5lF3nM9vJj80k9ybiiTTE= +github.com/pterm/pterm v0.12.36/go.mod h1:NjiL09hFhT/vWjQHSj1athJpx6H8cjpHXNAK5bUw8T8= +github.com/pterm/pterm v0.12.40/go.mod h1:ffwPLwlbXxP+rxT0GsgDTzS3y3rmpAO1NMjUkGTYf8s= +github.com/pterm/pterm v0.12.79 h1:lH3yrYMhdpeqX9y5Ep1u7DejyHy7NSQg9qrBjF9dFT4= +github.com/pterm/pterm v0.12.79/go.mod h1:1v/gzOF1N0FsjbgTHZ1wVycRkKiatFvJSJC4IGaQAAo= +github.com/rabbitmq/amqp091-go v1.9.0 h1:qrQtyzB4H8BQgEuJwhmVQqVHB9O4+MNDJCCAcpc3Aoo= +github.com/rabbitmq/amqp091-go v1.9.0/go.mod h1:+jPrT9iY2eLjRaMSRHUhc3z14E/l85kv/f+6luSD3pc= +github.com/redis/go-redis/v9 v9.0.2/go.mod h1:/xDTe9EF1LM61hek62Poq2nzQSGj0xSrEtEHbBQevps= +github.com/redis/go-redis/v9 v9.0.5/go.mod h1:WqMKv5vnQbRuZstUwxQI195wHy+t4PuXDOjzMvcuQHk= +github.com/redis/go-redis/v9 v9.5.5 h1:51VEyMF8eOO+NUHFm8fpg+IOc1xFuFOhxs3R+kPu1FM= +github.com/redis/go-redis/v9 v9.5.5/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 h1:mZHayPoR0lNmnHyvtYjDeq0zlVHn9K/ZXoy17ylucdo= +github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5/go.mod h1:GEXHk5HgEKCvEIIrSpFI3ozzG5xOKA2DVlEX/gGnewM= +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/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= +github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= +github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= +github.com/rotisserie/eris v0.5.4 h1:Il6IvLdAapsMhvuOahHWiBnl1G++Q0/L5UIkI5mARSk= +github.com/rotisserie/eris v0.5.4/go.mod h1:Z/kgYTJiJtocxCbFfvRmO+QejApzG6zpyky9G1A4g9s= +github.com/rs/cors v1.11.0 h1:0B9GE/r9Bc2UxRMMtymBkHTenPkHDv0CW4Y98GBY+po= +github.com/rs/cors v1.11.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= +github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= +github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= +github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= +github.com/savioxavier/termlink v1.3.0 h1:3Gl4FzQjUyiHzmoEDfmWEhgIwDiJY4poOQHP+k8ReA4= +github.com/savioxavier/termlink v1.3.0/go.mod h1:5T5ePUlWbxCHIwyF8/Ez1qufOoGM89RCg9NvG+3G3gc= +github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= +github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= +github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= +github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= +github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= +github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +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.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stvp/tempredis v0.0.0-20181119212430-b82af8480203 h1:QVqDTf3h2WHt08YuiTGPZLls0Wq99X9bWd0Q5ZSBesM= +github.com/stvp/tempredis v0.0.0-20181119212430-b82af8480203/go.mod h1:oqN97ltKNihBbwlX8dLpwxCl3+HnXKV/R0e+sRLd9C8= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +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/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= +github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/unrolled/secure v1.14.0 h1:u9vJTU/pR4Bny0ntLUMxdfLtmIRGvQf2sEFuA0TG9AE= +github.com/unrolled/secure v1.14.0/go.mod h1:BmF5hyM6tXczk3MpQkFf1hpKSRqCyhqcbiQtiAF7+40= +github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli/v2 v2.27.2 h1:6e0H+AkS+zDckwPCUrZkKX38mRaau4nL2uipkJpbkcI= +github.com/urfave/cli/v2 v2.27.2/go.mod h1:g0+79LmHHATl7DAcHO99smiR/T7uGLw84w8Y42x+4eM= +github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= +github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= +github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= +github.com/xdg-go/scram v1.1.1 h1:VOMT+81stJgXW3CpHyqHN3AXDYIMsx56mEFrB37Mb/E= +github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= +github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= +github.com/xdg-go/stringprep v1.0.3 h1:kdwGpVNwPFtjs98xCGkHjQtGKh86rDcRZN17QEMCOIs= +github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= +github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= +github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= +github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs= +github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= +github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= +github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 h1:+qGGcbkzsfDQNPPe9UDgpxAWQrhbbBXOYJFQDq/dtJw= +github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913/go.mod h1:4aEEwZQutDLsQv2Deui4iYQ6DWTxR14g6m8Wv88+Xqk= +github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA= +github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.einride.tech/aip v0.66.0 h1:XfV+NQX6L7EOYK11yoHHFtndeaWh3KbD9/cN/6iWEt8= +go.einride.tech/aip v0.66.0/go.mod h1:qAhMsfT7plxBX+Oy7Huol6YUvZ0ZzdUz26yZsQwfl1M= +go.mongodb.org/mongo-driver v1.4.6/go.mod h1:WcMNYLx/IlOxLe6JRJiv2uXuCz6zBLndR4SoGjYphSc= +go.mongodb.org/mongo-driver v1.7.5 h1:ny3p0reEpgsR2cfA5cjgwFZg3Cv/ofFh/8jbhGtz9VI= +go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= +go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= +go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= +go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= +go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= +go.opentelemetry.io/otel/sdk v1.22.0 h1:6coWHw9xw7EfClIC/+O31R8IY3/+EiRFHevmHafB2Gw= +go.opentelemetry.io/otel/sdk v1.22.0/go.mod h1:iu7luyVGYovrRpe2fmj3CVKouQNdTOkxtLzPvPz1DOc= +go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= +go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= +go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= +go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= +go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= +go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= +go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc= +golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= +golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= +golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210113205817-d3ed898aa8a3/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI= +golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +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.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= +golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= +golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= +golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA= +golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.39.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.171.0 h1:w174hnBPqut76FzW5Qaupt7zY8Kql6fiVjgys4f58sU= +google.golang.org/api v0.171.0/go.mod h1:Hnq5AHm4OTMt2BUVjael2CWZFD6vksJdWCWiUAmjC9o= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= +google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210207032614-bba0dbe2a9ea/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY= +google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo= +google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237 h1:RFiFrvy37/mpSpdySBDrUdipW/dHwsRwh3J3+A9VgT4= +google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237/go.mod h1:Z5Iiy3jtmioajWHDGFk7CeugTyHtPvMHA4UTmUkyalE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 h1:NnYq6UN9ReLM9/Y01KWNOWyI5xQ9kbIms5GGJVwS/Yc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= +google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= +google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/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/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/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= +gorm.io/driver/mysql v1.4.3/go.mod h1:sSIebwZAVPiT+27jK9HIwvsqOGKx3YMPmrA3mBJR10c= +gorm.io/driver/mysql v1.5.6 h1:Ld4mkIickM+EliaQZQx3uOJDJHtrd70MxAUqWqlx3Y8= +gorm.io/driver/mysql v1.5.6/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM= +gorm.io/driver/postgres v1.5.7 h1:8ptbNJTDbEmhdr62uReG5BGkdQyeasu/FZHxI0IMGnM= +gorm.io/driver/postgres v1.5.7/go.mod h1:3e019WlBaYI5o5LIdNV+LyxCMNtLOQETBXL2h4chKpA= +gorm.io/driver/sqlserver v1.5.3 h1:rjupPS4PVw+rjJkfvr8jn2lJ8BMhT4UW5FwuJY0P3Z0= +gorm.io/driver/sqlserver v1.5.3/go.mod h1:B+CZ0/7oFJ6tAlefsKoyxdgDCXJKSgwS2bMOQZT0I00= +gorm.io/gorm v1.23.8/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= +gorm.io/gorm v1.25.2/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= +gorm.io/gorm v1.25.7-0.20240204074919-46816ad31dde/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= +gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= +gorm.io/gorm v1.25.10 h1:dQpO+33KalOA+aFYGlK+EfxcI5MbO7EP2yYygwh9h+s= +gorm.io/gorm v1.25.10/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= +gorm.io/plugin/dbresolver v1.5.1 h1:s9Dj9f7r+1rE3nx/Ywzc85nXptUEaeOO0pt27xdopM8= +gorm.io/plugin/dbresolver v1.5.1/go.mod h1:l4Cn87EHLEYuqUncpEeTC2tTJQkjngPSD+lo8hIvcT0= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +modernc.org/libc v1.37.6 h1:orZH3c5wmhIQFTXF+Nt+eeauyd+ZIt2BX6ARe+kD+aw= +modernc.org/libc v1.37.6/go.mod h1:YAXkAZ8ktnkCKaN9sw/UDeUVkGYJ/YquGO4FTi5nmHE= +modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= +modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= +modernc.org/memory v1.7.2 h1:Klh90S215mmH8c9gO98QxQFsY+W451E8AnzjoE2ee1E= +modernc.org/memory v1.7.2/go.mod h1:NO4NVCQy0N7ln+T9ngWqOQfi7ley4vpwvARR+Hjw95E= +modernc.org/sqlite v1.28.0 h1:Zx+LyDDmXczNnEQdvPuEfcFVA2ZPyaD7UCZDjef3BHQ= +modernc.org/sqlite v1.28.0/go.mod h1:Qxpazz0zH8Z1xCFyi5GSL3FzbtZ3fvbjmywNogldEW0= +nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/frameworks/Go/goravel/src/gin/main.go b/frameworks/Go/goravel/src/gin/main.go new file mode 100644 index 00000000000..ddd89a4e1a1 --- /dev/null +++ b/frameworks/Go/goravel/src/gin/main.go @@ -0,0 +1,27 @@ +package main + +import ( + "github.com/goravel/framework/facades" + "github.com/goravel/framework/foundation" + + "goravel/config" +) + +func main() { + app := foundation.NewApplication() + + // Bootstrap the application + app.Boot() + + // Bootstrap the config. + config.Boot() + + // Start HTTP server by facades.Route(). + go func() { + if err := facades.Route().Run(); err != nil { + facades.Log().Errorf("Route run error: %v", err) + } + }() + + select {} +} diff --git a/frameworks/Go/goravel/src/gin/resources/views/fortunes.tmpl b/frameworks/Go/goravel/src/gin/resources/views/fortunes.tmpl new file mode 100644 index 00000000000..4c58fa53da0 --- /dev/null +++ b/frameworks/Go/goravel/src/gin/resources/views/fortunes.tmpl @@ -0,0 +1,22 @@ +{{define "fortunes.tmpl"}} + + + + Fortunes + + + + + + + + {{range .fortunes}} + + + + + {{end}} +
idmessage
{{.ID}}{{.Message}}
+ + +{{end}} diff --git a/frameworks/Go/goravel/src/gin/routes/web.go b/frameworks/Go/goravel/src/gin/routes/web.go new file mode 100644 index 00000000000..86bfbccc2d4 --- /dev/null +++ b/frameworks/Go/goravel/src/gin/routes/web.go @@ -0,0 +1,19 @@ +package routes + +import ( + "github.com/goravel/framework/facades" + + "goravel/app/http/controllers" +) + +func Web() { + testController := controllers.NewTestController() + facades.Route().Get("/plaintext", testController.Plaintext) + facades.Route().Get("/json", testController.JSON) + facades.Route().Get("/db", testController.DB) + facades.Route().Get("/queries", testController.Queries) + facades.Route().Get("/update", testController.Update) + facades.Route().Get("/fortunes", testController.Fortunes) + facades.Route().Get("/cached-worlds", testController.CacheQueries) + +} diff --git a/frameworks/Go/gramework/gramework.dockerfile b/frameworks/Go/gramework/gramework.dockerfile index 8e8ca15a775..0300eae4d3d 100644 --- a/frameworks/Go/gramework/gramework.dockerfile +++ b/frameworks/Go/gramework/gramework.dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.12 +FROM golang:1.24.2 WORKDIR /gramework diff --git a/frameworks/Go/gramework/src/go.mod b/frameworks/Go/gramework/src/go.mod index a0d6e1e03c0..dd29af0c71e 100644 --- a/frameworks/Go/gramework/src/go.mod +++ b/frameworks/Go/gramework/src/go.mod @@ -1,8 +1,35 @@ module gramework/src +go 1.24.1 + +require ( + github.com/apex/log v1.9.0 + github.com/gramework/gramework v1.8.0 +) + require ( - github.com/apex/log v1.1.0 - github.com/fatih/color v1.7.0 // indirect - github.com/gramework/gramework v1.6.2 - github.com/mattn/go-colorable v0.1.1 // indirect + github.com/VictoriaMetrics/fastcache v1.12.2 // indirect + github.com/andybalholm/brotli v1.1.1 // indirect + github.com/aymerick/douceur v0.2.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/cloudfoundry/gosigar v1.3.91 // indirect + github.com/fatih/color v1.18.0 // indirect + github.com/gocarina/gocsv v0.0.0-20240520201108-78e41c74b4b1 // indirect + github.com/golang/snappy v1.0.0 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/gorilla/css v1.0.1 // indirect + github.com/gramework/utils v0.0.0-20190202181041-3c30a162ea26 // indirect + github.com/kirillDanshin/go-accept-headers v0.0.0-20130320203746-c78f304b1b09 // 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/microcosm-cc/bluemonday v1.0.27 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pquerna/ffjson v0.0.0-20190930134022-aa0246cd15f7 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasthttp v1.60.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/text v0.23.0 // indirect ) diff --git a/frameworks/Go/gramework/src/go.sum b/frameworks/Go/gramework/src/go.sum index 0e58de2ce99..d09a0267907 100644 --- a/frameworks/Go/gramework/src/go.sum +++ b/frameworks/Go/gramework/src/go.sum @@ -1,81 +1,606 @@ -github.com/apex/log v1.0.0 h1:5UWeZC54mWVtOGSCjtuvDPgY/o0QxmjQgvYZ27pLVGQ= -github.com/apex/log v1.0.0/go.mod h1:yA770aXIDQrhVOIGurT/pVdfCpSq1GQV/auzMN5fzvY= -github.com/apex/log v1.1.0 h1:J5rld6WVFi6NxA6m8GJ1LJqu3+GiTFIt3mYv27gdQWI= -github.com/apex/log v1.1.0/go.mod h1:yA770aXIDQrhVOIGurT/pVdfCpSq1GQV/auzMN5fzvY= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +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= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/VictoriaMetrics/fastcache v1.7.0/go.mod h1:n7Sl+ioh/HlWeYHLSIBIE8TcZFHg/+xgvomWSS5xuEE= +github.com/VictoriaMetrics/fastcache v1.12.2 h1:N0y9ASrJ0F6h0QaC3o6uJb3NIZ9VKLjCM7NQbSmF7WI= +github.com/VictoriaMetrics/fastcache v1.12.2/go.mod h1:AmC+Nzz1+3G2eCPapF6UcsnkThDcMsQicp4xDukwJYI= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8= +github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= +github.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= +github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= +github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA= +github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA= +github.com/apex/log v1.9.0 h1:FHtw/xuaM8AgmvDDTI9fiwoAL25Sq2cxojnZICUU8l0= +github.com/apex/log v1.9.0/go.mod h1:m82fZlWIuiWzWP04XCTXmnX0xRkYYbCdYn8jbJeLBEA= +github.com/apex/logs v1.0.0/go.mod h1:XzxuLZ5myVHDy9SAmYpamKKRNApGj54PfYLcFrXqDwo= +github.com/aphistic/golf v0.0.0-20180712155816-02c07f170c5a/go.mod h1:3NqKYiepwy8kCu4PNA+aP7WUV72eXWJeP9/r3/K9aLE= +github.com/aphistic/sweet v0.2.0/go.mod h1:fWDlIh/isSE9n6EPsRmC0det+whmX6dJid3stzu0Xys= +github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= +github.com/aws/aws-sdk-go v1.20.6/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= +github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= +github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/cloudfoundry/gosigar v1.1.0 h1:V/dVCzhKOdIU3WRB5inQU20s4yIgL9Dxx/Mhi0SF8eM= -github.com/cloudfoundry/gosigar v1.1.0/go.mod h1:3qLfc2GlfmwOx2+ZDaRGH3Y9fwQ0sQeaAleo2GV5pH0= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +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/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudfoundry/gosigar v1.3.2/go.mod h1:tZGd29SDghYXnEP3vX7AGanIGEVZhGWcp/2HGSt1FXg= +github.com/cloudfoundry/gosigar v1.3.91 h1:kQ01WlgD2eOT73JjIwbtxRuc+tETue9U4HrmdJFkQEQ= +github.com/cloudfoundry/gosigar v1.3.91/go.mod h1:4prTPsneAn5biiNbw+mVUxJNeAYxOEcgkqvQ7L3UIzE= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +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/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= -github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fasthttp/websocket v1.4.3/go.mod h1:5r4oKssgS7W6Zn6mPWap3NWzNPJNzUUh3baWTOhcYQk= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= +github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= +github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/gocarina/gocsv v0.0.0-20190129143436-91f6fc13d488 h1:KKvJw2OFJn3Bh+BziYCFit6r4I70pjEfy9vtNXoxqD0= -github.com/gocarina/gocsv v0.0.0-20190129143436-91f6fc13d488/go.mod h1:/oj50ZdPq/cUjA02lMZhijk5kR31SEydKyqah1OgBuo= -github.com/gocarina/gocsv/v2 v2.0.0-20181019111052-71f99b1720d2/go.mod h1:g7SrNGzi3lNWhpogl2lrJ6qaoQDLAwPRiWedc4B0Grs= -github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +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-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= +github.com/gocarina/gocsv v0.0.0-20210516172204-ca9e8a8ddea8/go.mod h1:5YoVOkjYAQumqlV356Hj3xeYh4BdZuLE0/nRkf2NKkI= +github.com/gocarina/gocsv v0.0.0-20240520201108-78e41c74b4b1 h1:FWNFq4fM1wPfcK40yHE5UO3RUdSNPaBC+j3PokzA6OQ= +github.com/gocarina/gocsv v0.0.0-20240520201108-78e41c74b4b1/go.mod h1:5YoVOkjYAQumqlV356Hj3xeYh4BdZuLE0/nRkf2NKkI= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/google/uuid v1.0.0 h1:b4Gk+7WdP/d3HZH8EJsZpvV7EtDOgaZLtnaNGIu1adA= -github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gramework/gramework v1.6.2 h1:zaIz5Di9OEEWP2z2QztxRonqXBmqpkAj8i7+5BcwfQ4= -github.com/gramework/gramework v1.6.2/go.mod h1:QxHQqlQnDgQCtn7hp/M4fep9c8CYL/MTblVgMsQvqpQ= -github.com/gramework/runtimer v0.0.0-20171029174549-045ac3154a31 h1:ph474iyIY7FlcYg3PeMXtvWiwVhZEfo3Z9/LtTy+Pfo= -github.com/gramework/runtimer v0.0.0-20171029174549-045ac3154a31/go.mod h1:wJlXrZVkOeGRLwODHvQcpRKopvHHsPovXNB9AB1rqwQ= -github.com/gramework/utils v0.0.0-20180427183540-d82c91416f14 h1:KBCnx7osefkcnowspN4ChqmMedSUTB9C4r3rhwrVOUk= -github.com/gramework/utils v0.0.0-20180427183540-d82c91416f14/go.mod h1:62TH8ocqQEUeIL3WbQeqYWNe/jlWnqU3ero9T1WPXsk= -github.com/graph-gophers/graphql-go v0.0.0-20180806175703-94da0f0031f9/go.mod h1:aRnZGurV3LlZ1Y+ygyx1mAV6OUfq+nu6OgpJ6jKgZ3g= -github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs= +github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs= +github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +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/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= +github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8= +github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0= +github.com/gramework/gramework v1.8.0 h1:cYrp2Ss9wd0ZRJCfwxFsfvslu69mOjTZ1CMrLC0GlQA= +github.com/gramework/gramework v1.8.0/go.mod h1:59mpi71VX5AIKppxZNl5F4bshkPRUeYQRHI8iCl3+nQ= +github.com/gramework/utils v0.0.0-20190202181041-3c30a162ea26 h1:mmSirDkAeuEyGfCOLpKJRvumbJl/E5badSGxXnLt9uY= +github.com/gramework/utils v0.0.0-20190202181041-3c30a162ea26/go.mod h1:62TH8ocqQEUeIL3WbQeqYWNe/jlWnqU3ero9T1WPXsk= +github.com/graph-gophers/graphql-go v1.2.0/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7/go.mod h1:2iMrUgbbvHEiQClaW2NsSzMyGHqN+rDFqY705q49KG0= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kirillDanshin/go-accept-headers v0.0.0-20130320203746-c78f304b1b09 h1:8QCKmCB7k/3XCUaisDYqSpZ/KrEsh8h3gRpeBCwOg3Q= github.com/kirillDanshin/go-accept-headers v0.0.0-20130320203746-c78f304b1b09/go.mod h1:bzzcb9Lqedgb3IPjVjtnwhBK6v5gTLrKYimXqT4a+vw= -github.com/klauspost/compress v1.4.0 h1:8nsMz3tWa9SWWPL60G1V6CUsf4lLjWLTNEtibhe8gh8= -github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/cpuid v0.0.0-20180405133222-e7e905edc00e h1:+lIPJOWl+jSiJOc70QXJ07+2eg2Jy2EC7Mi11BWujeM= -github.com/klauspost/cpuid v0.0.0-20180405133222-e7e905edc00e/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= -github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.10.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= +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/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= -github.com/mattn/go-isatty v0.0.5 h1:tHXDdz1cpzGaovsTB+TVB8q90WEokoVmfMqoVcrLUgw= +github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +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.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +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/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= +github.com/microcosm-cc/bluemonday v1.0.15/go.mod h1:ZLvAzeakRwrGnzQEvstVzVt3ZpqOF2+sdFr0Om+ce30= +github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk= +github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/onsi/ginkgo v1.2.1-0.20160409220416-2c2e9bb47b4e/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0 h1:Ix8l273rp3QzYgXSR+c8d1fTG7UPgYkOSELPhiY/YGw= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/gomega v1.4.2 h1:3mYCb7aPxS/RU7TI1y4rkEn1oKmPRjNJLNEXgw7MH2I= -github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw= +github.com/onsi/ginkgo/v2 v2.23.3 h1:edHxnszytJ4lD9D5Jjc4tiDkPBZ3siDeJJkUZJJVkp0= +github.com/onsi/ginkgo/v2 v2.23.3/go.mod h1:zXTP6xIp3U8aVuXN8ENK9IXRaTjFnpVB9mGmaSRvxnM= +github.com/onsi/gomega v1.2.0/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8= +github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 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/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/pquerna/ffjson v0.0.0-20190930134022-aa0246cd15f7 h1:xoIK0ctDddBMnc74udxJYBqlo9Ylnsp1waqjLsnef20= +github.com/pquerna/ffjson v0.0.0-20190930134022-aa0246cd15f7/go.mod h1:YARuvh7BUWHNhzDq2OM5tzR2RiCcN2D7sapiKyCel/M= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.31.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/savsgio/gotils v0.0.0-20200608150037-a5f6f5aef16c/go.mod h1:TWNAOTaVzGOXq8RbEvHnhzA/A2sLZzgn0m6URjnukY8= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= +github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM= +github.com/smartystreets/gunit v1.0.0/go.mod h1:qwPWnhz6pn0NnRBP++URONOVyNkPyr4SauJk4cUOwJs= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.1.4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/valyala/bytebufferpool v0.0.0-20160817181652-e746df99fe4a h1:AOcehBWpFhYPYw0ioDTppQzgI8pAAahVCiMSKTp9rbo= -github.com/valyala/bytebufferpool v0.0.0-20160817181652-e746df99fe4a/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v0.0.0-20180831062205-5f6439b6df1c h1:Nsg22GybT+aOCsERTjVHvT+8ysOsUeBAM1/34qrKRTU= -github.com/valyala/fasthttp v0.0.0-20180831062205-5f6439b6df1c/go.mod h1:+g/po7GqyG5E+1CNgquiIxJnsXEi5vwFn5weFujbO78= -golang.org/x/crypto v0.0.0-20180830192347-182538f80094 h1:rVTAlhYa4+lCfNxmAIEOGQRoD23UqP72M3+rSWVGDTg= -golang.org/x/crypto v0.0.0-20180830192347-182538f80094/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd h1:nTDtHvHSdCn1m6ITfMRqtOd/9+7a3s8RBNOZ3eYZzJA= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tj/assert v0.0.0-20171129193455-018094318fb0/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0= +github.com/tj/assert v0.0.3 h1:Df/BlaZ20mq6kuai7f5z2TvPFiwC3xaWJSDQNiIS3Rk= +github.com/tj/assert v0.0.3/go.mod h1:Ne6X72Q+TB1AteidzQncjw9PabbMp4PBMZ1k+vd1Pvk= +github.com/tj/go-buffer v1.1.0/go.mod h1:iyiJpfFcR2B9sXu7KvjbT9fpM4mOelRSDTbntVj52Uc= +github.com/tj/go-elastic v0.0.0-20171221160941-36157cbbebc2/go.mod h1:WjeM0Oo1eNAjXGDx2yma7uG2XoyRZTq1uv3M/o7imD0= +github.com/tj/go-kinesis v0.0.0-20171128231115-08b17f58cb1b/go.mod h1:/yhzCV0xPfx6jb1bBgRFjl5lytqVqZXEaeqWP8lTEao= +github.com/tj/go-spin v1.1.0/go.mod h1:Mg1mzmePZm4dva8Qz60H2lHwmJ2loum4VIrLgVnKwh4= +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.14.0/go.mod h1:ol1PCaL0dX20wC0htZ7sYCsvCYmrouYra0zHzaclZhE= +github.com/valyala/fasthttp v1.31.0/go.mod h1:2rsYD01CKFrjjsvFxx75KlEUNpWNBY9JWD3K/7o2Cus= +github.com/valyala/fasthttp v1.60.0 h1:kBRYS0lOhVJ6V+bYN8PqAHELKHtXqwq9zNMLKx1MBsw= +github.com/valyala/fasthttp v1.60.0/go.mod h1:iY4kDgV3Gc6EqhRZ8icqcmlG6bqhcDXfuHgTO4FXCvc= +github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= +github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= +github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= +github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= +golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20171107184841-a337091b0525/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= +golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20171114162044-bf42f188b9bc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181023152157-44b849a8bc13 h1:ICvJQ9FL9kAAfwGwpoAmcE1O51M0zE++iVRxQ3xyiGE= -golang.org/x/sys v0.0.0-20181023152157-44b849a8bc13/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210910150752-751e447fb3d0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.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/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.1.1-0.20171102192421-88f656faf3f3/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= +golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.31.0 h1:0EedkvKDbh+qistFTd0Bcwe/YLh4vHwWEkiI0toFIBU= +golang.org/x/tools v0.31.0/go.mod h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/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= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/frameworks/Go/hertz/go.mod b/frameworks/Go/hertz/go.mod index a43ab903201..741b2016451 100644 --- a/frameworks/Go/hertz/go.mod +++ b/frameworks/Go/hertz/go.mod @@ -1,36 +1,37 @@ module hertz -go 1.20 +go 1.24.0 + +toolchain go1.24.1 require ( - github.com/cloudwego/hertz v0.7.1 - github.com/goccy/go-json v0.10.2 - github.com/jackc/pgx/v5 v5.4.3 + github.com/cloudwego/hertz v0.9.6 + github.com/goccy/go-json v0.10.5 + github.com/jackc/pgx/v5 v5.7.4 ) require ( - github.com/bytedance/go-tagexpr/v2 v2.9.2 // indirect - github.com/bytedance/gopkg v0.0.0-20220413063733-65bf48ffb3a7 // indirect - github.com/bytedance/sonic v1.8.1 // indirect - github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect - github.com/cloudwego/netpoll v0.5.0 // indirect - github.com/fsnotify/fsnotify v1.5.4 // indirect - github.com/golang/protobuf v1.5.0 // indirect - github.com/henrylee2cn/ameda v1.4.10 // indirect - github.com/henrylee2cn/goutil v0.0.0-20210127050712-89660552f6f8 // indirect + github.com/bytedance/gopkg v0.1.2 // indirect + github.com/bytedance/sonic v1.13.2 // indirect + github.com/bytedance/sonic/loader v0.2.4 // indirect + github.com/cloudwego/base64x v0.1.5 // indirect + github.com/cloudwego/gopkg v0.1.4 // indirect + github.com/cloudwego/netpoll v0.7.0 // indirect + github.com/fsnotify/fsnotify v1.8.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect - github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect - github.com/jackc/puddle/v2 v2.2.1 // indirect - github.com/klauspost/cpuid/v2 v2.0.9 // indirect - github.com/nyaruka/phonenumbers v1.0.55 // indirect - github.com/tidwall/gjson v1.14.4 // indirect + github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect + github.com/jackc/puddle/v2 v2.2.2 // indirect + github.com/klauspost/cpuid/v2 v2.2.10 // indirect + github.com/nyaruka/phonenumbers v1.6.0 // indirect + github.com/tidwall/gjson v1.18.0 // indirect github.com/tidwall/match v1.1.1 // indirect - github.com/tidwall/pretty v1.2.0 // indirect + github.com/tidwall/pretty v1.2.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect - golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect - golang.org/x/crypto v0.14.0 // indirect - golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.13.0 // indirect - golang.org/x/text v0.13.0 // indirect - google.golang.org/protobuf v1.28.0 // indirect + golang.org/x/arch v0.15.0 // indirect + golang.org/x/crypto v0.45.0 // indirect + golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // 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 + google.golang.org/protobuf v1.36.6 // indirect ) diff --git a/frameworks/Go/hertz/go.sum b/frameworks/Go/hertz/go.sum index fb87f4188a7..9159cda26d4 100644 --- a/frameworks/Go/hertz/go.sum +++ b/frameworks/Go/hertz/go.sum @@ -1,52 +1,53 @@ -github.com/bytedance/go-tagexpr/v2 v2.9.2 h1:QySJaAIQgOEDQBLS3x9BxOWrnhqu5sQ+f6HaZIxD39I= -github.com/bytedance/go-tagexpr/v2 v2.9.2/go.mod h1:5qsx05dYOiUXOUgnQ7w3Oz8BYs2qtM/bJokdLb79wRM= -github.com/bytedance/gopkg v0.0.0-20220413063733-65bf48ffb3a7 h1:PtwsQyQJGxf8iaPptPNaduEIu9BnrNms+pcRdHAxZaM= -github.com/bytedance/gopkg v0.0.0-20220413063733-65bf48ffb3a7/go.mod h1:2ZlV9BaUH4+NXIBF0aMdKKAnHTzqH+iMU4KUjAbL23Q= -github.com/bytedance/mockey v1.2.1 h1:g84ngI88hz1DR4wZTL3yOuqlEcq67MretBfQUdXwrmw= -github.com/bytedance/mockey v1.2.1/go.mod h1:+Jm/fzWZAuhEDrPXVjDf/jLM2BlLXJkwk94zf2JZ3X4= -github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= -github.com/bytedance/sonic v1.8.1 h1:NqAHCaGaTzro0xMmnTCLUyRlbEP6r8MCA1cJUrH3Pu4= -github.com/bytedance/sonic v1.8.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= -github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= -github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= -github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= -github.com/cloudwego/hertz v0.7.1 h1:4M8l4zvAE6yNxzfozpxHLMnRSRRPslKNw/McH5/qFns= -github.com/cloudwego/hertz v0.7.1/go.mod h1:WliNtVbwihWHHgAaIQEbVXl0O3aWj0ks1eoPrcEAnjs= -github.com/cloudwego/netpoll v0.5.0 h1:oRrOp58cPCvK2QbMozZNDESvrxQaEHW2dCimmwH1lcU= -github.com/cloudwego/netpoll v0.5.0/go.mod h1:xVefXptcyheopwNDZjDPcfU6kIjZXZ4nY550k1yH9eQ= +github.com/bytedance/gopkg v0.1.1/go.mod h1:576VvJ+eJgyCzdjS+c4+77QF3p7ubbtiKARP3TxducM= +github.com/bytedance/gopkg v0.1.2 h1:8o2feYuxknDpN+O7kPwvSXfMEKfYvJYiA2K7aonoMEQ= +github.com/bytedance/gopkg v0.1.2/go.mod h1:576VvJ+eJgyCzdjS+c4+77QF3p7ubbtiKARP3TxducM= +github.com/bytedance/mockey v1.2.12 h1:aeszOmGw8CPX8CRx1DZ/Glzb1yXvhjDh6jdFBNZjsU4= +github.com/bytedance/mockey v1.2.12/go.mod h1:3ZA4MQasmqC87Tw0w7Ygdy7eHIc2xgpZ8Pona5rsYIk= +github.com/bytedance/sonic v1.13.2 h1:8/H1FempDZqC4VqjptGo14QQlJx8VdZJegxs6wwfqpQ= +github.com/bytedance/sonic v1.13.2/go.mod h1:o68xyaF9u2gvVBuGHPlUVCy+ZfmNNO5ETf1+KgkJhz4= +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/cloudwego/base64x v0.1.5 h1:XPciSp1xaq2VCSt6lF0phncD4koWyULpl5bUxbfCyP4= +github.com/cloudwego/base64x v0.1.5/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= +github.com/cloudwego/gopkg v0.1.4 h1:EoQiCG4sTonTPHxOGE0VlQs+sQR+Hsi2uN0qqwu8O50= +github.com/cloudwego/gopkg v0.1.4/go.mod h1:FQuXsRWRsSqJLsMVd5SYzp8/Z1y5gXKnVvRrWUOsCMI= +github.com/cloudwego/hertz v0.9.6 h1:Kj5SSPlKBC32NIN7+B/tt8O1pdDz8brMai00rqqjULQ= +github.com/cloudwego/hertz v0.9.6/go.mod h1:X5Ez52XhtszU4t+CTBGIJI4PqmcI1oSf8ULBz0SWfLo= +github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= +github.com/cloudwego/netpoll v0.7.0 h1:bDrxQaNfijRI1zyGgXHQoE/nYegL0nr+ijO1Norelc4= +github.com/cloudwego/netpoll v0.7.0/go.mod h1:PI+YrmyS7cIr0+SD4seJz3Eo3ckkXdu2ZVKBLhURLNU= 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/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= -github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= -github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= -github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= +github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +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/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/henrylee2cn/ameda v1.4.8/go.mod h1:liZulR8DgHxdK+MEwvZIylGnmcjzQ6N6f2PlWe7nEO4= -github.com/henrylee2cn/ameda v1.4.10 h1:JdvI2Ekq7tapdPsuhrc4CaFiqw6QXFvZIULWJgQyCAk= -github.com/henrylee2cn/ameda v1.4.10/go.mod h1:liZulR8DgHxdK+MEwvZIylGnmcjzQ6N6f2PlWe7nEO4= -github.com/henrylee2cn/goutil v0.0.0-20210127050712-89660552f6f8 h1:yE9ULgp02BhYIrO6sdV/FPe0xQM6fNHkVQW2IAymfM0= -github.com/henrylee2cn/goutil v0.0.0-20210127050712-89660552f6f8/go.mod h1:Nhe/DM3671a5udlv2AdV2ni/MZzgfv2qrPL5nIi3EGQ= 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-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= -github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= -github.com/jackc/pgx/v5 v5.4.3 h1:cxFyXhxlvAifxnkKKdlxv8XqUf59tDlYjnV5YYfsJJY= -github.com/jackc/pgx/v5 v5.4.3/go.mod h1:Ig06C2Vu0t5qXC60W8sqIthScaEnFvojjj9dSljmHRA= -github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= -github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +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/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/nyaruka/phonenumbers v1.0.55 h1:bj0nTO88Y68KeUQ/n3Lo2KgK7lM1hF7L9NFuwcCl3yg= -github.com/nyaruka/phonenumbers v1.0.55/go.mod h1:sDaTZ/KPX5f8qyV9qN+hIm+4ZBARJrupC6LuhshJq1U= +github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= +github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/nyaruka/phonenumbers v1.6.0 h1:r9ax45fFg+YLUs2X4bNXm5RAxWl00hYjFgNlv32vtHk= +github.com/nyaruka/phonenumbers v1.6.0/go.mod h1:7gjs+Lchqm49adhAKB5cdcng5ZXgt6x7Jgvi0ZorUtU= 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/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= @@ -56,51 +57,87 @@ github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 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 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/tidwall/gjson v1.9.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= -github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM= -github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +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/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= +github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= -github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= +github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= 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= -golang.org/x/arch v0.0.0-20201008161808-52c3e6f60cff/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4= -golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU= -golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +golang.org/x/arch v0.15.0 h1:QtOrQd0bTUnhNVNndMpLHNWrDmYzZ2KDqSrEymqInZw= +golang.org/x/arch v0.15.0/go.mod h1:JmwW7aLIoRUKgaTzhkiEFxvcEiQGyOg9BMonBJUS7EE= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= +golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= +golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= +golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw= +golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +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.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20220110181412-a018aaa089fe/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.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.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +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/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= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= -google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= +golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/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= -rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= +nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= diff --git a/frameworks/Go/hertz/hertz-gorm.dockerfile b/frameworks/Go/hertz/hertz-gorm.dockerfile index c12fc259573..d33ba5dcc6b 100644 --- a/frameworks/Go/hertz/hertz-gorm.dockerfile +++ b/frameworks/Go/hertz/hertz-gorm.dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.20 +FROM golang:1.24.2 ENV GO111MODULE=on WORKDIR /src/ diff --git a/frameworks/Go/hertz/hertz-gorm/go.mod b/frameworks/Go/hertz/hertz-gorm/go.mod index f284bfed3b6..ad2a290dbdd 100644 --- a/frameworks/Go/hertz/hertz-gorm/go.mod +++ b/frameworks/Go/hertz/hertz-gorm/go.mod @@ -1,43 +1,41 @@ module hertz-gorm/main -go 1.19 +go 1.23.0 + +toolchain go1.24.1 require ( - github.com/cloudwego/hertz v0.7.0 - github.com/goccy/go-json v0.10.2 - gorm.io/driver/postgres v1.4.5 - gorm.io/gorm v1.25.4 + github.com/cloudwego/hertz v0.9.6 + github.com/goccy/go-json v0.10.5 + gorm.io/driver/postgres v1.5.11 + gorm.io/gorm v1.25.12 ) require ( - github.com/bytedance/go-tagexpr/v2 v2.9.2 // indirect - github.com/bytedance/gopkg v0.0.0-20220413063733-65bf48ffb3a7 // indirect - github.com/bytedance/sonic v1.8.1 // indirect - github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect - github.com/cloudwego/netpoll v0.5.0 // indirect - github.com/fsnotify/fsnotify v1.5.4 // indirect - github.com/golang/protobuf v1.5.0 // indirect - github.com/henrylee2cn/ameda v1.4.10 // indirect - github.com/henrylee2cn/goutil v0.0.0-20210127050712-89660552f6f8 // indirect - github.com/jackc/chunkreader/v2 v2.0.1 // indirect - github.com/jackc/pgconn v1.13.0 // indirect - github.com/jackc/pgio v1.0.0 // indirect + github.com/bytedance/gopkg v0.1.2 // indirect + github.com/bytedance/sonic v1.13.2 // indirect + github.com/bytedance/sonic/loader v0.2.4 // indirect + github.com/cloudwego/base64x v0.1.5 // indirect + github.com/cloudwego/gopkg v0.1.4 // indirect + github.com/cloudwego/netpoll v0.7.0 // indirect + github.com/fsnotify/fsnotify v1.8.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect - github.com/jackc/pgproto3/v2 v2.3.1 // indirect - github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect - github.com/jackc/pgtype v1.12.0 // indirect - github.com/jackc/pgx/v4 v4.17.2 // indirect + github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect + github.com/jackc/pgx/v5 v5.7.4 // indirect + github.com/jackc/puddle/v2 v2.2.2 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect - github.com/klauspost/cpuid/v2 v2.0.9 // indirect - github.com/nyaruka/phonenumbers v1.0.55 // indirect - github.com/tidwall/gjson v1.14.4 // indirect + github.com/klauspost/cpuid/v2 v2.2.10 // indirect + github.com/nyaruka/phonenumbers v1.6.0 // indirect + github.com/tidwall/gjson v1.18.0 // indirect github.com/tidwall/match v1.1.1 // indirect - github.com/tidwall/pretty v1.2.0 // indirect + github.com/tidwall/pretty v1.2.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect - golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect - golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect - golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect - golang.org/x/text v0.3.7 // indirect - google.golang.org/protobuf v1.28.0 // indirect + golang.org/x/arch v0.15.0 // indirect + golang.org/x/crypto v0.36.0 // indirect + golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect + golang.org/x/sync v0.12.0 // indirect + golang.org/x/sys v0.31.0 // indirect + golang.org/x/text v0.23.0 // indirect + google.golang.org/protobuf v1.36.6 // indirect ) diff --git a/frameworks/Go/hertz/hertz-gorm/go.sum b/frameworks/Go/hertz/hertz-gorm/go.sum index c84b073dce6..c67048d46ea 100644 --- a/frameworks/Go/hertz/hertz-gorm/go.sum +++ b/frameworks/Go/hertz/hertz-gorm/go.sum @@ -1,262 +1,151 @@ -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc= -github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= -github.com/bytedance/go-tagexpr/v2 v2.9.2 h1:QySJaAIQgOEDQBLS3x9BxOWrnhqu5sQ+f6HaZIxD39I= -github.com/bytedance/go-tagexpr/v2 v2.9.2/go.mod h1:5qsx05dYOiUXOUgnQ7w3Oz8BYs2qtM/bJokdLb79wRM= -github.com/bytedance/gopkg v0.0.0-20220413063733-65bf48ffb3a7 h1:PtwsQyQJGxf8iaPptPNaduEIu9BnrNms+pcRdHAxZaM= -github.com/bytedance/gopkg v0.0.0-20220413063733-65bf48ffb3a7/go.mod h1:2ZlV9BaUH4+NXIBF0aMdKKAnHTzqH+iMU4KUjAbL23Q= -github.com/bytedance/mockey v1.2.1 h1:g84ngI88hz1DR4wZTL3yOuqlEcq67MretBfQUdXwrmw= -github.com/bytedance/mockey v1.2.1/go.mod h1:+Jm/fzWZAuhEDrPXVjDf/jLM2BlLXJkwk94zf2JZ3X4= -github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= -github.com/bytedance/sonic v1.8.1 h1:NqAHCaGaTzro0xMmnTCLUyRlbEP6r8MCA1cJUrH3Pu4= -github.com/bytedance/sonic v1.8.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= -github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= -github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= -github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= -github.com/cloudwego/hertz v0.7.0 h1:9LFXPqHkGBNH/k/Y1h3udEloS5LVPNOUWekDfH0bQNM= -github.com/cloudwego/hertz v0.7.0/go.mod h1:WliNtVbwihWHHgAaIQEbVXl0O3aWj0ks1eoPrcEAnjs= -github.com/cloudwego/netpoll v0.5.0 h1:oRrOp58cPCvK2QbMozZNDESvrxQaEHW2dCimmwH1lcU= -github.com/cloudwego/netpoll v0.5.0/go.mod h1:xVefXptcyheopwNDZjDPcfU6kIjZXZ4nY550k1yH9eQ= -github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= -github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= -github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/bytedance/gopkg v0.1.1/go.mod h1:576VvJ+eJgyCzdjS+c4+77QF3p7ubbtiKARP3TxducM= +github.com/bytedance/gopkg v0.1.2 h1:8o2feYuxknDpN+O7kPwvSXfMEKfYvJYiA2K7aonoMEQ= +github.com/bytedance/gopkg v0.1.2/go.mod h1:576VvJ+eJgyCzdjS+c4+77QF3p7ubbtiKARP3TxducM= +github.com/bytedance/mockey v1.2.12 h1:aeszOmGw8CPX8CRx1DZ/Glzb1yXvhjDh6jdFBNZjsU4= +github.com/bytedance/mockey v1.2.12/go.mod h1:3ZA4MQasmqC87Tw0w7Ygdy7eHIc2xgpZ8Pona5rsYIk= +github.com/bytedance/sonic v1.13.2 h1:8/H1FempDZqC4VqjptGo14QQlJx8VdZJegxs6wwfqpQ= +github.com/bytedance/sonic v1.13.2/go.mod h1:o68xyaF9u2gvVBuGHPlUVCy+ZfmNNO5ETf1+KgkJhz4= +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/cloudwego/base64x v0.1.5 h1:XPciSp1xaq2VCSt6lF0phncD4koWyULpl5bUxbfCyP4= +github.com/cloudwego/base64x v0.1.5/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= +github.com/cloudwego/gopkg v0.1.4 h1:EoQiCG4sTonTPHxOGE0VlQs+sQR+Hsi2uN0qqwu8O50= +github.com/cloudwego/gopkg v0.1.4/go.mod h1:FQuXsRWRsSqJLsMVd5SYzp8/Z1y5gXKnVvRrWUOsCMI= +github.com/cloudwego/hertz v0.9.6 h1:Kj5SSPlKBC32NIN7+B/tt8O1pdDz8brMai00rqqjULQ= +github.com/cloudwego/hertz v0.9.6/go.mod h1:X5Ez52XhtszU4t+CTBGIJI4PqmcI1oSf8ULBz0SWfLo= +github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= +github.com/cloudwego/netpoll v0.7.0 h1:bDrxQaNfijRI1zyGgXHQoE/nYegL0nr+ijO1Norelc4= +github.com/cloudwego/netpoll v0.7.0/go.mod h1:PI+YrmyS7cIr0+SD4seJz3Eo3ckkXdu2ZVKBLhURLNU= 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/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= -github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= -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-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= -github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= -github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= -github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= +github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +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/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/henrylee2cn/ameda v1.4.8/go.mod h1:liZulR8DgHxdK+MEwvZIylGnmcjzQ6N6f2PlWe7nEO4= -github.com/henrylee2cn/ameda v1.4.10 h1:JdvI2Ekq7tapdPsuhrc4CaFiqw6QXFvZIULWJgQyCAk= -github.com/henrylee2cn/ameda v1.4.10/go.mod h1:liZulR8DgHxdK+MEwvZIylGnmcjzQ6N6f2PlWe7nEO4= -github.com/henrylee2cn/goutil v0.0.0-20210127050712-89660552f6f8 h1:yE9ULgp02BhYIrO6sdV/FPe0xQM6fNHkVQW2IAymfM0= -github.com/henrylee2cn/goutil v0.0.0-20210127050712-89660552f6f8/go.mod h1:Nhe/DM3671a5udlv2AdV2ni/MZzgfv2qrPL5nIi3EGQ= -github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= -github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= -github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= -github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= -github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= -github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE= -github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s= -github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= -github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= -github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= -github.com/jackc/pgconn v1.13.0 h1:3L1XMNV2Zvca/8BYhzcRFS70Lr0WlDg16Di6SFGAbys= -github.com/jackc/pgconn v1.13.0/go.mod h1:AnowpAqO4CMIIJNZl2VJp+KrkAZciAkhEl0W0JIobpI= -github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= -github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= -github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= -github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c= -github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc= -github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak= 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/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= -github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA= -github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg= -github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= -github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= -github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.3.1 h1:nwj7qwf0S+Q7ISFfBndqeLwSwxs+4DPsbRFjECT1Y4Y= -github.com/jackc/pgproto3/v2 v2.3.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg= -github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= -github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= -github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= -github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= -github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= -github.com/jackc/pgtype v1.12.0 h1:Dlq8Qvcch7kiehm8wPGIW0W3KsCCHJnRacKW0UM8n5w= -github.com/jackc/pgtype v1.12.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= -github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= -github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= -github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= -github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= -github.com/jackc/pgx/v4 v4.17.2 h1:0Ut0rpeKwvIVbMQ1KbMBU4h6wxehBI535LK6Flheh8E= -github.com/jackc/pgx/v4 v4.17.2/go.mod h1:lcxIZN44yMIrWI78a5CpucdD14hX0SBDbNRvjDBItsw= -github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +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/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= -github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= +github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8= -github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= -github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/nyaruka/phonenumbers v1.0.55 h1:bj0nTO88Y68KeUQ/n3Lo2KgK7lM1hF7L9NFuwcCl3yg= -github.com/nyaruka/phonenumbers v1.0.55/go.mod h1:sDaTZ/KPX5f8qyV9qN+hIm+4ZBARJrupC6LuhshJq1U= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/nyaruka/phonenumbers v1.6.0 h1:r9ax45fFg+YLUs2X4bNXm5RAxWl00hYjFgNlv32vtHk= +github.com/nyaruka/phonenumbers v1.6.0/go.mod h1:7gjs+Lchqm49adhAKB5cdcng5ZXgt6x7Jgvi0ZorUtU= 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.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -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= -github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= -github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= -github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= -github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 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 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/tidwall/gjson v1.9.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= -github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM= -github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +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/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= +github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= -github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= +github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= 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/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= -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= -go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= -go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= -go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= -golang.org/x/arch v0.0.0-20201008161808-52c3e6f60cff/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4= -golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU= -golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +golang.org/x/arch v0.15.0 h1:QtOrQd0bTUnhNVNndMpLHNWrDmYzZ2KDqSrEymqInZw= +golang.org/x/arch v0.15.0/go.mod h1:JmwW7aLIoRUKgaTzhkiEFxvcEiQGyOg9BMonBJUS7EE= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c= -golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= +golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= +golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= +golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw= +golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= +golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220110181412-a018aaa089fe/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.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.19.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/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= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= +golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= -google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 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= -gorm.io/driver/postgres v1.4.5 h1:mTeXTTtHAgnS9PgmhN2YeUbazYpLhUI1doLnw42XUZc= -gorm.io/driver/postgres v1.4.5/go.mod h1:GKNQYSJ14qvWkvPwXljMGehpKrhlDNsqYRr5HnYGncg= -gorm.io/gorm v1.24.1-0.20221019064659-5dd2bb482755/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA= -gorm.io/gorm v1.25.4 h1:iyNd8fNAe8W9dvtlgeRI5zSVZPsq3OpcTu37cYcpCmw= -gorm.io/gorm v1.25.4/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= +gorm.io/driver/postgres v1.5.11 h1:ubBVAfbKEUld/twyKZ0IYn9rSQh448EdelLYk9Mv314= +gorm.io/driver/postgres v1.5.11/go.mod h1:DX3GReXH+3FPWGrrgffdvCk3DQ1dwDPdmbenSkweRGI= +gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8= +gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ= +nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= diff --git a/frameworks/Go/hertz/hertz.dockerfile b/frameworks/Go/hertz/hertz.dockerfile index 60252e31ffd..6af119c4351 100644 --- a/frameworks/Go/hertz/hertz.dockerfile +++ b/frameworks/Go/hertz/hertz.dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/golang:1.20 +FROM docker.io/golang:1.24.2 WORKDIR /hertz diff --git a/frameworks/Go/indigo/README.md b/frameworks/Go/indigo/README.md new file mode 100644 index 00000000000..2349ae2cf15 --- /dev/null +++ b/frameworks/Go/indigo/README.md @@ -0,0 +1,14 @@ +# [Indigo](https://github.com/indigo-web/indigo) (Go) Benchmarking Test + +This is the go portion of a [benchmarking test suite](https://www.techempower.com/benchmarks/) comparing a variety of web development platforms. + +> Indigo is a web-framework focusing at performance, elegancy and robustness. + +## Test URLs +* http://localhost:8080/json +* http://localhost:8080/db +* http://localhost:8080/query?n=[1-500] +* http://localhost:8080/update?n=[1-500] +* http://localhost:8080/cached-query?n=[1-500] +* http://localhost:8080/fortune +* http://localhost:8080/plaintext diff --git a/frameworks/Go/indigo/benchmark_config.json b/frameworks/Go/indigo/benchmark_config.json new file mode 100644 index 00000000000..a1915a0fedf --- /dev/null +++ b/frameworks/Go/indigo/benchmark_config.json @@ -0,0 +1,31 @@ +{ + "framework": "indigo", + "tests": [ + { + "default": { + "json_url": "/json", + "db_url": "/db", + "query_url": "/query?n=", + "update_url": "/update?n=", + "cached_query_url": "/cached-query?n=", + "fortune_url": "/fortunes", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Platform", + "database": "Postgres", + "framework": "indigo", + "language": "Go", + "flavor": "None", + "orm": "Raw", + "platform": "None", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "Indigo", + "notes": "", + "versus": "go" + } + } + ] +} diff --git a/frameworks/Go/indigo/config.toml b/frameworks/Go/indigo/config.toml new file mode 100644 index 00000000000..abc0d4b02ce --- /dev/null +++ b/frameworks/Go/indigo/config.toml @@ -0,0 +1,20 @@ +[framework] +name = "indigo" + +[main] +urls.json = "/json" +urls.db = "/db" +urls.query = "/query?n=" +urls.update = "/update?n=" +urls.cached_query = "/cached-query?n=" +urls.fortune = "/fortunes" +urls.plaintext = "/plaintext" +approach = "Realistic" +classification = "Platform" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "None" +webserver = "None" +versus = "go" diff --git a/frameworks/Go/indigo/indigo.dockerfile b/frameworks/Go/indigo/indigo.dockerfile new file mode 100644 index 00000000000..3096d7cd738 --- /dev/null +++ b/frameworks/Go/indigo/indigo.dockerfile @@ -0,0 +1,19 @@ +FROM golang:1.25-alpine3.22 as builder + +WORKDIR /indigo + +COPY ./src /indigo + +RUN go mod download && \ + go generate -x ./templates && \ + GOAMD64=v3 go build -ldflags="-s -w" -o app . + +FROM alpine:3.22 + +WORKDIR /indigo + +COPY --from=builder /indigo/app . + +EXPOSE 8080 + +CMD ./app diff --git a/frameworks/Go/indigo/src/app.go b/frameworks/Go/indigo/src/app.go new file mode 100644 index 00000000000..f8aa2930462 --- /dev/null +++ b/frameworks/Go/indigo/src/app.go @@ -0,0 +1,163 @@ +package main + +import ( + "context" + "math/rand/v2" + "slices" + "strconv" + "time" + + "github.com/indigo-web/indigo/http" + "github.com/indigo-web/indigo/http/mime" + + "indigo/app/models" + "indigo/app/templates" +) + +type ( + App struct { + DB *DB + Cache models.Worlds + } +) + +func NewApp(DB *DB) *App { + return &App{DB: DB} +} + +func (app *App) PopulateCache(ctx context.Context) error { + cache := make(models.Worlds, 10000) + + err := app.DB.FillWorlds(context.Background(), cache) + if err != nil { + return err + } + + app.Cache = cache + + return nil +} + +func (app *App) HandleJSON(request *http.Request) *http.Response { + return request.Respond().Header("Date", time.Now().Format(time.RFC1123)).Header("Server", "indigo").JSON(&models.Message{ + Message: "Hello, World!", + }) +} + +func (app *App) HandleDB(request *http.Request) *http.Response { + world := &models.World{ + ID: rand.IntN(10000) + 1, + } + + err := app.DB.FillWorldByID(context.Background(), world) + if err != nil { + return http.Error(request, err) + } + + return request.Respond().Header("Date", time.Now().Format(time.RFC1123)).Header("Server", "indigo").JSON(world) +} + +func (app *App) HandleQuery(request *http.Request) *http.Response { + n := normalizeNumber(request.Params.Lookup("n")) + + i, worlds := 0, make(models.Worlds, n) + + for i = range worlds { + worlds[i].ID = rand.IntN(10000) + 1 + } + + err := app.DB.FillWorldsByID(context.Background(), worlds) + if err != nil { + return http.Error(request, err) + } + + return request.Respond().Header("Date", time.Now().Format(time.RFC1123)).Header("Server", "indigo").JSON(&worlds) +} + +func (app *App) HandleUpdate(request *http.Request) *http.Response { + n := normalizeNumber(request.Params.Lookup("n")) + + i, worlds := 0, make(models.Worlds, n) + + for i = range worlds { + worlds[i].ID = rand.IntN(10000) + 1 + } + + err := app.DB.FillWorldsByID(context.Background(), worlds) + if err != nil { + return http.Error(request, err) + } + + for i = range worlds { + worlds[i].RandomNumber = rand.IntN(10000) + 1 + } + + slices.SortFunc(worlds, func(a, b models.World) int { + return a.ID - b.ID + }) + + err = app.DB.UpdateWorlds(context.Background(), worlds) + if err != nil { + return http.Error(request, err) + } + + return request.Respond().Header("Date", time.Now().Format(time.RFC1123)).Header("Server", "indigo").JSON(&worlds) +} + +func (app *App) HandleCachedQuery(request *http.Request) *http.Response { + n := normalizeNumber(request.Params.Lookup("n")) + + i, worlds := 0, make(models.Worlds, n) + + for i = range worlds { + worlds[i] = app.Cache[rand.Int32N(10000)] + } + + return request.Respond().Header("Date", time.Now().Format(time.RFC1123)).Header("Server", "indigo").JSON(&worlds) +} + +func (app *App) HandleFortune(request *http.Request) *http.Response { + fortunes, err := app.DB.GetFortunes(context.Background()) + if err != nil { + return http.Error(request, err) + } + + fortunes = append(fortunes, models.Fortune{ + Message: "Additional fortune added at request time.", + }) + + slices.SortFunc(fortunes, func(a, b models.Fortune) int { + if a.Message < b.Message { + return -1 + } else if a.Message > b.Message { + return 1 + } + + return 0 + }) + + return request.Respond().Header("Date", time.Now().Format(time.RFC1123)).Header("Server", "indigo").ContentType(mime.HTML + "; charset=UTF-8").String(templates.HTMLFortunes(fortunes)) +} + +func (app *App) HandlePlaintext(request *http.Request) *http.Response { + return request.Respond().Header("Date", time.Now().Format(time.RFC1123)).Header("Server", "indigo").ContentType(mime.Plain).String("Hello, World!") +} + +func normalizeNumber(nString string, found bool) int { + if !found { + nString = "0" + } + + n, err := strconv.Atoi(nString) + if err != nil { + n = 0 + } + + if n < 1 { + n = 1 + } else if n > 500 { + n = 500 + } + + return n +} diff --git a/frameworks/Go/indigo/src/database.go b/frameworks/Go/indigo/src/database.go new file mode 100644 index 00000000000..476891408f8 --- /dev/null +++ b/frameworks/Go/indigo/src/database.go @@ -0,0 +1,124 @@ +package main + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgxpool" + + "indigo/app/models" +) + +type ( + DB struct { + pool *pgxpool.Pool + } +) + +func NewDB(pool *pgxpool.Pool) *DB { + return &DB{ + pool: pool, + } +} + +func (DB *DB) GetFortunes(ctx context.Context) ([]models.Fortune, error) { + query := `SELECT id, message FROM Fortune` + + rows, err := DB.pool.Query(ctx, query) + if err != nil { + return nil, err + } + + fortunes, fortune := []models.Fortune(nil), models.Fortune{} + + for rows.Next() { + err = rows.Scan(&fortune.ID, &fortune.Message) + if err != nil { + return nil, err + } + + fortunes = append(fortunes, fortune) + } + + err = rows.Err() + if err != nil { + return nil, err + } + + return fortunes, nil +} + +func (DB *DB) FillWorldByID(ctx context.Context, world *models.World) error { + query := `SELECT randomNumber FROM World WHERE id = $1 LIMIT 1` + + return DB.pool.QueryRow( + context.Background(), + query, + world.ID, + ).Scan(&world.RandomNumber) +} + +func (DB *DB) FillWorlds(ctx context.Context, worlds []models.World) error { + query := `SELECT id, randomNumber FROM World` + + rows, err := DB.pool.Query(ctx, query) + if err != nil { + return err + } + + i, world := 0, (*models.World)(nil) + + for rows.Next() && i < len(worlds) { + world = &worlds[i] + + err = rows.Scan(&world.ID, &world.RandomNumber) + if err != nil { + return err + } + + i += 1 + } + + return rows.Err() +} + +func (DB *DB) FillWorldsByID(ctx context.Context, worlds []models.World) error { + connection, err := DB.pool.Acquire(ctx) + if err != nil { + return err + } + defer connection.Release() + + query := `SELECT randomNumber FROM World WHERE id = $1 LIMIT 1` + + i, world, err := 0, (*models.World)(nil), error(nil) + + for i = range worlds { + world = &worlds[i] + + err = connection.QueryRow( + context.Background(), + query, + world.ID, + ).Scan(&world.RandomNumber) + if err != nil { + return err + } + } + + return nil +} + +func (DB *DB) UpdateWorlds(ctx context.Context, worlds models.Worlds) error { + query := `UPDATE World SET randomNumber = $1 WHERE id = $2` + batch := new(pgx.Batch) + + i, world := 0, (*models.World)(nil) + + for i = range worlds { + world = &worlds[i] + batch.Queue(query, &world.RandomNumber, &world.ID) + } + + return DB.pool.SendBatch(context.Background(), batch).Close() +} diff --git a/frameworks/Go/indigo/src/go.mod b/frameworks/Go/indigo/src/go.mod new file mode 100644 index 00000000000..874efeac4de --- /dev/null +++ b/frameworks/Go/indigo/src/go.mod @@ -0,0 +1,25 @@ +module indigo/app + +go 1.25 + +require ( + github.com/indigo-web/indigo v0.17.2 + github.com/jackc/pgx/v5 v5.7.5 + github.com/valyala/quicktemplate v1.8.0 +) + +require ( + github.com/flrdv/uf v1.0.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/json-iterator/go v1.1.12 // indirect + github.com/klauspost/compress v1.18.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + golang.org/x/crypto v0.45.0 // indirect + golang.org/x/net v0.47.0 // indirect + golang.org/x/sync v0.18.0 // indirect + golang.org/x/text v0.31.0 // indirect +) diff --git a/frameworks/Go/indigo/src/go.sum b/frameworks/Go/indigo/src/go.sum new file mode 100644 index 00000000000..99170600d2b --- /dev/null +++ b/frameworks/Go/indigo/src/go.sum @@ -0,0 +1,50 @@ +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/dchest/uniuri v1.2.0 h1:koIcOUdrTIivZgSLhHQvKgqdWZq5d7KdMEWF1Ud6+5g= +github.com/dchest/uniuri v1.2.0/go.mod h1:fSzm4SLHzNZvWLvWJew423PhAzkpNQYq+uNLq4kxhkY= +github.com/flrdv/uf v1.0.0 h1:udtfbC/UyGas47F4leoelaSvvCW27YOfyNe+7VZz2q8= +github.com/flrdv/uf v1.0.0/go.mod h1:vqLw82T3RKKxRXoXEPFgOaZNYCzE6Lz9e6NnALzVbI8= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/indigo-web/indigo v0.17.2 h1:3KEkVjTa5/URz44l2rUllK1lxau0fg5gh/emKBIfUgM= +github.com/indigo-web/indigo v0.17.2/go.mod h1:v1KnCE1B2Bx60WupVpZy3NQlH4oraxg3GpvpW2QTphk= +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.5 h1:JHGfMnQY+IEtGM63d+NGMjoRpysB2JBwDr5fsngwmJs= +github.com/jackc/pgx/v5 v5.7.5/go.mod h1:aruU7o91Tc2q2cFp5h4uP3f6ztExVpyVv88Xl/8Vl8M= +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/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +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/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +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.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +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/quicktemplate v1.8.0 h1:zU0tjbIqTRgKQzFY1L42zq0qR3eh4WoQQdIdqCysW5k= +github.com/valyala/quicktemplate v1.8.0/go.mod h1:qIqW8/igXt8fdrUln5kOSb+KWMaJ4Y8QUsfd1k6L2jM= +golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= +golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= +golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= +golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= +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/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/indigo/src/main.go b/frameworks/Go/indigo/src/main.go new file mode 100644 index 00000000000..6f8643b4b21 --- /dev/null +++ b/frameworks/Go/indigo/src/main.go @@ -0,0 +1,48 @@ +package main + +import ( + "context" + "fmt" + "log" + + "github.com/indigo-web/indigo" + "github.com/indigo-web/indigo/router/inbuilt" + "github.com/jackc/pgx/v5/pgxpool" +) + +func main() { + pool, err := pgxpool.New(context.Background(), + fmt.Sprintf( + "host=%s port=%d user=%s password=%s dbname=%s", + "tfb-database", 5432, + "benchmarkdbuser", + "benchmarkdbpass", + "hello_world", + )) + if err != nil { + log.Fatal(err) + } + + DB := NewDB(pool) + app := NewApp(DB) + + err = app.PopulateCache(context.Background()) + if err != nil { + log.Fatal(err) + } + + router := inbuilt.New() + + router.Resource("/json").Get(app.HandleJSON) + router.Resource("/db").Get(app.HandleDB) + router.Resource("/query").Get(app.HandleQuery) + router.Resource("/update").Get(app.HandleUpdate) + router.Resource("/cached-query").Get(app.HandleCachedQuery) + router.Resource("/fortunes").Get(app.HandleFortune) + router.Resource("/plaintext").Get(app.HandlePlaintext) + + err = indigo.New(":8080").Serve(router) + if err != nil { + log.Fatal(err) + } +} diff --git a/frameworks/Go/indigo/src/models/models.go b/frameworks/Go/indigo/src/models/models.go new file mode 100644 index 00000000000..021d79dc320 --- /dev/null +++ b/frameworks/Go/indigo/src/models/models.go @@ -0,0 +1,23 @@ +package models + +type ( + Message struct { + Message string `json:"message"` + } +) + +type ( + Worlds []World + + World struct { + ID int `json:"id"` + RandomNumber int `json:"randomNumber"` + } +) + +type ( + Fortune struct { + ID int `json:"id,omitempty"` + Message string `json:"message,omitempty"` + } +) diff --git a/frameworks/Go/indigo/src/templates/fortune.go b/frameworks/Go/indigo/src/templates/fortune.go new file mode 100644 index 00000000000..e7448b6fbd5 --- /dev/null +++ b/frameworks/Go/indigo/src/templates/fortune.go @@ -0,0 +1,3 @@ +package templates + +//go:generate go run github.com/valyala/quicktemplate/qtc diff --git a/frameworks/Go/indigo/src/templates/fortune.qtpl b/frameworks/Go/indigo/src/templates/fortune.qtpl new file mode 100644 index 00000000000..8438680c3e7 --- /dev/null +++ b/frameworks/Go/indigo/src/templates/fortune.qtpl @@ -0,0 +1,19 @@ +{% import "indigo/app/models" %} + +{% func HTMLFortunes(fortunes []models.Fortune) %} + + +Fortunes + + + + +{% code i, fortune := 0, (*models.Fortune)(nil) %} +{% for i = range fortunes %} +{% code fortune = &fortunes[i] %} + +{% endfor %} +
idmessage
{%d fortune.ID %}{%s fortune.Message %}
+ + +{% endfunc %} diff --git a/frameworks/Go/indigo/src/templates/fortune.qtpl.go b/frameworks/Go/indigo/src/templates/fortune.qtpl.go new file mode 100644 index 00000000000..d67ed68a8da --- /dev/null +++ b/frameworks/Go/indigo/src/templates/fortune.qtpl.go @@ -0,0 +1,96 @@ +// 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 "indigo/app/models" + +//line fortune.qtpl:3 +import ( + qtio422016 "io" + + qt422016 "github.com/valyala/quicktemplate" +) + +//line fortune.qtpl:3 +var ( + _ = qtio422016.Copy + _ = qt422016.AcquireByteBuffer +) + +//line fortune.qtpl:3 +func StreamHTMLFortunes(qw422016 *qt422016.Writer, fortunes []models.Fortune) { +//line fortune.qtpl:3 + qw422016.N().S(` + + +Fortunes + + + + +`) +//line fortune.qtpl:11 + i, fortune := 0, (*models.Fortune)(nil) + +//line fortune.qtpl:11 + qw422016.N().S(` +`) +//line fortune.qtpl:12 + for i = range fortunes { +//line fortune.qtpl:12 + qw422016.N().S(` +`) +//line fortune.qtpl:13 + fortune = &fortunes[i] + +//line fortune.qtpl:13 + qw422016.N().S(` + +`) +//line fortune.qtpl:15 + } +//line fortune.qtpl:15 + qw422016.N().S(` +
idmessage
`) +//line fortune.qtpl:14 + qw422016.N().D(fortune.ID) +//line fortune.qtpl:14 + qw422016.N().S(``) +//line fortune.qtpl:14 + qw422016.E().S(fortune.Message) +//line fortune.qtpl:14 + qw422016.N().S(`
+ + +`) +//line fortune.qtpl:19 +} + +//line fortune.qtpl:19 +func WriteHTMLFortunes(qq422016 qtio422016.Writer, fortunes []models.Fortune) { +//line fortune.qtpl:19 + qw422016 := qt422016.AcquireWriter(qq422016) +//line fortune.qtpl:19 + StreamHTMLFortunes(qw422016, fortunes) +//line fortune.qtpl:19 + qt422016.ReleaseWriter(qw422016) +//line fortune.qtpl:19 +} + +//line fortune.qtpl:19 +func HTMLFortunes(fortunes []models.Fortune) string { +//line fortune.qtpl:19 + qb422016 := qt422016.AcquireByteBuffer() +//line fortune.qtpl:19 + WriteHTMLFortunes(qb422016, fortunes) +//line fortune.qtpl:19 + qs422016 := string(qb422016.B) +//line fortune.qtpl:19 + qt422016.ReleaseByteBuffer(qb422016) +//line fortune.qtpl:19 + return qs422016 +//line fortune.qtpl:19 +} diff --git a/frameworks/Go/kami/kami.dockerfile b/frameworks/Go/kami/kami.dockerfile index fe22e5dd266..115e9b5e14c 100644 --- a/frameworks/Go/kami/kami.dockerfile +++ b/frameworks/Go/kami/kami.dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/golang:1.19 +FROM docker.io/golang:1.24.2 COPY ./src /kami WORKDIR /kami diff --git a/frameworks/Go/kami/src/go.mod b/frameworks/Go/kami/src/go.mod index 70f73076e82..6d7a0c8db8e 100644 --- a/frameworks/Go/kami/src/go.mod +++ b/frameworks/Go/kami/src/go.mod @@ -1,16 +1,20 @@ module kami -go 1.19 +go 1.23.0 + +toolchain go1.24.1 require ( - github.com/go-sql-driver/mysql v1.6.0 + github.com/go-sql-driver/mysql v1.9.1 github.com/guregu/kami v2.2.1+incompatible - golang.org/x/net v0.17.0 + golang.org/x/net v0.38.0 ) require ( + filippo.io/edwards25519 v1.1.0 // indirect github.com/dimfeld/httptreemux v5.0.1+incompatible // indirect - github.com/golang/protobuf v1.3.1 // indirect + github.com/golang/protobuf v1.5.4 // indirect github.com/zenazn/goji v1.0.1 // indirect - google.golang.org/appengine v1.6.7 // indirect + google.golang.org/appengine v1.6.8 // indirect + google.golang.org/protobuf v1.36.6 // indirect ) diff --git a/frameworks/Go/kami/src/go.sum b/frameworks/Go/kami/src/go.sum index 90b928c95f5..fa26ea93444 100644 --- a/frameworks/Go/kami/src/go.sum +++ b/frameworks/Go/kami/src/go.sum @@ -1,20 +1,50 @@ +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/dimfeld/httptreemux v5.0.1+incompatible h1:Qj3gVcDNoOthBAqftuD596rm4wg/adLLz5xh5CmpiCA= github.com/dimfeld/httptreemux v5.0.1+incompatible/go.mod h1:rbUlSV+CCpv/SuqUTP/8Bk2O3LyUV436/yaRGkhP6Z0= -github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= -github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= -github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/go-sql-driver/mysql v1.9.1 h1:FrjNGn/BsJQjVRuSa8CBrM5BWA9BWoXXat3KrtSb/iI= +github.com/go-sql-driver/mysql v1.9.1/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/guregu/kami v2.2.1+incompatible h1:G8vzA3Bx2jnm+AQOHXtHW0vTSQ7tQqfxLc5nuHFtkgI= github.com/guregu/kami v2.2.1+incompatible/go.mod h1:EWmehSBHxCbnLPj3XytBR5sht/UebNLwwFYpGcfbptQ= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/zenazn/goji v1.0.1 h1:4lbD8Mx2h7IvloP7r2C0D6ltZP6Ufip8Hn0wmSK5LR8= github.com/zenazn/goji v1.0.1/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= +golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +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= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= +google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= diff --git a/frameworks/Go/martini/benchmark_config.json b/frameworks/Go/martini/benchmark_config.json deleted file mode 100644 index fbf0a94cfb8..00000000000 --- a/frameworks/Go/martini/benchmark_config.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "framework": "martini", - "tests": [ - { - "default": { - "json_url": "/bench/json", - "db_url": "/bench/single", - "query_url": "/bench/multiple?queries=", - "update_url": "/bench/update?queries=", - "plaintext_url": "/bench/plaintext", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "Postgres", - "framework": "martini", - "language": "Go", - "flavor": "None", - "orm": "Raw", - "platform": "None", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "martini", - "notes": "", - "versus": "go" - } - } - ] -} diff --git a/frameworks/Go/martini/config.toml b/frameworks/Go/martini/config.toml deleted file mode 100644 index 58b7fec1bc9..00000000000 --- a/frameworks/Go/martini/config.toml +++ /dev/null @@ -1,18 +0,0 @@ -[framework] -name = "martini" - -[main] -urls.plaintext = "/bench/plaintext" -urls.json = "/bench/json" -urls.db = "/bench/single" -urls.query = "/bench/multiple?queries=" -urls.update = "/bench/update?queries=" -approach = "Realistic" -classification = "Micro" -database = "Postgres" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "None" -webserver = "None" -versus = "go" diff --git a/frameworks/Go/martini/go.mod b/frameworks/Go/martini/go.mod deleted file mode 100644 index f5af950e26b..00000000000 --- a/frameworks/Go/martini/go.mod +++ /dev/null @@ -1,10 +0,0 @@ -module martini - -go 1.19 - -require ( - github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab - github.com/lib/pq v1.10.7 -) - -require github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 // indirect diff --git a/frameworks/Go/martini/go.sum b/frameworks/Go/martini/go.sum deleted file mode 100644 index 7f8410d7c13..00000000000 --- a/frameworks/Go/martini/go.sum +++ /dev/null @@ -1,6 +0,0 @@ -github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 h1:sDMmm+q/3+BukdIpxwO365v/Rbspp2Nt5XntgQRXq8Q= -github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= -github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab h1:xveKWz2iaueeTaUgdetzel+U7exyigDYBryyVfV/rZk= -github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8= -github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= -github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= diff --git a/frameworks/Go/martini/main.go b/frameworks/Go/martini/main.go deleted file mode 100644 index 09e1a392f9e..00000000000 --- a/frameworks/Go/martini/main.go +++ /dev/null @@ -1,148 +0,0 @@ -package main - -import ( - "database/sql" - "encoding/json" - "log" - "net/http" - "time" - - "github.com/go-martini/martini" - _ "github.com/lib/pq" -) - -var ( - db *sql.DB - worldSelectPrepared *sql.Stmt - worldUpdatePrepared *sql.Stmt - fortuneSelectPrepared *sql.Stmt -) - -type World struct { - Id uint16 `json:"id"` - RandomNumber uint16 `json:"randomNumber"` -} - - -func main() { - initDB() - - m := martini.Classic() - - m.Use(setRequiredHeaders) - - m.Group("/bench", func (r martini.Router) { - r.Get("/plaintext", plaintextHandler) - r.Get("/json" , jsonHandler) - r.Get("/single" , singleQueryHandler) - r.Get("/multiple" , multipleQueriesHandler) - r.Get("/update" , updatesHandler) - }) - - m.RunOnAddr(":8080") -} - -// Initialize the connection to the database -func initDB() { - driverName := "postgres" - connectionString := "postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world?sslmode=disable" - worldSelect := "SELECT id, randomNumber FROM World WHERE id = $1" - worldUpdate := "UPDATE World SET randomNumber = $1 WHERE id = $2" - fortuneSelect := "SELECT id, message FROM Fortune" - // worldRowCount := 10000 - maxConnections := 256 - - db, err := sql.Open(driverName, connectionString) - - if err != nil { - log.Fatalf("Error opening database: %v", err) - } - - db.SetMaxIdleConns(maxConnections) - db.SetMaxOpenConns(maxConnections) - - worldSelectPrepared, err = db.Prepare(worldSelect) - if err != nil { - log.Fatal(err) - } - worldUpdatePrepared, err = db.Prepare(worldUpdate) - if err != nil { - log.Fatal(err) - } - fortuneSelectPrepared, err = db.Prepare(fortuneSelect) - if err != nil { - log.Fatal(err) - } -} - -// Create middleware to add Server and Date headers to all -// routes. -func setRequiredHeaders(w http.ResponseWriter, r *http.Request) { - t := time.Now(); - - w.Header().Set("Server", "Martini") - w.Header().Set("Date", t.Format(time.RFC1123)) -} - -// Route handlers -func plaintextHandler() string { - return "Hello, World!" -} - -func jsonHandler(w http.ResponseWriter) []byte { - message := map[string]interface{}{"message": "Hello, World!"} - w.Header().Set("Content-Type", "application/json") - - res, _ := json.Marshal(message); - return res -} - -func singleQueryHandler(w http.ResponseWriter) { - var world World - - w.Header().Set("Content-Type", "application/json") - - err := worldSelectPrepared.QueryRow(RandomNumber()).Scan(&world.Id, &world.RandomNumber) - if err != nil { - log.Fatalf("Error scanning world row: %s", err.Error()) - } - - // No need to return anything as we are writing straight - // to the response itself - json.NewEncoder(w).Encode(&world) -} - -func multipleQueriesHandler(w http.ResponseWriter, r *http.Request) { - queries := SanitizeQueries(r) - worlds := make([]World, queries) - - w.Header().Set("Content-Type", "application/json") - - for i := 0; i < queries; i += 1 { - err := worldSelectPrepared.QueryRow(RandomNumber()).Scan(&worlds[i].Id, &worlds[i].RandomNumber) - - if err != nil { - log.Fatalf("Error scanning world row: %v", err) - } - } - - json.NewEncoder(w).Encode(worlds) -} - -func updatesHandler(w http.ResponseWriter, r *http.Request) { - queries := SanitizeQueries(r) - - worlds := make([]World, queries) - for i := 0; i < queries; i++ { - if err := worldSelectPrepared.QueryRow(RandomNumber()).Scan(&worlds[i].Id, &worlds[i].RandomNumber); err != nil { - log.Fatalf("Error scanning world row: %v", err) - } - worlds[i].RandomNumber = uint16(RandomNumber()) - if _, err := worldUpdatePrepared.Exec(worlds[i].RandomNumber, worlds[i].Id); err != nil { - log.Fatalf("Error updating world row: %v", err) - } - } - - w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(worlds) -} diff --git a/frameworks/Go/martini/martini.dockerfile b/frameworks/Go/martini/martini.dockerfile deleted file mode 100644 index e538810471f..00000000000 --- a/frameworks/Go/martini/martini.dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM docker.io/golang:1.19 - -WORKDIR /home -COPY . . - -RUN go mod download - -EXPOSE 8080 - -CMD GOAMD64=v3 go run . diff --git a/frameworks/Go/martini/randomNumber.go b/frameworks/Go/martini/randomNumber.go deleted file mode 100644 index 8231cc48859..00000000000 --- a/frameworks/Go/martini/randomNumber.go +++ /dev/null @@ -1,9 +0,0 @@ -package main - -import "math/rand" - -func RandomNumber() uint16 { - max := 10000 - - return uint16(rand.Intn(max) + 1) -} diff --git a/frameworks/Go/martini/sanitizeQueries.go b/frameworks/Go/martini/sanitizeQueries.go deleted file mode 100644 index cc51bc5a1e8..00000000000 --- a/frameworks/Go/martini/sanitizeQueries.go +++ /dev/null @@ -1,25 +0,0 @@ -package main - -import ( - "net/http" - "strconv" -) - -func SanitizeQueries(r *http.Request) int { - n := 1 - max := 500 - min := 1 - - if nStr := r.URL.Query().Get("queries"); len(nStr) > 0 { - n, _ = strconv.Atoi(nStr) - } - - - if n < min { - return min - } else if n > max { - return max - } - - return n -} diff --git a/frameworks/Go/pine/README.md b/frameworks/Go/pine/README.md new file mode 100755 index 00000000000..1307a047c2c --- /dev/null +++ b/frameworks/Go/pine/README.md @@ -0,0 +1,11 @@ +# Pine Benchmarking Test + +## Test URLs + +### JSON + +http://localhost:8080/json + +### PLAINTEXT + +http://localhost:8080/plaintext diff --git a/frameworks/Go/pine/benchmark_config.json b/frameworks/Go/pine/benchmark_config.json new file mode 100755 index 00000000000..6c605348103 --- /dev/null +++ b/frameworks/Go/pine/benchmark_config.json @@ -0,0 +1,26 @@ +{ + "framework": "pine", + "tests": [ + { + "default": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "None", + "framework": "Pine", + "language": "Go", + "flavor": "None", + "orm": "None", + "platform": "None", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "Pine", + "notes": "", + "versus": "go" + } + } + ] +} diff --git a/frameworks/Go/pine/pine.dockerfile b/frameworks/Go/pine/pine.dockerfile new file mode 100644 index 00000000000..85a527400c5 --- /dev/null +++ b/frameworks/Go/pine/pine.dockerfile @@ -0,0 +1,10 @@ +FROM docker.io/golang:1.24.2 + +COPY ./src /pine +WORKDIR /pine + +RUN go mod download + +EXPOSE 8080 + +CMD go run . diff --git a/frameworks/Go/pine/src/go.mod b/frameworks/Go/pine/src/go.mod new file mode 100644 index 00000000000..f7fafc6c61b --- /dev/null +++ b/frameworks/Go/pine/src/go.mod @@ -0,0 +1,5 @@ +module pine + +go 1.23.0 + +require github.com/BryanMwangi/pine v1.1.1 diff --git a/frameworks/Go/pine/src/go.sum b/frameworks/Go/pine/src/go.sum new file mode 100644 index 00000000000..9e0303ed548 --- /dev/null +++ b/frameworks/Go/pine/src/go.sum @@ -0,0 +1,2 @@ +github.com/BryanMwangi/pine v1.1.1 h1:E/c2Cude6LNa77554imIPbz4sZagOARiPP2bX2FG3fo= +github.com/BryanMwangi/pine v1.1.1/go.mod h1:yfO8j8e/St7qQmj3LkKNoZWZGqav2fkAJcDU6NACAp8= diff --git a/frameworks/Go/pine/src/main.go b/frameworks/Go/pine/src/main.go new file mode 100644 index 00000000000..2f263adebcc --- /dev/null +++ b/frameworks/Go/pine/src/main.go @@ -0,0 +1,28 @@ +package main + +import ( + "log" + + "github.com/BryanMwangi/pine" +) + +func plaintextHandler(c *pine.Ctx) error { + c.Set("Server", "Pine") + return c.SendString("Hello, World!") +} + +func jsonHandler(c *pine.Ctx) error { + c.Set("Server", "Pine") + return c.JSON(map[string]string{ + "message": "Hello, World!", + }) +} + +func main() { + app := pine.New() + app.Get("/plaintext", plaintextHandler) + app.Get("/json", jsonHandler) + + // Start the server on port 3000 + log.Fatal(app.Start(":8080")) +} diff --git a/frameworks/Go/revel/revel-fast.dockerfile b/frameworks/Go/revel/revel-fast.dockerfile index eea3b0fc55d..57ae4455eda 100644 --- a/frameworks/Go/revel/revel-fast.dockerfile +++ b/frameworks/Go/revel/revel-fast.dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.14 +FROM golang:1.24.2 ADD ./ /revel WORKDIR /revel diff --git a/frameworks/Go/revel/revel-jet.dockerfile b/frameworks/Go/revel/revel-jet.dockerfile index 1b13e4eae97..e33c0464efb 100644 --- a/frameworks/Go/revel/revel-jet.dockerfile +++ b/frameworks/Go/revel/revel-jet.dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.14 +FROM golang:1.24.2 ADD ./ /revel WORKDIR /revel diff --git a/frameworks/Go/revel/revel-qbs.dockerfile b/frameworks/Go/revel/revel-qbs.dockerfile index 220d3539291..8252703fb1a 100644 --- a/frameworks/Go/revel/revel-qbs.dockerfile +++ b/frameworks/Go/revel/revel-qbs.dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.14 +FROM golang:1.24.2 ADD ./ /revel WORKDIR /revel diff --git a/frameworks/Go/revel/revel-raw.dockerfile b/frameworks/Go/revel/revel-raw.dockerfile index e1c908592e9..1f10775f1bc 100644 --- a/frameworks/Go/revel/revel-raw.dockerfile +++ b/frameworks/Go/revel/revel-raw.dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.14 +FROM golang:1.24.2 ADD ./ /revel WORKDIR /revel diff --git a/frameworks/Go/revel/revel.dockerfile b/frameworks/Go/revel/revel.dockerfile index 27c933f6d6d..9956c4e0d76 100644 --- a/frameworks/Go/revel/revel.dockerfile +++ b/frameworks/Go/revel/revel.dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.14 +FROM golang:1.24.2 ADD ./ /revel WORKDIR /revel diff --git a/frameworks/Go/ronykit/benchmark_config.json b/frameworks/Go/ronykit/benchmark_config.json index 69684f9bcef..dcff4ef38bd 100644 --- a/frameworks/Go/ronykit/benchmark_config.json +++ b/frameworks/Go/ronykit/benchmark_config.json @@ -18,6 +18,7 @@ "os": "Linux", "display_name": "RonyKIT", "notes": "", + "tags": ["broken"], "versus": "go" }, "prefork": { @@ -36,8 +37,9 @@ "os": "Linux", "display_name": "RonyKIT", "notes": "", + "tags": ["broken"], "versus": "go" } } ] -} \ No newline at end of file +} diff --git a/frameworks/Go/ronykit/src/go.mod b/frameworks/Go/ronykit/src/go.mod index 85b07b234d8..34a588b8500 100644 --- a/frameworks/Go/ronykit/src/go.mod +++ b/frameworks/Go/ronykit/src/go.mod @@ -27,7 +27,7 @@ require ( github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasthttp v1.50.0 // indirect github.com/valyala/tcplisten v1.0.0 // indirect - golang.org/x/net v0.17.0 // indirect - golang.org/x/sys v0.13.0 // indirect + golang.org/x/net v0.38.0 // indirect + golang.org/x/sys v0.31.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/frameworks/Go/ronykit/src/go.sum b/frameworks/Go/ronykit/src/go.sum index a63639eebcd..655a26a3d44 100644 --- a/frameworks/Go/ronykit/src/go.sum +++ b/frameworks/Go/ronykit/src/go.sum @@ -62,13 +62,13 @@ github.com/valyala/fasthttp v1.50.0 h1:H7fweIlBm0rXLs2q0XbalvJ6r0CUPFWK3/bB4N13e github.com/valyala/fasthttp v1.50.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA= github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= +golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= +golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= golang.org/x/tools v0.12.0 h1:YW6HUoUmYBpwSgyaGaZq1fHjrBjX1rlpZ54T6mu2kss= 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= diff --git a/frameworks/Go/silverlining/benchmark_config.json b/frameworks/Go/silverlining/benchmark_config.json index 368481b04cf..bd8544f9111 100644 --- a/frameworks/Go/silverlining/benchmark_config.json +++ b/frameworks/Go/silverlining/benchmark_config.json @@ -35,7 +35,7 @@ "webserver": "None", "os": "Linux", "database_os": "Linux", - "display_name": "silverlining", + "display_name": "silverlining [prefork]", "notes": "", "versus": "go" } diff --git a/frameworks/Go/silverlining/silverlining-prefork.dockerfile b/frameworks/Go/silverlining/silverlining-prefork.dockerfile index 73595cc1dc7..4883e2f9e58 100644 --- a/frameworks/Go/silverlining/silverlining-prefork.dockerfile +++ b/frameworks/Go/silverlining/silverlining-prefork.dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/golang:1.19 +FROM docker.io/golang:1.24.2 WORKDIR /silverlining diff --git a/frameworks/Go/silverlining/silverlining.dockerfile b/frameworks/Go/silverlining/silverlining.dockerfile index 11b32b1d20c..b8c4e505521 100644 --- a/frameworks/Go/silverlining/silverlining.dockerfile +++ b/frameworks/Go/silverlining/silverlining.dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/golang:1.19 +FROM docker.io/golang:1.24.2 WORKDIR /silverlining diff --git a/frameworks/Go/silverlining/src/go.mod b/frameworks/Go/silverlining/src/go.mod index 11b0d6425f0..5566b7e6b80 100644 --- a/frameworks/Go/silverlining/src/go.mod +++ b/frameworks/Go/silverlining/src/go.mod @@ -1,14 +1,16 @@ module silverlining/app -go 1.19 +go 1.23.0 -require github.com/go-www/silverlining v1.2.1 +toolchain go1.24.1 + +require github.com/go-www/silverlining v1.3.3 require ( github.com/gobwas/httphead v0.1.0 // indirect github.com/gobwas/pool v0.2.1 // indirect - github.com/gobwas/ws v1.1.0 // indirect - github.com/goccy/go-json v0.9.11 // indirect - github.com/libp2p/go-reuseport v0.2.0 // indirect - golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41 // indirect + github.com/gobwas/ws v1.4.0 // indirect + github.com/goccy/go-json v0.10.5 // indirect + github.com/libp2p/go-reuseport v0.4.0 // indirect + golang.org/x/sys v0.31.0 // indirect ) diff --git a/frameworks/Go/silverlining/src/go.sum b/frameworks/Go/silverlining/src/go.sum index 4b29ae74b21..cf8f13f37b1 100644 --- a/frameworks/Go/silverlining/src/go.sum +++ b/frameworks/Go/silverlining/src/go.sum @@ -1,19 +1,23 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/go-www/silverlining v1.2.1 h1:c5Jq+hTYlPlaM9Xd4V7VmdGkyx2WrwgKiWo3t+tHSr0= -github.com/go-www/silverlining v1.2.1/go.mod h1:19uoOu+jstnafSPQ9hhZNP+/nd0gTRmyAhMG25uXy8o= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-www/silverlining v1.3.3 h1:JNt561V3tvXBD0sw/slQP5UhvADeVxXN0AnT9WiG0yA= +github.com/go-www/silverlining v1.3.3/go.mod h1:eh9Fljz24Qn4zHyXInelstw4c89RqlS8R0s7oKtBdJw= github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU= github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= -github.com/gobwas/ws v1.1.0 h1:7RFti/xnNkMJnrK7D1yQ/iCIB5OrrY/54/H930kIbHA= -github.com/gobwas/ws v1.1.0/go.mod h1:nzvNcVha5eUziGrbxFCo6qFIojQHjJV5cLYIbezhfL0= -github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk= -github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= -github.com/libp2p/go-reuseport v0.2.0 h1:18PRvIMlpY6ZK85nIAicSBuXXvrYoSw3dsBAR7zc560= -github.com/libp2p/go-reuseport v0.2.0/go.mod h1:bvVho6eLMm6Bz5hmU0LYN3ixd3nPPvtIlaURZZgOY4k= +github.com/gobwas/ws v1.4.0 h1:CTaoG1tojrh4ucGPcoJFiAQUAsEWekEWvLy7GsVNqGs= +github.com/gobwas/ws v1.4.0/go.mod h1:G3gNqMNtPppf5XUz7O4shetPpcZ1VJ7zt18dlUeakrc= +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/libp2p/go-reuseport v0.4.0 h1:nR5KU7hD0WxXCJbmw7r2rhRYruNRl2koHw8fQscQm2s= +github.com/libp2p/go-reuseport v0.4.0/go.mod h1:ZtI03j/wO5hZVDFo2jKywN6bYKWLOy8Se6DrI2E1cLU= 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/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= -golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41 h1:ohgcoMbSofXygzo6AD2I1kz3BFmW1QArPYTtwEM3UXc= -golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= +golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/frameworks/Go/sprapp/benchmark_config.json b/frameworks/Go/sprapp/benchmark_config.json index a8764b2fe88..9074fd3c2db 100644 --- a/frameworks/Go/sprapp/benchmark_config.json +++ b/frameworks/Go/sprapp/benchmark_config.json @@ -19,6 +19,7 @@ "database_os": "Linux", "display_name": "SPRAPP", "notes": "", + "tags": ["broken"], "versus": "None" } } diff --git a/frameworks/Go/sprapp/go.mod b/frameworks/Go/sprapp/go.mod index 8a92f3e6416..54ae324ad27 100644 --- a/frameworks/Go/sprapp/go.mod +++ b/frameworks/Go/sprapp/go.mod @@ -3,32 +3,32 @@ module sprapp go 1.18 require ( - github.com/cloudwego/hertz v0.7.1 - github.com/cloudxaas/gocpu v0.0.10 - github.com/cloudxaas/gostrconv v0.0.4 - github.com/panjf2000/ants/v2 v2.8.2 - golang.org/x/sys v0.14.0 + github.com/cloudwego/hertz v0.7.1 + github.com/cloudxaas/gocpu v0.0.10 + github.com/cloudxaas/gostrconv v0.0.4 + github.com/panjf2000/ants/v2 v2.8.2 + golang.org/x/sys v0.14.0 ) require ( - github.com/bytedance/go-tagexpr/v2 v2.9.2 // indirect - github.com/bytedance/gopkg v0.0.0-20220413063733-65bf48ffb3a7 // indirect - github.com/bytedance/sonic v1.8.1 // indirect - github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect - github.com/cloudwego/netpoll v0.5.0 // indirect - github.com/cloudxaas/gocx v0.0.3 // indirect - github.com/cloudxaas/gohash v0.0.13 // indirect - github.com/fsnotify/fsnotify v1.5.4 // indirect - github.com/golang/protobuf v1.5.0 // indirect - github.com/henrylee2cn/ameda v1.4.10 // indirect - github.com/henrylee2cn/goutil v0.0.0-20210127050712-89660552f6f8 // indirect - github.com/klauspost/cpuid/v2 v2.0.9 // indirect - github.com/nyaruka/phonenumbers v1.0.55 // indirect - github.com/spf13/pflag v1.0.5 // indirect - github.com/tidwall/gjson v1.14.4 // indirect - github.com/tidwall/match v1.1.1 // indirect - github.com/tidwall/pretty v1.2.0 // indirect - github.com/twitchyliquid64/golang-asm v0.15.1 // indirect - golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect - google.golang.org/protobuf v1.27.1 // indirect + github.com/bytedance/go-tagexpr/v2 v2.9.2 // indirect + github.com/bytedance/gopkg v0.0.0-20220413063733-65bf48ffb3a7 // indirect + github.com/bytedance/sonic v1.8.1 // indirect + github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect + github.com/cloudwego/netpoll v0.5.0 // indirect + github.com/cloudxaas/gocx v0.0.3 // indirect + github.com/cloudxaas/gohash v0.0.13 // indirect + github.com/fsnotify/fsnotify v1.5.4 // indirect + github.com/golang/protobuf v1.5.0 // indirect + github.com/henrylee2cn/ameda v1.4.10 // indirect + github.com/henrylee2cn/goutil v0.0.0-20210127050712-89660552f6f8 // indirect + github.com/klauspost/cpuid/v2 v2.0.9 // indirect + github.com/nyaruka/phonenumbers v1.0.55 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/tidwall/gjson v1.14.4 // indirect + github.com/tidwall/match v1.1.1 // indirect + github.com/tidwall/pretty v1.2.0 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect + google.golang.org/protobuf v1.33.0 // indirect ) diff --git a/frameworks/Go/sprapp/go.sum b/frameworks/Go/sprapp/go.sum index 460ac53c333..60bedb8d316 100644 --- a/frameworks/Go/sprapp/go.sum +++ b/frameworks/Go/sprapp/go.sum @@ -93,8 +93,9 @@ golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/frameworks/Go/webgo/src/go.mod b/frameworks/Go/webgo/src/go.mod index b62bcd8c84a..79016d6bef6 100644 --- a/frameworks/Go/webgo/src/go.mod +++ b/frameworks/Go/webgo/src/go.mod @@ -1,17 +1,19 @@ module webgo -go 1.19 +go 1.23.0 -require github.com/JaCoB1123/web v0.5.3 +toolchain go1.24.1 require ( - github.com/josharian/intern v1.0.0 // indirect - github.com/mailru/easyjson v0.7.7 // indirect - github.com/tidwall/gjson v1.14.3 // indirect + github.com/JaCoB1123/web v0.5.3 + github.com/tidwall/sjson v1.2.5 +) + +require ( + github.com/tidwall/gjson v1.18.0 // indirect github.com/tidwall/match v1.1.1 // indirect - github.com/tidwall/pretty v1.2.0 // indirect - github.com/tidwall/sjson v1.2.5 // indirect - golang.org/x/crypto v0.0.0-20220919173607-35f4265a4bc0 // indirect - golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8 // indirect - golang.org/x/term v0.0.0-20220919170432-7a66f970e087 // indirect + github.com/tidwall/pretty v1.2.1 // indirect + golang.org/x/crypto v0.36.0 // indirect + golang.org/x/sys v0.31.0 // indirect + golang.org/x/term v0.30.0 // indirect ) diff --git a/frameworks/Go/webgo/src/go.sum b/frameworks/Go/webgo/src/go.sum index b6addf7bc4b..02ce773fc11 100644 --- a/frameworks/Go/webgo/src/go.sum +++ b/frameworks/Go/webgo/src/go.sum @@ -1,33 +1,28 @@ github.com/JaCoB1123/web v0.5.3 h1:PLoZorwPqDgRNStHxbbSBXbXdiBDmJP3bgBeFXO8Jhg= github.com/JaCoB1123/web v0.5.3/go.mod h1:wX1fuLSacW6lNgIVFGTyCDsUuDyWa92iy9xXCZCidUU= -github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= -github.com/tidwall/gjson v1.14.3 h1:9jvXn7olKEHU1S9vwoMGliaT8jq1vJ7IH/n9zD9Dnlw= -github.com/tidwall/gjson v1.14.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= +github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= -github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= +github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de h1:ikNHVSjEfnvz6sxdSPCaPt572qowuyMDMJLLm3Db3ig= golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20220919173607-35f4265a4bc0 h1:a5Yg6ylndHHYJqIPrdq0AhvR6KTvDTAvgBtaidhEevY= -golang.org/x/crypto v0.0.0-20220919173607-35f4265a4bc0/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= +golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200802091954-4b90ce9b60b3 h1:qDJKu1y/1SjhWac4BQZjLljqvqiWUhjmDMnonmVGDAU= golang.org/x/sys v0.0.0-20200802091954-4b90ce9b60b3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8 h1:h+EGohizhe9XlX18rfpa8k8RAc5XyaeamM+0VHRd4lc= -golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20220919170432-7a66f970e087 h1:tPwmk4vmvVCMdr98VgL4JH+qZxPL8fqlUOHnyOM8N3w= -golang.org/x/term v0.0.0-20220919170432-7a66f970e087/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= +golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y= +golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/frameworks/Go/webgo/webgo.dockerfile b/frameworks/Go/webgo/webgo.dockerfile index 28ee3a317b2..94d40bf5105 100644 --- a/frameworks/Go/webgo/webgo.dockerfile +++ b/frameworks/Go/webgo/webgo.dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/golang:1.19 +FROM docker.io/golang:1.24.2 ADD ./src /webgo WORKDIR /webgo diff --git a/frameworks/Haskell/ihp/ihp.dockerfile b/frameworks/Haskell/ihp/ihp.dockerfile index cc1f35a428c..f01fa42dd2f 100644 --- a/frameworks/Haskell/ihp/ihp.dockerfile +++ b/frameworks/Haskell/ihp/ihp.dockerfile @@ -1,14 +1,14 @@ FROM nixos/nix -COPY ./src /ihp -WORKDIR /ihp - # Add build dependencies -RUN nix-env -i cachix +RUN nix-env -f https://github.com/NixOS/nixpkgs/archive/54b4bb956f9891b872904abdb632cea85a033ff2.tar.gz -iA cachix RUN cachix use digitallyinduced +COPY ./src /ihp +WORKDIR /ihp + # Build -RUN nix-build -j auto --cores 0 +RUN nix --extra-experimental-features "nix-command flakes" build -j auto --cores 0 .#optimized-prod-server # Setup ENV DATABASE_URL=postgres://benchmarkdbuser:benchmarkdbpass@tfb-database:5432/hello_world diff --git a/frameworks/Haskell/ihp/src/.envrc b/frameworks/Haskell/ihp/src/.envrc new file mode 100644 index 00000000000..33b7d186799 --- /dev/null +++ b/frameworks/Haskell/ihp/src/.envrc @@ -0,0 +1,16 @@ +if ! has nix_direnv_version || ! nix_direnv_version 2.3.0; then + source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/2.3.0/direnvrc" "sha256-Dmd+j63L84wuzgyjITIfSxSD57Tx7v51DMxVZOsiUD8=" +fi + +use flake . --impure --accept-flake-config + +# Include .env file if it exists locally. Use the .env file to load env vars that you don't want to commit to git +if [ -f .env ] +then + set -o allexport + source .env + set +o allexport +fi +# Add your env vars here +# +# E.g. export AWS_ACCESS_KEY_ID="XXXXX" \ No newline at end of file diff --git a/frameworks/Haskell/ihp/src/.ghci b/frameworks/Haskell/ihp/src/.ghci index aceca281d6c..48ee12a2ed3 100644 --- a/frameworks/Haskell/ihp/src/.ghci +++ b/frameworks/Haskell/ihp/src/.ghci @@ -1,3 +1,4 @@ -import Prelude -:def source readFile -:source build/ihp-lib/applicationGhciConfig +:set -XNoImplicitPrelude +:def loadFromIHP \file -> (System.Environment.getEnv "IHP_LIB") >>= (\ihpLib -> readFile (ihpLib <> "/" <> file)) +:loadFromIHP applicationGhciConfig +import IHP.Prelude \ No newline at end of file diff --git a/frameworks/Haskell/ihp/src/.gitignore b/frameworks/Haskell/ihp/src/.gitignore index d27ddd2281d..6bb8d1fba18 100644 --- a/frameworks/Haskell/ihp/src/.gitignore +++ b/frameworks/Haskell/ihp/src/.gitignore @@ -1,5 +1,4 @@ .DS_Store -.envrc .idea tmp result @@ -17,3 +16,8 @@ gen del static/prod.* Config/client_session_key.aes + +.devenv* +devenv.local.nix +.direnv +.env \ No newline at end of file diff --git a/frameworks/Haskell/ihp/src/Makefile b/frameworks/Haskell/ihp/src/Makefile index eb103029c90..4482e99a6c6 100644 --- a/frameworks/Haskell/ihp/src/Makefile +++ b/frameworks/Haskell/ihp/src/Makefile @@ -1,11 +1,3 @@ -ifneq ($(wildcard IHP/.*),) -IHP = IHP/lib/IHP -else -IHP = $(shell dirname $$(which RunDevServer))/../lib/IHP -endif - -include ${IHP}/Makefile.dist - CSS_FILES += ${IHP}/static/vendor/bootstrap.min.css CSS_FILES += ${IHP}/static/vendor/flatpickr.min.css @@ -19,3 +11,5 @@ JS_FILES += ${IHP}/static/vendor/morphdom-umd.min.js JS_FILES += ${IHP}/static/vendor/turbolinks.js JS_FILES += ${IHP}/static/vendor/turbolinksInstantClick.js JS_FILES += ${IHP}/static/vendor/turbolinksMorphdom.js + +include ${IHP}/Makefile.dist \ No newline at end of file diff --git a/frameworks/Haskell/ihp/src/default.nix b/frameworks/Haskell/ihp/src/default.nix deleted file mode 100644 index 1bf1062066e..00000000000 --- a/frameworks/Haskell/ihp/src/default.nix +++ /dev/null @@ -1,21 +0,0 @@ -let - ihp = builtins.fetchGit { - url = "https://github.com/digitallyinduced/ihp.git"; - ref = "refs/tags/v1.0.1"; - }; - haskellEnv = import "${ihp}/NixSupport/default.nix" { - ihp = ihp; - haskellDeps = p: with p; [ - base - wai - text - p.ihp - ]; - otherDeps = p: with p; [ - # Native dependencies, e.g. imagemagick - ]; - projectPath = ./.; - optimized = true; - }; -in - haskellEnv diff --git a/frameworks/Haskell/ihp/src/flake.lock b/frameworks/Haskell/ihp/src/flake.lock new file mode 100644 index 00000000000..8529cf94aae --- /dev/null +++ b/frameworks/Haskell/ihp/src/flake.lock @@ -0,0 +1,1247 @@ +{ + "nodes": { + "cachix": { + "inputs": { + "devenv": "devenv_2", + "flake-compat": [ + "ihp", + "devenv", + "flake-compat" + ], + "nixpkgs": [ + "ihp", + "devenv", + "nixpkgs" + ], + "pre-commit-hooks": [ + "ihp", + "devenv", + "pre-commit-hooks" + ] + }, + "locked": { + "lastModified": 1712055811, + "narHash": "sha256-7FcfMm5A/f02yyzuavJe06zLa9hcMHsagE28ADcmQvk=", + "owner": "cachix", + "repo": "cachix", + "rev": "02e38da89851ec7fec3356a5c04bc8349cae0e30", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "cachix", + "type": "github" + } + }, + "devenv": { + "inputs": { + "cachix": "cachix", + "flake-compat": "flake-compat_2", + "nix": "nix_2", + "nixpkgs": [ + "ihp", + "nixpkgs" + ], + "pre-commit-hooks": "pre-commit-hooks" + }, + "locked": { + "lastModified": 1714390914, + "narHash": "sha256-W5DFIifCjGYJXJzLU3RpqBeqes4zrf0Sr/6rwzTygPU=", + "owner": "cachix", + "repo": "devenv", + "rev": "34e6461fd76b5f51ad5f8214f5cf22c4cd7a196e", + "type": "github" + }, + "original": { + "owner": "cachix", + "ref": "refs/tags/v1.0.5", + "repo": "devenv", + "type": "github" + } + }, + "devenv_2": { + "inputs": { + "flake-compat": [ + "ihp", + "devenv", + "cachix", + "flake-compat" + ], + "nix": "nix", + "nixpkgs": "nixpkgs", + "poetry2nix": "poetry2nix", + "pre-commit-hooks": [ + "ihp", + "devenv", + "cachix", + "pre-commit-hooks" + ] + }, + "locked": { + "lastModified": 1708704632, + "narHash": "sha256-w+dOIW60FKMaHI1q5714CSibk99JfYxm0CzTinYWr+Q=", + "owner": "cachix", + "repo": "devenv", + "rev": "2ee4450b0f4b95a1b90f2eb5ffea98b90e48c196", + "type": "github" + }, + "original": { + "owner": "cachix", + "ref": "python-rewrite", + "repo": "devenv", + "type": "github" + } + }, + "devenv_3": { + "inputs": { + "flake-compat": "flake-compat_3", + "nix": "nix_3", + "nixpkgs": [ + "ihp", + "ihp-boilerplate", + "ihp", + "nixpkgs" + ], + "pre-commit-hooks": "pre-commit-hooks_2" + }, + "locked": { + "lastModified": 1694422554, + "narHash": "sha256-s5NTPzT66yIMmau+ZGP7q9z4NjgceDETL4xZ6HJ/TBg=", + "owner": "cachix", + "repo": "devenv", + "rev": "63d20fe09aa09060ea9ec9bb6d582c025402ba15", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "devenv", + "type": "github" + } + }, + "devenv_4": { + "inputs": { + "flake-compat": "flake-compat_4", + "nix": "nix_4", + "nixpkgs": [ + "ihp", + "ihp-boilerplate", + "ihp", + "ihp-boilerplate", + "ihp", + "nixpkgs" + ], + "pre-commit-hooks": "pre-commit-hooks_3" + }, + "locked": { + "lastModified": 1686054274, + "narHash": "sha256-93aebyN7EMmeFFXisFIvp28UEbrozu79vd3pKPjvNR0=", + "owner": "cachix", + "repo": "devenv", + "rev": "c51a56bac8853c019241fe8d821c0a0d82422835", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "devenv", + "type": "github" + } + }, + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1673956053, + "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-compat_2": { + "flake": false, + "locked": { + "lastModified": 1696426674, + "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-compat_3": { + "flake": false, + "locked": { + "lastModified": 1673956053, + "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-compat_4": { + "flake": false, + "locked": { + "lastModified": 1673956053, + "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-parts": { + "inputs": { + "nixpkgs-lib": [ + "ihp", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1714641030, + "narHash": "sha256-yzcRNDoyVP7+SCNX0wmuDju1NUCt8Dz9+lyUXEI0dbI=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "e5d10a24b66c3ea8f150e47dfdb0416ab7c3390e", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "flake-parts_2": { + "inputs": { + "nixpkgs-lib": "nixpkgs-lib" + }, + "locked": { + "lastModified": 1693611461, + "narHash": "sha256-aPODl8vAgGQ0ZYFIRisxYG5MOGSkIczvu2Cd8Gb9+1Y=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "7f53fdb7bdc5bb237da7fefef12d099e4fd611ca", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "flake-parts_3": { + "inputs": { + "nixpkgs-lib": "nixpkgs-lib_2" + }, + "locked": { + "lastModified": 1685662779, + "narHash": "sha256-cKDDciXGpMEjP1n6HlzKinN0H+oLmNpgeCTzYnsA2po=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "71fb97f0d875fd4de4994dfb849f2c75e17eb6c3", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1689068808, + "narHash": "sha256-6ixXo3wt24N/melDWjq70UuHQLxGV8jZvooRanIHXw0=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "919d646de7be200f3bf08cb76ae1f09402b6f9b4", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_2": { + "inputs": { + "systems": "systems_2" + }, + "locked": { + "lastModified": 1710146030, + "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_3": { + "inputs": { + "systems": "systems_3" + }, + "locked": { + "lastModified": 1685518550, + "narHash": "sha256-o2d0KcvaXzTrPRIo0kOLV0/QXHhDQ5DTi+OxcjO8xqY=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "a1720a10a6cfe8234c0e93907ffe81be440f4cef", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_4": { + "locked": { + "lastModified": 1667395993, + "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "gitignore": { + "inputs": { + "nixpkgs": [ + "ihp", + "devenv", + "pre-commit-hooks", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1709087332, + "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, + "gitignore_2": { + "inputs": { + "nixpkgs": [ + "ihp", + "ihp-boilerplate", + "ihp", + "devenv", + "pre-commit-hooks", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1660459072, + "narHash": "sha256-8DFJjXG8zqoONA1vXtgeKXy68KdJL5UaXR8NtVMUbx8=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "a20de23b925fd8264fd7fad6454652e142fd7f73", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, + "gitignore_3": { + "inputs": { + "nixpkgs": [ + "ihp", + "ihp-boilerplate", + "ihp", + "ihp-boilerplate", + "ihp", + "devenv", + "pre-commit-hooks", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1660459072, + "narHash": "sha256-8DFJjXG8zqoONA1vXtgeKXy68KdJL5UaXR8NtVMUbx8=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "a20de23b925fd8264fd7fad6454652e142fd7f73", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, + "ihp": { + "inputs": { + "devenv": "devenv", + "flake-parts": "flake-parts", + "ihp-boilerplate": "ihp-boilerplate", + "nix-filter": "nix-filter_2", + "nixpkgs": "nixpkgs_4", + "systems": "systems_6" + }, + "locked": { + "lastModified": 1739859908, + "narHash": "sha256-UjXDYUmRpUbx9xNi6gA+dh4HDEvB67TvHovm79SRKHE=", + "owner": "digitallyinduced", + "repo": "ihp", + "rev": "4df99962603bf53514d5a645ccc5a596e8c57243", + "type": "github" + }, + "original": { + "owner": "digitallyinduced", + "ref": "v1.3.1", + "repo": "ihp", + "type": "github" + } + }, + "ihp-boilerplate": { + "inputs": { + "devenv": [ + "ihp", + "ihp-boilerplate", + "ihp", + "devenv" + ], + "flake-parts": [ + "ihp", + "ihp-boilerplate", + "ihp", + "flake-parts" + ], + "ihp": "ihp_2", + "nixpkgs": [ + "ihp", + "ihp-boilerplate", + "ihp", + "nixpkgs" + ], + "systems": [ + "ihp", + "ihp-boilerplate", + "ihp", + "systems" + ] + }, + "locked": { + "lastModified": 1710175252, + "narHash": "sha256-QIFqo64U69uUGJ7pgBr37T3yAKK0n1ueqagKmnm+XWw=", + "owner": "digitallyinduced", + "repo": "ihp-boilerplate", + "rev": "323591d6135f7a89b5b4e518d5d420cd5b046fe2", + "type": "github" + }, + "original": { + "owner": "digitallyinduced", + "repo": "ihp-boilerplate", + "type": "github" + } + }, + "ihp-boilerplate_2": { + "inputs": { + "devenv": [ + "ihp", + "ihp-boilerplate", + "ihp", + "ihp-boilerplate", + "ihp", + "devenv" + ], + "flake-parts": [ + "ihp", + "ihp-boilerplate", + "ihp", + "ihp-boilerplate", + "ihp", + "flake-parts" + ], + "ihp": "ihp_3", + "nixpkgs": [ + "ihp", + "ihp-boilerplate", + "ihp", + "ihp-boilerplate", + "ihp", + "nixpkgs" + ], + "systems": [ + "ihp", + "ihp-boilerplate", + "ihp", + "ihp-boilerplate", + "ihp", + "systems" + ] + }, + "locked": { + "lastModified": 1689954789, + "narHash": "sha256-RsgD1YGSlx+K/GkTspOdg/tz47PyZZDc66PzfFZvqBk=", + "owner": "digitallyinduced", + "repo": "ihp-boilerplate", + "rev": "832d1a5aed4dc3625486c82b06a1d07024267680", + "type": "github" + }, + "original": { + "owner": "digitallyinduced", + "repo": "ihp-boilerplate", + "type": "github" + } + }, + "ihp-boilerplate_3": { + "flake": false, + "locked": { + "lastModified": 1686165507, + "narHash": "sha256-ZaP8GfqjZDnMayPcvWxEqnZmRs4ixf5O5d1Ba867m4c=", + "owner": "digitallyinduced", + "repo": "ihp-boilerplate", + "rev": "ff63ce46b6fb68f1b8b3cdb0bdd6749f7ef1df93", + "type": "github" + }, + "original": { + "owner": "digitallyinduced", + "ref": "nicolas/flake", + "repo": "ihp-boilerplate", + "type": "github" + } + }, + "ihp_2": { + "inputs": { + "devenv": "devenv_3", + "flake-parts": "flake-parts_2", + "ihp-boilerplate": "ihp-boilerplate_2", + "nix-filter": "nix-filter", + "nixpkgs": "nixpkgs_3", + "systems": "systems_5" + }, + "locked": { + "lastModified": 1700013490, + "narHash": "sha256-oQz7ZBrHe6WwYMwnxxUgnYM55CuH5Oxjz6mrLnYbB7U=", + "owner": "digitallyinduced", + "repo": "ihp", + "rev": "d59a65d71943cb506eee3ad6255f017963237359", + "type": "github" + }, + "original": { + "owner": "digitallyinduced", + "ref": "v1.2", + "repo": "ihp", + "type": "github" + } + }, + "ihp_3": { + "inputs": { + "devenv": "devenv_4", + "flake-parts": "flake-parts_3", + "ihp-boilerplate": "ihp-boilerplate_3", + "nixpkgs": "nixpkgs_2", + "systems": "systems_4" + }, + "locked": { + "lastModified": 1689949405, + "narHash": "sha256-o0ZSDaDFgwbXqozHfcXKxW4FeF7JqaGprAh6r7NhvhE=", + "owner": "digitallyinduced", + "repo": "ihp", + "rev": "e6c6eaf1d089423a03e586cd25d1eda39f5a6b11", + "type": "github" + }, + "original": { + "owner": "digitallyinduced", + "ref": "v1.1", + "repo": "ihp", + "type": "github" + } + }, + "lowdown-src": { + "flake": false, + "locked": { + "lastModified": 1633514407, + "narHash": "sha256-Dw32tiMjdK9t3ETl5fzGrutQTzh2rufgZV4A/BbxuD4=", + "owner": "kristapsdz", + "repo": "lowdown", + "rev": "d2c2b44ff6c27b936ec27358a2653caaef8f73b8", + "type": "github" + }, + "original": { + "owner": "kristapsdz", + "repo": "lowdown", + "type": "github" + } + }, + "lowdown-src_2": { + "flake": false, + "locked": { + "lastModified": 1633514407, + "narHash": "sha256-Dw32tiMjdK9t3ETl5fzGrutQTzh2rufgZV4A/BbxuD4=", + "owner": "kristapsdz", + "repo": "lowdown", + "rev": "d2c2b44ff6c27b936ec27358a2653caaef8f73b8", + "type": "github" + }, + "original": { + "owner": "kristapsdz", + "repo": "lowdown", + "type": "github" + } + }, + "nix": { + "inputs": { + "flake-compat": "flake-compat", + "nixpkgs": [ + "ihp", + "devenv", + "cachix", + "devenv", + "nixpkgs" + ], + "nixpkgs-regression": "nixpkgs-regression" + }, + "locked": { + "lastModified": 1712911606, + "narHash": "sha256-BGvBhepCufsjcUkXnEEXhEVjwdJAwPglCC2+bInc794=", + "owner": "domenkozar", + "repo": "nix", + "rev": "b24a9318ea3f3600c1e24b4a00691ee912d4de12", + "type": "github" + }, + "original": { + "owner": "domenkozar", + "ref": "devenv-2.21", + "repo": "nix", + "type": "github" + } + }, + "nix-filter": { + "locked": { + "lastModified": 1694434370, + "narHash": "sha256-7yfdTR4mCvWZ39Q6HUcsa18tr0mg+fJZSaHE/63rwoo=", + "owner": "numtide", + "repo": "nix-filter", + "rev": "d6381c442f79f2f1fdfde00521c3d15d6c21218e", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "nix-filter", + "type": "github" + } + }, + "nix-filter_2": { + "locked": { + "lastModified": 1710156097, + "narHash": "sha256-1Wvk8UP7PXdf8bCCaEoMnOT1qe5/Duqgj+rL8sRQsSM=", + "owner": "numtide", + "repo": "nix-filter", + "rev": "3342559a24e85fc164b295c3444e8a139924675b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "nix-filter", + "type": "github" + } + }, + "nix-github-actions": { + "inputs": { + "nixpkgs": [ + "ihp", + "devenv", + "cachix", + "devenv", + "poetry2nix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1688870561, + "narHash": "sha256-4UYkifnPEw1nAzqqPOTL2MvWtm3sNGw1UTYTalkTcGY=", + "owner": "nix-community", + "repo": "nix-github-actions", + "rev": "165b1650b753316aa7f1787f3005a8d2da0f5301", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nix-github-actions", + "type": "github" + } + }, + "nix_2": { + "inputs": { + "flake-compat": [ + "ihp", + "devenv", + "flake-compat" + ], + "nixpkgs": [ + "ihp", + "devenv", + "nixpkgs" + ], + "nixpkgs-regression": "nixpkgs-regression_2" + }, + "locked": { + "lastModified": 1718382440, + "narHash": "sha256-aUqR+pxqKTKLtj8HAI5sbdT6C1VgtHDcrKjmn+wWkXQ=", + "owner": "domenkozar", + "repo": "nix", + "rev": "31b9700169d9bba693c379d59d587cd20bf115a6", + "type": "github" + }, + "original": { + "owner": "domenkozar", + "ref": "devenv-2.21", + "repo": "nix", + "type": "github" + } + }, + "nix_3": { + "inputs": { + "lowdown-src": "lowdown-src", + "nixpkgs": [ + "ihp", + "ihp-boilerplate", + "ihp", + "devenv", + "nixpkgs" + ], + "nixpkgs-regression": "nixpkgs-regression_3" + }, + "locked": { + "lastModified": 1676545802, + "narHash": "sha256-EK4rZ+Hd5hsvXnzSzk2ikhStJnD63odF7SzsQ8CuSPU=", + "owner": "domenkozar", + "repo": "nix", + "rev": "7c91803598ffbcfe4a55c44ac6d49b2cf07a527f", + "type": "github" + }, + "original": { + "owner": "domenkozar", + "ref": "relaxed-flakes", + "repo": "nix", + "type": "github" + } + }, + "nix_4": { + "inputs": { + "lowdown-src": "lowdown-src_2", + "nixpkgs": [ + "ihp", + "ihp-boilerplate", + "ihp", + "ihp-boilerplate", + "ihp", + "devenv", + "nixpkgs" + ], + "nixpkgs-regression": "nixpkgs-regression_4" + }, + "locked": { + "lastModified": 1676545802, + "narHash": "sha256-EK4rZ+Hd5hsvXnzSzk2ikhStJnD63odF7SzsQ8CuSPU=", + "owner": "domenkozar", + "repo": "nix", + "rev": "7c91803598ffbcfe4a55c44ac6d49b2cf07a527f", + "type": "github" + }, + "original": { + "owner": "domenkozar", + "ref": "relaxed-flakes", + "repo": "nix", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1692808169, + "narHash": "sha256-x9Opq06rIiwdwGeK2Ykj69dNc2IvUH1fY55Wm7atwrE=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "9201b5ff357e781bf014d0330d18555695df7ba8", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-lib": { + "locked": { + "dir": "lib", + "lastModified": 1693471703, + "narHash": "sha256-0l03ZBL8P1P6z8MaSDS/MvuU8E75rVxe5eE1N6gxeTo=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "3e52e76b70d5508f3cec70b882a29199f4d1ee85", + "type": "github" + }, + "original": { + "dir": "lib", + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-lib_2": { + "locked": { + "dir": "lib", + "lastModified": 1685564631, + "narHash": "sha256-8ywr3AkblY4++3lIVxmrWZFzac7+f32ZEhH/A8pNscI=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "4f53efe34b3a8877ac923b9350c874e3dcd5dc0a", + "type": "github" + }, + "original": { + "dir": "lib", + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-regression": { + "locked": { + "lastModified": 1643052045, + "narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", + "type": "github" + } + }, + "nixpkgs-regression_2": { + "locked": { + "lastModified": 1643052045, + "narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", + "type": "github" + } + }, + "nixpkgs-regression_3": { + "locked": { + "lastModified": 1643052045, + "narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", + "type": "github" + } + }, + "nixpkgs-regression_4": { + "locked": { + "lastModified": 1643052045, + "narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", + "type": "github" + } + }, + "nixpkgs-stable": { + "locked": { + "lastModified": 1710695816, + "narHash": "sha256-3Eh7fhEID17pv9ZxrPwCLfqXnYP006RKzSs0JptsN84=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "614b4613980a522ba49f0d194531beddbb7220d3", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-23.11", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-stable_2": { + "locked": { + "lastModified": 1685801374, + "narHash": "sha256-otaSUoFEMM+LjBI1XL/xGB5ao6IwnZOXc47qhIgJe8U=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "c37ca420157f4abc31e26f436c1145f8951ff373", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-23.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-stable_3": { + "locked": { + "lastModified": 1678872516, + "narHash": "sha256-/E1YwtMtFAu2KUQKV/1+KFuReYPANM2Rzehk84VxVoc=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "9b8e5abb18324c7fe9f07cb100c3cd4a29cda8b8", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-22.11", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1681488673, + "narHash": "sha256-PmojOyePBNvbY3snYE7NAQHTLB53t7Ro+pgiJ4wPCuk=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "a95ed9fe764c3ba2bf2d2fa223012c379cd6b32e", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "a95ed9fe764c3ba2bf2d2fa223012c379cd6b32e", + "type": "github" + } + }, + "nixpkgs_3": { + "locked": { + "lastModified": 1696291921, + "narHash": "sha256-isKgVAoUxuxYEuO3Q4xhbfKcZrF/+UkJtOTv0eb/W5E=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "ea0284a3da391822909be5e98a60c1e62572a7dc", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "ea0284a3da391822909be5e98a60c1e62572a7dc", + "type": "github" + } + }, + "nixpkgs_4": { + "locked": { + "lastModified": 1714864423, + "narHash": "sha256-Wx3Y6arRJD1pd3c8SnD7dfW7KWuCr/r248P/5XLaMdM=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "54b4bb956f9891b872904abdb632cea85a033ff2", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "54b4bb956f9891b872904abdb632cea85a033ff2", + "type": "github" + } + }, + "poetry2nix": { + "inputs": { + "flake-utils": "flake-utils", + "nix-github-actions": "nix-github-actions", + "nixpkgs": [ + "ihp", + "devenv", + "cachix", + "devenv", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1692876271, + "narHash": "sha256-IXfZEkI0Mal5y1jr6IRWMqK8GW2/f28xJenZIPQqkY0=", + "owner": "nix-community", + "repo": "poetry2nix", + "rev": "d5006be9c2c2417dafb2e2e5034d83fabd207ee3", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "poetry2nix", + "type": "github" + } + }, + "pre-commit-hooks": { + "inputs": { + "flake-compat": [ + "ihp", + "devenv", + "flake-compat" + ], + "flake-utils": "flake-utils_2", + "gitignore": "gitignore", + "nixpkgs": [ + "ihp", + "devenv", + "nixpkgs" + ], + "nixpkgs-stable": "nixpkgs-stable" + }, + "locked": { + "lastModified": 1713775815, + "narHash": "sha256-Wu9cdYTnGQQwtT20QQMg7jzkANKQjwBD9iccfGKkfls=", + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "rev": "2ac4dcbf55ed43f3be0bae15e181f08a57af24a4", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "type": "github" + } + }, + "pre-commit-hooks_2": { + "inputs": { + "flake-compat": [ + "ihp", + "ihp-boilerplate", + "ihp", + "devenv", + "flake-compat" + ], + "flake-utils": "flake-utils_3", + "gitignore": "gitignore_2", + "nixpkgs": [ + "ihp", + "ihp-boilerplate", + "ihp", + "devenv", + "nixpkgs" + ], + "nixpkgs-stable": "nixpkgs-stable_2" + }, + "locked": { + "lastModified": 1688056373, + "narHash": "sha256-2+SDlNRTKsgo3LBRiMUcoEUb6sDViRNQhzJquZ4koOI=", + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "rev": "5843cf069272d92b60c3ed9e55b7a8989c01d4c7", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "type": "github" + } + }, + "pre-commit-hooks_3": { + "inputs": { + "flake-compat": [ + "ihp", + "ihp-boilerplate", + "ihp", + "ihp-boilerplate", + "ihp", + "devenv", + "flake-compat" + ], + "flake-utils": "flake-utils_4", + "gitignore": "gitignore_3", + "nixpkgs": [ + "ihp", + "ihp-boilerplate", + "ihp", + "ihp-boilerplate", + "ihp", + "devenv", + "nixpkgs" + ], + "nixpkgs-stable": "nixpkgs-stable_3" + }, + "locked": { + "lastModified": 1682596858, + "narHash": "sha256-Hf9XVpqaGqe/4oDGr30W8HlsWvJXtMsEPHDqHZA6dDg=", + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "rev": "fb58866e20af98779017134319b5663b8215d912", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "type": "github" + } + }, + "root": { + "inputs": { + "devenv": [ + "ihp", + "devenv" + ], + "flake-parts": [ + "ihp", + "flake-parts" + ], + "ihp": "ihp", + "nixpkgs": [ + "ihp", + "nixpkgs" + ], + "systems": [ + "ihp", + "systems" + ] + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_2": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_3": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_4": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_5": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_6": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/frameworks/Haskell/ihp/src/flake.nix b/frameworks/Haskell/ihp/src/flake.nix new file mode 100644 index 00000000000..90f42b47ce8 --- /dev/null +++ b/frameworks/Haskell/ihp/src/flake.nix @@ -0,0 +1,37 @@ +{ + inputs = { + # Here you can adjust the IHP version of your project + # You can find new releases at https://github.com/digitallyinduced/ihp/releases + ihp.url = "github:digitallyinduced/ihp/v1.3.1"; + nixpkgs.follows = "ihp/nixpkgs"; + flake-parts.follows = "ihp/flake-parts"; + devenv.follows = "ihp/devenv"; + systems.follows = "ihp/systems"; + }; + + outputs = inputs@{ ihp, flake-parts, systems, ... }: + flake-parts.lib.mkFlake { inherit inputs; } { + + systems = import systems; + imports = [ ihp.flakeModules.default ]; + + perSystem = { pkgs, ... }: { + ihp = { + enable = true; + projectPath = ./.; + packages = with pkgs; [ + # Native dependencies, e.g. imagemagick + ]; + haskellPackages = p: with p; [ + # Haskell dependencies go here + p.ihp + cabal-install + base + wai + text + ]; + }; + }; + + }; +} \ No newline at end of file diff --git a/frameworks/Haskell/ihp/src/start b/frameworks/Haskell/ihp/src/start deleted file mode 100755 index a5642231608..00000000000 --- a/frameworks/Haskell/ihp/src/start +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env bash -# Script to start the local dev server - -set -e - -# Unless the RunDevServer binary is available, we rebuild the .envrc cache with nix-shell -# and config cachix for using our binary cache -command -v RunDevServer >/dev/null 2>&1 \ - || { echo "PATH_add $(nix-shell -j auto --cores 0 --run 'printf %q $PATH')" > .envrc; } - -# Now we have to load the PATH variable from the .envrc cache -direnv allow -eval "$(direnv hook bash)" -eval "$(direnv export bash)" - -# Finally start the dev server -RunDevServer diff --git a/frameworks/Haskell/postgrest/README.md b/frameworks/Haskell/postgrest/README.md old mode 100755 new mode 100644 index 385ebf7b6ab..3ecb125391a --- a/frameworks/Haskell/postgrest/README.md +++ b/frameworks/Haskell/postgrest/README.md @@ -7,7 +7,7 @@ * [DB](src/db.sql) * [QUERY](src/query.sql) * [CACHED QUERY] Not Implemented -* [UPDATE] Not Implemented +* [UPDATE](src/update.sql) * [FORTUNES](src/fortunes.sql) ## Important Libraries @@ -17,7 +17,7 @@ The tests were run with: ## Test URLs ### JSON -http://localhost:3000/rpc/json +http://localhost:3000/rpc/jsonser ### PLAINTEXT @@ -31,14 +31,25 @@ http://localhost:3000/rpc/db http://localhost:3000/rpc/query?queries= -### CACHED QUERY Not Implemented +### CACHED QUERY - Not Implemented http://localhost:8080/cached_query?queries= -### UPDATE Not Implemented +### UPDATE - Not Working -http://localhost:3000/rpc/update?queries= +http://localhost:3000/rpc/updates?queries= -### FORTUNES +Technically, this is implemented (maybe not correctly though). +However, the benchmark issues this as a GET request. +PostgREST sets the transaction to READ ONLY for GET requests, +as they are supposed to be idempotent. +Hence this results in an error. Calling the endpoint with POST +works though. + +### FORTUNES - Disabled http://localhost:3000/rpc/fortunes.html + +This is supposed to work, but somehow the benchmark harness +doesn't count the queries correctly? +Was not able to figure this one out. diff --git a/frameworks/Haskell/postgrest/benchmark_config.json b/frameworks/Haskell/postgrest/benchmark_config.json index be82b4771a8..835943c34d8 100755 --- a/frameworks/Haskell/postgrest/benchmark_config.json +++ b/frameworks/Haskell/postgrest/benchmark_config.json @@ -3,11 +3,10 @@ "tests": [ { "default": { - "json_url": "/rpc/json", + "json_url": "/rpc/jsonser", "plaintext_url": "/rpc/plaintext", "db_url": "/rpc/db", "query_url": "/rpc/queries?queries=", - "fortunes_url": "/rpc/fortunes.html", "port": 3000, "approach": "Realistic", "classification": "Micro", diff --git a/frameworks/Haskell/postgrest/config.toml b/frameworks/Haskell/postgrest/config.toml index b98dcecc8ed..a5606004603 100644 --- a/frameworks/Haskell/postgrest/config.toml +++ b/frameworks/Haskell/postgrest/config.toml @@ -6,6 +6,7 @@ urls.plaintext = "/rpc/plaintext" urls.json = "/rpc/json" urls.db = "/rpc/db" urls.query = "/rpc/queries?queries=" +urls.fortune = "/rpc/fortunes" approach = "Realistic" classification = "Micro" database = "postgres" diff --git a/frameworks/Haskell/postgrest/docker-compose.yml b/frameworks/Haskell/postgrest/docker-compose.yml index 8b8b2a03e0f..eca0e4bbfb8 100644 --- a/frameworks/Haskell/postgrest/docker-compose.yml +++ b/frameworks/Haskell/postgrest/docker-compose.yml @@ -1,4 +1,3 @@ -version: '3' services: tfb-database: build: @@ -13,4 +12,6 @@ services: dockerfile: postgrest.dockerfile context: . ports: - - 3030:3000 \ No newline at end of file + - 3030:3000 + depends_on: + - tfb-database diff --git a/frameworks/Haskell/postgrest/postgrest.conf b/frameworks/Haskell/postgrest/postgrest.conf index 688ef63d886..eaf7acfddac 100644 --- a/frameworks/Haskell/postgrest/postgrest.conf +++ b/frameworks/Haskell/postgrest/postgrest.conf @@ -16,4 +16,3 @@ role-claim-key = "$(PGRST_ROLE_CLAIM_KEY)" max-rows = "$(PGRST_MAX_ROWS)" pre-request = "$(PGRST_PRE_REQUEST)" root-spec = "$(PGRST_ROOT_SPEC)" -raw-media-types = "$(PGRST_RAW_MEDIA_TYPES)" \ No newline at end of file diff --git a/frameworks/Haskell/postgrest/postgrest.dockerfile b/frameworks/Haskell/postgrest/postgrest.dockerfile index fb5f224e9bd..fb25374ce37 100644 --- a/frameworks/Haskell/postgrest/postgrest.dockerfile +++ b/frameworks/Haskell/postgrest/postgrest.dockerfile @@ -23,12 +23,10 @@ ENV PGRST_MAX_ROWS= ENV PGRST_PRE_REQUEST= ENV PGRST_ROLE_CLAIM_KEY=.role ENV PGRST_ROOT_SPEC= -ENV PGRST_RAW_MEDIA_TYPES= ENV PGRST_DB_URI=postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world ENV PGRST_DB_SCHEMA=public ENV PGRST_DB_ANON_ROLE=benchmarkdbuser -ENV PGRST_RAW_MEDIA_TYPES="text/html, text/plain" ENV PGRST_DB_POOL=64 RUN mkdir /app COPY src /app @@ -37,4 +35,4 @@ WORKDIR /app EXPOSE 3000 -ENTRYPOINT [ "/app/entrypoint.sh" ] \ No newline at end of file +ENTRYPOINT [ "/app/entrypoint.sh" ] diff --git a/frameworks/Haskell/postgrest/src/fortunes.sql b/frameworks/Haskell/postgrest/src/fortunes.sql index 5d4444b9529..f8de4591c8c 100644 --- a/frameworks/Haskell/postgrest/src/fortunes.sql +++ b/frameworks/Haskell/postgrest/src/fortunes.sql @@ -1,35 +1,20 @@ -CREATE TYPE fortune_t AS (id int, message text); +create domain "text/html" as text; -create or replace function fortune_template(f fortune_t) returns text as $$ - SELECT format('%s%s', $1.id, regexp_replace($1.message, '<', '<','g')); -$$ language sql volatile; +create or replace function sanitize_html(text) returns text as $$ + select replace(replace(replace(replace(replace($1, '&', '&'), '"', '"'),'>', '>'),'<', '<'), '''', ''') +$$ language sql immutable; -create or replace function fortunes_template(fortunes fortune_t[]) returns text as $$ -WITH header AS ( - SELECT 0 as id,' -Fortunes' as html -), footer AS ( - SELECT 2,'
idmessage
' as html -), fortunes AS ( - SELECT unnest as fortune from unnest($1) -), additional AS ( - SELECT (-1, 'Additional fortune added at request time.')::fortune_t as f -), all_fortunes AS ( - SELECT * from (SELECT * FROM fortunes UNION ALL SELECT * from additional) p ORDER BY (fortune).message -), fortunes_html AS ( - SELECT 1,string_agg(fortune_template(fortune), '') from all_fortunes -), html AS ( - SELECT * FROM header UNION SELECT * FROM fortunes_html UNION SELECT * from footer ORDER BY id -) -SELECT string_agg(html,'') from html; -$$ language sql volatile; +create or replace function fortune_template("Fortune") returns text as $$ + SELECT format('%s%s', $1.id, sanitize_html($1.message)); +$$ language sql immutable; -create or replace function "fortunes.html"() returns bytea as $$ -DECLARE - fortunes fortune_t[]; -BEGIN - SET LOCAL "response.headers" = '[{"Content-Type": "text/html"}]'; - SELECT array_agg(CAST((id,message) AS fortune_t)) FROM "Fortunes" INTO fortunes; - RETURN convert_to(fortunes_template(fortunes), 'UTF8'); -END -$$ language plpgsql volatile; +create or replace function fortunes() returns "text/html" as $$ + -- This is only necessary bc. of the benchmark: The domain gives us content-type: text/html, + -- but the benchmark explicitly tests for the charset in the content-type. + select set_config('response.headers', '[{"Content-Type": "text/html; charset=utf-8"}]', true); + + select 'Fortunes' + || string_agg(fortune_template(f), NULL order by f.message collate unicode asc) + || '
idmessage
' + from (select * from "Fortune" union all select 0, 'Additional fortune added at request time.') f; +$$ language sql volatile; diff --git a/frameworks/Haskell/postgrest/src/json.sql b/frameworks/Haskell/postgrest/src/json.sql index 69f468887f8..5df9168e372 100644 --- a/frameworks/Haskell/postgrest/src/json.sql +++ b/frameworks/Haskell/postgrest/src/json.sql @@ -1,3 +1,3 @@ -create function json() returns json as $$ +create function jsonser() returns json as $$ SELECT json_build_object('message', 'Hello, World!'); -$$ language sql volatile; \ No newline at end of file +$$ language sql immutable; diff --git a/frameworks/Haskell/postgrest/src/plaintext.sql b/frameworks/Haskell/postgrest/src/plaintext.sql index ed9dbda1784..b5be0003fcc 100644 --- a/frameworks/Haskell/postgrest/src/plaintext.sql +++ b/frameworks/Haskell/postgrest/src/plaintext.sql @@ -1,3 +1,5 @@ -create function plaintext() returns text as $$ +create domain "text/plain" as text; + +create function plaintext() returns "text/plain" as $$ SELECT 'Hello, World!'; -$$ language sql volatile; \ No newline at end of file +$$ language sql immutable; diff --git a/frameworks/Haskell/postgrest/src/update.sql b/frameworks/Haskell/postgrest/src/update.sql index 541e2a507cc..71aededfe44 100644 --- a/frameworks/Haskell/postgrest/src/update.sql +++ b/frameworks/Haskell/postgrest/src/update.sql @@ -1,4 +1,4 @@ -create or replace function update(queries text default '') returns jsonb as $$ +create or replace function updates(queries text default '') returns jsonb as $$ DECLARE r "World"%ROWTYPE; j jsonb := jsonb_build_array(); @@ -6,11 +6,10 @@ DECLARE rnd_id int; count int; BEGIN - SET TRANSACTION READ WRITE; IF queries ~ '^[1-9]\d{0,2}$' THEN count := CAST(queries as int); - ELSE - count := 1; + ELSE + count := 1; END IF; IF count > 500 THEN count := 500; diff --git a/frameworks/Haskell/spock/.gitignore b/frameworks/Haskell/spock/.gitignore new file mode 100644 index 00000000000..8ee1bf9489a --- /dev/null +++ b/frameworks/Haskell/spock/.gitignore @@ -0,0 +1 @@ +.stack-work diff --git a/frameworks/Haskell/spock/benchmark_config.json b/frameworks/Haskell/spock/benchmark_config.json index 20337467cb5..71da216c231 100644 --- a/frameworks/Haskell/spock/benchmark_config.json +++ b/frameworks/Haskell/spock/benchmark_config.json @@ -14,7 +14,7 @@ "database": "Postgres", "framework": "Spock", "language": "Haskell", - "flavor": "GHC710", + "flavor": "GHC810", "orm": "Raw", "platform": "Wai", "webserver": "Warp", @@ -23,7 +23,7 @@ "display_name": "Spock", "notes": "", "versus": "", - "tags": ["broken"] + "tags": [] } }] } diff --git a/frameworks/Haskell/spock/spock.dockerfile b/frameworks/Haskell/spock/spock.dockerfile index bff65a2ef2b..848b3add166 100644 --- a/frameworks/Haskell/spock/spock.dockerfile +++ b/frameworks/Haskell/spock/spock.dockerfile @@ -1,4 +1,9 @@ -FROM haskell:8.6.3 +FROM haskell:8.10.7 + +# Fix Debian Buster repositories (moved to archive) +RUN sed -i 's/deb.debian.org/archive.debian.org/g' /etc/apt/sources.list && \ + sed -i 's/security.debian.org/archive.debian.org/g' /etc/apt/sources.list && \ + sed -i '/buster-updates/d' /etc/apt/sources.list RUN apt-get update -yqq && apt-get install -yqq xz-utils make RUN apt-get install -yqq libpq-dev diff --git a/frameworks/Haskell/spock/src/Main.hs b/frameworks/Haskell/spock/src/Main.hs index d5ac4e36a84..ee96c833454 100644 --- a/frameworks/Haskell/spock/src/Main.hs +++ b/frameworks/Haskell/spock/src/Main.hs @@ -3,43 +3,54 @@ module Main where +import qualified GHC.Conc import Control.Concurrent.Async import Control.Monad.IO.Class import Data.Aeson hiding (json) import Data.List (sort) import Data.Maybe (catMaybes, fromMaybe) -import Data.Pool +import Data.Pool (Pool) +import qualified Data.Pool as Pool import qualified Database.PostgreSQL.Simple as PG import GHC.Exts import Network.HTTP.Types.Status import Text.Blaze.Html.Renderer.Utf8 import qualified Text.Blaze.Html5 as H -import Web.Spock.Safe +import Web.Spock import Models.Fortune import Models.World import Views.Fortune - - -creds :: PG.ConnectInfo -creds = - PG.ConnectInfo - { PG.connectHost = "tfb-database" - , PG.connectPort = 5432 - , PG.connectUser = "benchmarkdbuser" - , PG.connectPassword = "benchmarkdbpass" - , PG.connectDatabase = "hello_world" - } - - -poolCfg :: PoolCfg -poolCfg = PoolCfg 50 50 60 - -pcconn :: ConnBuilder PG.Connection -pcconn = ConnBuilder (PG.connect creds) PG.close poolCfg - -dbConn :: PoolOrConn PG.Connection -dbConn = PCConn pcconn +import Web.Spock.Config + + +poolCfg :: Int -> PoolCfg +poolCfg numStripes = PoolCfg + { pc_stripes = numStripes + , pc_resPerStripe = 20 + , pc_keepOpenTime = 20 + } + + +mkPool :: PoolCfg -> IO (Pool PG.Connection) +mkPool cfg = Pool.createPool + dbConnect + PG.close + (pc_stripes cfg) + (pc_keepOpenTime cfg) + (pc_resPerStripe cfg) + +dbConnect :: IO PG.Connection +dbConnect = PG.connect creds + where + creds = + PG.ConnectInfo + { PG.connectHost = "tfb-database" + , PG.connectPort = 5432 + , PG.connectUser = "benchmarkdbuser" + , PG.connectPassword = "benchmarkdbpass" + , PG.connectDatabase = "hello_world" + } blaze :: MonadIO m => H.Html -> ActionCtxT ctx m a @@ -77,7 +88,7 @@ test2 = do test3 :: Pool PG.Connection -> ActionCtxT ctx (WebStateM PG.Connection b ()) a test3 pool = do queries <- getQueriesNumber - worlds <- liftIO $ mapConcurrently (const (withResource pool getRandomWorld)) [1..queries] + worlds <- liftIO $ mapConcurrently (const (Pool.withResource pool getRandomWorld)) [1..queries] setHeader "Content-Type" "application/json" lazyBytes $ encode worlds {-# INLINE test3 #-} @@ -95,8 +106,8 @@ test4 = do test5 :: Pool PG.Connection -> ActionCtxT ctx (WebStateM PG.Connection b ()) a test5 pool = do queries <- getQueriesNumber - worlds <- liftIO $ mapConcurrently (const (withResource pool getRandomWorld)) [1..queries] - updatedWorlds <- liftIO $ mapConcurrently (withResource pool . updateWorldRandom) (catMaybes worlds) + worlds <- liftIO $ mapConcurrently (const (Pool.withResource pool getRandomWorld)) [1..queries] + updatedWorlds <- liftIO $ mapConcurrently (Pool.withResource pool . updateWorldRandom) (catMaybes worlds) setHeader "Content-Type" "application/json" lazyBytes $ encode updatedWorlds {-# INLINE test5 #-} @@ -111,10 +122,11 @@ test6 = do main :: IO () main = do - pool <- createPool (cb_createConn pcconn) (cb_destroyConn pcconn) - (pc_stripes poolCfg) (pc_keepOpenTime poolCfg) - (pc_resPerStripe poolCfg) - runSpock 3000 $ spock (defaultSpockCfg Nothing dbConn ()) $ do + numCaps <- GHC.Conc.getNumCapabilities + let numStripes = max 1 numCaps + pool <- mkPool (poolCfg numStripes) + spockCfg <- defaultSpockCfg () (PCPool pool) () + runSpock 3000 $ spock spockCfg $ do get "json" test1 get "db" test2 get "queries" $ test3 pool diff --git a/frameworks/Haskell/spock/stack.yaml b/frameworks/Haskell/spock/stack.yaml index 79abbef4a66..da0996716cd 100644 --- a/frameworks/Haskell/spock/stack.yaml +++ b/frameworks/Haskell/spock/stack.yaml @@ -2,13 +2,21 @@ # For more information, see: http://docs.haskellstack.org/en/stable/yaml_configuration/ # Specifies the GHC version and set of packages available (e.g., lts-3.5, nightly-2015-09-21, ghc-7.10.2) -resolver: lts-6.3 +resolver: lts-18.28 # Local packages, usually specified by relative directory name packages: - '.' # Packages to be pulled from upstream that are not in the resolver (e.g., acme-missiles-0.3) -extra-deps: [] +extra-deps: + - Spock-0.14.0.0 + - Spock-core-0.14.0.0 + - reroute-0.6.0.0 + - stm-containers-1.2 + - focus-1.0.1.4 + - stm-hamt-1.2.0.4 + - primitive-extras-0.8 + - primitive-unlifted-0.1.3.0 # Override default flag values for local packages and extra-deps flags: {} diff --git a/frameworks/Haskell/spock/stack.yaml.lock b/frameworks/Haskell/spock/stack.yaml.lock new file mode 100644 index 00000000000..86b7fe920c8 --- /dev/null +++ b/frameworks/Haskell/spock/stack.yaml.lock @@ -0,0 +1,68 @@ +# This file was autogenerated by Stack. +# You should not edit this file by hand. +# For more information, please see the documentation at: +# https://docs.haskellstack.org/en/stable/topics/lock_files + +packages: +- completed: + hackage: Spock-0.14.0.0@sha256:7e86ccc9e66ce0fdb84d1dcd328f852d3754c2dbfcb60d0e7e2f1cce2f32f177,3681 + pantry-tree: + sha256: 6829dae9ba2492fae3e447afe13013dd863bd48fd5b8addfa74fc55d979de7b2 + size: 1118 + original: + hackage: Spock-0.14.0.0 +- completed: + hackage: Spock-core-0.14.0.0@sha256:386d330115cf7f82984cfbfd5190a0009b7bf6b4759acbddf2a1c05e0ef57e77,3580 + pantry-tree: + sha256: 8b6ae16a663f791109b6aee858b7989239a9ecd2d58e34f098d42da93f0d3960 + size: 1113 + original: + hackage: Spock-core-0.14.0.0 +- completed: + hackage: reroute-0.6.0.0@sha256:43805b3fdc7ed1ba701cd10e249abc997b2291c8f374b8333bb2ea0e0d1dad0b,2382 + pantry-tree: + sha256: 0a27afabb1730147d6aa0ddf5cc6368951c4625e3706cb8f5388da9739372fa3 + size: 660 + original: + hackage: reroute-0.6.0.0 +- completed: + hackage: stm-containers-1.2@sha256:a887f2e7692b7cf20e0b081e2d66e21076e2bd4b57016ec59c484edfa2d29397,3244 + pantry-tree: + sha256: 20b1076bdb121347ccc512a67df697eed34815a8e35279b6b9a0951963b1eba2 + size: 761 + original: + hackage: stm-containers-1.2 +- completed: + hackage: focus-1.0.1.4@sha256:fb2da753531be62e81da10eefbb6cd91d55b60612c3bbd6d82855664347da2fd,2647 + pantry-tree: + sha256: 0f76ffc78fb23e36c63e8a3e66d09d9e072bd891054adfff48b1983727d2394d + size: 325 + original: + hackage: focus-1.0.1.4 +- completed: + hackage: stm-hamt-1.2.0.4@sha256:7957497c022554b7599e790696d1a3e56359ad99e5da36a251894c626ca1f60a,3970 + pantry-tree: + sha256: d9a8be48da86bd4a2ba9d52ea29b9a74f1b686d439ba1bbfba04ab1a002391da + size: 1009 + original: + hackage: stm-hamt-1.2.0.4 +- completed: + hackage: primitive-extras-0.8@sha256:fca0310150496867f5b9421fe1541ecda87fae17eae44885a29f9c52dd00c8ff,2963 + pantry-tree: + sha256: e7c1d26202b80d1fca2ef780ec7fe76ede1275f4d9a996c6d44c08d8de1c45db + size: 1105 + original: + hackage: primitive-extras-0.8 +- completed: + hackage: primitive-unlifted-0.1.3.0@sha256:a98f827740f5dcf097d885b3a47c32f4462204449620abc9d51b8c4f8619f9e6,1427 + pantry-tree: + sha256: c882dca2a96b98d02b0d21875b651edb11ac67d90e736c0de7a92c410a19eb7f + size: 420 + original: + hackage: primitive-unlifted-0.1.3.0 +snapshots: +- completed: + sha256: 428ec8d5ce932190d3cbe266b9eb3c175cd81e984babf876b64019e2cbe4ea68 + size: 590100 + url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/18/28.yaml + original: lts-18.28 diff --git a/frameworks/Haskell/warp/.gitignore b/frameworks/Haskell/warp/.gitignore new file mode 100644 index 00000000000..c1d9b4c9b89 --- /dev/null +++ b/frameworks/Haskell/warp/.gitignore @@ -0,0 +1 @@ +.stack-work \ No newline at end of file diff --git a/frameworks/Haskell/warp/benchmark_config.json b/frameworks/Haskell/warp/benchmark_config.json index 686d95a1758..e96726ac64d 100644 --- a/frameworks/Haskell/warp/benchmark_config.json +++ b/frameworks/Haskell/warp/benchmark_config.json @@ -14,16 +14,16 @@ "database": "Postgres", "framework": "Warp", "language": "Haskell", - "flavor": "GHC683", + "flavor": "GHC910", "orm": "Raw", "platform": "Wai", "webserver": "Wai", "os": "Linux", "database_os": "Linux", - "display_name": "Warp+Postgres-wire", + "display_name": "Warp+Postgres-simple", "notes": "Pure haskell.", "dockerfile": "warp-shared.dockerfile", - "tags": ["broken"] + "tags": [] }, "hasql": { "json_url": "/json", @@ -38,7 +38,7 @@ "database": "Postgres", "framework": "Warp", "language": "Haskell", - "flavor": "GHC683", + "flavor": "GHC910", "orm": "Raw", "platform": "Wai", "webserver": "Wai", @@ -47,7 +47,7 @@ "display_name": "Warp+Hasql", "notes": "Uses libpq system dependency.", "dockerfile": "warp-shared.dockerfile", - "tags": ["broken"] + "tags": [] }, "mysql-haskell": { "json_url": "/json", @@ -62,7 +62,7 @@ "database": "MySQL", "framework": "Warp", "language": "Haskell", - "flavor": "GHC683", + "flavor": "GHC910", "orm": "Raw", "platform": "Wai", "webserver": "Wai", diff --git a/frameworks/Haskell/warp/shared/tfb-hasql/TFB/Db.hs b/frameworks/Haskell/warp/shared/tfb-hasql/TFB/Db.hs index 8dcca736120..435d35e8f79 100644 --- a/frameworks/Haskell/warp/shared/tfb-hasql/TFB/Db.hs +++ b/frameworks/Haskell/warp/shared/tfb-hasql/TFB/Db.hs @@ -1,74 +1,101 @@ {-# OPTIONS -funbox-strict-fields #-} -{-# LANGUAGE OverloadedStrings #-} - -module TFB.Db ( - Pool - , mkPool - , Config(..) - , queryWorldById - , queryWorldByIds - , updateWorlds - , queryFortunes - , Error -) where - -import qualified TFB.Types as Types -import Control.Monad (forM, forM_) - -import qualified Hasql.Decoders as HasqlDec -import qualified Hasql.Encoders as HasqlEnc -import Hasql.Pool (Pool, acquire, UsageError, use) -import qualified Hasql.Statement as HasqlStatement -import Hasql.Session (statement) -import Hasql.Connection (settings, Settings) -import Data.Functor.Contravariant (contramap) -import Data.ByteString (ByteString) +{-# LANGUAGE OverloadedStrings #-} + +module TFB.Db + ( Pool, + mkPool, + Config (..), + queryWorldById, + queryWorldByIds, + updateWorlds, + queryFortunes, + Error, + ) +where + +import Control.Monad (forM, forM_) +import Data.ByteString (ByteString) import qualified Data.ByteString.Char8 as BSC +import Data.Functor.Contravariant (contramap) +import qualified Data.Text as T +import qualified Data.Text.Encoding as TE +import qualified Hasql.Connection.Setting as ConnectionSetting +import Hasql.Connection.Setting.Connection (params) +import qualified Hasql.Connection.Setting.Connection.Param as ConnectionParam +import qualified Hasql.Decoders as HasqlDec +import qualified Hasql.Encoders as HasqlEnc +import Hasql.Pool (Pool, UsageError, acquire, use) +import qualified Hasql.Pool.Config as PoolCfg +import Hasql.Session (statement) +import qualified Hasql.Statement as HasqlStatement +import qualified TFB.Types as Types ------------------------------------------------------------------------------- + -- * Database data Config = Config - { configHost :: String - , configName :: ByteString - , configUser :: ByteString - , configPass :: ByteString - , configStripes :: Int - , configPoolSize :: Int + { configHost :: String, + configName :: ByteString, + configUser :: ByteString, + configPass :: ByteString, + configStripes :: Int, + configPoolSize :: Int } + instance Show Config where - show c - = "Config {" - <> " configHost = " <> configHost c - <> ", configName = " <> BSC.unpack (configName c) - <> ", configUser = " <> BSC.unpack (configUser c) - <> ", configPass = REDACTED" - <> ", configStripes = " <> show (configStripes c) - <> ", configPoolSize = " <> show (configPoolSize c) - <> " }" + show c = + "Config {" + <> " configHost = " + <> configHost c + <> ", configName = " + <> BSC.unpack (configName c) + <> ", configUser = " + <> BSC.unpack (configUser c) + <> ", configPass = REDACTED" + <> ", configStripes = " + <> show (configStripes c) + <> ", configPoolSize = " + <> show (configPoolSize c) + <> " }" type Error = UsageError -mkSettings :: Config -> Settings -mkSettings c = settings (BSC.pack $ configHost c) 5432 (configUser c) (configPass c) (configName c) +mkSettings :: Config -> ConnectionSetting.Setting +mkSettings c = + ConnectionSetting.connection $ + params + [ ConnectionParam.host (T.pack $ configHost c), + ConnectionParam.port 5432, + ConnectionParam.user (TE.decodeUtf8 $ configUser c), + ConnectionParam.password (TE.decodeUtf8 $ configPass c), + ConnectionParam.dbname (TE.decodeUtf8 $ configName c) + ] mkPool :: Config -> IO Pool -mkPool c = acquire (configPoolSize c, 0.5, mkSettings c) +mkPool c = + acquire $ + PoolCfg.settings + [ PoolCfg.staticConnectionSettings [mkSettings c], + PoolCfg.size (configPoolSize c) + ] + +qidEnc :: HasqlEnc.Params Types.QId +qidEnc = contramap fromIntegral (HasqlEnc.param (HasqlEnc.nonNullable HasqlEnc.int4)) -intValEnc :: HasqlEnc.Params Types.QId -intValEnc = contramap fromIntegral $ HasqlEnc.param HasqlEnc.int2 -intValDec :: HasqlDec.Row Types.QId -intValDec = fmap fromIntegral $ HasqlDec.column HasqlDec.int2 +qidDec :: HasqlDec.Row Types.QId +qidDec = fromIntegral <$> (HasqlDec.column . HasqlDec.nonNullable) HasqlDec.int4 ------------------------------------------------------------------------------- + -- * World selectSingle :: HasqlStatement.Statement Types.QId Types.World -selectSingle = HasqlStatement.Statement q intValEnc decoder True +selectSingle = HasqlStatement.Statement q qidEnc decoder True where - q = "SELECT * FROM World WHERE (id = $1)" - decoder = HasqlDec.singleRow $ Types.World <$> intValDec <*> intValDec + q = "SELECT * FROM World WHERE (id = $1)" + decoder = HasqlDec.singleRow $ Types.World <$> qidDec <*> qidDec queryWorldById :: Pool -> Types.QId -> IO (Either Error Types.World) queryWorldById pool wId = use pool (statement wId selectSingle) @@ -79,11 +106,10 @@ queryWorldByIds pool wIds = use pool $ do forM wIds $ \wId -> statement wId selectSingle updateSingle :: HasqlStatement.Statement (Types.QId, Types.QId) () -updateSingle = HasqlStatement.Statement q encoder decoder True +updateSingle = HasqlStatement.Statement q encoder HasqlDec.noResult True where q = "UPDATE World SET randomNumber = $1 WHERE id = $2" - encoder = contramap fst intValEnc <> contramap snd intValEnc - decoder = HasqlDec.unit + encoder = contramap fst qidEnc <> contramap snd qidEnc updateWorlds :: Pool -> [(Types.World, Types.QId)] -> IO (Either Error [Types.World]) updateWorlds _ [] = pure . pure $ mempty @@ -93,18 +119,19 @@ updateWorlds pool wsUpdates = use pool $ do statement (Types.wId w, wNum) updateSingle return ws where - updateW (w,wNum) = w { Types.wRandomNumber = wNum } + updateW (w, wNum) = w {Types.wRandomNumber = wNum} ------------------------------------------------------------------------------- + -- * Fortunes selectFortunes :: HasqlStatement.Statement () [Types.Fortune] selectFortunes = HasqlStatement.Statement q encoder decoder True where - q = "SELECT * FROM Fortune" - encoder = HasqlEnc.unit - -- TODO: investigate whether 'rowList' is worth the more expensive 'cons'. - decoder = HasqlDec.rowList $ Types.Fortune <$> intValDec <*> HasqlDec.column HasqlDec.text + q = "SELECT * FROM Fortune" + encoder = HasqlEnc.noParams + -- TODO: investigate whether 'rowList' is worth the more expensive 'cons'. + decoder = HasqlDec.rowList $ Types.Fortune <$> qidDec <*> HasqlDec.column (HasqlDec.nonNullable HasqlDec.text) {-# INLINE selectFortunes #-} queryFortunes :: Pool -> IO (Either Error [Types.Fortune]) diff --git a/frameworks/Haskell/warp/shared/tfb-hasql/tfb-hasql.cabal b/frameworks/Haskell/warp/shared/tfb-hasql/tfb-hasql.cabal index 77e0b24cd9a..b9524dc33c3 100644 --- a/frameworks/Haskell/warp/shared/tfb-hasql/tfb-hasql.cabal +++ b/frameworks/Haskell/warp/shared/tfb-hasql/tfb-hasql.cabal @@ -15,10 +15,11 @@ library default-language: Haskell2010 exposed-modules: TFB.Db build-depends: - base >= 4.7 && < 5 + base >= 4.18 && < 5 , tfb-types , bytestring , text - , hasql >= 0.19 - , hasql-pool >= 0.4 + , hasql >= 1.9.3 + , hasql-pool >= 1.3.0 + , hasql-th >= 0.4.0 , contravariant diff --git a/frameworks/Haskell/warp/shared/tfb-mysql-haskell/README.md b/frameworks/Haskell/warp/shared/tfb-mysql-haskell/README.md index 8c156e8b795..f506958767d 100644 --- a/frameworks/Haskell/warp/shared/tfb-mysql-haskell/README.md +++ b/frameworks/Haskell/warp/shared/tfb-mysql-haskell/README.md @@ -1,3 +1,6 @@ # TFB MySQLHaskell `mysql-haskell` backend for TFB benchmarks that can re-used with any server. + +Note: Currently broken, as test server uses `caching_sha2_password` authentication, +but library mysql-haskell does not support this yet. diff --git a/frameworks/Haskell/warp/shared/tfb-mysql-haskell/TFB/Db.hs b/frameworks/Haskell/warp/shared/tfb-mysql-haskell/TFB/Db.hs index 057d0986911..2aa6e8d637d 100644 --- a/frameworks/Haskell/warp/shared/tfb-mysql-haskell/TFB/Db.hs +++ b/frameworks/Haskell/warp/shared/tfb-mysql-haskell/TFB/Db.hs @@ -1,76 +1,93 @@ -{-# OPTIONS -funbox-strict-fields #-} -{-# LANGUAGE OverloadedStrings #-} - -module TFB.Db ( - Pool - , mkPool - , Config(..) - , queryWorldById - , queryWorldByIds - , updateWorlds - , queryFortunes - , Error -) where - -import qualified TFB.Types as Types -import qualified Data.Either as Either -import Control.Monad (forM, forM_) - -import qualified Data.Pool as Pool -import Data.ByteString (ByteString) -import qualified Data.ByteString.Char8 as BSC -import qualified Database.MySQL.Base as MySQL -import qualified System.IO.Streams as Streams -import Data.Text (Text) -import qualified Data.Text as Text +{-# LANGUAGE OverloadedStrings #-} + +module TFB.Db + ( Pool, + mkPool, + Config (..), + queryWorldById, + queryWorldByIds, + updateWorlds, + queryFortunes, + Error, + ) +where + +import Control.Monad (forM, forM_) +import Data.ByteString (ByteString) +import Data.ByteString.Char8 qualified as BSC +import Data.Either qualified as Either +import Data.Pool qualified as Pool +import Data.Text (Text) +import Data.Text qualified as Text +import Database.MySQL.Base qualified as MySQL +import System.IO.Streams qualified as Streams +import TFB.Types qualified as Types ------------------------------------------------------------------------------- + -- * Database data Config = Config - { configHost :: String - , configName :: ByteString - , configUser :: ByteString - , configPass :: ByteString - , configStripes :: Int - , configPoolSize :: Int + { configHost :: String, + configName :: ByteString, + configUser :: ByteString, + configPass :: ByteString, + configStripes :: Int, + configPoolSize :: Int } + instance Show Config where - show c - = "Config {" - <> " configHost = " <> configHost c - <> ", configName = " <> BSC.unpack (configName c) - <> ", configUser = " <> BSC.unpack (configUser c) - <> ", configPass = REDACTED" - <> ", configStripes = " <> show (configStripes c) - <> ", configPoolSize = " <> show (configPoolSize c) - <> " }" + show c = + "Config {" + <> " configHost = " + <> configHost c + <> ", configName = " + <> BSC.unpack (configName c) + <> ", configUser = " + <> BSC.unpack (configUser c) + <> ", configPass = REDACTED" + <> ", configStripes = " + <> show (configStripes c) + <> ", configPoolSize = " + <> show (configPoolSize c) + <> " }" type Connection = MySQL.MySQLConn + type Pool = Pool.Pool Connection + type Error = Text + type DbRow = [MySQL.MySQLValue] connect :: Config -> IO Connection connect c = MySQL.connect myc where - myc = MySQL.defaultConnectInfoMB4 - { MySQL.ciHost = configHost c - , MySQL.ciDatabase = configName c - , MySQL.ciUser = configUser c - , MySQL.ciPassword = configPass c + myc = + MySQL.defaultConnectInfoMB4 + { MySQL.ciHost = configHost c, + MySQL.ciDatabase = configName c, + MySQL.ciUser = configUser c, + MySQL.ciPassword = configPass c } close :: Connection -> IO () close = MySQL.close mkPool :: Config -> IO Pool -mkPool c = Pool.createPool (connect c) close (configStripes c) 0.5 (configPoolSize c) +mkPool c = + Pool.newPool $ + Pool.setNumStripes (Just $ configStripes c) $ + Pool.defaultPoolConfig + (connect c) + close + 0.5 + (configPoolSize c) {-# SPECIALIZE intValEnc :: Int -> MySQL.MySQLValue #-} {-# SPECIALIZE intValEnc :: Types.QId -> MySQL.MySQLValue #-} -intValEnc :: Integral a => a -> MySQL.MySQLValue +intValEnc :: (Integral a) => a -> MySQL.MySQLValue intValEnc = MySQL.MySQLInt16U . fromIntegral intValDec :: MySQL.MySQLValue -> Either Text Int @@ -82,19 +99,20 @@ intValDec (MySQL.MySQLInt32U i) = pure . fromIntegral $ i intValDec (MySQL.MySQLInt32 i) = pure . fromIntegral $ i intValDec (MySQL.MySQLInt64U i) = pure . fromIntegral $ i intValDec (MySQL.MySQLInt64 i) = pure . fromIntegral $ i -intValDec x = Left $ "Expected MySQLInt*, received" <> (Text.pack $ show x) +intValDec x = Left $ "Expected MySQLInt*, received" <> Text.pack (show x) textValDec :: MySQL.MySQLValue -> Either Text Text textValDec (MySQL.MySQLText t) = pure t -textValDec x = Left $ "Expected Text, received" <> (Text.pack $ show x) +textValDec x = Left $ "Expected Text, received" <> Text.pack (show x) ------------------------------------------------------------------------------- + -- * World decodeWorld :: DbRow -> Either Error Types.World decodeWorld [] = Left "MarshalError: Expected 2 columns for World, found 0" -decodeWorld (_:[]) = Left "MarshalError: Expected 2 columns for World, found 1" -decodeWorld (c1:c2:_) = Types.World <$> intValDec c1 <*> intValDec c2 +decodeWorld [_] = Left "MarshalError: Expected 2 columns for World, found 1" +decodeWorld (c1 : c2 : _) = Types.World <$> intValDec c1 <*> intValDec c2 queryWorldById :: Pool -> Types.QId -> IO (Either Error Types.World) queryWorldById dbPool wId = Pool.withResource dbPool $ \conn -> do @@ -105,7 +123,7 @@ queryWorldById dbPool wId = Pool.withResource dbPool $ \conn -> do return $ case err of [] -> case oks of [] -> Left "World not found!" - ws -> pure $ head ws + w : _ -> pure w _ -> Left . mconcat $ err where s = "SELECT * FROM World WHERE id = ?" @@ -134,15 +152,16 @@ updateWorlds dbPool wsUpdates = Pool.withResource dbPool $ \conn -> do MySQL.closeStmt conn sId return . pure $ ws where - updateW (w,wNum) = w { Types.wRandomNumber = wNum } + updateW (w, wNum) = w {Types.wRandomNumber = wNum} ------------------------------------------------------------------------------- + -- * Fortunes decodeFortune :: DbRow -> Either Error Types.Fortune decodeFortune [] = Left "MarshalError: Expected 2 columns for Fortune, found 0" -decodeFortune (_:[]) = Left "MarshalError: Expected 2 columns for Fortune, found 1" -decodeFortune (c1:c2:_) = Types.Fortune <$> intValDec c1 <*> textValDec c2 +decodeFortune [_] = Left "MarshalError: Expected 2 columns for Fortune, found 1" +decodeFortune (c1 : c2 : _) = Types.Fortune <$> intValDec c1 <*> textValDec c2 queryFortunes :: Pool -> IO (Either Error [Types.Fortune]) queryFortunes dbPool = Pool.withResource dbPool $ \conn -> do @@ -152,4 +171,4 @@ queryFortunes dbPool = Pool.withResource dbPool $ \conn -> do let (err, oks) = Either.partitionEithers eFortunes return $ case err of [] -> pure oks - _ -> Left $ head err + w : _ -> Left w diff --git a/frameworks/Haskell/warp/shared/tfb-mysql-haskell/tfb-mysql-haskell.cabal b/frameworks/Haskell/warp/shared/tfb-mysql-haskell/tfb-mysql-haskell.cabal index 637c615e498..f1c17cf7ba8 100644 --- a/frameworks/Haskell/warp/shared/tfb-mysql-haskell/tfb-mysql-haskell.cabal +++ b/frameworks/Haskell/warp/shared/tfb-mysql-haskell/tfb-mysql-haskell.cabal @@ -12,10 +12,11 @@ extra-source-files: README.md library hs-source-dirs: . - default-language: Haskell2010 + default-language: GHC2021 + ghc-options: -funbox-strict-fields exposed-modules: TFB.Db build-depends: - base >= 4.7 && < 5 + base >= 4.18 && < 5 , tfb-types , bytestring , text diff --git a/frameworks/Haskell/warp/shared/tfb-postgres-simple/README.md b/frameworks/Haskell/warp/shared/tfb-postgres-simple/README.md new file mode 100644 index 00000000000..e558b2ae6f0 --- /dev/null +++ b/frameworks/Haskell/warp/shared/tfb-postgres-simple/README.md @@ -0,0 +1,3 @@ +# TFB PostgresSimple + +`postgres-simple` backend for TFB benchmarks that can re-used with any server. diff --git a/frameworks/Haskell/warp/shared/tfb-postgres-simple/TFB/Db.hs b/frameworks/Haskell/warp/shared/tfb-postgres-simple/TFB/Db.hs new file mode 100644 index 00000000000..3b1ed8e52f5 --- /dev/null +++ b/frameworks/Haskell/warp/shared/tfb-postgres-simple/TFB/Db.hs @@ -0,0 +1,155 @@ +{-# OPTIONS -Wno-orphans #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE OverloadedStrings #-} + +module TFB.Db + ( Pool, + mkPool, + Config (..), + queryWorldById, + queryWorldByIds, + updateWorlds, + queryFortunes, + Error, + ) +where + +import Control.Exception (catch, try) +import Control.Monad (forM) +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.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 System.IO.Error qualified as Error +import TFB.Types qualified as Types + +------------------------------------------------------------------------------- + +-- * Database + +data Config + = Config + { configHost :: String, + configName :: ByteString, + configUser :: ByteString, + configPass :: ByteString, + configStripes :: Int, + configPoolSize :: Int + } + +instance Show Config where + show c = + "Config {" + <> " configHost = " + <> configHost c + <> ", configName = " + <> BSC.unpack (configName c) + <> ", configUser = " + <> BSC.unpack (configUser c) + <> ", configPass = REDACTED" + <> ", configStripes = " + <> show (configStripes c) + <> ", configPoolSize = " + <> show (configPoolSize c) + <> " }" + +instance FromRow Types.World where + fromRow = Types.World <$> field <*> field + +instance FromRow Types.Fortune where + fromRow = Types.Fortune <$> field <*> field + +type Connection = PG.Connection + +type Pool = Pool.Pool Connection + +data Error + = DbError ByteString + | DbErrors [ByteString] + | NotFound + deriving (Show) + +connect :: Config -> IO Connection +connect c = catch (PG.connect pgc) failError + where + failError :: PG.SomePostgreSqlException -> IO a + failError = Error.ioError . Error.userError . show + pgc = + PG.defaultConnectInfo + { PG.connectHost = configHost c, + PG.connectDatabase = BSC.unpack $ configName c, + PG.connectUser = BSC.unpack $ configUser c, + PG.connectPassword = BSC.unpack $ configPass c + } + +close :: Connection -> IO () +close = PG.close + +mkPool :: Config -> IO Pool +mkPool c = + Pool.newPool $ + Pool.setNumStripes (Just $ configStripes c) $ + Pool.defaultPoolConfig + (connect c) + close + 0.5 + (configPoolSize c) + +------------------------------------------------------------------------------- + +-- * World + +queryWorldByIdInner :: Types.QId -> Connection -> IO (Either Error Types.World) +queryWorldByIdInner wId conn = do + let query = PG.query conn "SELECT * FROM World WHERE id = ?" (PG.Only wId :: PG.Only Types.QId) :: IO [Types.World] + res <- try @SomePostgreSqlException query + pure $ Either.either (Left . DbError . BSC.pack . show) mkW res + where + mkW [] = Left NotFound + mkW (w : _) = pure w + +queryWorldById :: Pool -> Types.QId -> IO (Either Error Types.World) +queryWorldById dbPool wId = Pool.withResource dbPool (queryWorldByIdInner wId) + +queryWorldByIds :: Pool -> [Types.QId] -> IO (Either Error [Types.World]) +queryWorldByIds dbPool wIds = Pool.withResource dbPool $ \conn -> do + rows <- forM wIds $ \wId -> queryWorldByIdInner wId conn + let (errs, rowsList) = Either.partitionEithers rows + return $ case errs of + [] -> pure rowsList + _ -> + Left . DbErrors $ + map + ( \case + DbError e -> e + _ -> error "Unexpected error" + ) + errs + +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 + res <- + try @SomePostgreSqlException $ + PG.executeMany + conn + "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 + Right _ -> return () + pure $ Bi.bimap (DbError . BSC.pack . show) (const $ map (uncurry Types.World) worlds) res + +------------------------------------------------------------------------------- + +-- * Fortunes + +queryFortunes :: Pool -> IO (Either Error [Types.Fortune]) +queryFortunes dbPool = Pool.withResource dbPool $ \conn -> do + let query = PG.query_ conn "SELECT * FROM Fortune" :: IO [Types.Fortune] + res <- try @SomePostgreSqlException query + pure $ Bi.first (DbError . BSC.pack . show) res diff --git a/frameworks/Haskell/warp/shared/tfb-postgres-simple/tfb-postgres-simple.cabal b/frameworks/Haskell/warp/shared/tfb-postgres-simple/tfb-postgres-simple.cabal new file mode 100644 index 00000000000..53e42d1c36d --- /dev/null +++ b/frameworks/Haskell/warp/shared/tfb-postgres-simple/tfb-postgres-simple.cabal @@ -0,0 +1,25 @@ +name: tfb-postgres-simple +version: 0.1.0.0 +homepage: https://github.com/TechEmpower/FrameworkBenchmarks/tree/master/frameworks/Haskell/warp/shared/tfb-postgres-simple +license: BSD3 +author: Naushadh +maintainer: naushadh@protonmail.com +copyright: 2019 Naushadh +category: Web +build-type: Simple +cabal-version: >=1.10 +extra-source-files: README.md + +library + hs-source-dirs: . + default-language: GHC2021 + ghc-options: -funbox-strict-fields + exposed-modules: TFB.Db + build-depends: + base >= 4.18 && < 5 + , tfb-types + , resource-pool + , postgresql-simple + , bytestring + , vector + , text diff --git a/frameworks/Haskell/warp/shared/tfb-postgres-wire/README.md b/frameworks/Haskell/warp/shared/tfb-postgres-wire/README.md deleted file mode 100644 index 070d34f71a9..00000000000 --- a/frameworks/Haskell/warp/shared/tfb-postgres-wire/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# TFB PostgresWire - -`postgres-wire` backend for TFB benchmarks that can re-used with any server. diff --git a/frameworks/Haskell/warp/shared/tfb-postgres-wire/TFB/Db.hs b/frameworks/Haskell/warp/shared/tfb-postgres-wire/TFB/Db.hs deleted file mode 100644 index 00d35a9aa75..00000000000 --- a/frameworks/Haskell/warp/shared/tfb-postgres-wire/TFB/Db.hs +++ /dev/null @@ -1,174 +0,0 @@ -{-# OPTIONS -funbox-strict-fields #-} -{-# LANGUAGE OverloadedStrings #-} - -module TFB.Db ( - Pool - , mkPool - , Config(..) - , queryWorldById - , queryWorldByIds - , updateWorlds - , queryFortunes - , Error -) where - -import qualified TFB.Types as Types -import qualified Data.Either as Either -import qualified System.IO.Error as Error -import Control.Monad (replicateM, forM) - -import qualified Data.Pool as Pool -import Data.ByteString (ByteString) -import qualified Data.ByteString.Char8 as BSC -import qualified Database.PostgreSQL.Driver as PG -import qualified Database.PostgreSQL.Protocol.Types as PGT -import qualified Database.PostgreSQL.Protocol.DataRows as PGD -import qualified Database.PostgreSQL.Protocol.Store.Decode as PGSD -import qualified Database.PostgreSQL.Protocol.Store.Encode as PGSE -import qualified Database.PostgreSQL.Protocol.Codecs.Decoders as PGCD -import qualified Database.PostgreSQL.Protocol.Codecs.Encoders as PGCE -import qualified Database.PostgreSQL.Protocol.Codecs.PgTypes as PGCT -import qualified Data.Vector as V -import Data.Text (Text) -import qualified Data.Text.Encoding as TE - -------------------------------------------------------------------------------- --- * Database - -data Config - = Config - { configHost :: String - , configName :: ByteString - , configUser :: ByteString - , configPass :: ByteString - , configStripes :: Int - , configPoolSize :: Int - } -instance Show Config where - show c - = "Config {" - <> " configHost = " <> configHost c - <> ", configName = " <> BSC.unpack (configName c) - <> ", configUser = " <> BSC.unpack (configUser c) - <> ", configPass = REDACTED" - <> ", configStripes = " <> show (configStripes c) - <> ", configPoolSize = " <> show (configPoolSize c) - <> " }" - -type Connection = PG.Connection -type Pool = Pool.Pool Connection -data Error - = DbError PG.Error - | DbErrors [PG.Error] - | NotFound - deriving Show - -connect :: Config -> IO Connection -connect c = simplifyError =<< PG.connect pgc - where - simplifyError = Either.either (Error.ioError . Error.userError . show) pure - pgc = PG.defaultConnectionSettings - { PG.settingsHost = BSC.pack $ configHost c - , PG.settingsDatabase = configName c - , PG.settingsUser = configUser c - , PG.settingsPassword = configPass c - } - -close :: Connection -> IO () -close = PG.close - -mkPool :: Config -> IO Pool -mkPool c = Pool.createPool (connect c) close (configStripes c) 0.5 (configPoolSize c) - -runQuery :: Connection -> PGSD.Decode a -> PG.Query -> IO (Either PG.Error (V.Vector a)) -runQuery conn dec q = do - PG.sendBatchAndSync conn [q] - eRows <- PG.readNextData conn - _ <- PG.waitReadyForQuery conn - return $ fmap (PGD.decodeManyRows dec) eRows - -decodeInt :: PGSD.Decode Int -decodeInt = fromIntegral <$> PGCD.getNonNullable PGCD.int4 - -decodeText :: PGSD.Decode Text -decodeText = TE.decodeUtf8 <$> PGCD.getNonNullable PGCD.bytea - -encodeInt :: Integral a => a -> (PGCT.Oids, PGSE.Encode) -encodeInt qId = (PGCT.int2, PGCE.int2 $ fromIntegral qId) - -mkQuery :: ByteString -> [(PGCT.Oids, PGSE.Encode)] -> PG.Query -mkQuery q es = PG.Query q ps PGT.Binary PGT.Binary PG.NeverCache - where - mkP (oid, e) = (PGCT.oidType oid, Just e) - ps = fmap mkP es - -------------------------------------------------------------------------------- --- * World - -decodeWorld :: PGSD.Decode Types.World -decodeWorld = PGCD.dataRowHeader *> decoder - where - decoder = Types.World - <$> decodeInt - <*> decodeInt - -queryWorldById :: Pool -> Types.QId -> IO (Either Error Types.World) -queryWorldById dbPool wId = Pool.withResource dbPool $ \conn -> do - fmap go $ runQuery conn decodeWorld q - where - s = "SELECT * FROM World WHERE id = $1" - q = mkQuery s [encodeInt wId] - mkW [] = Left NotFound - mkW ws = pure . head $ ws - go = Either.either (Left . DbError) (mkW . V.toList) - -queryWorldByIds :: Pool -> [Types.QId] -> IO (Either Error [Types.World]) -queryWorldByIds _ [] = pure . pure $ mempty -queryWorldByIds dbPool wIds = Pool.withResource dbPool $ \conn -> do - let s = "SELECT * FROM World WHERE id = $1" - let mkQ wId = mkQuery s [encodeInt wId] - let qs = fmap mkQ wIds - PG.sendBatchAndSync conn qs - eRowsMany <- replicateM (length qs) $ PG.readNextData conn - _ <- PG.waitReadyForQuery conn - let (errs, rowsList) = Either.partitionEithers eRowsMany - return $ case errs of - [] -> pure . mconcat $ fmap (V.toList . PGD.decodeManyRows decodeWorld) rowsList - _ -> Left . DbErrors $ errs - -updateWorlds :: Pool -> [(Types.World, Int)] -> IO (Either Error [Types.World]) -updateWorlds _ [] = pure . pure $ mempty -updateWorlds dbPool wsUpdates = Pool.withResource dbPool $ \conn -> do - let ws = fmap updateW wsUpdates - let qs = fmap mkQ ws - eRowsMany <- forM qs $ \q -> do - PG.sendBatchAndSync conn [q] - eRows <- PG.readNextData conn - _ <- PG.waitReadyForQuery conn - return eRows - let (errs, _) = Either.partitionEithers eRowsMany - return $ case errs of - [] -> pure ws - _ -> Left . DbErrors $ errs - where - s = "UPDATE World SET randomNumber = $1 WHERE id = $2" - updateW (w,wNum) = w { Types.wRandomNumber = wNum } - mkQ w = mkQuery s [encodeInt . Types.wRandomNumber $ w, encodeInt . Types.wId $ w] - -------------------------------------------------------------------------------- --- * Fortunes - -decodeFortune :: PGSD.Decode Types.Fortune -decodeFortune = PGCD.dataRowHeader *> decoder - where - decoder = Types.Fortune - <$> decodeInt - <*> decodeText - -queryFortunes :: Pool -> IO (Either Error [Types.Fortune]) -queryFortunes dbPool = Pool.withResource dbPool $ \conn -> do - fmap go $ runQuery conn decodeFortune q - where - s = "SELECT * FROM Fortune" - q = mkQuery s [] - go = Either.either (Left . DbError) (pure . V.toList) diff --git a/frameworks/Haskell/warp/shared/tfb-postgres-wire/tfb-postgres-wire.cabal b/frameworks/Haskell/warp/shared/tfb-postgres-wire/tfb-postgres-wire.cabal deleted file mode 100644 index ac031c383ab..00000000000 --- a/frameworks/Haskell/warp/shared/tfb-postgres-wire/tfb-postgres-wire.cabal +++ /dev/null @@ -1,24 +0,0 @@ -name: tfb-postgres-wire -version: 0.1.0.0 -homepage: https://github.com/TechEmpower/FrameworkBenchmarks/tree/master/frameworks/Haskell/warp/shared/tfb-postgres-wire -license: BSD3 -author: Naushadh -maintainer: naushadh@protonmail.com -copyright: 2019 Naushadh -category: Web -build-type: Simple -cabal-version: >=1.10 -extra-source-files: README.md - -library - hs-source-dirs: . - default-language: Haskell2010 - exposed-modules: TFB.Db - build-depends: - base >= 4.7 && < 5 - , tfb-types - , resource-pool - , postgres-wire - , bytestring - , vector - , text diff --git a/frameworks/Haskell/warp/shared/tfb-types/TFB/Types.hs b/frameworks/Haskell/warp/shared/tfb-types/TFB/Types.hs index 0d0718e7b37..e0f0cd55319 100644 --- a/frameworks/Haskell/warp/shared/tfb-types/TFB/Types.hs +++ b/frameworks/Haskell/warp/shared/tfb-types/TFB/Types.hs @@ -1,30 +1,24 @@ {-# OPTIONS -funbox-strict-fields #-} -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE DataKinds #-} -{-# LANGUAGE TypeOperators #-} - -module TFB.Types ( - unsafeJsonString - , parseCount - , getCount - , Count - , World(..) - , Fortune(..) - , FortunesHtml - , QId -) where - -import qualified Data.Either as Either -import qualified Data.Char as Char +{-# LANGUAGE OverloadedStrings #-} + +module TFB.Types + ( unsafeJsonString, + parseCount, + getCount, + Count, + World (..), + Fortune (..), + QId, + ) +where -import Data.ByteString (ByteString) import qualified Data.Attoparsec.ByteString.Char8 as Parsec -import qualified Data.BufferBuilder.Utf8 as Utf8 +import Data.BufferBuilder.Json ((.=)) import qualified Data.BufferBuilder.Json as Json -import Data.BufferBuilder.Json ((.=)) -import qualified Html -import Html (type (#), type (>)) -import Data.Text (Text) +import qualified Data.BufferBuilder.Utf8 as Utf8 +import Data.ByteString (ByteString) +import qualified Data.Either as Either +import Data.Text (Text) ------------------------------------------------------------------------------- -- * Inputs @@ -32,65 +26,28 @@ import Data.Text (Text) newtype Count = Count Int parseCount :: ByteString -> Maybe Count -parseCount = fmap Count . Either.either (const Nothing) pure . Parsec.parseOnly parseInt +parseCount = fmap Count . Either.either (const Nothing) pure . Parsec.parseOnly Parsec.decimal getCount :: Maybe Count -> Int getCount Nothing = 1 getCount (Just (Count c)) = max 1 (min c 500) --- https://stackoverflow.com/a/24171263 -parseInt :: Parsec.Parser Int -parseInt = do - digits <- Parsec.many1 parseIntDigit - let n = foldl (\x d -> 10*x + (Char.digitToInt d)) 0 digits - seq n (return n) - -parseIntDigit :: Parsec.Parser Char -parseIntDigit = digit - where - digit = Parsec.satisfy isDigit - isDigit c = c >= '0' && c <= '9' - type QId = Int ------------------------------------------------------------------------------- -- * Outputs -data World = World { wId :: QId , wRandomNumber :: QId } - deriving Show +data World = World {wId :: QId, wRandomNumber :: QId} + deriving (Show) instance Json.ToJson World where - toJson w - = Json.toJson - $ "id" .= wId w - <> "randomNumber" .= wRandomNumber w - -data Fortune = Fortune { fId :: QId , fMessage :: Text } - deriving Show + toJson w = + Json.toJson $ + "id" .= wId w + <> "randomNumber" .= wRandomNumber w -type FortunesHtml - = (('Html.DOCTYPE Html.> ()) - # ('Html.Html - > (('Html.Head > ('Html.Title > Html.Raw Text)) - # ('Html.Body - > ('Html.Table - > ( - ('Html.Tr - > ( ('Html.Th > Html.Raw Text) - # ('Html.Th > Html.Raw Text) - ) - ) - # ['Html.Tr - > ( ('Html.Td > QId) - # ('Html.Td > Text) - ) - ] - ) - ) - ) - ) - ) - ) +data Fortune = Fortune {fId :: QId, fMessage :: Text} + deriving (Show) unsafeJsonString :: ByteString -> Json.Value unsafeJsonString = Json.unsafeValueUtf8Builder . Utf8.appendBS7 . quote diff --git a/frameworks/Haskell/warp/shared/tfb-types/tfb-types.cabal b/frameworks/Haskell/warp/shared/tfb-types/tfb-types.cabal index 250ed43cf8e..3fc2c9446f9 100644 --- a/frameworks/Haskell/warp/shared/tfb-types/tfb-types.cabal +++ b/frameworks/Haskell/warp/shared/tfb-types/tfb-types.cabal @@ -15,9 +15,8 @@ library default-language: Haskell2010 exposed-modules: TFB.Types build-depends: - base >= 4.7 && < 5 + base >= 4.18 && < 5 , bytestring , attoparsec , buffer-builder - , type-of-html , text diff --git a/frameworks/Haskell/warp/stack.yaml b/frameworks/Haskell/warp/stack.yaml index ff09c250201..7df4cd85668 100644 --- a/frameworks/Haskell/warp/stack.yaml +++ b/frameworks/Haskell/warp/stack.yaml @@ -1,18 +1,16 @@ -resolver: lts-13.13 +resolver: lts-24.11 packages: - ./shared/tfb-types - ./shared/tfb-hasql - ./shared/tfb-mysql-haskell -- ./shared/tfb-postgres-wire +- ./shared/tfb-postgres-simple - ./warp-shared extra-deps: -- socket-0.8.2.0 -- socket-unix-0.2.0.0 -- git: https://github.com/postgres-haskell/postgres-wire.git - commit: fda5e3b70c3cc0bab8365b4b872991d50da0348c +- buffer-builder-0.2.4.9 +- mysql-haskell-1.1.7 # the following flags are meant for use with warp.dockerfile -compiler: ghc-8.6.3 # this MUST match the resolver's GHC; minor hack to ensure GHC isn't downloaded into sandbox. +compiler: ghc-9.10.2 # 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 new file mode 100644 index 00000000000..16819ffff37 --- /dev/null +++ b/frameworks/Haskell/warp/stack.yaml.lock @@ -0,0 +1,26 @@ +# This file was autogenerated by Stack. +# You should not edit this file by hand. +# For more information, please see the documentation at: +# https://docs.haskellstack.org/en/stable/topics/lock_files + +packages: +- completed: + hackage: buffer-builder-0.2.4.9@sha256:22600bcca6b8657865d1dce07cfa791767bdb6241c0cd5cadd6444678bf9a8a7,5257 + pantry-tree: + sha256: f5eddef2db3cd6e0c2e2199a5a59cae0329b057045aa67705492d069f9e204f0 + size: 1155 + original: + hackage: buffer-builder-0.2.4.9 +- completed: + hackage: mysql-haskell-1.1.7@sha256:e1fc81c03063a50a169464e9983466249339c718b28012e2b69cd58e7c18487c,5498 + pantry-tree: + sha256: 8720dcd88265638550d96b2ef560fafd1b708bcf196a1c3add5f98c82d014711 + size: 4968 + original: + 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 diff --git a/frameworks/Haskell/warp/warp-shared.dockerfile b/frameworks/Haskell/warp/warp-shared.dockerfile index 9c8091768d9..635674f2f46 100644 --- a/frameworks/Haskell/warp/warp-shared.dockerfile +++ b/frameworks/Haskell/warp/warp-shared.dockerfile @@ -1,7 +1,11 @@ -FROM haskell:8.6.3 +FROM haskell:9.10-slim-bullseye -RUN apt-get update -yqq && apt-get install -yqq xz-utils make -RUN apt-get install -yqq libpq-dev +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 apt-get update && apt-get install -yqq libpq-dev WORKDIR /app @@ -9,7 +13,7 @@ COPY stack.yaml ./ COPY ./shared/tfb-types/tfb-types.cabal ./shared/tfb-types/ COPY ./shared/tfb-hasql/tfb-hasql.cabal ./shared/tfb-hasql/ COPY ./shared/tfb-mysql-haskell/tfb-mysql-haskell.cabal ./shared/tfb-mysql-haskell/ -COPY ./shared/tfb-postgres-wire/tfb-postgres-wire.cabal ./shared/tfb-postgres-wire/ +COPY ./shared/tfb-postgres-simple/tfb-postgres-simple.cabal ./shared/tfb-postgres-simple/ COPY ./warp-shared/warp-shared.cabal ./warp-shared/ RUN stack setup RUN stack install --dependencies-only @@ -17,7 +21,7 @@ RUN stack install --dependencies-only ADD ./shared ./shared ADD ./warp-shared ./warp-shared RUN stack build --pedantic --copy-bins -RUN ln -s ~/.local/bin/warp-postgres-wire ~/.local/bin/warp +RUN ln -s ~/.local/bin/warp-postgres-simple ~/.local/bin/warp ARG TFB_TEST_NAME ENV TFB_TEST_NAME=${TFB_TEST_NAME} diff --git a/frameworks/Haskell/warp/warp-shared/README.md b/frameworks/Haskell/warp/warp-shared/README.md index 49bf57aef21..cc08a916e62 100644 --- a/frameworks/Haskell/warp/warp-shared/README.md +++ b/frameworks/Haskell/warp/warp-shared/README.md @@ -4,4 +4,4 @@ This is a generic test that produces an executable for each supported backend li - `warp-hasql`: PostgreSQL database via the [`hasql`](https://github.com/nikita-volkov/hasql) library. - `warp-mysql-haskell`: MySQL database via the [`mysql-haskell`](https://github.com/winterland1989/mysql-haskell) library. -- `warp-postgres-wire` (default): PostgreSQL database via the [`postgres-wire`](https://github.com/postgres-haskell/postgres-wire) library. +- `warp-postgres-simple` (default): PostgreSQL database via the [`postgres-simple`](https://github.com/postgres-haskell/postgres-simple) library. diff --git a/frameworks/Haskell/warp/warp-shared/src/Lib.hs b/frameworks/Haskell/warp/warp-shared/src/Lib.hs index 3b419a88eaa..210db9b25ab 100644 --- a/frameworks/Haskell/warp/warp-shared/src/Lib.hs +++ b/frameworks/Haskell/warp/warp-shared/src/Lib.hs @@ -1,27 +1,27 @@ -{-# LANGUAGE OverloadedStrings #-} - -module Lib ( - main - , Db.Config(..) -) where - -import qualified TFB.Types as Types -import qualified TFB.Db as Db -import qualified Data.Either as Either -import Data.List (sortOn) -import Control.Monad (replicateM, join) - -import qualified Data.ByteString.Lazy as LBS -import qualified Data.ByteString.Lazy.Char8 as LBSC -import qualified Network.HTTP.Types.Status as Status -import qualified Network.HTTP.Types.Header as Header -import qualified Network.Wai as Wai -import qualified Network.Wai.Handler.Warp as Warp -import qualified Data.BufferBuilder.Json as Json -import Data.BufferBuilder.Json ((.=)) -import qualified System.Random.MWC as MWC -import qualified Html -import Html ((#)) +{-# LANGUAGE OverloadedStrings #-} + +module Lib + ( main, + Db.Config (..), + ) +where + +import Control.Monad (join, replicateM) +import Data.BufferBuilder.Json ((.=)) +import Data.BufferBuilder.Json qualified as Json +import Data.ByteString.Lazy qualified as LBS +import Data.ByteString.Lazy.Char8 qualified as LBSC +import Data.Either qualified as Either +import Data.List (sortOn) +import Network.HTTP.Types.Header qualified as Header +import Network.HTTP.Types.Status qualified as Status +import Network.Wai qualified as Wai +import Network.Wai.Handler.Warp qualified as Warp +import System.Random.MWC qualified as MWC +import TFB.Db qualified as Db +import TFB.Types qualified as Types +import Text.Blaze.Html.Renderer.Utf8 qualified as Html +import Text.Blaze.Html5 qualified as Html -- entry point main :: Db.Config -> IO () @@ -41,18 +41,18 @@ app gen dbPool req respond = do let qParams = Wai.queryString req let mCount = Types.parseCount =<< join (lookup "queries" qParams) case (Wai.requestMethod req, Wai.pathInfo req) of - ("GET", ["plaintext"]) - -> respond getPlaintext - ("GET", ["json"]) - -> respond getJson - ("GET", ["db"]) - -> respond =<< getWorld gen dbPool - ("GET", ["fortunes"]) - -> respond =<< getFortunes dbPool - ("GET", ["queries"]) - -> respond =<< getWorlds gen dbPool mCount - ("GET", ["updates"]) - -> respond =<< updateWorlds gen dbPool mCount + ("GET", ["plaintext"]) -> + respond getPlaintext + ("GET", ["json"]) -> + respond getJson + ("GET", ["db"]) -> + respond =<< getWorld gen dbPool + ("GET", ["fortunes"]) -> + respond =<< getFortunes dbPool + ("GET", ["queries"]) -> + respond =<< getWorlds gen dbPool mCount + ("GET", ["updates"]) -> + respond =<< updateWorlds gen dbPool mCount _ -> respond routeNotFound -- * response helpers @@ -68,7 +68,7 @@ contentJson = [(Header.hContentType, "application/json")] {-# SPECIALIZE respondJson :: Json.ObjectBuilder -> Wai.Response #-} {-# SPECIALIZE respondJson :: Types.World -> Wai.Response #-} -respondJson :: Json.ToJson a => a -> Wai.Response +respondJson :: (Json.ToJson a) => a -> Wai.Response respondJson = Wai.responseLBS Status.status200 contentJson . mkBs where mkBs = LBS.fromStrict . Json.encodeJson @@ -76,8 +76,8 @@ respondJson = Wai.responseLBS Status.status200 contentJson . mkBs contentHtml :: Header.ResponseHeaders contentHtml = [(Header.hContentType, "text/html; charset=UTF-8")] -respondHtml :: Types.FortunesHtml -> Wai.Response -respondHtml = Wai.responseLBS Status.status200 contentHtml . Html.renderByteString +respondHtml :: Html.Html -> Wai.Response +respondHtml = Wai.responseBuilder Status.status200 contentHtml . Html.renderHtmlBuilder -- * error responses @@ -138,20 +138,22 @@ getFortunes dbPool = do res <- Db.queryFortunes dbPool return $ case res of Left e -> respondDbError e - Right fs -> respondHtml $ do + Right fs -> let new = Types.Fortune 0 "Additional fortune added at request time." - let header = Html.tr_ $ Html.th_ (Html.Raw "id") # Html.th_ (Html.Raw "message") - let mkRow f = Html.tr_ $ Html.td_ (fromIntegral $ Types.fId f) # Html.td_ (Types.fMessage $ f) - let rows = fmap mkRow $ sortOn Types.fMessage (new : fs) - Html.doctype_ # - Html.html_ ( - Html.head_ ( - Html.title_ (Html.Raw "Fortunes") - ) # - Html.body_ ( Html.table_ $ - header # rows - ) - ) + header = Html.tr $ do + Html.th $ Html.preEscapedToHtml ("id" :: String) + Html.th $ Html.preEscapedToHtml ("message" :: String) + mkRow f = Html.tr $ do + Html.td $ Html.toHtml ((fromIntegral $ Types.fId f) :: Int) + Html.td $ Html.toHtml (Types.fMessage f) + rows = (mkRow <$> sortOn Types.fMessage (new : fs)) + in respondHtml $ Html.docTypeHtml $ do + Html.head $ do + Html.title $ Html.preEscapedToHtml ("Fortunes" :: String) + Html.body $ do + Html.table $ do + header + sequence_ rows {-# INLINE getFortunes #-} randomId :: MWC.GenIO -> IO Types.QId diff --git a/frameworks/Haskell/warp/warp-shared/src/Main.hs b/frameworks/Haskell/warp/warp-shared/src/Main.hs index 654e19ac5da..4f85fa6e5de 100644 --- a/frameworks/Haskell/warp/warp-shared/src/Main.hs +++ b/frameworks/Haskell/warp/warp-shared/src/Main.hs @@ -1,10 +1,10 @@ -{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE OverloadedStrings #-} module Main where -import qualified Lib -import qualified GHC.Conc -import System.Environment (getArgs, lookupEnv) +import GHC.Conc qualified +import Lib qualified +import System.Environment (getArgs, lookupEnv) main :: IO () main = do @@ -15,11 +15,12 @@ main = do [x] -> pure x _ -> pure "0.0.0.0" numCaps <- GHC.Conc.getNumCapabilities - Lib.main $ Lib.Config { - Lib.configHost = dbHost, - Lib.configName = "hello_world", - Lib.configUser = "benchmarkdbuser", - Lib.configPass = "benchmarkdbpass", - Lib.configStripes = numCaps, - Lib.configPoolSize= 512 - } + Lib.main $ + Lib.Config + { Lib.configHost = dbHost, + Lib.configName = "hello_world", + Lib.configUser = "benchmarkdbuser", + Lib.configPass = "benchmarkdbpass", + Lib.configStripes = numCaps, + Lib.configPoolSize = 512 + } diff --git a/frameworks/Haskell/warp/warp-shared/warp-shared.cabal b/frameworks/Haskell/warp/warp-shared/warp-shared.cabal index 75d6a72ff5d..bc7bf933d48 100644 --- a/frameworks/Haskell/warp/warp-shared/warp-shared.cabal +++ b/frameworks/Haskell/warp/warp-shared/warp-shared.cabal @@ -1,4 +1,4 @@ -cabal-version: 2.4 +cabal-version: 3.8 -- `cabal-version` MUST match the version bundled with stack. -- run `stack exec -- cabal --version` to find out name: warp-shared @@ -15,15 +15,15 @@ extra-source-files: README.md common deps hs-source-dirs: src other-modules: Lib - default-language: Haskell2010 + default-language: GHC2021 ghc-options: -Wall -threaded -rtsopts -O2 -funbox-strict-fields build-depends: - base >= 4.7 && < 5 + base >= 4.18 && < 5 , bytestring , text , attoparsec , buffer-builder - , type-of-html + , blaze-html , mwc-random , wai , warp @@ -45,10 +45,10 @@ executable warp-mysql-haskell tfb-types , tfb-mysql-haskell -executable warp-postgres-wire +executable warp-postgres-simple import: deps main-is: Main.hs build-depends: tfb-types - , tfb-postgres-wire + , tfb-postgres-simple diff --git a/frameworks/Java/act/pom.xml b/frameworks/Java/act/pom.xml index 6d22ea17292..8e66efe9a01 100644 --- a/frameworks/Java/act/pom.xml +++ b/frameworks/Java/act/pom.xml @@ -70,7 +70,7 @@ 1.8 8.0.28 - 42.4.1 + 42.7.2 1.3.2 3.4 com.techempower.act.AppEntry diff --git a/frameworks/Java/activej/activej.dockerfile b/frameworks/Java/activej/activej.dockerfile index cea75f79e0d..da3ba92ee5a 100644 --- a/frameworks/Java/activej/activej.dockerfile +++ b/frameworks/Java/activej/activej.dockerfile @@ -1,11 +1,11 @@ -FROM maven:3.6.1-jdk-11-slim as maven - +FROM maven:3.9.0-eclipse-temurin-17 as maven WORKDIR /activej COPY pom.xml pom.xml COPY src src RUN mvn compile assembly:single -q -FROM openjdk:11.0.3-jdk-slim +FROM amazoncorretto:25 WORKDIR /activej COPY --from=maven /activej/target/activej-server-benchmark-0.0.1-SNAPSHOT-jar-with-dependencies.jar app.jar -CMD ["java", "-Xms2G", "-Xmx2G", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AggressiveOpts", "-DHttpServerConnection.initialWriteBufferSize=4096", "-DHttpHeadersMultimap.initialSize=16", "-jar", "app.jar"] \ No newline at end of file +EXPOSE 8080 +CMD ["java", "-server", "-XX:+UseParallelGC", "-jar", "app.jar"] \ No newline at end of file diff --git a/frameworks/Java/activeweb/pom.xml b/frameworks/Java/activeweb/pom.xml index e3f9f0c430d..2f073f2424d 100644 --- a/frameworks/Java/activeweb/pom.xml +++ b/frameworks/Java/activeweb/pom.xml @@ -115,12 +115,12 @@ com.fasterxml.jackson.core jackson-core - 2.9.9 + 2.15.0 com.fasterxml.jackson.core jackson-databind - 2.13.4.2 + 2.16.0 diff --git a/frameworks/Java/aio-socket/.dockerignore b/frameworks/Java/aio-socket/.dockerignore new file mode 100644 index 00000000000..cba5dfe3c3b --- /dev/null +++ b/frameworks/Java/aio-socket/.dockerignore @@ -0,0 +1,19 @@ +.github +.git +.DS_Store +docs +kubernetes +node_modules +/.svelte-kit +/package +.env +.env.* +vite.config.js.timestamp-* +vite.config.ts.timestamp-* +__pycache__ +.env +_old +uploads +.ipynb_checkpoints +**/*.db +_test \ No newline at end of file diff --git a/frameworks/Java/aio-socket/.gitignore b/frameworks/Java/aio-socket/.gitignore new file mode 100644 index 00000000000..2f089945614 --- /dev/null +++ b/frameworks/Java/aio-socket/.gitignore @@ -0,0 +1,3 @@ +/target/ +logs +.settings \ No newline at end of file diff --git a/frameworks/Java/aio-socket/README.md b/frameworks/Java/aio-socket/README.md new file mode 100644 index 00000000000..118b271982c --- /dev/null +++ b/frameworks/Java/aio-socket/README.md @@ -0,0 +1,77 @@ +# t-io Benchmarking Test + +This is the tio-server portion of a [benchmarking test suite](../) comparing a variety of web development platforms. + +## Controller + +These implementations use the tio-server's controller. + +### Plaintext Test + +* [Plaintext test source](src/main/java/com/litongjava/tio/http/server/controller/IndexController.java) + +### JSON Serialization Test + +* [JSON test source](src/main/java/com/litongjava/tio/http/server/controller/IndexController.java) + + +## Versions +3.7.3.v20231218-RELEASE (https://gitee.com/litongjava/t-io) + +## Test URLs + +All implementations use the same URLs. + +### Plaintext Test + + http://localhost:8080/plaintext + +### JSON Encoding Test + + http://localhost:8080/json + + + + ## Hot to run + ### install mysql 8 + - 1.please instal mysql 8.0.32,example cmd + ``` + docker run --restart=always -d --name mysql_8 --hostname mysql \ +-p 3306:3306 \ +-e 'MYSQL_ROOT_PASSWORD=robot_123456#' -e 'MYSQL_ROOT_HOST=%' -e 'MYSQL_DATABASE=hello_world' \ +mysql/mysql-server:8.0.32 \ +--character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --lower_case_table_names=1 + ``` + - 2.create database schema hello_world + - 3.create tablle,[example](sql/hello_world.sql) + - 4.import data + + ### docker + ``` + docker build -t tio-server-benchmark -f tio-server.dockerfile . +``` +The run is to specify the mysql database +``` +docker run --rm -p 8080:8080 \ +-e JDBC_URL="jdbc:mysql://192.168.3.9/hello_world" \ +-e JDBC_USER="root" \ +-e JDBC_PSWD="robot_123456#" \ +tio-server-benchmark +``` + +### windows + +-windows +``` +D:\java\jdk1.8.0_121\bin\java -jar target\tio-server-benchmark-1.0.jar --JDBC_URL=jdbc:mysql://192.168.3.9/hello_world?useSSL=false --JDBC_USER=root --JDBC_PSWD=robot_123456# +``` +or +``` +set JDBC_URL=jdbc:mysql://192.168.3.9/hello_world +set jdbc.user=root +set JDBC_PSWD=robot_123456# +D:\java\jdk1.8.0_121\bin\java -jar target\tio-server-benchmark-1.0.jar +``` + + + diff --git a/frameworks/Java/aio-socket/aio-socket.dockerfile b/frameworks/Java/aio-socket/aio-socket.dockerfile new file mode 100644 index 00000000000..7aa11987383 --- /dev/null +++ b/frameworks/Java/aio-socket/aio-socket.dockerfile @@ -0,0 +1,19 @@ +FROM litongjava/maven:3.8.8-jdk8u391 AS builder +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 + +WORKDIR /app + +COPY --from=builder /app/target/aio-socket-benchmark-1.0-jar-with-dependencies.jar /app/aio-socket-benchmark-1.0.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 diff --git a/frameworks/Java/aio-socket/benchmark_config.json b/frameworks/Java/aio-socket/benchmark_config.json new file mode 100644 index 00000000000..135582cd342 --- /dev/null +++ b/frameworks/Java/aio-socket/benchmark_config.json @@ -0,0 +1,23 @@ +{ + "framework": "aio-socket", + "tests": [{ + "default": { + "plaintext_url": "/plaintext", + "json_url": "/json", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "framework": "aio-socket", + "language": "Java", + "flavor": "None", + "orm": "Raw", + "platform": "t-io", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "aio-socket", + "notes": "aio-socket", + "versus": "t-io" + } + }] +} diff --git a/frameworks/Java/aio-socket/config.toml b/frameworks/Java/aio-socket/config.toml new file mode 100644 index 00000000000..31b198ee34b --- /dev/null +++ b/frameworks/Java/aio-socket/config.toml @@ -0,0 +1,15 @@ +[framework] +name = "t-io" + +[main] +urls.plaintext = "/plaintext" +urls.json = "/json" +approach = "Realistic" +classification = "Micro" +database = "None" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "t-io" +webserver = "None" +versus = "t-io" diff --git a/frameworks/Java/aio-socket/pom.xml b/frameworks/Java/aio-socket/pom.xml new file mode 100644 index 00000000000..2b5dacefe65 --- /dev/null +++ b/frameworks/Java/aio-socket/pom.xml @@ -0,0 +1,90 @@ + + 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 + + + + + + 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 + + + + + + + \ 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 new file mode 100644 index 00000000000..fa954b4cef4 --- /dev/null +++ b/frameworks/Java/aio-socket/src/main/java/com/litongjava/aio/http/server/HttpServer.java @@ -0,0 +1,169 @@ +package com.litongjava.aio.http.server; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.nio.ByteBuffer; +import java.nio.channels.AsynchronousChannelGroup; +import java.nio.channels.AsynchronousSocketChannel; +import java.nio.channels.CompletionHandler; +import java.nio.charset.StandardCharsets; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.ZoneId; +import java.util.concurrent.ThreadFactory; + +import com.alibaba.fastjson.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; +import com.litongjava.enhance.channel.EnhanceAsynchronousServerSocketChannel; + +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)); + } + + // 异步写响应 + 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 { + // 注意:如果在写操作中已经归还了虚拟缓冲区,则不要重复释放 + } + } + + @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 new file mode 100644 index 00000000000..76f56b22dc9 --- /dev/null +++ b/frameworks/Java/aio-socket/src/main/java/com/litongjava/aio/http/server/model/Fortune.java @@ -0,0 +1,23 @@ +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/aio-socket/src/main/java/com/litongjava/aio/http/server/model/Message.java b/frameworks/Java/aio-socket/src/main/java/com/litongjava/aio/http/server/model/Message.java new file mode 100644 index 00000000000..2365bf4d708 --- /dev/null +++ b/frameworks/Java/aio-socket/src/main/java/com/litongjava/aio/http/server/model/Message.java @@ -0,0 +1,13 @@ +package com.litongjava.aio.http.server.model; + +public final class Message { + private final String message; + + public Message(String message) { + this.message = message; + } + + public String getMessage() { + return message; + } +} diff --git a/frameworks/Java/aio-socket/src/main/java/com/litongjava/aio/http/server/model/World.java b/frameworks/Java/aio-socket/src/main/java/com/litongjava/aio/http/server/model/World.java new file mode 100644 index 00000000000..3fec0068ea5 --- /dev/null +++ b/frameworks/Java/aio-socket/src/main/java/com/litongjava/aio/http/server/model/World.java @@ -0,0 +1,32 @@ +package com.litongjava.aio.http.server.model; + +public final class World { + + public int id; + public int randomnumber; + + protected World() { + } + + public World(int id, int randomnumber) { + this.id = id; + this.randomnumber = randomnumber; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public int getRandomnumber() { + return randomnumber; + } + + public void setRandomnumber(int randomnumber) { + this.randomnumber = randomnumber; + } + +} \ No newline at end of file diff --git a/frameworks/Java/aio-socket/src/main/java/com/litongjava/aio/http/server/utils/RandomUtils.java b/frameworks/Java/aio-socket/src/main/java/com/litongjava/aio/http/server/utils/RandomUtils.java new file mode 100644 index 00000000000..c2b73f8dca2 --- /dev/null +++ b/frameworks/Java/aio-socket/src/main/java/com/litongjava/aio/http/server/utils/RandomUtils.java @@ -0,0 +1,36 @@ +package com.litongjava.aio.http.server.utils; + +import java.util.concurrent.ThreadLocalRandom; +import java.util.stream.IntStream; + +public class RandomUtils { + + private static final int MIN_WORLD_NUMBER = 1; + private static final int MAX_WORLD_NUMBER_PLUS_ONE = 10_001; + // private static final int MAX_WORLD_NUMBER_PLUS_ONE = 30; + + 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() allows us to avoid using Hibernate's first-level cache in + // the JPA-based implementation. Using a cache like that would bypass + // querying the database, which would violate the test requirements. + .distinct(); + } + + public 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/aio-socket/src/main/resources/app.properties b/frameworks/Java/aio-socket/src/main/resources/app.properties new file mode 100644 index 00000000000..52083ea13ff --- /dev/null +++ b/frameworks/Java/aio-socket/src/main/resources/app.properties @@ -0,0 +1,9 @@ +http.response.header.showServer=true +server.port=8080 +#JDBC_URL=jdbc:mysql://192.168.3.9/hello_world?useSSL=false&allowPublicKeyRetrieval=true +#JDBC_USER=root +#JDBC_PSWD=robot_123456# + +JDBC_URL=jdbc:mysql://tfb-database/hello_world +JDBC_USER=benchmarkdbuser +JDBC_PSWD=benchmarkdbpass \ No newline at end of file diff --git a/frameworks/Java/aio-socket/src/main/resources/ehcache.xml b/frameworks/Java/aio-socket/src/main/resources/ehcache.xml new file mode 100644 index 00000000000..79b79e49479 --- /dev/null +++ b/frameworks/Java/aio-socket/src/main/resources/ehcache.xml @@ -0,0 +1,9 @@ + + + + + + + diff --git a/frameworks/Java/aio-socket/src/main/resources/logback.xml b/frameworks/Java/aio-socket/src/main/resources/logback.xml new file mode 100644 index 00000000000..6065c075e78 --- /dev/null +++ b/frameworks/Java/aio-socket/src/main/resources/logback.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + ${CONSOLE_LOG_PATTERN} + + + + + + + ${CONSOLE_LOG_PATTERN} + + + + ${LOG_HOME}/log.%d{yyyyMMddHH}.%i.log + + 180 + + 100MB + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frameworks/Java/aio-socket/src/main/resources/templates/fortunes.html b/frameworks/Java/aio-socket/src/main/resources/templates/fortunes.html new file mode 100644 index 00000000000..1f6817df007 --- /dev/null +++ b/frameworks/Java/aio-socket/src/main/resources/templates/fortunes.html @@ -0,0 +1,20 @@ + + + + Fortunes + + + + + + + + #for(fortune : fortunes) + + + + + #end +
idmessage
#(fortune.id)#escape(fortune.message)
+ + diff --git a/frameworks/Java/armeria/README.md b/frameworks/Java/armeria/README.md index 8ab23b8bcc6..685cebe559e 100644 --- a/frameworks/Java/armeria/README.md +++ b/frameworks/Java/armeria/README.md @@ -4,10 +4,10 @@ This is the armeria portion of a [benchmarking test suite](../) comparing a vari ## Infrastructure Software Versions -* [Armeria 0.71.1](https://line.github.io/armeria/) -* [HikariCP 2.7.8](https://github.com/brettwooldridge/HikariCP) -* [Postgresql 42.1.4](https://jdbc.postgresql.org/) -* [Mustache 0.9.5](https://mustache.github.io/) +* [Armeria 1.33.4](https://armeria.dev/) +* [HikariCP 7.0.2](https://github.com/brettwooldridge/HikariCP) +* [Postgresql 42.7.8](https://jdbc.postgresql.org/) +* [Mustache 0.9.14](https://mustache.github.io/) ## Source for Tests diff --git a/frameworks/Java/armeria/armeria.dockerfile b/frameworks/Java/armeria/armeria.dockerfile index c6d4e268f7a..ed0d6f546b3 100644 --- a/frameworks/Java/armeria/armeria.dockerfile +++ b/frameworks/Java/armeria/armeria.dockerfile @@ -1,10 +1,10 @@ -FROM maven:3.6.1-jdk-11-slim as maven +FROM maven:3.9.11-eclipse-temurin-25-alpine as maven WORKDIR /armeria COPY src src COPY pom.xml pom.xml RUN mvn package -q -FROM openjdk:11.0.3-jdk-slim +FROM eclipse-temurin:25-jre-alpine WORKDIR /armeria COPY --from=maven /armeria/target/hello-1.0-SNAPSHOT.jar app.jar diff --git a/frameworks/Java/armeria/benchmark_config.json b/frameworks/Java/armeria/benchmark_config.json index 32cdbd6303f..bdc474dfd9b 100644 --- a/frameworks/Java/armeria/benchmark_config.json +++ b/frameworks/Java/armeria/benchmark_config.json @@ -7,6 +7,7 @@ "db_url": "/db", "query_url": "/queries/", "update_url": "/updates/", + "fortune_url": "/fortunes", "port": 8080, "approach": "Realistic", "classification": "Micro", diff --git a/frameworks/Java/armeria/pom.xml b/frameworks/Java/armeria/pom.xml index a568b3035f6..2b749491eb0 100644 --- a/frameworks/Java/armeria/pom.xml +++ b/frameworks/Java/armeria/pom.xml @@ -12,11 +12,11 @@ - 11 - 11 + 25 + 25 - 1.24.3 + 1.33.4 @@ -28,22 +28,22 @@ org.apache.logging.log4j log4j-slf4j-impl - 2.12.1 + 2.25.2 org.postgresql postgresql - 42.4.3 + 42.7.8 com.github.spullara.mustache.java compiler - 0.9.6 + 0.9.14 com.zaxxer HikariCP - 3.3.1 + 7.0.2 compile @@ -53,7 +53,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.8.0 + 3.14.1 false @@ -62,7 +62,7 @@ org.springframework.boot spring-boot-maven-plugin - 2.1.8.RELEASE + 3.5.6 diff --git a/frameworks/Java/avaje-jex/README.md b/frameworks/Java/avaje-jex/README.md new file mode 100644 index 00000000000..54e62058c3d --- /dev/null +++ b/frameworks/Java/avaje-jex/README.md @@ -0,0 +1,81 @@ +# Avaje Jex Benchmarking Test + +## Important Libraries +The tests were run with: +* [Java 24](https://openjdk.java.net) +* [Avaje Http 3.3](https://github.com/avaje/avaje-http) +* [Avaje Inject 11.5](https://github.com/avaje/avaje-inject) +* [Avaje Jex 3.2](https://github.com/avaje/avaje-jex) +* [HikariCP 6.3.0](https://github.com/brettwooldridge/HikariCP) +* [jstachio 1.3.7](https://github.com/jstachio/jstachio) + +[Avaje Jex](https://avaje.io) is a micro web framework for Java's built-in `jdk.httpserver` API. + +```java + Jex.create() + .get("/", ctx -> ctx.text("hello")) + .start(); +``` + +## Test Implementation Source Code + +### Plain Text Test +* [Plain test source](src/main/java/benchmark/Main.java) + +### JSON Encoding Test +* [JSON test source](src/main/java/benchmark/Main.java) + +### Single Query Test +* [Single query test source](src/main/java/benchmark/DatabaseController.java) + +### Multiple Queries Test +* [Multiple queries test source](src/main/java/benchmark/DatabaseController.java) + +### Database Update Test +* [Database update test source](src/main/java/benchmark/DatabaseController.java) + +### Fortunes Test +* [Fortunes test source](src/main/java/benchmark/DatabaseController.java) + +## Test URLs +### JSON + +http://localhost:8080/json + +### PLAINTEXT + +http://localhost:8080/plaintext + +### DB + +http://localhost:8080/db + +### QUERY + +http://localhost:8080/queries?queries= + +### UPDATE + +http://localhost:8080/updates?queries= + +### FORTUNES + +http://localhost:8080/fortunes + +## build + +### java's httpserver impl + + `mvn clean package` + +### robaho's httpserver impl + + `mvn clean package -P robaho` + +### jetty's httpserver impl + + `mvn clean package -P jetty` + +## run + + `java -p ./target/modules/ -m avaje.techempower` \ No newline at end of file diff --git a/frameworks/Java/avaje-jex/avaje-jex-jetty.dockerfile b/frameworks/Java/avaje-jex/avaje-jex-jetty.dockerfile new file mode 100644 index 00000000000..80fc05c124d --- /dev/null +++ b/frameworks/Java/avaje-jex/avaje-jex-jetty.dockerfile @@ -0,0 +1,8 @@ +FROM maven:3.9.9-eclipse-temurin-24 AS build +WORKDIR /avaje-jex +COPY pom.xml pom.xml +COPY src src +RUN mvn package -q -P jetty +EXPOSE 8080 + +CMD ["java", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-p", "./target/modules/", "-m", "avaje.techempower"] diff --git a/frameworks/Java/avaje-jex/avaje-jex-robaho.dockerfile b/frameworks/Java/avaje-jex/avaje-jex-robaho.dockerfile new file mode 100644 index 00000000000..d62eb71d124 --- /dev/null +++ b/frameworks/Java/avaje-jex/avaje-jex-robaho.dockerfile @@ -0,0 +1,8 @@ +FROM maven:3.9.9-eclipse-temurin-24 AS build +WORKDIR /avaje-jex +COPY pom.xml pom.xml +COPY src src +RUN mvn package -q -P robaho +EXPOSE 8080 + +CMD ["java", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-p", "./target/modules/", "-m", "avaje.techempower"] diff --git a/frameworks/Java/avaje-jex/avaje-jex.dockerfile b/frameworks/Java/avaje-jex/avaje-jex.dockerfile new file mode 100644 index 00000000000..a9c8578c4f5 --- /dev/null +++ b/frameworks/Java/avaje-jex/avaje-jex.dockerfile @@ -0,0 +1,8 @@ +FROM maven:3.9.9-eclipse-temurin-24 AS build +WORKDIR /avaje-jex +COPY pom.xml pom.xml +COPY src src +RUN mvn package -q +EXPOSE 8080 + +CMD ["java", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-p", "./target/modules/", "-m", "avaje.techempower"] diff --git a/frameworks/Java/avaje-jex/benchmark_config.json b/frameworks/Java/avaje-jex/benchmark_config.json new file mode 100644 index 00000000000..90b7a6ed051 --- /dev/null +++ b/frameworks/Java/avaje-jex/benchmark_config.json @@ -0,0 +1,76 @@ +{ + "framework": "avaje-jex", + "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": "Micro", + "framework": "avaje-jex", + "language": "Java", + "flavor": "None", + "platform": "httpserver", + "database": "Postgres", + "database_os": "Linux", + "orm": "Raw", + "webserver": "None", + "os": "Linux", + "notes": "avaje-jex using jdk.httpserver", + "display_name": "avaje-jex", + "versus": "httpserver" + }, + "robaho": { + "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": "Micro", + "framework": "avaje-jex", + "language": "Java", + "flavor": "None", + "platform": "robaho", + "database": "Postgres", + "database_os": "Linux", + "orm": "Raw", + "webserver": "None", + "os": "Linux", + "notes": "avaje-jex using robaho's httpserver", + "display_name": "avaje-jex-robaho", + "versus": "robaho-httpserver" + }, + "jetty": { + "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": "Micro", + "framework": "avaje-jex", + "language": "Java", + "flavor": "None", + "platform": "Jetty", + "database": "Postgres", + "database_os": "Linux", + "orm": "Raw", + "webserver": "None", + "os": "Linux", + "notes": "avaje-jex using Jetty", + "display_name": "avaje-jex-jetty", + "versus": "jetty" + } + } + ] +} \ No newline at end of file diff --git a/frameworks/Java/avaje-jex/config.toml b/frameworks/Java/avaje-jex/config.toml new file mode 100644 index 00000000000..ec60cda08fa --- /dev/null +++ b/frameworks/Java/avaje-jex/config.toml @@ -0,0 +1,53 @@ +[framework] +name = "avaje-jex" + +[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 = "jdk-httpserver" +webserver = "None" +versus = "httpserver" + +[robaho] +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 = "robaho-httpserver" +webserver = "None" +versus = "robaho-httpserver" + +[jetty] +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 = "Jetty" +webserver = "None" +versus = "jetty" \ No newline at end of file diff --git a/frameworks/Java/avaje-jex/pom.xml b/frameworks/Java/avaje-jex/pom.xml new file mode 100644 index 00000000000..4ede9b91c6a --- /dev/null +++ b/frameworks/Java/avaje-jex/pom.xml @@ -0,0 +1,173 @@ + + + 4.0.0 + + io.avaje + avaje-jex-parent + 3.2 + + benchmark + avaje-jex + 1.0 + + + 24 + 2.0.17 + + + + + io.avaje + avaje-config + + + io.avaje + avaje-http-api + + + io.avaje + avaje-inject + + + io.avaje + avaje-jex + + + io.avaje + avaje-jsonb + + + + org.slf4j + slf4j-api + ${slf4j.version} + + + org.slf4j + slf4j-simple + ${slf4j.version} + + + + com.zaxxer + HikariCP + 6.3.0 + + + org.postgresql + postgresql + 42.7.7 + + + + io.jstach + jstachio + 1.3.7 + + + + + io.jstach + jstachio-apt + 1.3.7 + provided + + + io.avaje + avaje-http-jex-generator + provided + + + io.avaje + avaje-inject-generator + provided + + + io.avaje + avaje-jsonb-generator + provided + + + + + + + io.avaje + avaje-provides-maven-plugin + 2.3 + + + + com.spotify.fmt + fmt-maven-plugin + 2.25 + + + + format + + + + + + + + maven-jar-plugin + + ${project.build.directory}/modules + + + benchmark.Main + + + + + + maven-dependency-plugin + + + copy-modules + package + + copy-dependencies + + + ${project.build.directory}/modules + runtime + + + + + + + + + + robaho + + false + + + + io.github.robaho + httpserver + + + + + jetty + + false + + + + org.eclipse.jetty + jetty-http-spi + 12.0.19 + + + + + \ No newline at end of file diff --git a/frameworks/Java/avaje-jex/src/main/java/benchmark/DatabaseController.java b/frameworks/Java/avaje-jex/src/main/java/benchmark/DatabaseController.java new file mode 100644 index 00000000000..295c01c01b7 --- /dev/null +++ b/frameworks/Java/avaje-jex/src/main/java/benchmark/DatabaseController.java @@ -0,0 +1,57 @@ +package benchmark; + +import benchmark.model.Fortune; +import benchmark.model.FortuneTemplate; +import benchmark.model.World; +import benchmark.repository.DbService; +import io.avaje.http.api.Controller; +import io.avaje.http.api.Get; +import java.sql.SQLException; +import java.util.List; + +@Controller +public class DatabaseController { + + private static final int MIN_QUERIES = 1; + private static final int MAX_QUERIES = 500; + + private final DbService dbService; + + public DatabaseController(DbService dbService) { + + this.dbService = dbService; + } + + @Get("/db") + public World handleSingleDbQuery() throws SQLException { + return dbService.getWorld(1).get(0); + } + + @Get("/queries") + public List handleMultipleDbQueries(String queries) throws SQLException { + int num = getBoundedRowNumber(queries); + return dbService.getWorld(num); + } + + @Get("/fortunes") + public FortuneTemplate handleFortunes() throws SQLException { + List fortuneList = dbService.getFortune(); + return new FortuneTemplate(fortuneList); + } + + @Get("/updates") + public List handleUpdates(String queries) throws SQLException { + int num = getBoundedRowNumber(queries); + return dbService.updateWorld(num); + } + + private static int getBoundedRowNumber(String number) { + int num; + try { + num = Integer.parseInt(number); + } catch (NumberFormatException e) { + num = MIN_QUERIES; + } + return Math.max(MIN_QUERIES, Math.min(num, MAX_QUERIES)); + } +} diff --git a/frameworks/Java/avaje-jex/src/main/java/benchmark/Main.java b/frameworks/Java/avaje-jex/src/main/java/benchmark/Main.java new file mode 100644 index 00000000000..88666251bf5 --- /dev/null +++ b/frameworks/Java/avaje-jex/src/main/java/benchmark/Main.java @@ -0,0 +1,27 @@ +package benchmark; + +import io.avaje.inject.BeanScope; +import io.avaje.jex.Jex; +import io.avaje.jex.Routing.HttpService; +import io.avaje.jsonb.Jsonb; +import io.avaje.jsonb.Types; +import java.util.Map; + +public class Main { + + public static void main(String[] args) { + + var beans = BeanScope.builder().build(); + var routes = beans.list(HttpService.class); + var type = Jsonb.builder().build().type(Types.mapOf(String.class)); + + Jex.create() + .config(c -> c.compression().disableCompression()) + .get("/plaintext", ctx -> ctx.text("Hello, World!")) + .get("/json", ctx -> ctx.jsonb(type, Map.of("message", "Hello, World!"))) + .before(ctx -> ctx.header("Server", "avaje-jex")) + .error(Exception.class, (ctx, _) -> ctx.status(503).text("503 Service Unavailable")) + .routing(routes) + .start(); + } +} diff --git a/frameworks/Java/avaje-jex/src/main/java/benchmark/model/Fortune.java b/frameworks/Java/avaje-jex/src/main/java/benchmark/model/Fortune.java new file mode 100644 index 00000000000..b582775b5e6 --- /dev/null +++ b/frameworks/Java/avaje-jex/src/main/java/benchmark/model/Fortune.java @@ -0,0 +1,6 @@ +package benchmark.model; + +import io.avaje.jsonb.Json; + +@Json +public record Fortune(int id, String message) {} diff --git a/frameworks/Java/avaje-jex/src/main/java/benchmark/model/FortuneTemplate.java b/frameworks/Java/avaje-jex/src/main/java/benchmark/model/FortuneTemplate.java new file mode 100644 index 00000000000..6de30cc4730 --- /dev/null +++ b/frameworks/Java/avaje-jex/src/main/java/benchmark/model/FortuneTemplate.java @@ -0,0 +1,7 @@ +package benchmark.model; + +import io.jstach.jstache.JStache; +import java.util.List; + +@JStache(path = "fortunes.mustache") +public record FortuneTemplate(List fortunes) {} diff --git a/frameworks/Java/avaje-jex/src/main/java/benchmark/model/World.java b/frameworks/Java/avaje-jex/src/main/java/benchmark/model/World.java new file mode 100644 index 00000000000..473d1bf6efd --- /dev/null +++ b/frameworks/Java/avaje-jex/src/main/java/benchmark/model/World.java @@ -0,0 +1,38 @@ +package benchmark.model; + +import io.avaje.jsonb.Json; + +@Json +public class World { + + private int id; + private int randomNumber; + + public World() {} + + public World(int id, int randomNumber) { + this.id = id; + this.randomNumber = randomNumber; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public int getRandomNumber() { + return randomNumber; + } + + public void setRandomNumber(int randomNumber) { + this.randomNumber = randomNumber; + } + + @Override + public String toString() { + return "World{" + "id=" + id + ", randomNumber=" + randomNumber + '}'; + } +} diff --git a/frameworks/Java/avaje-jex/src/main/java/benchmark/repository/DbService.java b/frameworks/Java/avaje-jex/src/main/java/benchmark/repository/DbService.java new file mode 100644 index 00000000000..551268734e2 --- /dev/null +++ b/frameworks/Java/avaje-jex/src/main/java/benchmark/repository/DbService.java @@ -0,0 +1,33 @@ +package benchmark.repository; + +import benchmark.model.Fortune; +import benchmark.model.World; +import java.sql.SQLException; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.ThreadLocalRandom; + +public interface DbService { + + int MIN_RANDOM_NUMBER = 1; + int MAX_RANDOM_NUMBER_PLUS_ONE = 10001; + int defaultFortuneId = 0; + String defaultFortuneMessage = "Additional fortune added at request time."; + + List getWorld(int num) throws SQLException; + + List getFortune() throws SQLException; + + List updateWorld(int num) throws SQLException; + + default int getRandomNumber() { + return ThreadLocalRandom.current().nextInt(MIN_RANDOM_NUMBER, MAX_RANDOM_NUMBER_PLUS_ONE); + } + + default Set getRandomNumberSet(int num) { + Set set = new HashSet<>(); + while (set.size() < num) set.add(getRandomNumber()); + return set; + } +} diff --git a/frameworks/Java/avaje-jex/src/main/java/benchmark/repository/HikariFactory.java b/frameworks/Java/avaje-jex/src/main/java/benchmark/repository/HikariFactory.java new file mode 100644 index 00000000000..bcd9e24a1dd --- /dev/null +++ b/frameworks/Java/avaje-jex/src/main/java/benchmark/repository/HikariFactory.java @@ -0,0 +1,43 @@ +package benchmark.repository; + +import com.zaxxer.hikari.HikariConfig; +import com.zaxxer.hikari.HikariDataSource; +import io.avaje.config.Config; +import io.avaje.inject.Bean; +import io.avaje.inject.Factory; +import java.util.concurrent.Executors; +import javax.sql.DataSource; + +@Factory +public class HikariFactory { + + @Bean + DataSource dataSource() { + int maxPoolSize; + var env = System.getenv("BENCHMARK_ENV"); + if (Config.get("physicalTag").equals(env)) { + maxPoolSize = Config.getInt("postgresPhysicalPoolSize"); + } else if (Config.get("cloudTag").equals(env)) { + maxPoolSize = Config.getInt("postgresCloudPoolSize"); + } else { + maxPoolSize = Config.getInt("postgresDefaultPoolSize"); + } + + maxPoolSize = Math.max(maxPoolSize, Runtime.getRuntime().availableProcessors() * 2); + HikariConfig hikariConfig = new HikariConfig("hikari.properties"); + + var vtThreadFactory = Thread.ofVirtual().factory(); + hikariConfig.setThreadFactory(vtThreadFactory); + hikariConfig.setScheduledExecutor( + Executors.newScheduledThreadPool(maxPoolSize, vtThreadFactory)); + + // data source properties + hikariConfig.addDataSourceProperty("cachePrepStmts", "true"); + hikariConfig.addDataSourceProperty("prepStmtCacheSize", "250"); + hikariConfig.addDataSourceProperty("prepStmtCacheSqlLimit", "2048"); + hikariConfig.addDataSourceProperty("ssl", "false"); + hikariConfig.addDataSourceProperty("tcpKeepAlive", "true"); + hikariConfig.setMaximumPoolSize(maxPoolSize); + return new HikariDataSource(hikariConfig); + } +} diff --git a/frameworks/Java/avaje-jex/src/main/java/benchmark/repository/JDBCDbService.java b/frameworks/Java/avaje-jex/src/main/java/benchmark/repository/JDBCDbService.java new file mode 100644 index 00000000000..8cf49d5223a --- /dev/null +++ b/frameworks/Java/avaje-jex/src/main/java/benchmark/repository/JDBCDbService.java @@ -0,0 +1,93 @@ +package benchmark.repository; + +import benchmark.model.Fortune; +import benchmark.model.World; +import jakarta.inject.Singleton; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import javax.sql.DataSource; + +@Singleton +public class JDBCDbService implements DbService { + + private final DataSource datasource; + + public JDBCDbService(DataSource connectionFactory) { + this.datasource = connectionFactory; + } + + @Override + public List getWorld(int num) throws SQLException { + + String select = "select id, randomNumber from World where id = ?"; + List worldList = new ArrayList<>(); + + try (Connection conn = datasource.getConnection(); + PreparedStatement pstm = conn.prepareStatement(select)) { + + for (int randomId : getRandomNumberSet(num)) { + pstm.setInt(1, randomId); + try (ResultSet rs = pstm.executeQuery()) { + rs.next(); + worldList.add(new World(rs.getInt("id"), rs.getInt("randomNumber"))); + } + } + } + + return worldList; + } + + @Override + public List getFortune() throws SQLException { + + String select = "select id, message from Fortune"; + List fortuneList = new ArrayList<>(); + + try (Connection conn = datasource.getConnection(); + PreparedStatement pstm = conn.prepareStatement(select); + ResultSet rs = pstm.executeQuery()) { + + while (rs.next()) { + fortuneList.add(new Fortune(rs.getInt(1), rs.getString(2))); + } + fortuneList.add(new Fortune(defaultFortuneId, defaultFortuneMessage)); + } + + fortuneList.sort(Comparator.comparing(Fortune::message)); + return fortuneList; + } + + @Override + public List updateWorld(int num) throws SQLException { + + String update = "update World set randomNumber = ? where id = ?"; + List worldList = getWorld(num); + + try (Connection conn = datasource.getConnection(); + PreparedStatement pstm = conn.prepareStatement(update)) { + + conn.setAutoCommit(false); + for (World world : worldList) { + int newRandomNumber; + do { + newRandomNumber = getRandomNumber(); + } while (newRandomNumber == world.getRandomNumber()); + + pstm.setInt(1, newRandomNumber); + pstm.setInt(2, world.getId()); + pstm.addBatch(); + + world.setRandomNumber(newRandomNumber); + } + pstm.executeBatch(); + conn.commit(); + } + + return worldList; + } +} diff --git a/frameworks/Java/avaje-jex/src/main/java/module-info.java b/frameworks/Java/avaje-jex/src/main/java/module-info.java new file mode 100644 index 00000000000..342462fdb08 --- /dev/null +++ b/frameworks/Java/avaje-jex/src/main/java/module-info.java @@ -0,0 +1,19 @@ +module avaje.techempower { + // jdk.httpserver wrapper + requires jdk.httpserver; + requires io.avaje.jex; + /// Postgres driver and pool + requires java.sql; + requires org.postgresql.jdbc; + requires com.zaxxer.hikari; + // template engine + requires io.jstach.jstachio; + /// Configuration + requires io.avaje.config; + // controller generation + requires io.avaje.http.api; + /// Dependency Injection + requires io.avaje.inject; + /// Json + requires io.avaje.jsonb; +} diff --git a/frameworks/Java/avaje-jex/src/main/resources/application.properties b/frameworks/Java/avaje-jex/src/main/resources/application.properties new file mode 100644 index 00000000000..5976084e167 --- /dev/null +++ b/frameworks/Java/avaje-jex/src/main/resources/application.properties @@ -0,0 +1,6 @@ +physicalTag=Citrine +cloudTag=Azure + +postgresPhysicalPoolSize=64 +postgresCloudPoolSize=16 +postgresDefaultPoolSize=10 \ No newline at end of file diff --git a/frameworks/Java/avaje-jex/src/main/resources/fortunes.mustache b/frameworks/Java/avaje-jex/src/main/resources/fortunes.mustache new file mode 100644 index 00000000000..ec4599da71f --- /dev/null +++ b/frameworks/Java/avaje-jex/src/main/resources/fortunes.mustache @@ -0,0 +1,20 @@ + + + + Fortunes + + + + + + + + {{#fortunes}} + + + + + {{/fortunes}} +
idmessage
{{id}}{{message}}
+ + \ No newline at end of file diff --git a/frameworks/Java/avaje-jex/src/main/resources/hikari.properties b/frameworks/Java/avaje-jex/src/main/resources/hikari.properties new file mode 100644 index 00000000000..85001e992ba --- /dev/null +++ b/frameworks/Java/avaje-jex/src/main/resources/hikari.properties @@ -0,0 +1,7 @@ +jdbcUrl=jdbc:postgresql://tfb-database:5432/hello_world +dataSource.serverName=tfb-database +dataSource.portNumber=5432 +dataSource.user=benchmarkdbuser +dataSource.password=benchmarkdbpass +dataSource.databaseName=hello_world + diff --git a/frameworks/Java/baratine/README.md b/frameworks/Java/baratine/README.md index ac2a02a2563..6f1616520ce 100644 --- a/frameworks/Java/baratine/README.md +++ b/frameworks/Java/baratine/README.md @@ -13,7 +13,7 @@ This is the Baratine portion of a [benchmarking test suite](../) comparing a var ## Software Versions * [Java OpenJDK 1.8](http://openjdk.java.net/) -* [Baratine 0.11.0](http://baratine.io/) +* [Baratine 0.11.0](https://github.com/baratine/baratine) ## Test URLs diff --git a/frameworks/Java/bayou/pom.xml b/frameworks/Java/bayou/pom.xml index feee2d76073..638a06778e2 100644 --- a/frameworks/Java/bayou/pom.xml +++ b/frameworks/Java/bayou/pom.xml @@ -33,7 +33,7 @@ com.fasterxml.jackson.core jackson-databind - 2.13.4.2 + 2.16.0 diff --git a/frameworks/Java/comsat/README.md b/frameworks/Java/comsat/README.md deleted file mode 100644 index d30c5cdd7d4..00000000000 --- a/frameworks/Java/comsat/README.md +++ /dev/null @@ -1,39 +0,0 @@ -# Parallel Universe Comsat Benchmarking Test - -This is the [Parallel Universe Comsat](http://docs.paralleluniverse.co/comsat/#overview) version of a [benchmarking test suite](../) comparing a variety of web development platforms. It serves requests in lightweight [Quasar fibers](http://docs.paralleluniverse.co/quasar/#fibers) rather than heavyweight Java threads. There are two main flavors: Comsat Servlet and Comsat Web Actors. - -## Comsat Servlet - -[Parallel Universe Comsat Servlet](http://docs.paralleluniverse.co/comsat/#servlets) works with any servlet containers (tests are run against embedded Undertow and Jetty). - -### JSON Encoding and Plaintext Tests - -* [JSON test source](src/main/java/hello/servlet/JsonServlet.java) -* [Plaintext test source](src/main/java/hello/servlet/PlaintextServlet.java) - -## Comsat Web Actors - -[Parallel Universe Comsat Web Actors](http://docs.paralleluniverse.co/comsat/#web-actors) runs as an Undertow or Netty handler. - -### JSON and Plaintest Encoding Tests - -* [JSON test source](src/main/java/hello/webactors/HelloWebActor.java) - -## Versions - -* Jackson JSON 2.7.4 (https://github.com/FasterXML/jackson) -* Quasar 0.7.5 (http://docs.paralleluniverse.co/quasar) -* Comsat 0.7.0 (http://docs.paralleluniverse.co/comsat) -* Jetty 9.3.9.v20160517 (https://www.eclipse.org/jetty/) -* Netty 4.0.36.Final (http://netty.io/) -* Undertow 1.3.22-final (http://undertow.io) - -## Test URLs - -### JSON Encoding Test - - http://localhost:8080/json - -### Plaintest - - http://localhost:8080/plaintest diff --git a/frameworks/Java/comsat/benchmark_config.json b/frameworks/Java/comsat/benchmark_config.json deleted file mode 100644 index e6c79e87238..00000000000 --- a/frameworks/Java/comsat/benchmark_config.json +++ /dev/null @@ -1,83 +0,0 @@ -{ - "framework": "comsat", - "tests": [ - { - "default": { - "json_url": "/json", - "plaintext_url": "/plaintext", - "port": 8080, - "approach": "Realistic", - "classification": "Platform", - "database": "None", - "framework": "None", - "language": "Java", - "flavor": "None", - "orm": "Raw", - "platform": "Servlet", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "comsat-servlet-jetty", - "notes": "Comsat servlet on embedded Jetty", - "versus": "" - }, - "servlet-undertow": { - "json_url": "/json", - "plaintext_url": "/plaintext", - "port": 8080, - "approach": "Realistic", - "classification": "Platform", - "database": "None", - "framework": "None", - "language": "Java", - "flavor": "None", - "orm": "Raw", - "platform": "Servlet", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "Comsat", - "notes": "Comsat servlet on embedded Undertow", - "versus": "comsat" - }, - "webactors-netty": { - "json_url": "/json", - "plaintext_url": "/plaintext", - "port": 8080, - "approach": "Realistic", - "classification": "Platform", - "database": "None", - "framework": "None", - "language": "Java", - "flavor": "None", - "orm": "Raw", - "platform": "Comsat", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "Comsat", - "notes": "Comsat Web Actors run as Netty handler", - "versus": "" - }, - "webactors-undertow": { - "json_url": "/json", - "plaintext_url": "/plaintext", - "port": 8080, - "approach": "Realistic", - "classification": "Platform", - "database": "None", - "framework": "None", - "language": "Java", - "flavor": "None", - "orm": "Raw", - "platform": "Comsat", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "Comsat", - "notes": "Comsat Web Actors run as Undertow handler", - "versus": "comsat-webactors-netty" - } - } - ] -} diff --git a/frameworks/Java/comsat/build.gradle b/frameworks/Java/comsat/build.gradle deleted file mode 100644 index 89bc28d3dc5..00000000000 --- a/frameworks/Java/comsat/build.gradle +++ /dev/null @@ -1,100 +0,0 @@ -// Capsule plugin -plugins { - id "us.kirchmeier.capsule" version "1.0.2" -} - -apply plugin: 'java' - -sourceCompatibility = 1.8 -targetCompatibility = 1.8 - -version = '0.3' - -ext.jacksonVer = '2.9.9' -ext.quasarVer = '0.7.5' -ext.comsatVer = '0.7.0' -ext.capsuleVer = '1.0.2' - -ext.jettyVer = '9.3.9.v20160517' -ext.undertowVer = '1.3.22.Final' -ext.nettyVer = '4.0.37.Final' - -ext.slf4jVer = '1.7.21' - -[compileJava, compileTestJava]*.options*.encoding = "UTF-8" - -repositories { - mavenCentral() - maven { url 'https://oss.sonatype.org/content/repositories/snapshots' } - // mavenLocal() -} - -configurations { - quasar -} - -configurations.all { - resolutionStrategy { - failOnVersionConflict() - force "org.eclipse.jetty:jetty-util:$jettyVer" - force "org.eclipse.jetty:jetty-io:$jettyVer" - force "org.eclipse.jetty:jetty-http:$jettyVer" - force "org.eclipse.jetty:jetty-server:$jettyVer" - force "org.eclipse.jetty:jetty-servlet:$jettyVer" - force "org.eclipse.jetty:jetty-webapp:$jettyVer" - force "org.eclipse.jetty:jetty-xml:$jettyVer" - force "org.eclipse.jetty.websocket:websocket-server:$jettyVer" - force "org.eclipse.jetty.websocket:websocket-servlet:$jettyVer" - force "org.eclipse.jetty.websocket:websocket-client:$jettyVer" - force "io.undertow:undertow-core:$undertowVer" - force "io.undertow:undertow-servlet:$undertowVer" - force "io.netty:netty-all:$nettyVer" - force "org.slf4j:slf4j-api:$slf4jVer" - force "co.paralleluniverse:quasar-actors:$quasarVer" - } -} - -configurations.capsule.dependencies.clear() - -dependencies { - compile "co.paralleluniverse:quasar-core:$quasarVer:jdk8" - compile "com.fasterxml.jackson.core:jackson-databind:$jacksonVer" - compile "co.paralleluniverse:comsat-servlet:$comsatVer" - compile "co.paralleluniverse:comsat-test-utils:$comsatVer" - compile "co.paralleluniverse:comsat-actors-api:$comsatVer" - compile "co.paralleluniverse:comsat-actors-netty:$comsatVer" - compile "co.paralleluniverse:comsat-actors-undertow:$comsatVer" - compile "co.paralleluniverse:comsat-test-utils:$comsatVer" - - capsule "co.paralleluniverse:capsule:$capsuleVer" - - quasar "co.paralleluniverse:quasar-core:$quasarVer:jdk8" -} - -task capsule(type: FatCapsule) { - applicationClass "hello.World" - - capsuleManifest { - javaAgents = [configurations.quasar.iterator().next().getName()] - - mode('servlet-undertow') { - systemProperties['serverClass'] = 'hello.servlet.UndertowServer' - } - - mode('servlet-jetty') { - systemProperties['serverClass'] = 'hello.servlet.JettyServer' - } - - mode('webactors-netty') { - systemProperties['serverClass'] = 'hello.webactors.NettyServer' - } - - mode('webactors-undertow') { - systemProperties['serverClass'] = 'hello.webactors.UndertowServer' - } - } -} - -task wrapper(type: Wrapper) { - gradleVersion = '2.14' -} diff --git a/frameworks/Java/comsat/comsat-servlet-undertow.dockerfile b/frameworks/Java/comsat/comsat-servlet-undertow.dockerfile deleted file mode 100644 index 75468d15b33..00000000000 --- a/frameworks/Java/comsat/comsat-servlet-undertow.dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM gradle:4.7.0-jdk8 as gradle -USER root -WORKDIR /comsat -COPY build.gradle build.gradle -COPY src src -RUN gradle capsule -q - -FROM openjdk:8-jre-slim -WORKDIR /comsat -COPY --from=gradle /comsat/build/libs/comsat-0.3-capsule.jar app.jar - -EXPOSE 8080 - -CMD ["java", "-Dcapsule.mode=servlet-undertow", "-jar", "app.jar"] diff --git a/frameworks/Java/comsat/comsat-webactors-netty.dockerfile b/frameworks/Java/comsat/comsat-webactors-netty.dockerfile deleted file mode 100644 index 35868380185..00000000000 --- a/frameworks/Java/comsat/comsat-webactors-netty.dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM gradle:4.7.0-jdk8 as gradle -USER root -WORKDIR /comsat -COPY build.gradle build.gradle -COPY src src -RUN gradle capsule -q - -FROM openjdk:8-jre-slim -WORKDIR /comsat -COPY --from=gradle /comsat/build/libs/comsat-0.3-capsule.jar app.jar - -EXPOSE 8080 - -CMD ["java", "-Dcapsule.mode=webactors-netty", "-jar", "app.jar"] diff --git a/frameworks/Java/comsat/comsat-webactors-undertow.dockerfile b/frameworks/Java/comsat/comsat-webactors-undertow.dockerfile deleted file mode 100644 index 482244a4415..00000000000 --- a/frameworks/Java/comsat/comsat-webactors-undertow.dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM gradle:4.7.0-jdk8 as gradle -USER root -WORKDIR /comsat -COPY build.gradle build.gradle -COPY src src -RUN gradle capsule -q - -FROM openjdk:8-jre-slim -WORKDIR /comsat -COPY --from=gradle /comsat/build/libs/comsat-0.3-capsule.jar app.jar - -EXPOSE 8080 - -CMD ["java", "-Dcapsule.mode=webactors-undertow", "-jar", "app.jar"] diff --git a/frameworks/Java/comsat/comsat.dockerfile b/frameworks/Java/comsat/comsat.dockerfile deleted file mode 100644 index d3b4d40cc6b..00000000000 --- a/frameworks/Java/comsat/comsat.dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM gradle:4.7.0-jdk8 as gradle -USER root -WORKDIR /comsat -COPY build.gradle build.gradle -COPY src src -RUN gradle capsule -q - -FROM openjdk:8-jre-slim -WORKDIR /comsat -COPY --from=gradle /comsat/build/libs/comsat-0.3-capsule.jar app.jar - -EXPOSE 8080 - -CMD ["java", "-Dcapsule.mode=servlet-jetty", "-jar", "app.jar"] diff --git a/frameworks/Java/comsat/config.toml b/frameworks/Java/comsat/config.toml deleted file mode 100644 index ab16ef16e3b..00000000000 --- a/frameworks/Java/comsat/config.toml +++ /dev/null @@ -1,54 +0,0 @@ -[framework] -name = "comsat" - -[main] -urls.plaintext = "/plaintext" -urls.json = "/json" -approach = "Realistic" -classification = "Platform" -database = "None" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "Servlet" -webserver = "None" -versus = "" - -[servlet-undertow] -urls.plaintext = "/plaintext" -urls.json = "/json" -approach = "Realistic" -classification = "Platform" -database = "None" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "Servlet" -webserver = "None" -versus = "comsat" - -[webactors-netty] -urls.plaintext = "/plaintext" -urls.json = "/json" -approach = "Realistic" -classification = "Platform" -database = "None" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "Comsat" -webserver = "None" -versus = "" - -[webactors-undertow] -urls.plaintext = "/plaintext" -urls.json = "/json" -approach = "Realistic" -classification = "Platform" -database = "None" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "Comsat" -webserver = "None" -versus = "comsat-webactors-netty" diff --git a/frameworks/Java/comsat/src/main/java/hello/Server.java b/frameworks/Java/comsat/src/main/java/hello/Server.java deleted file mode 100644 index 9b7c04de733..00000000000 --- a/frameworks/Java/comsat/src/main/java/hello/Server.java +++ /dev/null @@ -1,6 +0,0 @@ -package hello; - -@FunctionalInterface -public interface Server { - void run() throws Exception; -} diff --git a/frameworks/Java/comsat/src/main/java/hello/World.java b/frameworks/Java/comsat/src/main/java/hello/World.java deleted file mode 100644 index 22f147b0470..00000000000 --- a/frameworks/Java/comsat/src/main/java/hello/World.java +++ /dev/null @@ -1,10 +0,0 @@ -package hello; - -public final class World { - public static void main(String[] args) throws Exception { - final Server s = (Server) Class.forName(System.getProperty("serverClass", "hello.JettyServer")).newInstance(); - s.run(); - } - - private World() {} -} diff --git a/frameworks/Java/comsat/src/main/java/hello/servlet/JettyServer.java b/frameworks/Java/comsat/src/main/java/hello/servlet/JettyServer.java deleted file mode 100644 index a55985bd8b3..00000000000 --- a/frameworks/Java/comsat/src/main/java/hello/servlet/JettyServer.java +++ /dev/null @@ -1,46 +0,0 @@ -package hello.servlet; - -import hello.Server; -import co.paralleluniverse.embedded.containers.AbstractEmbeddedServer; - -import org.eclipse.jetty.server.ServerConnector; -import org.eclipse.jetty.servlet.ServletContextHandler; -import org.eclipse.jetty.servlet.ServletHolder; -import org.eclipse.jetty.util.thread.QueuedThreadPool; - -/** - * An implementation of the TechEmpower benchmark tests using Comsat servlets and the Jetty servlet container. - */ -public final class JettyServer implements Server { - @Override - public final void run() throws Exception { - final org.eclipse.jetty.server.Server s = new org.eclipse.jetty.server.Server(new QueuedThreadPool(200, Runtime.getRuntime().availableProcessors())); - - final ServerConnector http = new ServerConnector(s); - http.setReuseAddress(true); - http.setAcceptQueueSize(100000); - http.setPort(8080); - s.addConnector(http); - - final ServletContextHandler context = new ServletContextHandler(); - context.setContextPath("/"); - - final ServletHolder holder1 = new ServletHolder(new PlaintextServlet()); - context.addServlet(holder1, "/plaintext"); - holder1.setAsyncSupported(true); - final ServletHolder holder2 = new ServletHolder(new JsonServlet()); - context.addServlet(holder2, "/json"); - holder2.setAsyncSupported(true); - - s.setHandler(context); - - s.start(); - System.err.println("Server is up."); - - AbstractEmbeddedServer.waitUrlAvailable("http://localhost:8080/plaintext"); - AbstractEmbeddedServer.waitUrlAvailable("http://localhost:8080/json"); - System.err.println("Server test cases are instrumented and bootstrapped."); - - s.join(); - } -} diff --git a/frameworks/Java/comsat/src/main/java/hello/servlet/JsonServlet.java b/frameworks/Java/comsat/src/main/java/hello/servlet/JsonServlet.java deleted file mode 100644 index 86cb5957058..00000000000 --- a/frameworks/Java/comsat/src/main/java/hello/servlet/JsonServlet.java +++ /dev/null @@ -1,30 +0,0 @@ -package hello.servlet; - -import co.paralleluniverse.fibers.Suspendable; -import co.paralleluniverse.fibers.servlet.FiberHttpServlet; - -import com.fasterxml.jackson.databind.ObjectMapper; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import java.io.IOException; - -@SuppressWarnings("serial") -public final class JsonServlet extends FiberHttpServlet { - private static final class HelloWorldData { - @SuppressWarnings("unused") - public final String message = "Hello, World!"; - } - - private static final ObjectMapper mapper = new ObjectMapper(); - - @Override - @Suspendable - protected final void doGet(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException { - resp.setContentType("application/json"); - resp.setHeader("Server", "comsat-servlet-undertow"); - mapper.writeValue(resp.getOutputStream(), new HelloWorldData()); - } -} diff --git a/frameworks/Java/comsat/src/main/java/hello/servlet/PlaintextServlet.java b/frameworks/Java/comsat/src/main/java/hello/servlet/PlaintextServlet.java deleted file mode 100644 index d42d4749f03..00000000000 --- a/frameworks/Java/comsat/src/main/java/hello/servlet/PlaintextServlet.java +++ /dev/null @@ -1,24 +0,0 @@ -package hello.servlet; - -import co.paralleluniverse.fibers.Suspendable; -import co.paralleluniverse.fibers.servlet.FiberHttpServlet; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import java.io.IOException; -import java.nio.charset.StandardCharsets; - -@SuppressWarnings("serial") -public final class PlaintextServlet extends FiberHttpServlet { - private static final byte[] helloWorld = "Hello, World!".getBytes(StandardCharsets.ISO_8859_1); - - @Override - @Suspendable - protected final void doGet(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException { - resp.setContentType("text/plain"); - resp.setHeader("Server", "comsat-servlet-undertow"); - resp.getOutputStream().write(helloWorld); - } -} diff --git a/frameworks/Java/comsat/src/main/java/hello/servlet/UndertowServer.java b/frameworks/Java/comsat/src/main/java/hello/servlet/UndertowServer.java deleted file mode 100644 index 3b14f754015..00000000000 --- a/frameworks/Java/comsat/src/main/java/hello/servlet/UndertowServer.java +++ /dev/null @@ -1,101 +0,0 @@ -package hello.servlet; - -import co.paralleluniverse.embedded.containers.AbstractEmbeddedServer; -import hello.Server; -import io.undertow.Undertow; -import io.undertow.UndertowOptions; -import io.undertow.server.HttpHandler; -import io.undertow.servlet.Servlets; -import io.undertow.servlet.api.DeploymentInfo; -import io.undertow.servlet.api.DeploymentManager; - -import org.xnio.Options; - -import java.io.IOException; - -/** - * An implementation of the TechEmpower benchmark tests using Comsat servlets and the Undertow servlet container. - */ -public final class UndertowServer implements Server { - @Override - public final void run() throws Exception { - final DeploymentInfo deployment = Servlets.deployment().setDeploymentName("") - .setClassLoader(ClassLoader.getSystemClassLoader()) - .setContextPath("/"); - - deployment.addServlet(Servlets.servlet("plaintext", PlaintextServlet.class).addMapping("/plaintext").setAsyncSupported(true)); - deployment.addServlet(Servlets.servlet("json", JsonServlet.class).addMapping("/json").setAsyncSupported(true)); - - final DeploymentManager servletsContainer = Servlets.defaultContainer().addDeployment(deployment); - - servletsContainer.deploy(); - - final HttpHandler handler = servletsContainer.start(); - - //noinspection deprecation - final Undertow server = Undertow.builder() - .setHandler(handler) - .setDirectBuffers(true) - - .setIoThreads(100) - .setWorkerThreads(100) - - .setServerOption(Options.CONNECTION_HIGH_WATER, 100_000) - .setServerOption(Options.CONNECTION_LOW_WATER, 100_000) - - .setBufferSize(1024) - .setBuffersPerRegion(100) - - // .setSocketOption(Options.ALLOW_BLOCKING, true) - .setSocketOption(Options.REUSE_ADDRESSES, true) - // .setSocketOption(Options.CORK, true) - // .setSocketOption(Options.USE_DIRECT_BUFFERS, true) - .setSocketOption(Options.BACKLOG, 100000) - .setSocketOption(Options.TCP_NODELAY, true) - // .setSocketOption(Options.RECEIVE_BUFFER, 2048) - // .setSocketOption(Options.SEND_BUFFER, 2048) - // .setSocketOption(Options.CONNECTION_HIGH_WATER, Integer.MAX_VALUE) - // .setSocketOption(Options.CONNECTION_LOW_WATER, Integer.MAX_VALUE) - // .setSocketOption(Options.READ_TIMEOUT, Integer.MAX_VALUE) - // .setSocketOption(Options.WRITE_TIMEOUT, Integer.MAX_VALUE) - // .setServerOption(UndertowOptions.ALWAYS_SET_KEEP_ALIVE, false) //don't send a keep-alive header for HTTP/1.1 requests, as it is not required - - // .setServerOption(UndertowOptions.ALWAYS_SET_DATE, true) - .setServerOption(UndertowOptions.ENABLE_CONNECTOR_STATISTICS, false) - .setServerOption(UndertowOptions.RECORD_REQUEST_START_TIME, false) - - .addHttpListener(8080, "0.0.0.0") - .build(); - - server.start(); - - System.err.println("Server is up."); - - Runtime.getRuntime().addShutdownHook(new Thread() { - @Override - public final void run() { - try { - server.stop(); - - System.err.println("Server is down."); - } catch (final Exception e) { - throw new RuntimeException(e); - } - } - }); - - new Thread() { - @Override - public final void run() { - try { - AbstractEmbeddedServer.waitUrlAvailable("http://localhost:8080/plaintext"); - AbstractEmbeddedServer.waitUrlAvailable("http://localhost:8080/json"); - - System.err.println("Server test cases are instrumented and bootstrapped."); - } catch (final InterruptedException | IOException e) { - throw new RuntimeException(e); - } - } - }.start(); - } -} diff --git a/frameworks/Java/comsat/src/main/java/hello/webactors/NettyServer.java b/frameworks/Java/comsat/src/main/java/hello/webactors/NettyServer.java deleted file mode 100644 index 46ceca57efd..00000000000 --- a/frameworks/Java/comsat/src/main/java/hello/webactors/NettyServer.java +++ /dev/null @@ -1,68 +0,0 @@ -package hello.webactors; - -import co.paralleluniverse.comsat.webactors.netty.AutoWebActorHandler; -import co.paralleluniverse.embedded.containers.AbstractEmbeddedServer; -import hello.Server; -import io.netty.bootstrap.ServerBootstrap; -import io.netty.buffer.PooledByteBufAllocator; -import io.netty.channel.*; -import io.netty.channel.nio.NioEventLoopGroup; -import io.netty.channel.socket.SocketChannel; -import io.netty.channel.socket.nio.NioServerSocketChannel; -import io.netty.handler.codec.http.HttpObjectAggregator; -import io.netty.handler.codec.http.HttpRequestDecoder; -import io.netty.handler.codec.http.HttpResponseEncoder; - -import java.util.Map; -import java.util.concurrent.Callable; - -public final class NettyServer implements Server { - @Override - public final void run() throws Exception { - WebActor.SERVER = "comsat-webactors-netty"; - final ServerBootstrap b = new ServerBootstrap(); - - b.option(ChannelOption.SO_BACKLOG, 100000); - b.childOption(ChannelOption.CONNECT_TIMEOUT_MILLIS, 0); - b.childOption(ChannelOption.TCP_NODELAY, true); - b.childOption(ChannelOption.SO_REUSEADDR, true); - b.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT); - - final ChannelInitializer childHandler = new SocketChannelChannelInitializer(() -> new AutoWebActorHandler() { - @Override - protected AutoContextProvider newContextProvider(ClassLoader userClassLoader, Map, Object[]> actorParams) { - return new AutoContextProvider(userClassLoader, actorParams, 1_000_000L /* ms */); - } - }); - final NioEventLoopGroup group = new NioEventLoopGroup(200); - b.group(group) - .channel(NioServerSocketChannel.class) - .childHandler(childHandler); - - final ChannelFuture cf = b.bind(8080); - cf.sync(); - - System.err.println("Server is up."); - - AbstractEmbeddedServer.waitUrlAvailable("http://localhost:8080/plaintext"); - AbstractEmbeddedServer.waitUrlAvailable("http://localhost:8080/json"); - System.err.println("Server test cases are instrumented and bootstrapped."); - } - - private static final class SocketChannelChannelInitializer extends ChannelInitializer { - private final Callable> handlerProvider; - - public SocketChannelChannelInitializer(Callable> handlerProvider) { - this.handlerProvider = handlerProvider; - } - - @Override - public final void initChannel(SocketChannel ch) throws Exception { - final ChannelPipeline pipeline = ch.pipeline(); - pipeline.addLast(new HttpRequestDecoder()); - pipeline.addLast(new HttpResponseEncoder()); - pipeline.addLast(new HttpObjectAggregator(65536)); - pipeline.addLast(handlerProvider.call()); - } - } -} diff --git a/frameworks/Java/comsat/src/main/java/hello/webactors/UndertowServer.java b/frameworks/Java/comsat/src/main/java/hello/webactors/UndertowServer.java deleted file mode 100644 index cb86911ebd3..00000000000 --- a/frameworks/Java/comsat/src/main/java/hello/webactors/UndertowServer.java +++ /dev/null @@ -1,57 +0,0 @@ -package hello.webactors; - -import co.paralleluniverse.comsat.webactors.undertow.AutoWebActorHandler; -import co.paralleluniverse.embedded.containers.AbstractEmbeddedServer; -import hello.Server; -import io.undertow.Undertow; -import io.undertow.UndertowOptions; - -import org.xnio.Options; - -public final class UndertowServer implements Server { - @Override - public final void run() throws Exception { - WebActor.SERVER = "comsat-webactors-undertow"; - //noinspection deprecation - final Undertow u = io.undertow.Undertow.builder() - .setHandler(new AutoWebActorHandler()) - - .setIoThreads(100) - .setWorkerThreads(100) - .setServerOption(Options.CONNECTION_HIGH_WATER, 100_000) - .setServerOption(Options.CONNECTION_LOW_WATER, 100_000) - - .setDirectBuffers(true) - .setBufferSize(1024) - .setBuffersPerRegion(100) - - // .setSocketOption(Options.ALLOW_BLOCKING, true) - .setSocketOption(Options.REUSE_ADDRESSES, true) - // .setSocketOption(Options.CORK, true) - // .setSocketOption(Options.USE_DIRECT_BUFFERS, true) - .setSocketOption(Options.BACKLOG, 100000) - .setSocketOption(Options.TCP_NODELAY, true) - // .setSocketOption(Options.RECEIVE_BUFFER, 2048) - // .setSocketOption(Options.SEND_BUFFER, 2048) - // .setSocketOption(Options.CONNECTION_HIGH_WATER, Integer.MAX_VALUE) - // .setSocketOption(Options.CONNECTION_LOW_WATER, Integer.MAX_VALUE) - // .setSocketOption(Options.READ_TIMEOUT, Integer.MAX_VALUE) - // .setSocketOption(Options.WRITE_TIMEOUT, Integer.MAX_VALUE) - // .setServerOption(UndertowOptions.ALWAYS_SET_KEEP_ALIVE, false) //don't send a keep-alive header for HTTP/1.1 requests, as it is not required - - // .setServerOption(UndertowOptions.ALWAYS_SET_DATE, true) - .setServerOption(UndertowOptions.ENABLE_CONNECTOR_STATISTICS, false) - .setServerOption(UndertowOptions.RECORD_REQUEST_START_TIME, false) - - .addHttpListener(8080, "0.0.0.0") - .build(); - - new Thread(u::start).start(); - - System.err.println("Server is up."); - - AbstractEmbeddedServer.waitUrlAvailable("http://localhost:8080/plaintext"); - AbstractEmbeddedServer.waitUrlAvailable("http://localhost:8080/json"); - System.err.println("Server test cases are instrumented and bootstrapped."); - } -} diff --git a/frameworks/Java/comsat/src/main/java/hello/webactors/WebActor.java b/frameworks/Java/comsat/src/main/java/hello/webactors/WebActor.java deleted file mode 100644 index 8fb559ff3a6..00000000000 --- a/frameworks/Java/comsat/src/main/java/hello/webactors/WebActor.java +++ /dev/null @@ -1,57 +0,0 @@ -package hello.webactors; - -import co.paralleluniverse.actors.BasicActor; -import co.paralleluniverse.comsat.webactors.HttpRequest; -import co.paralleluniverse.comsat.webactors.HttpResponse; - -import co.paralleluniverse.fibers.SuspendExecution; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; - -import java.nio.ByteBuffer; - -import static co.paralleluniverse.comsat.webactors.HttpResponse.error; -import static co.paralleluniverse.comsat.webactors.HttpResponse.ok; - -@co.paralleluniverse.comsat.webactors.WebActor(httpUrlPatterns = {"/*"}) -public final class WebActor extends BasicActor { - static String SERVER = "comsat-webactors"; - - private static final String HELLO_WORLD = "Hello, World!"; - private static final byte[] HELLO_WORLD_A = HELLO_WORLD.getBytes(); - - private static final class HelloWorldData { - @SuppressWarnings("unused") - public final String message = HELLO_WORLD; - } - - private static final ObjectMapper mapper = new ObjectMapper(); - - @Override - protected final Void doRun() throws InterruptedException, SuspendExecution { - final Object message = receive(); - if (message instanceof HttpRequest) { - final HttpRequest req = (HttpRequest) message; - HttpResponse.Builder res; - final String s = req.getRequestURI(); - if ("/plaintext".equals(s)) { - final ByteBuffer b = ByteBuffer.wrap(HELLO_WORLD_A); - res = ok(self(), req, b).setContentType("text/plain"); - } else if ("/json".equals(s)) { - try { - res = ok(self(), req, mapper.writeValueAsString(new HelloWorldData())).setContentType("application/json"); - } catch (final JsonProcessingException e) { - throw new RuntimeException(e); - } - } else { - res = error(self(), req, 404, "Not found"); - } - req.getFrom().send ( - res - .addHeader("Server", SERVER) - .build() - ); - } - return null; - } -} diff --git a/frameworks/Java/dropwizard/dropwizard-jdbi-postgres.dockerfile b/frameworks/Java/dropwizard/dropwizard-jdbi-postgres.dockerfile index 21a897236d7..13b5b94ce53 100644 --- a/frameworks/Java/dropwizard/dropwizard-jdbi-postgres.dockerfile +++ b/frameworks/Java/dropwizard/dropwizard-jdbi-postgres.dockerfile @@ -4,7 +4,7 @@ COPY pom.xml pom.xml COPY src src RUN mvn package -q -P postgres,jdbi -FROM openjdk:11.0.3-jdk-slim +FROM amazoncorretto:25 WORKDIR /dropwizard COPY --from=maven /dropwizard/target/hello-world-0.0.1-SNAPSHOT.jar app.jar COPY hello-world-jdbi-postgres.yml hello-world-jdbi-postgres.yml diff --git a/frameworks/Java/dropwizard/dropwizard-mongodb.dockerfile b/frameworks/Java/dropwizard/dropwizard-mongodb.dockerfile index 1d13f4f9013..ce1fb9d4bbc 100644 --- a/frameworks/Java/dropwizard/dropwizard-mongodb.dockerfile +++ b/frameworks/Java/dropwizard/dropwizard-mongodb.dockerfile @@ -4,7 +4,7 @@ COPY pom.xml pom.xml COPY src src RUN mvn package -q -P mongo -FROM openjdk:11.0.3-jdk-slim +FROM amazoncorretto:25 WORKDIR /dropwizard COPY --from=maven /dropwizard/target/hello-world-0.0.1-SNAPSHOT.jar app.jar COPY hello-world-mongo.yml hello-world-mongo.yml diff --git a/frameworks/Java/dropwizard/dropwizard-postgres.dockerfile b/frameworks/Java/dropwizard/dropwizard-postgres.dockerfile index b088d2df510..25cb2080922 100644 --- a/frameworks/Java/dropwizard/dropwizard-postgres.dockerfile +++ b/frameworks/Java/dropwizard/dropwizard-postgres.dockerfile @@ -4,7 +4,7 @@ COPY pom.xml pom.xml COPY src src RUN mvn package -q -P postgres -FROM openjdk:11.0.3-jdk-slim +FROM amazoncorretto:25 WORKDIR /dropwizard COPY --from=maven /dropwizard/target/hello-world-0.0.1-SNAPSHOT.jar app.jar COPY hello-world-postgres.yml hello-world-postgres.yml diff --git a/frameworks/Java/dropwizard/dropwizard.dockerfile b/frameworks/Java/dropwizard/dropwizard.dockerfile index af3b49c8682..206455df590 100644 --- a/frameworks/Java/dropwizard/dropwizard.dockerfile +++ b/frameworks/Java/dropwizard/dropwizard.dockerfile @@ -4,7 +4,7 @@ COPY pom.xml pom.xml COPY src src RUN mvn package -q -P mysql -FROM openjdk:11.0.3-jdk-slim +FROM amazoncorretto:25 WORKDIR /dropwizard COPY --from=maven /dropwizard/target/hello-world-0.0.1-SNAPSHOT.jar app.jar COPY hello-world-mysql.yml hello-world-mysql.yml diff --git a/frameworks/Java/dropwizard/pom.xml b/frameworks/Java/dropwizard/pom.xml index 312ba647189..5188cb78b1c 100644 --- a/frameworks/Java/dropwizard/pom.xml +++ b/frameworks/Java/dropwizard/pom.xml @@ -19,7 +19,7 @@ 2.3.0 8.0.28 2.9.4 - 42.4.3 + 42.7.2 3.8.0 3.1.0 3.1.1 diff --git a/frameworks/Java/edap-http/edap-http-fast.dockerfile b/frameworks/Java/edap-http/edap-http-fast.dockerfile index 4142e4f5785..43c1cdfe073 100644 --- a/frameworks/Java/edap-http/edap-http-fast.dockerfile +++ b/frameworks/Java/edap-http/edap-http-fast.dockerfile @@ -1,13 +1,13 @@ -FROM maven:3.6.3-openjdk-8-slim as maven +FROM maven:3.9.11-amazoncorretto-21 as maven WORKDIR /edap-http COPY pom.xml pom.xml COPY src src RUN mvn compile assembly:single -q -FROM openjdk:8u275-jdk-slim +FROM amazoncorretto:21.0.8 WORKDIR /edap-http COPY --from=maven /edap-http/target/edap-http-benchmark-1.0-SNAPSHOT-jar-with-dependencies.jar app.jar EXPOSE 8080 -CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AggressiveOpts", "-Dedap.http.decoder.type=fast", "-cp", "app.jar", "io.edap.http.Bootstrap"] +CMD ["java", "-DlazyParseHeader=true", "-server", "--add-exports", "java.base/sun.security.action=ALL-UNNAMED", "--add-exports", "java.naming/com.sun.jndi.ldap=ALL-UNNAMED", "--add-exports", "java.naming/com.sun.jndi.url.ldap=ALL-UNNAMED", "--add-exports", "jdk.naming.dns/com.sun.jndi.dns=ALL-UNNAMED", "--add-exports", "jdk.naming.dns/com.sun.jndi.url.dns=ALL-UNNAMED", "--add-exports", "java.security.jgss/sun.security.krb5.internal=ALL-UNNAMED", "--add-exports", "jdk.attach/sun.tools.attach=ALL-UNNAMED", "--add-opens", "java.base/java.util=ALL-UNNAMED", "--add-opens", "java.base/java.lang=ALL-UNNAMED", "--add-opens", "java.base/java.util.concurrent=ALL-UNNAMED", "--add-opens", "java.base/java.io=ALL-UNNAMED", "--add-opens", "java.base/java.nio=ALL-UNNAMED", "--add-opens", "java.base/sun.nio.ch=ALL-UNNAMED", "--add-opens", "java.naming/javax.naming.spi=ALL-UNNAMED", "--add-opens", "java.naming/com.sun.naming.internal=ALL-UNNAMED", "--add-opens", "jdk.naming.rmi/com.sun.jndi.url.rmi=ALL-UNNAMED", "--add-opens", "java.naming/javax.naming=ALL-UNNAMED", "--add-opens", "java.rmi/java.rmi=ALL-UNNAMED", "--add-opens", "java.sql/java.sql=ALL-UNNAMED", "--add-opens", "java.management/javax.management=ALL-UNNAMED", "--add-opens", "java.base/java.lang.reflect=ALL-UNNAMED", "--add-opens", "java.desktop/java.awt.image=ALL-UNNAMED", "--add-opens", "java.base/java.security=ALL-UNNAMED", "--add-opens", "java.base/java.net=ALL-UNNAMED", "--add-opens", "java.base/java.text=ALL-UNNAMED", "--add-opens", "java.base/sun.net.www.protocol.https=ALL-UNNAMED", "--add-exports", "jdk.management.agent/jdk.internal.agent=ALL-UNNAMED", "--add-exports", "java.base/jdk.internal.vm=ALL-UNNAMED", "--add-opens", "java.base/java.lang.ref=ALL-UNNAMED", "--add-opens=java.rmi/sun.rmi.transport=ALL-UNNAMED", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-cp", "app.jar", "io.edap.http.Bootstrap"] diff --git a/frameworks/Java/edap-http/edap-http.dockerfile b/frameworks/Java/edap-http/edap-http.dockerfile index 9d20ae4ceab..2028d1c3939 100644 --- a/frameworks/Java/edap-http/edap-http.dockerfile +++ b/frameworks/Java/edap-http/edap-http.dockerfile @@ -1,13 +1,13 @@ -FROM maven:3.6.3-openjdk-8-slim as maven +FROM maven:3.9.11-amazoncorretto-21 as maven WORKDIR /edap-http COPY pom.xml pom.xml COPY src src RUN mvn compile assembly:single -q -FROM openjdk:8u275-jdk-slim +FROM amazoncorretto:21.0.8 WORKDIR /edap-http COPY --from=maven /edap-http/target/edap-http-benchmark-1.0-SNAPSHOT-jar-with-dependencies.jar app.jar EXPOSE 8080 -CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AggressiveOpts", "-cp", "app.jar", "io.edap.http.Bootstrap"] +CMD ["java", "-server", "--add-exports", "java.base/sun.security.action=ALL-UNNAMED", "--add-exports", "java.naming/com.sun.jndi.ldap=ALL-UNNAMED", "--add-exports", "java.naming/com.sun.jndi.url.ldap=ALL-UNNAMED", "--add-exports", "jdk.naming.dns/com.sun.jndi.dns=ALL-UNNAMED", "--add-exports", "jdk.naming.dns/com.sun.jndi.url.dns=ALL-UNNAMED", "--add-exports", "java.security.jgss/sun.security.krb5.internal=ALL-UNNAMED", "--add-exports", "jdk.attach/sun.tools.attach=ALL-UNNAMED", "--add-opens", "java.base/java.util=ALL-UNNAMED", "--add-opens", "java.base/java.lang=ALL-UNNAMED", "--add-opens", "java.base/java.util.concurrent=ALL-UNNAMED", "--add-opens", "java.base/java.io=ALL-UNNAMED", "--add-opens", "java.base/java.nio=ALL-UNNAMED", "--add-opens", "java.base/sun.nio.ch=ALL-UNNAMED", "--add-opens", "java.naming/javax.naming.spi=ALL-UNNAMED", "--add-opens", "java.naming/com.sun.naming.internal=ALL-UNNAMED", "--add-opens", "jdk.naming.rmi/com.sun.jndi.url.rmi=ALL-UNNAMED", "--add-opens", "java.naming/javax.naming=ALL-UNNAMED", "--add-opens", "java.rmi/java.rmi=ALL-UNNAMED", "--add-opens", "java.sql/java.sql=ALL-UNNAMED", "--add-opens", "java.management/javax.management=ALL-UNNAMED", "--add-opens", "java.base/java.lang.reflect=ALL-UNNAMED", "--add-opens", "java.desktop/java.awt.image=ALL-UNNAMED", "--add-opens", "java.base/java.security=ALL-UNNAMED", "--add-opens", "java.base/java.net=ALL-UNNAMED", "--add-opens", "java.base/java.text=ALL-UNNAMED", "--add-opens", "java.base/sun.net.www.protocol.https=ALL-UNNAMED", "--add-exports", "jdk.management.agent/jdk.internal.agent=ALL-UNNAMED", "--add-exports", "java.base/jdk.internal.vm=ALL-UNNAMED", "--add-opens", "java.base/java.lang.ref=ALL-UNNAMED", "--add-opens=java.rmi/sun.rmi.transport=ALL-UNNAMED", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-cp", "app.jar", "io.edap.http.Bootstrap"] diff --git a/frameworks/Java/edap-http/pom.xml b/frameworks/Java/edap-http/pom.xml index 9a9a52fe8c2..65b9af2fa54 100644 --- a/frameworks/Java/edap-http/pom.xml +++ b/frameworks/Java/edap-http/pom.xml @@ -11,52 +11,32 @@ UTF-8 - 8 - 8 - 8 - 8 + 21 + 21 + 21 + 21 0.1-SNAPSHOT - edapx + edap io.edap - ${edap.name}-http + ${edap.name}-http-server ${edap.version} - 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 - + ossrh + ossrh + https://central.sonatype.com/repository/maven-snapshots/ true - - + + @@ -67,8 +47,8 @@ 3.8.0 false - 8 - 8 + 21 + 21
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 3d177057454..74c331be93d 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 @@ -1,25 +1,32 @@ package io.edap.http; import io.edap.http.model.Message; -import io.edap.x.Edap; -import io.edap.x.http.HttpServer; -import io.edap.x.http.HttpServerBuilder; +import io.edap.Edap; +import io.edap.http.server.HttpServer; +import io.edap.http.server.HttpServerBuilder; import java.io.IOException; -import static io.edap.x.http.header.ContentType.JSON; -import static io.edap.x.http.header.ContentType.PLAIN; +import static io.edap.http.header.ContentTypeHeader.JSON; +import static io.edap.http.header.ContentTypeHeader.PLAIN; public class Bootstrap { static final byte[] PLAIN_TEXT_CONTENT = "Hello, World!".getBytes(); public static void main(String[] args) throws IOException { - + HttpHandleOption option = new HttpHandleOption(); + String lazyParseHeaderStr = System.getProperty("lazyParseHeader", "false"); + if (Boolean.parseBoolean(lazyParseHeaderStr)) { + option.setLazyParseHeader(true); + } HttpServer httpServer = new HttpServerBuilder() .listen(8080) - .req("/plaintext", (req, resp) -> resp.contentType(PLAIN).write(PLAIN_TEXT_CONTENT)) - .get("/json", (req, resp) -> resp.contentType(JSON).write(new Message("Hello, World!"))) + .req("/plaintext", (req, resp) -> + resp.contentType(PLAIN).write(PLAIN_TEXT_CONTENT), option) + .get("/json", (req, resp) -> { + resp.contentType(JSON).write(new Message("Hello, World!")); + }, option) .build(); Edap edap = new Edap(); edap.addServer(httpServer); diff --git a/frameworks/Java/gemini/benchmark_config.json b/frameworks/Java/gemini/benchmark_config.json index e4049a488c6..0f051744dfa 100644 --- a/frameworks/Java/gemini/benchmark_config.json +++ b/frameworks/Java/gemini/benchmark_config.json @@ -20,6 +20,7 @@ "database_os": "Linux", "display_name": "Gemini", "notes": "", + "tags": ["broken"], "versus": "servlet" }, "mysql": { @@ -42,6 +43,7 @@ "database_os": "Linux", "display_name": "Gemini", "notes": "", + "tags": ["broken"], "versus": "servlet" }, "postgres": { @@ -64,6 +66,7 @@ "database_os": "Linux", "display_name": "Gemini", "notes": "", + "tags": ["broken"], "versus": "servlet" } } diff --git a/frameworks/Java/gemini/servlet/pom.xml b/frameworks/Java/gemini/servlet/pom.xml index c1a1a797344..053c91c81df 100644 --- a/frameworks/Java/gemini/servlet/pom.xml +++ b/frameworks/Java/gemini/servlet/pom.xml @@ -29,7 +29,7 @@ org.postgresql postgresql - 42.2.5 + 42.7.2 com.techempower diff --git a/frameworks/Java/grizzly/pom.xml b/frameworks/Java/grizzly/pom.xml index 0cf5f082fd4..527560610b6 100644 --- a/frameworks/Java/grizzly/pom.xml +++ b/frameworks/Java/grizzly/pom.xml @@ -72,7 +72,7 @@ com.fasterxml.jackson.core jackson-databind - 2.13.4.2 + 2.16.0 diff --git a/frameworks/Java/helidon/helidon-nima.dockerfile b/frameworks/Java/helidon/helidon-nima.dockerfile index 94f67c40ffb..25278db67a9 100644 --- a/frameworks/Java/helidon/helidon-nima.dockerfile +++ b/frameworks/Java/helidon/helidon-nima.dockerfile @@ -1,17 +1,17 @@ -FROM docker.io/maven:3.9.2-eclipse-temurin-20 as maven +FROM docker.io/maven:3.9.6-eclipse-temurin-21 as maven WORKDIR /helidon COPY nima/src src COPY nima/pom.xml pom.xml RUN mvn package -q -FROM openjdk:20-jdk-slim +FROM openjdk:25-jdk-slim WORKDIR /helidon COPY --from=maven /helidon/target/libs libs COPY --from=maven /helidon/target/benchmark-nima.jar app.jar EXPOSE 8080 -CMD java --enable-preview \ - -XX:+UseNUMA \ +CMD java -XX:+UseNUMA \ + -server \ -XX:+UseParallelGC \ -jar app.jar diff --git a/frameworks/Java/helidon/nima/pom.xml b/frameworks/Java/helidon/nima/pom.xml index f558927de94..0d312c8eed8 100644 --- a/frameworks/Java/helidon/nima/pom.xml +++ b/frameworks/Java/helidon/nima/pom.xml @@ -21,7 +21,7 @@ io.helidon.applications helidon-se - 4.0.0-ALPHA6 + 4.1.5 @@ -33,25 +33,26 @@ io.helidon.benchmark.nima.Main - 20 + 21 3.11.0 1.3.0 - 4.4.2 + 4.5.3 0.9.23 + 3.1.15 - io.helidon.nima.webserver - helidon-nima-webserver + io.helidon.webserver + helidon-webserver io.helidon.config helidon-config-yaml - io.helidon.nima.http.media - helidon-nima-http-media-jsonp + io.helidon.http.media + helidon-http-media-jsonp io.helidon.common @@ -75,16 +76,16 @@ org.postgresql postgresql - 42.6.0 + 42.6.1 - com.fizzed - rocker-runtime - ${rocker.version} + gg.jte + jte + ${jte.version} - io.helidon.nima.testing.junit5 - helidon-nima-testing-junit5-webserver + io.helidon.common.testing + helidon-common-testing-junit5 test @@ -98,7 +99,6 @@ test - @@ -113,7 +113,6 @@ -Xlint:unchecked -Xpkginfo:always - --enable-preview @@ -126,20 +125,21 @@
+ - com.fizzed - rocker-maven-plugin - ${rocker.version} + gg.jte + jte-maven-plugin + ${jte.version} + + ${project.basedir}/src/main/resources/views + Html + - generate-rocker-templates generate-sources generate - - src/main/resources - diff --git a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/JsonSerializer.java b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/JsonSerializer.java new file mode 100644 index 00000000000..0564fa8a911 --- /dev/null +++ b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/JsonSerializer.java @@ -0,0 +1,97 @@ +package io.helidon.benchmark.nima; + +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import com.jsoniter.output.JsonStream; +import com.jsoniter.output.JsonStreamPool; +import com.jsoniter.spi.JsonException; + +public class JsonSerializer { + + private JsonSerializer() { + } + + /** + * Serialize an instance into a byte array. + * + * @param obj the instance + * @return the byte array + */ + public static byte[] serialize(Object obj) { + JsonStream stream = JsonStreamPool.borrowJsonStream(); + try { + stream.reset(null); + stream.writeVal(obj.getClass(), obj); + return Arrays.copyOfRange(stream.buffer().data(), 0, stream.buffer().tail()); + } catch (IOException e) { + throw new JsonException(e); + } + } + + /** + * Serialize an instance into a JSON stream. + * + * @param obj the instance + * @param stream the JSON stream + */ + public static void serialize(Object obj, JsonStream stream) { + try { + stream.reset(null); + stream.writeVal(obj.getClass(), obj); + } catch (IOException e) { + throw new JsonException(e); + } + } + + /** + * Serialize a map of strings into a JSON stream. + * + * @param map the map + * @param stream the JSON stream + */ + public static void serialize(Map map, JsonStream stream) { + try { + stream.reset(null); + stream.writeObjectStart(); + map.forEach((k, v) -> { + try { + stream.writeObjectField(k); + stream.writeVal(v); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + stream.writeObjectEnd(); + } catch (IOException e) { + throw new JsonException(e); + } + } + + /** + * Serialize a list of objects into a JSON stream. + * + * @param objs the list of objects + * @param stream the JSON stream + */ + public static void serialize(List objs, JsonStream stream) { + try { + stream.reset(null); + stream.writeArrayStart(); + int i = 0; + int n = objs.size(); + for (Object obj : objs) { + stream.writeVal(obj.getClass(), obj); + if (i++ < n - 1) { + stream.writeMore(); + } + + } + stream.writeArrayEnd(); + } catch (IOException e) { + throw new JsonException(e); + } + } +} diff --git a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/Main.java b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/Main.java index 6572acf9b27..800ce927537 100644 --- a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/Main.java +++ b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Oracle and/or its affiliates. + * Copyright (c) 2022, 2025 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,31 +16,29 @@ package io.helidon.benchmark.nima; -import java.io.IOException; import java.nio.charset.StandardCharsets; -import java.util.Arrays; import java.util.logging.Logger; import com.jsoniter.output.JsonStream; import com.jsoniter.output.JsonStreamPool; -import com.jsoniter.spi.JsonException; import io.helidon.benchmark.nima.models.DbRepository; import io.helidon.benchmark.nima.models.HikariJdbcRepository; import io.helidon.benchmark.nima.models.PgClientRepository; import io.helidon.benchmark.nima.services.DbService; import io.helidon.benchmark.nima.services.FortuneHandler; -import io.helidon.common.http.Http; -import io.helidon.common.http.Http.Header; -import io.helidon.common.http.Http.HeaderValue; -import io.helidon.common.http.Http.HeaderValues; import io.helidon.config.Config; import io.helidon.config.ConfigException; +import io.helidon.http.Header; +import io.helidon.http.HeaderNames; +import io.helidon.http.HeaderValues; import io.helidon.logging.common.LogConfig; -import io.helidon.nima.webserver.WebServer; -import io.helidon.nima.webserver.http.Handler; -import io.helidon.nima.webserver.http.HttpRules; -import io.helidon.nima.webserver.http.ServerRequest; -import io.helidon.nima.webserver.http.ServerResponse; +import io.helidon.webserver.WebServer; +import io.helidon.webserver.http.Handler; +import io.helidon.webserver.http.HttpRules; +import io.helidon.webserver.http.ServerRequest; +import io.helidon.webserver.http.ServerResponse; + +import static io.helidon.benchmark.nima.JsonSerializer.serialize; /** * Main class of the benchmark. @@ -50,9 +48,9 @@ public final class Main { private static final Logger LOGGER = Logger.getLogger(Main.class.getName()); - public static final Http.HeaderValue CONTENT_TYPE_HTML = - Http.Header.createCached(Http.Header.CONTENT_TYPE, "text/html; charset=UTF-8"); - public static final Http.HeaderValue SERVER = Http.Header.createCached(Http.Header.SERVER, "Nima"); + public static final Header CONTENT_TYPE_HTML = + HeaderValues.createCached(HeaderNames.CONTENT_TYPE, "text/html; charset=UTF-8"); + public static final Header SERVER = HeaderValues.createCached(HeaderNames.SERVER, "Nima"); private Main() { } @@ -67,11 +65,14 @@ public static void main(String[] args) { LogConfig.configureRuntime(); WebServer.builder() + .config(Config.create().get("server")) .routing(Main::routing) + .build() .start(); } // exposed for tests + @SuppressWarnings("unchecked") static void routing(HttpRules rules) { Config config = Config.create(); @@ -88,29 +89,14 @@ static void routing(HttpRules rules) { rules.get("/plaintext", new PlaintextHandler()) .get("/json", new JsonHandler()) - .get("/10k", new JsonKHandler(10)) .get("/fortunes", new FortuneHandler(repository)) .register("/", new DbService(repository)); } - private static byte[] serializeMsg(Message obj) { - JsonStream stream = JsonStreamPool.borrowJsonStream(); - try { - stream.reset(null); - stream.writeVal(Message.class, obj); - return Arrays.copyOfRange(stream.buffer().data(), 0, stream.buffer().tail()); - } catch (IOException e) { - throw new JsonException(e); - } finally { - JsonStreamPool.returnJsonStream(stream); - } - } - static class PlaintextHandler implements Handler { - static final HeaderValue CONTENT_TYPE = Header.createCached(Header.CONTENT_TYPE, + static final Header CONTENT_TYPE = HeaderValues.createCached(HeaderNames.CONTENT_TYPE, "text/plain; charset=UTF-8"); - static final HeaderValue CONTENT_LENGTH = Header.createCached(Header.CONTENT_LENGTH, "13"); - + static final Header CONTENT_LENGTH = HeaderValues.createCached(HeaderNames.CONTENT_LENGTH, "13"); private static final byte[] RESPONSE_BYTES = "Hello, World!".getBytes(StandardCharsets.UTF_8); @Override @@ -124,44 +110,22 @@ public void handle(ServerRequest req, ServerResponse res) { static class JsonHandler implements Handler { private static final String MESSAGE = "Hello, World!"; - private static final int JSON_LENGTH = serializeMsg(new Message(MESSAGE)).length; - static final HeaderValue CONTENT_LENGTH = Header.createCached(Header.CONTENT_LENGTH, + private static final int JSON_LENGTH = serialize(new Message(MESSAGE)).length; + static final Header CONTENT_LENGTH = HeaderValues.createCached(HeaderNames.CONTENT_LENGTH, String.valueOf(JSON_LENGTH)); @Override public void handle(ServerRequest req, ServerResponse res) { - res.header(CONTENT_LENGTH); - res.header(HeaderValues.CONTENT_TYPE_JSON); - res.header(Main.SERVER); - res.send(serializeMsg(newMsg())); - } - - private static Message newMsg() { - return new Message("Hello, World!"); - } - } - - static class JsonKHandler implements Handler { - private final HeaderValue contentLength; - private final String message; - - JsonKHandler(int kilobytes) { - this.message = "a".repeat(1024 * kilobytes); - int length = serializeMsg(new Message(message)).length; - this.contentLength = Header.createCached(Header.CONTENT_LENGTH, - String.valueOf(length)); - } - - @Override - public void handle(ServerRequest req, ServerResponse res) { - res.header(contentLength); - res.header(HeaderValues.CONTENT_TYPE_JSON); - res.header(Main.SERVER); - res.send(serializeMsg(newMsg())); - } - - private Message newMsg() { - return new Message(message); + JsonStream stream = JsonStreamPool.borrowJsonStream(); + try { + res.header(CONTENT_LENGTH); + res.header(HeaderValues.CONTENT_TYPE_JSON); + res.header(Main.SERVER); + serialize(new Message(MESSAGE), stream); + res.send(stream.buffer().data(), 0, stream.buffer().tail()); + } finally { + JsonStreamPool.returnJsonStream(stream); + } } } @@ -191,4 +155,4 @@ public String getMessage() { return message; } } -} +} \ No newline at end of file diff --git a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/DbRepository.java b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/DbRepository.java index 204c9ad5ad1..41af9c03b8e 100644 --- a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/DbRepository.java +++ b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/DbRepository.java @@ -1,42 +1,15 @@ package io.helidon.benchmark.nima.models; -import java.util.Collections; import java.util.List; import java.util.concurrent.ThreadLocalRandom; -import jakarta.json.Json; -import jakarta.json.JsonArray; -import jakarta.json.JsonArrayBuilder; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; - public interface DbRepository { - JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap()); - - default World getWorld() { - return getWorld(randomWorldNumber()); - } - World getWorld(int id); - default JsonObject getWorldAsJson(int id) { - return getWorld().toJson(); - } - List getWorlds(int count); - default JsonArray getWorldsAsJson(int count) { - JsonArrayBuilder result = JSON.createArrayBuilder(); - for (World world : getWorlds(count)) { - result.add(world.toJson()); - } - return result.build(); - } - - World updateWorld(World world); - List updateWorlds(int count); List getFortunes(); diff --git a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/Fortune.java b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/Fortune.java index 96a5e2070be..190c792d345 100644 --- a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/Fortune.java +++ b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/Fortune.java @@ -1,7 +1,7 @@ package io.helidon.benchmark.nima.models; -public final class Fortune { +public final class Fortune implements Comparable { public int id; public String message; @@ -17,4 +17,8 @@ public int getId() { public String getMessage() { return message; } + @Override + public int compareTo(Fortune other) { + return message.compareTo(other.message); + } } diff --git a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/HikariJdbcRepository.java b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/HikariJdbcRepository.java index 686559b2fd9..7bf7e8c72b8 100644 --- a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/HikariJdbcRepository.java +++ b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/HikariJdbcRepository.java @@ -7,6 +7,8 @@ import java.sql.SQLException; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadFactory; import java.util.logging.Logger; import com.zaxxer.hikari.HikariConfig; @@ -22,20 +24,31 @@ public class HikariJdbcRepository implements DbRepository { private final HikariConfig hikariConfig; public HikariJdbcRepository(Config config) { + // hikari connection configuration String url = "jdbc:postgresql://" + config.get("host").asString().orElse("tfb-database") + ":" + config.get("port").asString().orElse("5432") + "/" + config.get("db").asString().orElse("hello_world"); - hikariConfig = new HikariConfig(); hikariConfig.setJdbcUrl(url); hikariConfig.setUsername(config.get("username").asString().orElse("benchmarkdbuser")); hikariConfig.setPassword(config.get("password").asString().orElse("benchmarkdbpass")); - hikariConfig.addDataSourceProperty("cachePrepStmts", "true"); + // hikari additional configuration int poolSize = config.get("sql-pool-size").asInt().orElse(64); - hikariConfig.addDataSourceProperty("maximumPoolSize", poolSize); - LOGGER.info("Db pool size is set to " + poolSize); + hikariConfig.setMaximumPoolSize(poolSize); + LOGGER.info("Hikari pool size is set to " + poolSize); + ThreadFactory vtThreadFactory = Thread.ofVirtual().factory(); + hikariConfig.setThreadFactory(vtThreadFactory); + hikariConfig.setScheduledExecutor(Executors.newScheduledThreadPool(poolSize, vtThreadFactory)); + LOGGER.info("Set thread factory to VTs"); + + // data source properties + hikariConfig.addDataSourceProperty("cachePrepStmts","true"); + hikariConfig.addDataSourceProperty("prepStmtCacheSize","250"); + hikariConfig.addDataSourceProperty("prepStmtCacheSqlLimit","2048"); + hikariConfig.addDataSourceProperty("ssl", "false"); + hikariConfig.addDataSourceProperty("tcpKeepAlive", "true"); } private Connection getConnection() throws SQLException { @@ -67,15 +80,6 @@ public List getWorlds(int count) { } } - @Override - public World updateWorld(World world) { - try (Connection c = getConnection()) { - return updateWorld(world, c); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - @Override public List updateWorlds(int count) { try (Connection c = getConnection()) { diff --git a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/PgClientConnection.java b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/PgClientConnection.java new file mode 100644 index 00000000000..956a5ef1ba1 --- /dev/null +++ b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/PgClientConnection.java @@ -0,0 +1,80 @@ + +package io.helidon.benchmark.nima.models; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +import io.vertx.pgclient.PgConnection; +import io.vertx.sqlclient.PreparedQuery; +import io.vertx.sqlclient.PreparedStatement; +import io.vertx.sqlclient.Row; +import io.vertx.sqlclient.RowSet; + +public class PgClientConnection implements AutoCloseable { + static final int UPDATE_QUERIES = 500; + private static String SELECT_WORLD = "SELECT id, randomnumber from WORLD where id=$1"; + private static String SELECT_FORTUNE = "SELECT * from FORTUNE"; + + private CompletableFuture worldQuery; + private CompletableFuture fortuneQuery; + private CompletableFuture[] updateQuery; + + private final PgConnection conn; + + PgClientConnection(PgConnection conn) { + this.conn = conn; + } + + public PgConnection pgConnection() { + return conn; + } + + @Override + public void close() { + conn.close(); + } + + public PreparedQuery> worldQuery() throws ExecutionException, InterruptedException { + return worldQuery.get().query(); + } + + public PreparedQuery> fortuneQuery() throws ExecutionException, InterruptedException { + return fortuneQuery.get().query(); + } + + public PreparedQuery> updateQuery(int queryCount) throws ExecutionException, InterruptedException { + return updateQuery[queryCount - 1].get().query(); + } + + @SuppressWarnings("unchecked") + void prepare() { + try { + worldQuery = conn.prepare(SELECT_WORLD).toCompletionStage().toCompletableFuture(); + fortuneQuery = conn.prepare(SELECT_FORTUNE).toCompletionStage().toCompletableFuture(); + updateQuery = (CompletableFuture[]) new CompletableFuture[UPDATE_QUERIES]; + for (int i = 0; i < UPDATE_QUERIES; i++) { + updateQuery[i] = conn.prepare(singleUpdate(i + 1)) + .toCompletionStage().toCompletableFuture(); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private static String singleUpdate(int count) { + StringBuilder sql = new StringBuilder(); + sql.append("UPDATE WORLD SET RANDOMNUMBER = CASE ID"); + for (int i = 0; i < count; i++) { + int k = i * 2 + 1; + sql.append(" WHEN $").append(k).append(" THEN $").append(k + 1); + } + sql.append(" ELSE RANDOMNUMBER"); + sql.append(" END WHERE ID IN ($1"); + for (int i = 1; i < count; i++) { + int k = i * 2 + 1; + sql.append(",$").append(k); + } + sql.append(")"); + return sql.toString(); + } +} diff --git a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/PgClientConnectionPool.java b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/PgClientConnectionPool.java new file mode 100644 index 00000000000..c8c267e8246 --- /dev/null +++ b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/PgClientConnectionPool.java @@ -0,0 +1,38 @@ + +package io.helidon.benchmark.nima.models; + +import io.helidon.config.Config; +import io.vertx.core.Vertx; +import io.vertx.pgclient.PgConnectOptions; +import io.vertx.pgclient.PgConnection; + +abstract class PgClientConnectionPool implements AutoCloseable { + + private final Config config; + private final Vertx vertx; + private final PgConnectOptions options; + + static PgClientConnectionPool create(Vertx vertx, PgConnectOptions options, Config config) { + return new PgClientConnectionPoolArray(vertx, options, config); + } + + PgClientConnectionPool(Vertx vertx, PgConnectOptions options, Config config) { + this.vertx = vertx; + this.options = options; + this.config = config; + } + + abstract PgClientConnection clientConnection(); + + protected PgClientConnection newConnection() { + try { + PgConnection conn = PgConnection.connect(vertx, options) + .toCompletionStage().toCompletableFuture().get(); + PgClientConnection clientConn = new PgClientConnection(conn); + clientConn.prepare(); + return clientConn; + } catch (Exception e) { + throw new RuntimeException(e); + } + } +} diff --git a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/PgClientConnectionPoolArray.java b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/PgClientConnectionPoolArray.java new file mode 100644 index 00000000000..5469941c44c --- /dev/null +++ b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/PgClientConnectionPoolArray.java @@ -0,0 +1,64 @@ + +package io.helidon.benchmark.nima.models; + +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.logging.Logger; + +import io.helidon.config.Config; +import io.vertx.core.Vertx; +import io.vertx.pgclient.PgConnectOptions; + +class PgClientConnectionPoolArray extends PgClientConnectionPool { + private static final Logger LOGGER = Logger.getLogger(PgClientConnectionPoolArray.class.getName()); + + private final int connections; + private final PgClientConnection[] connectionArray; + private final ReadWriteLock lock = new ReentrantReadWriteLock(); + + PgClientConnectionPoolArray(Vertx vertx, PgConnectOptions options, Config config) { + super(vertx, options, config); + double sizeFactor = config.get("pgclient-connection-pool.size-factor") + .asDouble() + .orElse(1.0); + connections = (int) (Runtime.getRuntime().availableProcessors() * sizeFactor); + connectionArray = new PgClientConnection[connections]; + LOGGER.info("Connection pool is " + getClass().getSimpleName()); + LOGGER.info("Size of connection pool is " + connections); + } + + @Override + public PgClientConnection clientConnection() { + int index = Thread.currentThread().hashCode() % connections; + if (connectionArray[index] == null) { + lock.readLock().lock(); + if (connectionArray[index] == null) { + lock.readLock().unlock(); + lock.writeLock().lock(); + try { + if (connectionArray[index] == null) { + connectionArray[index] = newConnection(); + } + } finally { + lock.writeLock().unlock(); + } + } else { + lock.readLock().unlock(); + } + } + return connectionArray[index]; + } + + @Override + public void close() { + try { + for (PgClientConnection connection : connectionArray) { + if (connection != null) { + connection.close(); + } + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } +} diff --git a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/PgClientRepository.java b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/PgClientRepository.java index 02a768add6c..1af13ae8930 100644 --- a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/PgClientRepository.java +++ b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/PgClientRepository.java @@ -2,88 +2,54 @@ import java.util.ArrayList; import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.logging.Logger; -import io.helidon.common.reactive.Multi; -import io.helidon.common.reactive.Single; import io.helidon.config.Config; +import io.vertx.core.Future; 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; +import io.vertx.sqlclient.PreparedQuery; import io.vertx.sqlclient.Row; -import io.vertx.sqlclient.SqlClient; +import io.vertx.sqlclient.RowSet; import io.vertx.sqlclient.Tuple; -import jakarta.json.JsonArray; -import jakarta.json.JsonArrayBuilder; -import jakarta.json.JsonObject; import static io.helidon.benchmark.nima.models.DbRepository.randomWorldNumber; +import static io.helidon.benchmark.nima.models.PgClientConnection.UPDATE_QUERIES; public class PgClientRepository implements DbRepository { - private static final Logger LOGGER = Logger.getLogger(PgClientRepository.class.getName()); - - private final SqlClient queryPool; - private final SqlClient updatePool; - - private final int batchSize; - private final long updateTimeout; - private final int maxRetries; + private final PgClientConnectionPool connectionPool; public PgClientRepository(Config config) { - Vertx vertx = Vertx.vertx(new VertxOptions() - .setPreferNativeTransport(true)); + VertxOptions vertxOptions = new VertxOptions() + .setPreferNativeTransport(true) + .setBlockedThreadCheckInterval(100000); + Vertx vertx = Vertx.vertx(vertxOptions); PgConnectOptions connectOptions = new PgConnectOptions() .setPort(config.get("port").asInt().orElse(5432)) - .setCachePreparedStatements(config.get("cache-prepared-statements").asBoolean().orElse(true)) .setHost(config.get("host").asString().orElse("tfb-database")) .setDatabase(config.get("db").asString().orElse("hello_world")) .setUser(config.get("username").asString().orElse("benchmarkdbuser")) - .setPassword(config.get("password").asString().orElse("benchmarkdbpass")); - - int sqlPoolSize = config.get("sql-pool-size").asInt().orElse(64); - PoolOptions clientOptions = new PoolOptions().setMaxSize(sqlPoolSize); - LOGGER.info("sql-pool-size is " + sqlPoolSize); - batchSize = config.get("update-batch-size").asInt().orElse(20); - LOGGER.info("update-batch-size is " + batchSize); - updateTimeout = config.get("update-timeout-millis").asInt().orElse(5000); - LOGGER.info("update-timeout-millis is " + updateTimeout); - maxRetries = config.get("update-max-retries").asInt().orElse(3); - LOGGER.info("update-max-retries is " + maxRetries); - - queryPool = PgPool.client(vertx, connectOptions, clientOptions); - updatePool = PgPool.client(vertx, connectOptions, clientOptions); - } - - @Override - public JsonObject getWorldAsJson(int id) { - return getWorld(id, queryPool).map(World::toJson).await(); + .setPassword(config.get("password").asString().orElse("benchmarkdbpass")) + .setCachePreparedStatements(true) + .setPreparedStatementCacheMaxSize(UPDATE_QUERIES + 2) + .setPreparedStatementCacheSqlFilter(s -> true) // cache all + .setTcpNoDelay(true) + .setTcpQuickAck(true) + .setTcpKeepAlive(true) + .setPipeliningLimit(100000); + connectionPool = PgClientConnectionPool.create(vertx, connectOptions, config); } @Override public World getWorld(int id) { try { - return getWorld(id, queryPool).toCompletableFuture().get(); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - @Override - public JsonArray getWorldsAsJson(int count) { - try { - return Multi.range(0, count) - .flatMap(i -> getWorld(randomWorldNumber(), queryPool)) - .map(World::toJson) - .reduce(JSON::createArrayBuilder, JsonArrayBuilder::add) - .map(JsonArrayBuilder::build) - .await(); + PreparedQuery> worldQuery = connectionPool.clientConnection().worldQuery(); + return worldQuery.execute(Tuple.of(id)) + .map(rows -> { + Row r = rows.iterator().next(); + return new World(r.getInteger(0), r.getInteger(1)); + }).toCompletionStage().toCompletableFuture().get(); } catch (Exception e) { throw new RuntimeException(e); } @@ -92,27 +58,16 @@ public JsonArray getWorldsAsJson(int count) { @Override public List getWorlds(int count) { try { - List result = new ArrayList<>(count); + PreparedQuery> worldQuery = connectionPool.clientConnection().worldQuery(); + List> futures = new ArrayList<>(); for (int i = 0; i < count; i++) { - World world = queryPool.preparedQuery("SELECT id, randomnumber FROM world WHERE id = $1") - .execute(Tuple.of(randomWorldNumber())) + futures.add(worldQuery.execute(Tuple.of(randomWorldNumber())) .map(rows -> { Row r = rows.iterator().next(); return new World(r.getInteger(0), r.getInteger(1)); - }).toCompletionStage().toCompletableFuture().get(); - result.add(world); + })); } - return result; - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - @Override - public World updateWorld(World world) { - try { - updateWorlds(List.of(world), 0, updatePool); - return world; + return Future.all(futures).toCompletionStage().toCompletableFuture().get().list(); } catch (Exception e) { throw new RuntimeException(e); } @@ -121,38 +76,19 @@ public World updateWorld(World world) { @Override public List updateWorlds(int count) { List worlds = getWorlds(count); - for (World w : worlds) { - w.randomNumber = randomWorldNumber(); - } - if (count <= batchSize) { - LOGGER.finest(() -> "Updating single batch of size " + count); - updateWorldsRetry(worlds, 0, 0); - } else { - int batches = count / batchSize + (count % batchSize == 0 ? 0 : 1); - for (int i = 0; i < batches; i++) { - final int from = i * batchSize; - LOGGER.finest(() -> "Updating batch from " + from + " to " + (from + batchSize)); - updateWorldsRetry(worlds, from, 0); - } - } - return worlds; - } - - private List updateWorldsRetry(List worlds, int from, int retries) { - if (retries > maxRetries) { - throw new RuntimeException("Too many transaction retries"); - } - CompletableFuture> cf = null; try { - cf = updateWorlds(worlds, from, updatePool); - cf.get(updateTimeout, TimeUnit.MILLISECONDS); - return worlds; - } catch (ExecutionException | TimeoutException e) { - cf.cancel(true); - retries++; - final int finalRetries = retries; - LOGGER.fine(() -> "Retrying batch update after cancellation (retries=" + finalRetries + ")"); - return updateWorldsRetry(worlds, from, retries); // retry + PreparedQuery> updateQuery = connectionPool.clientConnection().updateQuery(count); + List updateParams = new ArrayList<>(count * 2); + for (World world : worlds) { + updateParams.add(world.id); + world.randomNumber = randomWorldNumber(); + updateParams.add(world.randomNumber); + } + return updateQuery.execute(Tuple.wrap(updateParams)) + .toCompletionStage() + .thenApply(rows -> worlds) + .toCompletableFuture() + .get(); } catch (Exception e) { throw new RuntimeException(e); } @@ -160,38 +96,18 @@ private List updateWorldsRetry(List worlds, int from, int retries) @Override public List getFortunes() { - return Single.create(queryPool.preparedQuery("SELECT id, message FROM fortune") - .execute() - .map(rows -> { - List fortunes = new ArrayList<>(rows.size() + 1); - for (Row r : rows) { - fortunes.add(new Fortune(r.getInteger(0), r.getString(1))); - } - return fortunes; - }).toCompletionStage()).await(); - } - - private static Single getWorld(int id, SqlClient pool) { - return Single.create(pool.preparedQuery("SELECT id, randomnumber FROM world WHERE id = $1") - .execute(Tuple.of(id)) - .map(rows -> { - Row r = rows.iterator().next(); - return new World(r.getInteger(0), r.getInteger(1)); - }).toCompletionStage()); - - } - - private CompletableFuture> updateWorlds(List worlds, int from, SqlClient pool) { - List tuples = new ArrayList<>(); - int to = Math.min(from + batchSize, worlds.size()); - for (int i = from; i < to; i++) { - World w = worlds.get(i); - tuples.add(Tuple.of(w.randomNumber, w.id)); + try { + PreparedQuery> fortuneQuery = connectionPool.clientConnection().fortuneQuery(); + return fortuneQuery.execute() + .map(rows -> { + List fortunes = new ArrayList<>(rows.size() + 1); + for (Row r : rows) { + fortunes.add(new Fortune(r.getInteger(0), r.getString(1))); + } + return fortunes; + }).toCompletionStage().toCompletableFuture().get(); + } catch (Exception e) { + throw new RuntimeException(e); } - return pool.preparedQuery("UPDATE world SET randomnumber = $1 WHERE id = $2") - .executeBatch(tuples) - .toCompletionStage() - .thenApply(rows -> worlds) - .toCompletableFuture(); } } \ No newline at end of file diff --git a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/World.java b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/World.java index ee8eb9194cd..dbcba61a8ca 100644 --- a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/World.java +++ b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/models/World.java @@ -1,18 +1,8 @@ package io.helidon.benchmark.nima.models; -import java.util.Collections; - -import jakarta.json.Json; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; - public final class World { - private static final String ID_KEY = "id"; - private static final String ID_RANDOM_NUMBER = "randomNumber"; - private static final JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap()); - public int id; public int randomNumber; @@ -20,8 +10,4 @@ public World(int id, int randomNumber) { this.id = id; this.randomNumber = randomNumber; } - - public JsonObject toJson() { - return JSON.createObjectBuilder().add(ID_KEY, id).add(ID_RANDOM_NUMBER, randomNumber).build(); - } } diff --git a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/services/DbService.java b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/services/DbService.java index 086c620f0c5..a1e97de44b5 100644 --- a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/services/DbService.java +++ b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/services/DbService.java @@ -1,27 +1,21 @@ - package io.helidon.benchmark.nima.services; -import java.util.Collections; -import java.util.List; - +import com.jsoniter.output.JsonStream; +import com.jsoniter.output.JsonStreamPool; import io.helidon.benchmark.nima.models.DbRepository; -import io.helidon.benchmark.nima.models.World; +import io.helidon.common.mapper.OptionalValue; import io.helidon.common.parameters.Parameters; -import io.helidon.nima.webserver.http.HttpRules; -import io.helidon.nima.webserver.http.HttpService; -import io.helidon.nima.webserver.http.ServerRequest; -import io.helidon.nima.webserver.http.ServerResponse; - -import jakarta.json.Json; -import jakarta.json.JsonArrayBuilder; -import jakarta.json.JsonBuilderFactory; -import jakarta.json.JsonObject; +import io.helidon.http.HeaderValues; +import io.helidon.webserver.http.HttpRules; +import io.helidon.webserver.http.HttpService; +import io.helidon.webserver.http.ServerRequest; +import io.helidon.webserver.http.ServerResponse; +import static io.helidon.benchmark.nima.JsonSerializer.serialize; import static io.helidon.benchmark.nima.Main.SERVER; import static io.helidon.benchmark.nima.models.DbRepository.randomWorldNumber; public class DbService implements HttpService { - private static final JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap()); private final DbRepository repository; @@ -37,40 +31,54 @@ public void routing(HttpRules httpRules) { } private void db(ServerRequest req, ServerResponse res) { - res.header(SERVER); - res.send(repository.getWorldAsJson(randomWorldNumber())); + JsonStream stream = JsonStreamPool.borrowJsonStream(); + try { + res.header(SERVER); + res.header(HeaderValues.CONTENT_TYPE_JSON); + serialize(repository.getWorld(randomWorldNumber()), stream); + res.send(stream.buffer().data(), 0, stream.buffer().tail()); + } finally { + JsonStreamPool.returnJsonStream(stream); + } } private void queries(ServerRequest req, ServerResponse res) { - res.header(SERVER); - int count = parseQueryCount(req.query()); - res.send(repository.getWorldsAsJson(count)); + JsonStream stream = JsonStreamPool.borrowJsonStream(); + try { + res.header(SERVER); + res.header(HeaderValues.CONTENT_TYPE_JSON); + int count = parseQueryCount(req.query()); + serialize(repository.getWorlds(count), stream); + res.send(stream.buffer().data(), 0, stream.buffer().tail()); + } finally { + JsonStreamPool.returnJsonStream(stream); + } } private void updates(ServerRequest req, ServerResponse res) { - res.header(SERVER); - int count = parseQueryCount(req.query()); - List worlds = repository.updateWorlds(count); - JsonArrayBuilder arrayBuilder = JSON.createArrayBuilder(); - for (World world : worlds) { - JsonObject json = world.toJson(); - arrayBuilder.add(json); + JsonStream stream = JsonStreamPool.borrowJsonStream(); + try { + res.header(SERVER); + res.header(HeaderValues.CONTENT_TYPE_JSON); + int count = parseQueryCount(req.query()); + serialize(repository.updateWorlds(count), stream); + res.send(stream.buffer().data(), 0, stream.buffer().tail()); + } finally { + JsonStreamPool.returnJsonStream(stream); } - res.send(arrayBuilder.build()); } private int parseQueryCount(Parameters parameters) { - List values = parameters.all("queries"); - if (values.isEmpty()) { + OptionalValue value = parameters.first("queries"); + if (value.isEmpty()) { return 1; } - String first = values.get(0); int parsedValue; try { - parsedValue = Integer.parseInt(first, 10); + parsedValue = Integer.parseInt(value.get(), 10); } catch (NumberFormatException e) { return 1; } return Math.min(500, Math.max(1, parsedValue)); } -} \ No newline at end of file +} diff --git a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/services/FortuneHandler.java b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/services/FortuneHandler.java index 38eb950fcc1..173f3549f3b 100644 --- a/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/services/FortuneHandler.java +++ b/frameworks/Java/helidon/nima/src/main/java/io/helidon/benchmark/nima/services/FortuneHandler.java @@ -1,16 +1,21 @@ package io.helidon.benchmark.nima.services; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.charset.StandardCharsets; import java.util.Comparator; import java.util.List; -import com.fizzed.rocker.runtime.ArrayOfByteArraysOutput; +import gg.jte.TemplateOutput; import io.helidon.benchmark.nima.models.DbRepository; import io.helidon.benchmark.nima.models.Fortune; -import io.helidon.nima.webserver.http.Handler; -import io.helidon.nima.webserver.http.ServerRequest; -import io.helidon.nima.webserver.http.ServerResponse; -import views.fortunes; +import io.helidon.webserver.http.Handler; +import io.helidon.webserver.http.ServerRequest; +import io.helidon.webserver.http.ServerResponse; + +import gg.jte.html.OwaspHtmlTemplateOutput; +import gg.jte.generated.precompiled.JtefortunesGenerated; import static io.helidon.benchmark.nima.Main.CONTENT_TYPE_HTML; import static io.helidon.benchmark.nima.Main.SERVER; @@ -33,8 +38,38 @@ public void handle(ServerRequest req, ServerResponse res) { List fortuneList = repository.getFortunes(); fortuneList.add(ADDITIONAL_FORTUNE); fortuneList.sort(Comparator.comparing(Fortune::getMessage)); - res.send(fortunes.template(fortuneList) - .render(ArrayOfByteArraysOutput.FACTORY) - .toByteArray()); + try (OutputStream os = res.outputStream()) { + JtefortunesGenerated.render(new OwaspHtmlTemplateOutput(new HelidonTemplateOutput(os)), + null, fortuneList); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + static class HelidonTemplateOutput implements TemplateOutput{ + private final OutputStream os; + + HelidonTemplateOutput(OutputStream os) { + this.os = os; + } + + @Override + public void writeContent(String value) { + writeBinaryContent(value.getBytes(StandardCharsets.UTF_8)); + } + + @Override + public void writeContent(String value, int beginIndex, int endIndex) { + writeBinaryContent(value.substring(beginIndex, endIndex).getBytes(StandardCharsets.UTF_8)); + } + + @Override + public void writeBinaryContent(byte[] value) { + try { + os.write(value); + } catch (IOException e) { + throw new RuntimeException(e); + } + } } } \ No newline at end of file diff --git a/frameworks/Java/helidon/nima/src/main/resources/application.yaml b/frameworks/Java/helidon/nima/src/main/resources/application.yaml index 511b0173ae5..d4db8d75119 100644 --- a/frameworks/Java/helidon/nima/src/main/resources/application.yaml +++ b/frameworks/Java/helidon/nima/src/main/resources/application.yaml @@ -1,5 +1,5 @@ # -# Copyright (c) 2022, 2023 Oracle and/or its affiliates. +# Copyright (c) 2022, 2024 Oracle and/or its affiliates. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -15,36 +15,28 @@ # server: + host: 0.0.0.0 port: 8080 - sockets: - - name: "@default" - host: 0.0.0.0 - port: 8080 - backlog: 8192 - receive-buffer-size: 64000 - # set write-queue-length to 0 or not setting it will disable async writes - # write-queue-length: 1024 - connection-options: - read-timeout-seconds: 0 - connect-timeout-seconds: 0 - send-buffer-size: 64000 - receive-buffer-size: 64000 - connection-providers: + backlog: 8192 + write-queue-length: 8192 + smart-async-writes: true + connection-options: + read-timeout: PT0S + connect-timeout: PT0S + tcp-no-delay: true + protocols: "http_1_1": - validate-headers: false + validate-request-headers: false + validate-response-headers: false validate-path: false recv-log: false send-log: false host: "tfb-database" -#host: "localhost" db: "hello_world" username: benchmarkdbuser password: benchmarkdbpass -sql-pool-size: 200 db-repository: "pgclient" # "pgclient" (default) or "hikari" +pgclient-connection-pool: + size-factor: 1.0 # size = available-processors * size-factor -# The following for pgclient only -update-batch-size: 4 -update-timeout-millis: 10000 -update-max-retries: 3 diff --git a/frameworks/Java/helidon/nima/src/main/resources/views/fortunes.jte b/frameworks/Java/helidon/nima/src/main/resources/views/fortunes.jte new file mode 100644 index 00000000000..52dc350b25f --- /dev/null +++ b/frameworks/Java/helidon/nima/src/main/resources/views/fortunes.jte @@ -0,0 +1,2 @@ +@param java.util.List fortunes +Fortunes@for(io.helidon.benchmark.nima.models.Fortune fortune : fortunes)@endfor
idmessage
${fortune.getId()}${fortune.getMessage()}
\ No newline at end of file diff --git a/frameworks/Java/helidon/nima/src/main/resources/views/fortunes.rocker.html b/frameworks/Java/helidon/nima/src/main/resources/views/fortunes.rocker.html deleted file mode 100644 index 3ebcae44729..00000000000 --- a/frameworks/Java/helidon/nima/src/main/resources/views/fortunes.rocker.html +++ /dev/null @@ -1,24 +0,0 @@ -@import io.helidon.benchmark.nima.models.Fortune -@import java.util.List -@args (List fortunes) - - - - -Fortunes - - - - - - - - @for (f : fortunes) { - - - - - } -
idmessage
@f.getId()@f.getMessage()
- - \ No newline at end of file diff --git a/frameworks/Java/hserver-business/README.md b/frameworks/Java/hserver-business/README.md new file mode 100644 index 00000000000..4e033e0d570 --- /dev/null +++ b/frameworks/Java/hserver-business/README.md @@ -0,0 +1,39 @@ +# hserver-business Benchmarking Test +This is the HServer portion of a [benchmarking test suite](../) comparing a variety of web development platforms. + +### Tests +* [JSON test source](src/main/java/com/test/hserver/controller/TestController.java) +* [Plaintext test source](src/main/java/com/test/hserver/controller/TestController.java) +* [Data-Store test source](src/main/java/com/test/hserver/controller/TestController.java) +* [Data-Update test source](src/main/java/com/test/hserver/controller/TestController.java) +* [Fortunes test source](src/main/java/com/test/hserver/controller/TestController.java) + +## Infrastructure Software Versions + +* [HServer](https://gitee.com/HServer/HServer) +* [Java OpenJDK 1.8](http://openjdk.java.net/) + +## Test URLs + +### JSON Encoding Test + +http://localhost:8888/json + +### Plain Text Test + +http://localhost:8888/plaintext + +### Data-Store/Database Mapping Test + +http://localhost:8888/db?queries=2 + +### Update Test + +http://localhost:8888/updates?queries=2 + +### Fortunes Test + +http://localhost:8888/fortunes + +### Query Test +http://localhost:8888/queries?queries=2 diff --git a/frameworks/Java/hserver-business/benchmark_config.json b/frameworks/Java/hserver-business/benchmark_config.json new file mode 100644 index 00000000000..bd9e4a47600 --- /dev/null +++ b/frameworks/Java/hserver-business/benchmark_config.json @@ -0,0 +1,31 @@ + +{ + "framework": "hserver-business", + "tests": [ + { + "default": { + "db_url": "/db", + "fortune_url": "/fortunes", + "plaintext_url": "/plaintext", + "json_url": "/json", + "query_url": "/queries?queries=", + "update_url": "/updates?queries=", + "port": 8888, + "approach": "Realistic", + "classification": "Fullstack", + "database": "Postgres", + "framework": "hserver-business", + "language": "Java", + "flavor": "None", + "orm": "Full", + "platform": "hserver-business", + "webserver": "hserver-business", + "os": "Linux", + "database_os": "Linux", + "display_name": "hserver-business", + "notes": "", + "versus": "hserver-business" + } + } + ] +} diff --git a/frameworks/Java/hserver-business/config.toml b/frameworks/Java/hserver-business/config.toml new file mode 100644 index 00000000000..ef213a045ff --- /dev/null +++ b/frameworks/Java/hserver-business/config.toml @@ -0,0 +1,17 @@ +[framework] +name = "hserver-business" + +[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" +os = "Linux" +orm = "Full" +platform = "hserver-business" +webserver = "hserver-business" +versus = "hserver-business" diff --git a/frameworks/Java/hserver-business/hserver-business.dockerfile b/frameworks/Java/hserver-business/hserver-business.dockerfile new file mode 100644 index 00000000000..d58e8b83ffa --- /dev/null +++ b/frameworks/Java/hserver-business/hserver-business.dockerfile @@ -0,0 +1,14 @@ +FROM maven:3.6.1-jdk-11-slim as maven +WORKDIR /hserver-business +COPY pom.xml pom.xml +COPY src src +RUN mvn package --quiet + +FROM openjdk:11.0.3-jdk-slim +WORKDIR /hserver-business +COPY --from=maven /hserver-business/target/hserver-business-1.0.jar app.jar + +EXPOSE 8888 + +CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AggressiveOpts", "-Dio.netty.buffer.checkBounds=false", "-Dio.netty.buffer.checkAccessible=false", "-Dio.netty.iouring.iosqeAsyncThreshold=32000", "-jar", "app.jar"] + diff --git a/frameworks/Java/hserver-business/pom.xml b/frameworks/Java/hserver-business/pom.xml new file mode 100644 index 00000000000..391ac6bb666 --- /dev/null +++ b/frameworks/Java/hserver-business/pom.xml @@ -0,0 +1,51 @@ + + + 4.0.0 + + com.test.hserver + hserver-business + 1.0 + + + hserver-parent + cn.hserver + 4.0.0-beta.3 + + + UTF-8 + 3.3.1 + 42.7.2 + + + + + hserver-web-starter + cn.hserver + + + org.slf4j + slf4j-api + 2.0.17 + + + com.zaxxer + HikariCP + ${version.hikaricp} + + + org.postgresql + postgresql + ${version.postgres} + + + + + + hserver-maven + cn.hserver + + + + diff --git a/frameworks/Java/hserver-business/src/main/java/com/test/hserver/StartApp.java b/frameworks/Java/hserver-business/src/main/java/com/test/hserver/StartApp.java new file mode 100644 index 00000000000..5169f645377 --- /dev/null +++ b/frameworks/Java/hserver-business/src/main/java/com/test/hserver/StartApp.java @@ -0,0 +1,16 @@ +package com.test.hserver; + + +import cn.hserver.core.boot.HServerApplication; +import cn.hserver.core.boot.annotation.HServerBoot; + +/** + * @author hxm + */ +@HServerBoot +public class StartApp { + + public static void main(String[] args) { + HServerApplication.run(StartApp.class, args); + } +} diff --git a/frameworks/Java/hserver-business/src/main/java/com/test/hserver/bean/Fortune.java b/frameworks/Java/hserver-business/src/main/java/com/test/hserver/bean/Fortune.java new file mode 100644 index 00000000000..ce67c19ea45 --- /dev/null +++ b/frameworks/Java/hserver-business/src/main/java/com/test/hserver/bean/Fortune.java @@ -0,0 +1,24 @@ +package com.test.hserver.bean; + +public final class Fortune implements Comparable { + public final int id; + + public final String message; + + public Fortune(int id, String message) { + this.id = id; + this.message = message; + } + @Override + public int compareTo(Fortune other) { + return message.compareTo(other.message); + } + + public int getId() { + return id; + } + + public String getMessage() { + return message; + } +} \ No newline at end of file diff --git a/frameworks/Java/hserver-business/src/main/java/com/test/hserver/bean/Message.java b/frameworks/Java/hserver-business/src/main/java/com/test/hserver/bean/Message.java new file mode 100644 index 00000000000..ec823bfb974 --- /dev/null +++ b/frameworks/Java/hserver-business/src/main/java/com/test/hserver/bean/Message.java @@ -0,0 +1,13 @@ +package com.test.hserver.bean; + +public class Message { + private String message = "Hello, World!"; + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } +} \ No newline at end of file diff --git a/frameworks/Java/hserver-business/src/main/java/com/test/hserver/bean/World.java b/frameworks/Java/hserver-business/src/main/java/com/test/hserver/bean/World.java new file mode 100644 index 00000000000..206846abcc3 --- /dev/null +++ b/frameworks/Java/hserver-business/src/main/java/com/test/hserver/bean/World.java @@ -0,0 +1,24 @@ +package com.test.hserver.bean; + +public class World implements Comparable { + private final int id; + + private final int randomNumber; + + public World(int id, int randomNumber) { + this.id = id; + this.randomNumber = randomNumber; + } + + public int getId() { + return id; + } + + public int getRandomNumber() { + return randomNumber; + } + + @Override public int compareTo(World o) { + return id - o.id; + } +} \ No newline at end of file diff --git a/frameworks/Java/hserver-business/src/main/java/com/test/hserver/controller/TestController.java b/frameworks/Java/hserver-business/src/main/java/com/test/hserver/controller/TestController.java new file mode 100644 index 00000000000..de963b2db86 --- /dev/null +++ b/frameworks/Java/hserver-business/src/main/java/com/test/hserver/controller/TestController.java @@ -0,0 +1,134 @@ +package com.test.hserver.controller; + +import cn.hserver.core.ioc.annotation.Autowired; +import cn.hserver.mvc.annotation.Controller; +import cn.hserver.mvc.annotation.router.GET; +import cn.hserver.mvc.request.Request; +import cn.hserver.mvc.response.Response; +import com.test.hserver.bean.Fortune; +import com.test.hserver.bean.Message; +import com.test.hserver.bean.World; +import com.test.hserver.util.DateUtil; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.*; + +import static com.test.hserver.util.Util.getQueries; +import static com.test.hserver.util.Util.randomWorld; + +/** + * @author hxm + */ +@Controller +public class TestController { + private static final String HELLO = "Hello, World!"; + private static final String SELECT_WORLD = "select * from world where id=?"; + + @Autowired + private DataSource dataSource; + + @GET("/json") + public Message json(Response response) { + response.addHeader("Date", DateUtil.getTime()); + return new Message(); + } + + @GET("/plaintext") + public String plaintext(Response response) { + response.addHeader("Date", DateUtil.getTime()); + return HELLO; + } + + @GET("/db") + public void db(Response response) throws SQLException { + World result; + try (Connection conn = dataSource.getConnection()) { + try (final PreparedStatement statement = conn.prepareStatement(SELECT_WORLD)) { + statement.setInt(1, randomWorld()); + try (ResultSet rs = statement.executeQuery()) { + rs.next(); + result = new World(rs.getInt("id"), rs.getInt("randomNumber")); + } + } + } + response.addHeader("Date", DateUtil.getTime()); + response.sendJson(result); + } + + @GET("/queries") + public void queries(Request request, Response response) throws Exception { + World[] result = new World[getQueries(request.query("queries"))]; + try (Connection conn = dataSource.getConnection()) { + for (int i = 0; i < result.length; i++) { + try (final PreparedStatement statement = conn.prepareStatement(SELECT_WORLD)) { + statement.setInt(1, randomWorld()); + try (ResultSet rs = statement.executeQuery()) { + rs.next(); + result[i] = new World(rs.getInt("id"), rs.getInt("randomNumber")); + } + } + } + } + response.addHeader("Date", DateUtil.getTime()); + response.sendJson(result); + } + + + @GET("/updates") + public void updates(Request request,Response response) throws Exception { + World[] result = new World[getQueries(request.query("queries"))]; + StringJoiner updateSql = new StringJoiner( + ", ", + "UPDATE world SET randomNumber = temp.randomNumber FROM (VALUES ", + " ORDER BY 1) AS temp(id, randomNumber) WHERE temp.id = world.id"); + + try (Connection connection = dataSource.getConnection()) { + try (PreparedStatement statement = connection.prepareStatement(SELECT_WORLD)) { + for (int i = 0; i < result.length; i++) { + statement.setInt(1, randomWorld()); + try (ResultSet rs = statement.executeQuery()) { + rs.next(); + result[i] = new World(rs.getInt("id"), randomWorld()); + } + // prepare update query + updateSql.add("(?, ?)"); + } + } + + try (PreparedStatement statement = connection.prepareStatement(updateSql.toString())) { + int i = 0; + for (World world : result) { + statement.setInt(++i, world.getRandomNumber()); + statement.setInt(++i, world.getRandomNumber()); + } + statement.executeUpdate(); + } + } + response.addHeader("Date", DateUtil.getTime()); + response.sendJson(result); + } + + @GET("/fortunes") + public void fortunes(Response response) throws Exception { + List fortunes = new ArrayList<>(); + try (Connection connection = dataSource.getConnection()) { + try (PreparedStatement stt = connection.prepareStatement("select * from fortune")) { + try (ResultSet rs = stt.executeQuery()) { + while (rs.next()) { + fortunes.add(new Fortune(rs.getInt("id"), rs.getString("message"))); + } + } + } + } + fortunes.add(new Fortune(0, "Additional fortune added at request time.")); + Collections.sort(fortunes); + response.addHeader("Date", DateUtil.getTime()); + Map data=new HashMap<>(); + data.put("data",fortunes); + response.sendTemplate("fortunes.ftl",data); + } +} diff --git a/frameworks/Java/hserver-business/src/main/java/com/test/hserver/db/DataSourceConfig.java b/frameworks/Java/hserver-business/src/main/java/com/test/hserver/db/DataSourceConfig.java new file mode 100644 index 00000000000..9781d6d3fbd --- /dev/null +++ b/frameworks/Java/hserver-business/src/main/java/com/test/hserver/db/DataSourceConfig.java @@ -0,0 +1,25 @@ +package com.test.hserver.db; + +import cn.hserver.core.config.annotation.Configuration; +import cn.hserver.core.ioc.annotation.Autowired; +import cn.hserver.core.ioc.annotation.Bean; +import com.zaxxer.hikari.HikariDataSource; + +import javax.sql.DataSource; + +@Configuration +public class DataSourceConfig { + + @Autowired + private PostgresConfig postgresConfig; + + @Bean + public DataSource initDataSource() { + HikariDataSource ds = new HikariDataSource(); + ds.setJdbcUrl(postgresConfig.getJdbcUrl()); + ds.setUsername(postgresConfig.getUsername()); + ds.setPassword(postgresConfig.getPassword()); + ds.setMaximumPoolSize(postgresConfig.getMaximumPoolSize()); + return ds; + } +} diff --git a/frameworks/Java/hserver-business/src/main/java/com/test/hserver/db/PostgresConfig.java b/frameworks/Java/hserver-business/src/main/java/com/test/hserver/db/PostgresConfig.java new file mode 100644 index 00000000000..420c8a78ce1 --- /dev/null +++ b/frameworks/Java/hserver-business/src/main/java/com/test/hserver/db/PostgresConfig.java @@ -0,0 +1,57 @@ +package com.test.hserver.db; + + +import cn.hserver.core.config.annotation.ConfigurationProperties; + +@ConfigurationProperties +public class PostgresConfig { + private String jdbcUrl; + private String username; + private String password; + private int maximumPoolSize; + + public PostgresConfig() { + } + + public String getJdbcUrl() { + return jdbcUrl; + } + + public void setJdbcUrl(String jdbcUrl) { + this.jdbcUrl = jdbcUrl; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public int getMaximumPoolSize() { + return maximumPoolSize; + } + + public void setMaximumPoolSize(int maximumPoolSize) { + this.maximumPoolSize = maximumPoolSize; + } + + @Override + public String toString() { + return "PostgresConfig{" + + "jdbcUrl='" + jdbcUrl + '\'' + + ", username='" + username + '\'' + + ", password='" + password + '\'' + + ", maximumPoolSize=" + maximumPoolSize + + '}'; + } +} \ No newline at end of file diff --git a/frameworks/Java/hserver-business/src/main/java/com/test/hserver/task/TimeAdd.java b/frameworks/Java/hserver-business/src/main/java/com/test/hserver/task/TimeAdd.java new file mode 100644 index 00000000000..0390b60971a --- /dev/null +++ b/frameworks/Java/hserver-business/src/main/java/com/test/hserver/task/TimeAdd.java @@ -0,0 +1,15 @@ +package com.test.hserver.task; + +import cn.hserver.core.ioc.annotation.Component; +import cn.hserver.core.scheduling.annotation.Task; +import com.test.hserver.util.DateUtil; + +@Component +public class TimeAdd { + + @Task(name = "时间计算", time = "1000") + public void add() { + DateUtil.time = DateUtil.getNow(); + } + +} diff --git a/frameworks/Java/hserver-business/src/main/java/com/test/hserver/util/DateUtil.java b/frameworks/Java/hserver-business/src/main/java/com/test/hserver/util/DateUtil.java new file mode 100644 index 00000000000..0874b9bd9eb --- /dev/null +++ b/frameworks/Java/hserver-business/src/main/java/com/test/hserver/util/DateUtil.java @@ -0,0 +1,25 @@ +package com.test.hserver.util; + +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.Locale; + +/** + * @author hxm + */ +public class DateUtil { + private static final DateTimeFormatter GMT_FMT = DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US); + private static final ZoneId zoneId = ZoneId.of("GMT"); + public static String getNow() { + return GMT_FMT.format(LocalDateTime.now().atZone(zoneId)); + } + public static String time; + public static String getTime(){ + if (time==null){ + time=getNow(); + return time; + } + return time; + } +} diff --git a/frameworks/Java/hserver-business/src/main/java/com/test/hserver/util/Util.java b/frameworks/Java/hserver-business/src/main/java/com/test/hserver/util/Util.java new file mode 100644 index 00000000000..775f4f8f0f6 --- /dev/null +++ b/frameworks/Java/hserver-business/src/main/java/com/test/hserver/util/Util.java @@ -0,0 +1,18 @@ +package com.test.hserver.util; + +import java.util.concurrent.ThreadLocalRandom; + +public class Util { + public static int randomWorld() { + return 1 + ThreadLocalRandom.current().nextInt(10000); + } + + public static int getQueries(String queries) { + try { + int count = Integer.parseInt(queries); + return Math.min(500, Math.max(1, count)); + } catch (Exception e) { + return 1; + } + } +} \ No newline at end of file diff --git a/frameworks/Java/hserver-business/src/main/resources/app.properties b/frameworks/Java/hserver-business/src/main/resources/app.properties new file mode 100644 index 00000000000..39bb1a65409 --- /dev/null +++ b/frameworks/Java/hserver-business/src/main/resources/app.properties @@ -0,0 +1,7 @@ +jdbcUrl= jdbc:postgresql://tfb-database:5432/hello_world +username= benchmarkdbuser +password= benchmarkdbpass +maximumPoolSize= 256 + +log=info +netty.pool= 64 diff --git a/frameworks/Java/hserver-business/src/main/resources/template/fortunes.ftl b/frameworks/Java/hserver-business/src/main/resources/template/fortunes.ftl new file mode 100644 index 00000000000..233927248fa --- /dev/null +++ b/frameworks/Java/hserver-business/src/main/resources/template/fortunes.ftl @@ -0,0 +1,20 @@ + + + + Fortunes + + + + + + + + <#list data as fortune> + + + + + +
idmessage
${fortune.id?html}${fortune.message?html}
+ + \ No newline at end of file diff --git a/frameworks/Java/hserver/benchmark_config.json b/frameworks/Java/hserver/benchmark_config.json index 87397f30d93..035eae68c9c 100644 --- a/frameworks/Java/hserver/benchmark_config.json +++ b/frameworks/Java/hserver/benchmark_config.json @@ -5,11 +5,11 @@ { "default": { "db_url": "/db", - "query_url": "/queries?queries=", "fortune_url": "/fortunes", "plaintext_url": "/plaintext", - "update_url": "/updates?queries=", "json_url": "/json", + "query_url": "/queries?queries=", + "update_url": "/updates?queries=", "port": 8888, "approach": "Realistic", "classification": "Fullstack", @@ -18,8 +18,8 @@ "language": "Java", "flavor": "None", "orm": "Full", - "platform": "None", - "webserver": "None", + "platform": "hserver", + "webserver": "hserver", "os": "Linux", "database_os": "Linux", "display_name": "hserver", @@ -28,4 +28,4 @@ } } ] -} \ No newline at end of file +} diff --git a/frameworks/Java/hserver/config.toml b/frameworks/Java/hserver/config.toml index db5b6ff47a1..6979faa03a0 100644 --- a/frameworks/Java/hserver/config.toml +++ b/frameworks/Java/hserver/config.toml @@ -12,6 +12,6 @@ approach = "Realistic" classification = "Fullstack" os = "Linux" orm = "Full" -platform = "None" -webserver = "None" -versus = "hserver" \ No newline at end of file +platform = "hserver" +webserver = "hserver" +versus = "hserver" diff --git a/frameworks/Java/hserver/hserver.dockerfile b/frameworks/Java/hserver/hserver.dockerfile index 483485da30f..67095536752 100644 --- a/frameworks/Java/hserver/hserver.dockerfile +++ b/frameworks/Java/hserver/hserver.dockerfile @@ -1,13 +1,13 @@ -FROM maven:3.6.3-openjdk-8-slim as maven +FROM maven:3.6.1-jdk-11-slim as maven WORKDIR /hserver COPY pom.xml pom.xml COPY src src -RUN mvn package +RUN mvn package --quiet -FROM openjdk:8u275-jdk-slim +FROM openjdk:11.0.3-jdk-slim WORKDIR /hserver COPY --from=maven /hserver/target/hserver-1.0.jar app.jar EXPOSE 8888 -CMD ["java", "-jar", "app.jar"] \ No newline at end of file +CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AggressiveOpts", "-Dio.netty.buffer.checkBounds=false", "-Dio.netty.buffer.checkAccessible=false", "-Dio.netty.iouring.iosqeAsyncThreshold=32000", "-jar", "app.jar"] diff --git a/frameworks/Java/hserver/pom.xml b/frameworks/Java/hserver/pom.xml index 8d63b000645..3aba63dfa4b 100644 --- a/frameworks/Java/hserver/pom.xml +++ b/frameworks/Java/hserver/pom.xml @@ -11,24 +11,24 @@ hserver-parent cn.hserver - 3.1.M2 + 4.0.0-beta.3 + UTF-8 3.3.1 - 42.3.8 + 42.7.2 - - hserver + hserver-web-starter cn.hserver - - hserver-plugin-web - cn.hserver + org.slf4j + slf4j-api + 2.0.17 com.zaxxer @@ -44,9 +44,9 @@ - hserver-plugin-maven + hserver-maven cn.hserver - \ No newline at end of file + diff --git a/frameworks/Java/hserver/src/main/java/com/test/hserver/StartApp.java b/frameworks/Java/hserver/src/main/java/com/test/hserver/StartApp.java index 87c5642d0b8..3ee44fa000c 100644 --- a/frameworks/Java/hserver/src/main/java/com/test/hserver/StartApp.java +++ b/frameworks/Java/hserver/src/main/java/com/test/hserver/StartApp.java @@ -1,10 +1,10 @@ package com.test.hserver; -import cn.hserver.HServerApplication; -import cn.hserver.core.ioc.annotation.HServerBoot; -import cn.hserver.core.server.context.ConstConfig; - +import cn.hserver.core.boot.HServerApplication; +import cn.hserver.core.boot.annotation.HServerBoot; +import cn.hserver.mvc.server.WebServer; +import com.test.hserver.controller.TestController; /** * @author hxm @@ -13,8 +13,14 @@ public class StartApp { public static void main(String[] args) { - ConstConfig.bossPool = Runtime.getRuntime().availableProcessors()/2; - ConstConfig.workerPool = Runtime.getRuntime().availableProcessors(); - HServerApplication.run(StartApp.class, 8888, args); + WebServer.router + .get("/json", TestController::json) + .get("/plaintext", TestController::plaintext) + .get("/db", TestController::db) + .get("/queries", TestController::queries) + .get("/updates", TestController::updates) + .get("/fortunes", TestController::fortunes) + ; + HServerApplication.run(StartApp.class, args); } } diff --git a/frameworks/Java/hserver/src/main/java/com/test/hserver/controller/TestController.java b/frameworks/Java/hserver/src/main/java/com/test/hserver/controller/TestController.java index 9ab5d958039..7bea7268f33 100644 --- a/frameworks/Java/hserver/src/main/java/com/test/hserver/controller/TestController.java +++ b/frameworks/Java/hserver/src/main/java/com/test/hserver/controller/TestController.java @@ -1,14 +1,12 @@ package com.test.hserver.controller; -import cn.hserver.core.ioc.annotation.Autowired; -import cn.hserver.plugin.web.annotation.Controller; -import cn.hserver.plugin.web.annotation.GET; -import cn.hserver.plugin.web.interfaces.HttpResponse; +import cn.hserver.core.context.IocApplicationContext; + +import cn.hserver.mvc.context.WebContext; import com.test.hserver.bean.Fortune; import com.test.hserver.bean.Message; import com.test.hserver.bean.World; import com.test.hserver.util.DateUtil; - import javax.sql.DataSource; import java.sql.Connection; import java.sql.PreparedStatement; @@ -22,30 +20,34 @@ /** * @author hxm */ -@Controller public class TestController { private static final String HELLO = "Hello, World!"; private static final String SELECT_WORLD = "select * from world where id=?"; - @Autowired - private DataSource dataSource; + private static DataSource dataSource; + + public static DataSource getDataSource() { + if (dataSource == null) { + dataSource= IocApplicationContext.getBean(DataSource.class); + } + return dataSource; + } + - @GET("/json") - public Message json(HttpResponse response) { - response.setHeader("Date", DateUtil.getTime()); - return new Message(); + public static void json(WebContext webContext) { + webContext.response.addHeader("Date", DateUtil.getTime()); + webContext.response.sendJson(new Message()); } - @GET("/plaintext") - public String plaintext(HttpResponse response) { - response.setHeader("Date", DateUtil.getTime()); - return HELLO; + public static void plaintext(WebContext webContext) { + webContext.response.addHeader("Date", DateUtil.getTime()); + webContext.response.sendText(HELLO); + } - @GET("/db") - public void db(HttpResponse response) throws SQLException { + public static void db(WebContext webContext) throws SQLException { World result; - try (Connection conn = dataSource.getConnection()) { + try (Connection conn = getDataSource().getConnection()) { try (final PreparedStatement statement = conn.prepareStatement(SELECT_WORLD)) { statement.setInt(1, randomWorld()); try (ResultSet rs = statement.executeQuery()) { @@ -54,14 +56,13 @@ public void db(HttpResponse response) throws SQLException { } } } - response.setHeader("Date", DateUtil.getTime()); - response.sendJson(result); + webContext.response.addHeader("Date", DateUtil.getTime()); + webContext.response.sendJson(result); } - @GET("/queries") - public void queries(String queries,HttpResponse response) throws Exception { - World[] result = new World[getQueries(queries)]; - try (Connection conn = dataSource.getConnection()) { + public static void queries(WebContext webContext) throws Exception { + World[] result = new World[getQueries(webContext.request.query("queries"))]; + try (Connection conn = getDataSource().getConnection()) { for (int i = 0; i < result.length; i++) { try (final PreparedStatement statement = conn.prepareStatement(SELECT_WORLD)) { statement.setInt(1, randomWorld()); @@ -72,20 +73,19 @@ public void queries(String queries,HttpResponse response) throws Exception { } } } - response.setHeader("Date", DateUtil.getTime()); - response.sendJson(result); + webContext.response.addHeader("Date", DateUtil.getTime()); + webContext.response.sendJson(result); } - @GET("/updates") - public void updates(String queries,HttpResponse response) throws Exception { - World[] result = new World[getQueries(queries)]; + public static void updates(WebContext webContext) throws Exception { + World[] result = new World[getQueries(webContext.request.query("queries"))]; StringJoiner updateSql = new StringJoiner( ", ", "UPDATE world SET randomNumber = temp.randomNumber FROM (VALUES ", " ORDER BY 1) AS temp(id, randomNumber) WHERE temp.id = world.id"); - try (Connection connection = dataSource.getConnection()) { + try (Connection connection = getDataSource().getConnection()) { try (PreparedStatement statement = connection.prepareStatement(SELECT_WORLD)) { for (int i = 0; i < result.length; i++) { statement.setInt(1, randomWorld()); @@ -107,14 +107,13 @@ public void updates(String queries,HttpResponse response) throws Exception { statement.executeUpdate(); } } - response.setHeader("Date", DateUtil.getTime()); - response.sendJson(result); + webContext.response.addHeader("Date", DateUtil.getTime()); + webContext.response.sendJson(result); } - @GET("/fortunes") - public void fortunes(HttpResponse response) throws Exception { + public static void fortunes(WebContext webContext) throws Exception { List fortunes = new ArrayList<>(); - try (Connection connection = dataSource.getConnection()) { + try (Connection connection = getDataSource().getConnection()) { try (PreparedStatement stt = connection.prepareStatement("select * from fortune")) { try (ResultSet rs = stt.executeQuery()) { while (rs.next()) { @@ -125,9 +124,9 @@ public void fortunes(HttpResponse response) throws Exception { } fortunes.add(new Fortune(0, "Additional fortune added at request time.")); Collections.sort(fortunes); - response.setHeader("Date", DateUtil.getTime()); + webContext.response.addHeader("Date", DateUtil.getTime()); Map data=new HashMap<>(); data.put("data",fortunes); - response.sendTemplate("fortunes.ftl",data); + webContext.response.sendTemplate("fortunes.ftl",data); } } diff --git a/frameworks/Java/hserver/src/main/java/com/test/hserver/db/DataSourceConfig.java b/frameworks/Java/hserver/src/main/java/com/test/hserver/db/DataSourceConfig.java index 0fee7b56b1c..9781d6d3fbd 100644 --- a/frameworks/Java/hserver/src/main/java/com/test/hserver/db/DataSourceConfig.java +++ b/frameworks/Java/hserver/src/main/java/com/test/hserver/db/DataSourceConfig.java @@ -1,8 +1,8 @@ package com.test.hserver.db; +import cn.hserver.core.config.annotation.Configuration; import cn.hserver.core.ioc.annotation.Autowired; import cn.hserver.core.ioc.annotation.Bean; -import cn.hserver.core.ioc.annotation.Configuration; import com.zaxxer.hikari.HikariDataSource; import javax.sql.DataSource; diff --git a/frameworks/Java/hserver/src/main/java/com/test/hserver/db/PostgresConfig.java b/frameworks/Java/hserver/src/main/java/com/test/hserver/db/PostgresConfig.java index 57c08ea4b25..420c8a78ce1 100644 --- a/frameworks/Java/hserver/src/main/java/com/test/hserver/db/PostgresConfig.java +++ b/frameworks/Java/hserver/src/main/java/com/test/hserver/db/PostgresConfig.java @@ -1,7 +1,7 @@ package com.test.hserver.db; -import cn.hserver.core.ioc.annotation.ConfigurationProperties; +import cn.hserver.core.config.annotation.ConfigurationProperties; @ConfigurationProperties public class PostgresConfig { diff --git a/frameworks/Java/hserver/src/main/java/com/test/hserver/task/TimeAdd.java b/frameworks/Java/hserver/src/main/java/com/test/hserver/task/TimeAdd.java index a1f866b2d89..0390b60971a 100644 --- a/frameworks/Java/hserver/src/main/java/com/test/hserver/task/TimeAdd.java +++ b/frameworks/Java/hserver/src/main/java/com/test/hserver/task/TimeAdd.java @@ -1,10 +1,10 @@ package com.test.hserver.task; -import cn.hserver.core.ioc.annotation.Bean; -import cn.hserver.core.ioc.annotation.Task; +import cn.hserver.core.ioc.annotation.Component; +import cn.hserver.core.scheduling.annotation.Task; import com.test.hserver.util.DateUtil; -@Bean +@Component public class TimeAdd { @Task(name = "时间计算", time = "1000") diff --git a/frameworks/Java/hserver/src/main/resources/app.properties b/frameworks/Java/hserver/src/main/resources/app.properties index 78b388d9923..4fa6afbf7cc 100644 --- a/frameworks/Java/hserver/src/main/resources/app.properties +++ b/frameworks/Java/hserver/src/main/resources/app.properties @@ -3,6 +3,4 @@ username= benchmarkdbuser password= benchmarkdbpass maximumPoolSize= 256 -level=info -#业务线程池 -web.businessPool=-1 +log=info \ No newline at end of file diff --git a/frameworks/Java/httpserver/README.md b/frameworks/Java/httpserver/README.md index 881dcb4f97e..fae36815472 100755 --- a/frameworks/Java/httpserver/README.md +++ b/frameworks/Java/httpserver/README.md @@ -1,26 +1,30 @@ -# httpserver Benchmarking Test - -This is the com.sun.net.httpserver portion of a [benchmarking test suite](../) comparing a variety of web development platforms. +# Benchmarking Test +## httpserver +This is the com.sun.net.httpserver portion of a [benchmarking test suite](../) comparing a variety of web development +platforms. Package [com.sun.net.httpserver](https://docs.oracle.com/javase/8/docs/jre/api/net/httpserver/spec/com/sun/net/httpserver/HttpServer.html) provides a simple high-level Http server API, which can be used to build embedded HTTP servers. It is built-in to the Oracle JDK and OpenJDK (but is not part of the Java standard and is not available in other JDKs). - - +## Robaho httpserver +This is an alternative version of the [com.sun.net.httpserver](https://docs.oracle.com/javase/8/docs/jre/api/net/httpserver/spec/com/sun/net/httpserver/HttpServer.html) +Package [robaho.net.httpserver](https://github.com/robaho/httpserver) provides an implementation of `com.sun.net.httpserver` designed for virtual threads, thus requiring JDK21+. ### Test Type Implementation Source Code - * [JSON](src/main/java/benchmarks/Server.java) * [Plaintext](src/main/java/benchmarks/Server.java) * [Fortunes](src/main/java/benchmarks/Server.java) ## Important Libraries + The tests were run with: + * [Jackson](https://github.com/FasterXML/jackson) * [HikariCP](https://github.com/brettwooldridge/HikariCP) * [HTTL](https://httl.github.io/en/) +* [Robaho httpserver](https://github.com/robaho/httpserver) ## Test URLs ### JSON diff --git a/frameworks/Java/httpserver/benchmark_config.json b/frameworks/Java/httpserver/benchmark_config.json index 99f040ca11b..16e9cdab907 100755 --- a/frameworks/Java/httpserver/benchmark_config.json +++ b/frameworks/Java/httpserver/benchmark_config.json @@ -38,6 +38,81 @@ "display_name": "httpserver-postgres", "notes": "", "versus": "" + }, + "graalvm": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Platform", + "database": "None", + "framework": "None", + "language": "Java", + "flavor": "None", + "orm": "Raw", + "platform": "httpserver", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "httpserver-graalvm", + "notes": "", + "versus": "httpserver" + }, + "robaho": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Platform", + "database": "None", + "framework": "None", + "language": "Java", + "flavor": "None", + "orm": "Raw", + "platform": "httpserver", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "httpserver-robaho", + "notes": "", + "versus": "" + }, + "robaho-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-robaho-postgres", + "notes": "", + "versus": "" + }, + "robaho-graalvm": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Platform", + "database": "None", + "framework": "None", + "language": "Java", + "flavor": "None", + "orm": "Raw", + "platform": "httpserver", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "httpserver-robaho-graalvm", + "notes": "", + "versus": "httpserver-robaho" } } ] diff --git a/frameworks/Java/httpserver/config.toml b/frameworks/Java/httpserver/config.toml index 72dd4414ff3..3531b9e5e9f 100644 --- a/frameworks/Java/httpserver/config.toml +++ b/frameworks/Java/httpserver/config.toml @@ -25,3 +25,58 @@ orm = "Raw" platform = "httpserver" webserver = "None" versus = "" + + +[graalvm] +urls.plaintext = "/plaintext" +urls.json = "/json" +approach = "Realistic" +classification = "Platform" +database = "None" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "httpserver" +webserver = "None" +versus = "httpserver" + + +[robaho] +urls.plaintext = "/plaintext" +urls.json = "/json" +approach = "Realistic" +classification = "Platform" +database = "None" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "httpserver" +webserver = "None" +versus = "httpserver" + + +[robaho-postgres] +urls.fortune = "/fortunes" +approach = "Realistic" +classification = "Platform" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "httpserver" +webserver = "None" +versus = "" + + +[robaho-graalvm] +urls.plaintext = "/plaintext" +urls.json = "/json" +approach = "Realistic" +classification = "Platform" +database = "None" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "httpserver" +webserver = "None" +versus = "httpserver-robaho" diff --git a/frameworks/Java/httpserver/httpserver-graalvm.dockerfile b/frameworks/Java/httpserver/httpserver-graalvm.dockerfile new file mode 100644 index 00000000000..f9cd7e29cfb --- /dev/null +++ b/frameworks/Java/httpserver/httpserver-graalvm.dockerfile @@ -0,0 +1,13 @@ +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 ghcr.io/graalvm/graalvm-community:25 +WORKDIR /httpserver +COPY --from=maven /httpserver/target/httpserver-1.0-jar-with-dependencies.jar app.jar + +EXPOSE 8080 + +CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-jar", "app.jar"] diff --git a/frameworks/Java/httpserver/httpserver-postgres.dockerfile b/frameworks/Java/httpserver/httpserver-postgres.dockerfile index f9441b41a27..5991ae20026 100644 --- a/frameworks/Java/httpserver/httpserver-postgres.dockerfile +++ b/frameworks/Java/httpserver/httpserver-postgres.dockerfile @@ -1,13 +1,13 @@ -FROM maven:3.6.1-jdk-11-slim as maven +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 openjdk:11.0.3-jdk-slim +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:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AggressiveOpts", "-jar", "app.jar", "postgres"] +CMD ["java", "-server", "-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 new file mode 100644 index 00000000000..44b6b0975f0 --- /dev/null +++ b/frameworks/Java/httpserver/httpserver-robaho-graalvm.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 ghcr.io/graalvm/graalvm-community:25 +WORKDIR /httpserver-robaho +COPY --from=maven /httpserver-robaho/target/httpserver-1.0-jar-with-dependencies.jar app.jar + +EXPOSE 8080 + +CMD ["java", "-server", "-jar", "app.jar"] diff --git a/frameworks/Java/httpserver/httpserver-robaho-postgres.dockerfile b/frameworks/Java/httpserver/httpserver-robaho-postgres.dockerfile new file mode 100644 index 00000000000..e7bdfb11102 --- /dev/null +++ b/frameworks/Java/httpserver/httpserver-robaho-postgres.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", "-jar", "app.jar", "postgres"] diff --git a/frameworks/Java/httpserver/httpserver-robaho.dockerfile b/frameworks/Java/httpserver/httpserver-robaho.dockerfile new file mode 100644 index 00000000000..77f57658d2a --- /dev/null +++ b/frameworks/Java/httpserver/httpserver-robaho.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", "-jar", "app.jar"] diff --git a/frameworks/Java/httpserver/httpserver.dockerfile b/frameworks/Java/httpserver/httpserver.dockerfile index 9e85735fed8..b50fbadc157 100644 --- a/frameworks/Java/httpserver/httpserver.dockerfile +++ b/frameworks/Java/httpserver/httpserver.dockerfile @@ -1,13 +1,13 @@ -FROM maven:3.6.1-jdk-11-slim as maven +FROM maven:3-eclipse-temurin-24-alpine as maven WORKDIR /httpserver COPY pom.xml pom.xml COPY src src RUN mvn compile assembly:single -q -FROM openjdk:11.0.3-jdk-slim +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:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AggressiveOpts", "-jar", "app.jar"] +CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-jar", "app.jar"] diff --git a/frameworks/Java/httpserver/pom.xml b/frameworks/Java/httpserver/pom.xml index 931c9c56f94..5b983699fe6 100644 --- a/frameworks/Java/httpserver/pom.xml +++ b/frameworks/Java/httpserver/pom.xml @@ -1,5 +1,5 @@ + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> 4.0.0 @@ -10,45 +10,57 @@ UTF-8 - 11 - 11 + 25 + 25 com.fasterxml.jackson.core jackson-databind - 2.13.4.2 + 2.19.1 com.fasterxml.jackson.module jackson-module-afterburner - 2.9.9 + 2.19.1 - org.postgresql postgresql - 42.4.1 - - - com.zaxxer - HikariCP - 3.3.1 + 42.7.2 - com.github.httl httl 1.0.11 - org.slf4j slf4j-simple 1.8.0-beta4 + + com.zaxxer + HikariCP + 7.0.2 + + + + robaho + + false + + + + io.github.robaho + httpserver + 1.0.23 + + + + @@ -59,6 +71,8 @@ 3.8.0 false + 21 + 21 diff --git a/frameworks/Java/httpserver/src/main/java/benchmarks/Fortune.java b/frameworks/Java/httpserver/src/main/java/benchmarks/Fortune.java index 2b420fb4764..7320e188beb 100644 --- a/frameworks/Java/httpserver/src/main/java/benchmarks/Fortune.java +++ b/frameworks/Java/httpserver/src/main/java/benchmarks/Fortune.java @@ -1,22 +1,6 @@ package benchmarks; -public class Fortune implements Comparable { - - private final int id; - private final String message; - - public Fortune(int id, String message) { - this.id = id; - this.message = message; - } - - public int getId() { - return id; - } - - public String getMessage() { - return message; - } +public record Fortune(int id, String message) implements Comparable { @Override public int compareTo(Fortune other) { diff --git a/frameworks/Java/httpserver/src/main/java/benchmarks/Message.java b/frameworks/Java/httpserver/src/main/java/benchmarks/Message.java index 6a84fb9e7ca..3568e9b90d2 100755 --- a/frameworks/Java/httpserver/src/main/java/benchmarks/Message.java +++ b/frameworks/Java/httpserver/src/main/java/benchmarks/Message.java @@ -1,15 +1,4 @@ package benchmarks; -public class Message { +public record Message(String message) {} - private final String message; - - public Message(String message) { - this.message = message; - } - - public String getMessage() { - return message; - } - -} diff --git a/frameworks/Java/httpserver/src/main/java/benchmarks/Server.java b/frameworks/Java/httpserver/src/main/java/benchmarks/Server.java index 60893b4ba2e..80566641a9f 100755 --- a/frameworks/Java/httpserver/src/main/java/benchmarks/Server.java +++ b/frameworks/Java/httpserver/src/main/java/benchmarks/Server.java @@ -8,18 +8,23 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.text.ParseException; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; import java.util.concurrent.Executors; -import java.util.concurrent.SynchronousQueue; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; + import javax.sql.DataSource; + import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.module.afterburner.AfterburnerModule; import com.sun.net.httpserver.HttpHandler; import com.sun.net.httpserver.HttpServer; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; + import httl.Engine; import httl.Template; @@ -47,23 +52,34 @@ private static List queryFortunes(DataSource ds) throws SQLException { } private static DataSource createPostgresDataSource() throws ClassNotFoundException { - Class.forName("org.postgresql.Driver"); HikariConfig config = new HikariConfig(); + config.setJdbcUrl("jdbc:postgresql://tfb-database:5432/hello_world"); config.setUsername("benchmarkdbuser"); config.setPassword("benchmarkdbpass"); - config.setMaximumPoolSize(512); + + config.setMaximumPoolSize(64); + config.setMinimumIdle(16); + + config.setConnectionTimeout(10000); + config.setIdleTimeout(600000); + config.setMaxLifetime(1800000); + + config.setAutoCommit(true); + + config.setPoolName("PostgreSQL-HikariCP-Pool"); + return new HikariDataSource(config); } - private static Template loadTemplate(String filename) throws IOException, ParseException { + private static Template loadTemplate() throws IOException, ParseException { Properties props = new Properties(); props.put("import.packages", "java.util," + Fortune.class.getPackage().getName()); props.put("input.encoding", "UTF-8"); props.put("output.encoding", "UTF-8"); props.put("precompiled", "false"); Engine engine = Engine.getEngine(props); - return engine.getTemplate(filename); + return engine.getTemplate("/fortunes.template.httl"); } private static HttpHandler createPlaintextHandler() { @@ -72,7 +88,6 @@ 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(); }; } @@ -98,7 +113,7 @@ private static HttpHandler createJSONHandler() { } private static HttpHandler createFortunesHandler(DataSource ds) throws IOException, ParseException { - Template template = loadTemplate("/fortunes.template.httl"); + Template template = loadTemplate(); return t -> { try { // query db @@ -116,7 +131,6 @@ 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); @@ -124,7 +138,7 @@ private static HttpHandler createFortunesHandler(DataSource ds) throws IOExcepti }; } - public static void main(String[] args) throws Exception { + static void main(String[] args) throws Exception { // parse arguments String settings = args.length > 0 ? args[0] : ""; int port = args.length > 1 ? Integer.parseInt(args[1]) : 8080; @@ -132,8 +146,7 @@ public 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.newFixedThreadPool(Runtime.getRuntime().availableProcessors())); - // add context handlers + server.setExecutor(Executors.newVirtualThreadPerTaskExecutor()); server.createContext("/plaintext", createPlaintextHandler()); server.createContext("/json", createJSONHandler()); if (settings.contains("postgres")) { @@ -143,4 +156,4 @@ public static void main(String[] args) throws Exception { // start server server.start(); } -} +} \ No newline at end of file diff --git a/frameworks/Java/inverno/README.md b/frameworks/Java/inverno/README.md index b205ef706b6..492cd60e430 100755 --- a/frameworks/Java/inverno/README.md +++ b/frameworks/Java/inverno/README.md @@ -2,20 +2,23 @@ ### Test Type Implementation Source Code -* [JSON](src/main/java/com/techempower/inverno/benchmark/internal/Handler.java) -* [PLAINTEXT](src/main/java/com/techempower/inverno/benchmark/internal/Handler.java) -* [DB](src/main/java/com/techempower/inverno/benchmark/internal/Handler.java) -* [QUERY](src/main/java/com/techempower/inverno/benchmark/internal/Handler.java) -* [CACHED QUERY](src/main/java/com/techempower/inverno/benchmark/internal/Handler.java) -* [UPDATE](src/main/java/com/techempower/inverno/benchmark/internal/Handler.java) -* [FORTUNES](src/main/java/com/techempower/inverno/benchmark/internal/Handler.java) +* [JSON](src/main/java/com/techempower/inverno/benchmark/internal/Controller.java) +* [PLAINTEXT](src/main/java/com/techempower/inverno/benchmark/internal/Controller.java) +* [DB](src/main/java/com/techempower/inverno/benchmark/internal/Controller.java) +* [QUERY](src/main/java/com/techempower/inverno/benchmark/internal/Controller.java) +* [CACHED QUERY](src/main/java/com/techempower/inverno/benchmark/internal/Controller.java) +* [UPDATE](src/main/java/com/techempower/inverno/benchmark/internal/Controller.java) +* [FORTUNES](src/main/java/com/techempower/inverno/benchmark/internal/Controller.java) ## Important Libraries + The tests were run with: -* [Java OpenJDK 16](https://openjdk.java.net/) -* [Inverno 1.4.1](https://inverno.io) +* [Java OpenJDK 21](https://openjdk.java.net/) +* [Inverno 1.12.0](https://inverno.io) +* [DSL-JSON 2.0.2](https://github.com/ngs-doo/dsl-json) ## Test URLs + ### JSON http://localhost:8080/json diff --git a/frameworks/Java/inverno/inverno-postgres.dockerfile b/frameworks/Java/inverno/inverno-postgres.dockerfile index 5a2928679e3..1435b348829 100644 --- a/frameworks/Java/inverno/inverno-postgres.dockerfile +++ b/frameworks/Java/inverno/inverno-postgres.dockerfile @@ -1,11 +1,12 @@ -FROM maven:3.8.2-openjdk-16 as maven +FROM maven:3.9.9-eclipse-temurin-21 as maven WORKDIR /inverno COPY src src COPY pom.xml pom.xml -RUN mvn package -q +RUN mvn package -q -Pio.inverno.epoll EXPOSE 8080 -# CMD [ "target/maven-inverno/application_linux_amd64/inverno-benchmark-1.0.0-SNAPSHOT/bin/inverno-benchmark" ] CMD export DBIP=`getent hosts tfb-database | awk '{ print $1 }'` && \ - target/maven-inverno/application_linux_amd64/inverno-benchmark-1.0.0-SNAPSHOT/bin/inverno-benchmark --com.techempower.inverno.benchmark.appConfiguration.db_host=\"$DBIP\" \ No newline at end of file + target/inverno-benchmark-1.0.0-SNAPSHOT-application_linux_amd64/bin/inverno-benchmark \ + --com.techempower.inverno.benchmark.appConfiguration.db_host=\"$DBIP\" \ + --com.techempower.inverno.benchmark.appConfiguration.boot.reactor_event_loop_group_size=$((`grep --count ^processor /proc/cpuinfo`)) diff --git a/frameworks/Java/inverno/inverno.dockerfile b/frameworks/Java/inverno/inverno.dockerfile index 6af60a189dc..6744f548c14 100644 --- a/frameworks/Java/inverno/inverno.dockerfile +++ b/frameworks/Java/inverno/inverno.dockerfile @@ -1,9 +1,9 @@ -FROM maven:3.8.2-openjdk-16 as maven +FROM maven:3.9.9-eclipse-temurin-21 as maven WORKDIR /inverno COPY src src COPY pom.xml pom.xml -RUN mvn package -q +RUN mvn package -q -Pio.inverno.epoll EXPOSE 8080 -CMD [ "target/maven-inverno/application_linux_amd64/inverno-benchmark-1.0.0-SNAPSHOT/bin/inverno-benchmark", "--com.techempower.inverno.benchmark.appConfiguration.boot.reactor_prefer_vertx=false" ] +CMD [ "target/inverno-benchmark-1.0.0-SNAPSHOT-application_linux_amd64/bin/inverno-benchmark", "--com.techempower.inverno.benchmark.appConfiguration.boot.reactor_prefer_vertx=false" ] diff --git a/frameworks/Java/inverno/pom.xml b/frameworks/Java/inverno/pom.xml index 296f7d99246..3b11a165f97 100644 --- a/frameworks/Java/inverno/pom.xml +++ b/frameworks/Java/inverno/pom.xml @@ -6,7 +6,7 @@ io.inverno.dist inverno-parent - 1.4.1 + 1.12.0 com.techempower inverno-benchmark @@ -17,9 +17,9 @@ Inverno framework benchmark test - 16 - 16 - 16 + 21 + 21 + 21 @@ -47,12 +47,17 @@ io.inverno.mod inverno-sql-vertx - + org.unbescape unbescape 1.1.6.RELEASE + + com.dslplatform + dsl-json + 2.0.2 + io.vertx vertx-pg-client @@ -71,20 +76,12 @@ io.netty netty-handler-proxy - ${version.netty} io.netty netty-resolver-dns - ${version.netty} - - io.netty - netty-transport-native-epoll - linux-x86_64 - - org.apache.logging.log4j log4j-core @@ -94,32 +91,133 @@ - io.inverno.tool - inverno-maven-plugin + org.apache.maven.plugins + maven-compiler-plugin - inverno-package - package - - build-app - + default-compile - server - - - inverno-benchmark - -Xms2g -Xmx2g -server -XX:+UseNUMA -XX:+UseParallelGC -Dio.netty.leakDetection.level=disabled -Dvertx.disableHttpHeadersValidation=true -Dvertx.disableMetrics=true -Dvertx.disableH2c=true -Dvertx.disableWebsockets=true -Dvertx.flashPolicyHandler=false -Dvertx.threadChecks=false -Dvertx.disableContextTimings=true -Dvertx.disableTCCL=true --add-modules io.netty.transport.unix.common,io.netty.transport.epoll - - - - zip - + + + com.dslplatform + dsl-json + 2.0.2 + + + + + + + io.inverno.tool + inverno-maven-plugin + + + + com.dslplatform.dsl.json + + + com.dslplatform.json.Configuration + + + + + -Dlog4j2.simplelogLevel=INFO -Dlog4j2.level=INFO --add-reads com.techempower.inverno.benchmark=com.dslplatform.dsl.json --add-opens com.techempower.inverno.benchmark/com.techempower.inverno.benchmark.model=com.dslplatform.dsl.json + + + + + + + io.inverno.epoll + + + io.netty + netty-transport-native-epoll + linux-x86_64 + + + + + + io.inverno.tool + inverno-maven-plugin + + + inverno-package-app + package + + package-app + + + server + + + inverno-benchmark + -Xms2g -Xmx2g -server -XX:+UseNUMA -XX:+UseParallelGC -Dlog4j2.level=OFF -Dio.netty.leakDetection.level=disabled -Dio.netty.buffer.checkBounds=false -Dio.netty.buffer.checkAccessible=false -Dvertx.disableHttpHeadersValidation=true -Dvertx.disableMetrics=true -Dvertx.disableH2c=true -Dvertx.disableWebsockets=true -Dvertx.flashPolicyHandler=false -Dvertx.threadChecks=false -Dvertx.disableContextTimings=true -Dvertx.disableTCCL=true --add-modules io.netty.transport.unix.common,io.netty.transport.classes.epoll,io.netty.transport.epoll.linux.x86_64 --add-reads com.techempower.inverno.benchmark=com.dslplatform.dsl.json --add-opens com.techempower.inverno.benchmark/com.techempower.inverno.benchmark.model=com.dslplatform.dsl.json + + + + zip + + + + + + + + + + io.inverno.io_uring + + + io.netty.incubator + netty-incubator-transport-native-io_uring + linux-x86_64 + + + + io.vertx + vertx-io_uring-incubator + + + + + + io.inverno.tool + inverno-maven-plugin + + + inverno-package-app + package + + package-app + + + server + + + inverno-benchmark + -Xms2g -Xmx2g -server -XX:+UseNUMA -XX:+UseParallelGC -Dlog4j2.level=OFF -Dio.netty.leakDetection.level=disabled -Dio.netty.buffer.checkBounds=false -Dio.netty.buffer.checkAccessible=false -Dvertx.disableHttpHeadersValidation=true -Dvertx.disableMetrics=true -Dvertx.disableH2c=true -Dvertx.disableWebsockets=true -Dvertx.flashPolicyHandler=false -Dvertx.threadChecks=false -Dvertx.disableContextTimings=true -Dvertx.disableTCCL=true --add-modules io.netty.transport.unix.common,io.netty.incubator.transport.classes.io_uring,io.netty.incubator.transport.io_uring.linux.x86_64 --add-reads com.techempower.inverno.benchmark=com.dslplatform.dsl.json --add-opens com.techempower.inverno.benchmark/com.techempower.inverno.benchmark.model=com.dslplatform.dsl.json + + + + zip + + + + + + + + + + diff --git a/frameworks/Java/inverno/src/jmods/io.vertx.core/module-info.java b/frameworks/Java/inverno/src/jmods/io.vertx.core/module-info.java deleted file mode 100644 index 56fbff0c18c..00000000000 --- a/frameworks/Java/inverno/src/jmods/io.vertx.core/module-info.java +++ /dev/null @@ -1,99 +0,0 @@ -module io.vertx.core { - requires io.netty.handler.proxy; - requires io.netty.resolver.dns; - requires io.netty.transport.epoll; - requires io.netty.transport.unix.common; - requires java.naming; - requires org.apache.logging.log4j; - - requires transitive com.fasterxml.jackson.core; - requires transitive com.fasterxml.jackson.databind; - requires transitive io.netty.buffer; - requires transitive io.netty.codec; - requires transitive io.netty.codec.dns; - requires transitive io.netty.codec.http; - requires transitive io.netty.codec.http2; - requires transitive io.netty.common; - requires transitive io.netty.handler; - requires transitive io.netty.resolver; - requires transitive io.netty.transport; - requires transitive java.compiler; - requires transitive java.logging; - - exports io.vertx.core; - exports io.vertx.core.buffer; - exports io.vertx.core.buffer.impl; - exports io.vertx.core.cli; - exports io.vertx.core.cli.annotations; - exports io.vertx.core.cli.converters; - exports io.vertx.core.cli.impl; - exports io.vertx.core.datagram; - exports io.vertx.core.datagram.impl; - exports io.vertx.core.dns; - exports io.vertx.core.dns.impl; - exports io.vertx.core.dns.impl.decoder; - exports io.vertx.core.eventbus; - exports io.vertx.core.eventbus.impl; - exports io.vertx.core.eventbus.impl.clustered; - exports io.vertx.core.eventbus.impl.codecs; - exports io.vertx.core.file; - exports io.vertx.core.file.impl; - exports io.vertx.core.http; - exports io.vertx.core.http.impl; - exports io.vertx.core.http.impl.cgbystrom; - exports io.vertx.core.http.impl.headers; - exports io.vertx.core.http.impl.ws; - exports io.vertx.core.impl; - exports io.vertx.core.impl.cpu; - exports io.vertx.core.impl.future; - exports io.vertx.core.impl.launcher; - exports io.vertx.core.impl.launcher.commands; - exports io.vertx.core.impl.logging; - exports io.vertx.core.impl.resolver; - exports io.vertx.core.impl.utils; - exports io.vertx.core.impl.verticle; - exports io.vertx.core.json; - exports io.vertx.core.json.impl; - exports io.vertx.core.json.jackson; - exports io.vertx.core.json.pointer; - exports io.vertx.core.json.pointer.impl; - exports io.vertx.core.logging; - exports io.vertx.core.metrics; - exports io.vertx.core.metrics.impl; - exports io.vertx.core.net; - exports io.vertx.core.net.impl; - exports io.vertx.core.net.impl.pkcs1; - exports io.vertx.core.net.impl.pool; - exports io.vertx.core.net.impl.transport; - exports io.vertx.core.parsetools; - exports io.vertx.core.parsetools.impl; - exports io.vertx.core.shareddata; - exports io.vertx.core.shareddata.impl; - exports io.vertx.core.spi; - exports io.vertx.core.spi.cluster; - exports io.vertx.core.spi.cluster.impl; - exports io.vertx.core.spi.cluster.impl.selector; - exports io.vertx.core.spi.json; - exports io.vertx.core.spi.launcher; - exports io.vertx.core.spi.logging; - exports io.vertx.core.spi.metrics; - exports io.vertx.core.spi.observability; - exports io.vertx.core.spi.resolver; - exports io.vertx.core.spi.tracing; - exports io.vertx.core.streams; - exports io.vertx.core.streams.impl; - exports io.vertx.core.tracing; - - provides io.vertx.core.spi.launcher.CommandFactory with - io.vertx.core.impl.launcher.commands.RunCommandFactory, - io.vertx.core.impl.launcher.commands.VersionCommandFactory, - io.vertx.core.impl.launcher.commands.BareCommandFactory, - io.vertx.core.impl.launcher.commands.ListCommandFactory, - io.vertx.core.impl.launcher.commands.StartCommandFactory, - io.vertx.core.impl.launcher.commands.StopCommandFactory; - - uses io.vertx.core.spi.VertxServiceProvider; - uses io.vertx.core.spi.VerticleFactory; - uses io.vertx.core.spi.JsonFactory; - -} diff --git a/frameworks/Java/inverno/src/jmods/r2dbc.postgresql/module-info.java b/frameworks/Java/inverno/src/jmods/r2dbc.postgresql/module-info.java deleted file mode 100644 index 18208e43b04..00000000000 --- a/frameworks/Java/inverno/src/jmods/r2dbc.postgresql/module-info.java +++ /dev/null @@ -1,38 +0,0 @@ -module r2dbc.postgresql { - requires com.ongres.scram.client; - requires com.ongres.scram.common; - requires io.netty.codec; - requires io.netty.resolver; - requires io.netty.transport; - requires io.netty.transport.epoll; - requires io.netty.transport.unix.common; - requires java.naming; - - requires transitive io.netty.buffer; - requires transitive io.netty.common; - requires transitive io.netty.handler; - requires transitive org.reactivestreams; - requires transitive r2dbc.spi; - requires transitive reactor.core; - requires transitive reactor.netty.core; - - exports io.r2dbc.postgresql; - exports io.r2dbc.postgresql.api; - exports io.r2dbc.postgresql.authentication; - exports io.r2dbc.postgresql.client; - exports io.r2dbc.postgresql.codec; - exports io.r2dbc.postgresql.extension; - exports io.r2dbc.postgresql.message; - exports io.r2dbc.postgresql.message.backend; - exports io.r2dbc.postgresql.message.frontend; - exports io.r2dbc.postgresql.replication; - exports io.r2dbc.postgresql.util; - - provides io.r2dbc.postgresql.extension.Extension with - io.r2dbc.postgresql.codec.BuiltinDynamicCodecs; - provides io.r2dbc.spi.ConnectionFactoryProvider with - io.r2dbc.postgresql.PostgresqlConnectionFactoryProvider; - - uses io.r2dbc.postgresql.extension.Extension; - -} diff --git a/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/Main.java b/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/Main.java index 74aaf730a7e..42695fc65e7 100644 --- a/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/Main.java +++ b/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/Main.java @@ -1,17 +1,16 @@ package com.techempower.inverno.benchmark; -import java.io.IOException; -import java.util.function.Supplier; - import io.inverno.core.annotation.Bean; import io.inverno.core.v1.Application; import io.inverno.mod.configuration.ConfigurationSource; import io.inverno.mod.configuration.source.BootstrapConfigurationSource; +import java.io.IOException; +import java.util.function.Supplier; public class Main { @Bean - public interface AppConfigurationSource extends Supplier> {} + public interface AppConfigurationSource extends Supplier {} public static void main(String[] args) throws IllegalStateException, IOException { Application.with(new Benchmark.Builder() diff --git a/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/internal/Controller.java b/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/internal/Controller.java new file mode 100644 index 00000000000..c16e6d4d767 --- /dev/null +++ b/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/internal/Controller.java @@ -0,0 +1,265 @@ +package com.techempower.inverno.benchmark.internal; + +import com.techempower.inverno.benchmark.model.Fortune; +import com.techempower.inverno.benchmark.model.Message; +import com.techempower.inverno.benchmark.model.World; +import com.techempower.inverno.benchmark.templates.FortunesTemplate; +import io.inverno.core.annotation.Bean; +import io.inverno.core.annotation.Bean.Visibility; +import io.inverno.core.annotation.Destroy; +import io.inverno.core.annotation.Init; +import io.inverno.mod.base.Charsets; +import io.inverno.mod.base.concurrent.Reactor; +import io.inverno.mod.base.concurrent.ReactorScope; +import io.inverno.mod.base.converter.ConverterException; +import io.inverno.mod.base.reflect.Types; +import io.inverno.mod.http.base.ExchangeContext; +import io.inverno.mod.http.base.HttpException; +import io.inverno.mod.http.base.Parameter; +import io.inverno.mod.http.base.Status; +import io.inverno.mod.http.server.ErrorExchange; +import io.inverno.mod.http.server.Exchange; +import io.inverno.mod.http.server.ServerController; +import io.inverno.mod.sql.UnsafeSqlOperations; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.EventLoopGroup; +import io.netty.handler.codec.http.HttpHeaderNames; +import io.netty.handler.codec.http.HttpHeaderValues; +import io.netty.util.AsciiString; +import java.lang.reflect.Type; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.TimeUnit; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +@Bean( visibility = Visibility.PRIVATE ) +public class Controller implements ServerController, ErrorExchange> { + + 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"; + + public static final String DB_SELECT_WORLD = "SELECT id, randomnumber from WORLD where id = $1"; + + private static final CharSequence STATIC_SERVER = AsciiString.cached("inverno"); + + private static final Type LIST_WORLD_TYPE = Types.type(List.class).type(World.class).and().build(); + + private final Reactor reactor; + private final ReactorScope jsonSerializer; + private final ReactorScope> dbRepository; + + private EventLoopGroup dateEventLoopGroup; + + private CharSequence date; + + public Controller(Reactor reactor, + ReactorScope jsonSerializer, + ReactorScope> dbRepository + ) { + this.reactor = reactor; + this.jsonSerializer = jsonSerializer; + this.dbRepository = dbRepository; + } + + @Init + public void init() { + this.dateEventLoopGroup = this.reactor.createIoEventLoopGroup(1); + this.dateEventLoopGroup.scheduleAtFixedRate(() -> this.date = new AsciiString(DateTimeFormatter.RFC_1123_DATE_TIME.format(ZonedDateTime.now())), 0, 1000, TimeUnit.MILLISECONDS); + } + + @Destroy + public void destroy() { + this.dateEventLoopGroup.shutdownGracefully(); + } + + @Override + public void handle(Exchange exchange) throws HttpException { + switch(exchange.request().getPath()) { + case PATH_PLAINTEXT: { + this.handle_plaintext(exchange); + break; + } + case PATH_JSON: { + this.handle_json(exchange); + break; + } + case PATH_DB: { + this.handle_db(exchange); + break; + } + case PATH_FORTUNES: { + this.handle_fortunes(exchange); + break; + } + default: { + switch(exchange.request().getPathAbsolute()) { + case PATH_QUERIES: { + this.handle_queries(exchange); + break; + } + case PATH_UPDATES: { + this.handle_updates(exchange); + break; + } + default: { + exchange.response() + .headers(h -> h.status(Status.NOT_FOUND)) + .body() + .empty(); + } + } + } + } + } + + private static final byte[] STATIC_PLAINTEXT = "Hello, World!".getBytes(Charsets.UTF_8); + private static final int STATIC_PLAINTEXT_LEN = STATIC_PLAINTEXT.length; + + private static final ByteBuf STATIC_PLAINTEXT_BYTEBUF; + static { + ByteBuf tmpBuf = Unpooled.buffer(STATIC_PLAINTEXT_LEN); + tmpBuf.writeBytes(STATIC_PLAINTEXT); + STATIC_PLAINTEXT_BYTEBUF = Unpooled.unreleasableBuffer(tmpBuf); + } + + private static final CharSequence STATIC_PLAINTEXT_LEN_VALUE = AsciiString.cached(String.valueOf(STATIC_PLAINTEXT_LEN)); + + private static final Mono PLAIN_TEXT_MONO = Mono.fromSupplier(STATIC_PLAINTEXT_BYTEBUF::duplicate); + + public void handle_plaintext(Exchange exchange) throws HttpException { + exchange.response() + .headers(h -> h + .add(HttpHeaderNames.SERVER, STATIC_SERVER) + .add(HttpHeaderNames.DATE, date) + .add(HttpHeaderNames.CONTENT_LENGTH, STATIC_PLAINTEXT_LEN_VALUE) + .add(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) + ) + .body() + .raw() + .stream(PLAIN_TEXT_MONO); + } + + public void handle_json(Exchange exchange) throws HttpException { + exchange.response() + .headers(h -> h + .add(HttpHeaderNames.SERVER, STATIC_SERVER) + .add(HttpHeaderNames.DATE, this.date) + .add(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.APPLICATION_JSON) + ) + .body() + .raw() + .value(this.jsonSerializer.get().serialize(new Message("Hello, World!"), Message.class)); + } + + private static int randomWorldId() { + return 1 + ThreadLocalRandom.current().nextInt(10000); + } + + public void handle_db(Exchange exchange) throws HttpException { + exchange.response() + .headers(h -> h + .add(HttpHeaderNames.SERVER, STATIC_SERVER) + .add(HttpHeaderNames.DATE, this.date) + .add(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.APPLICATION_JSON) + ) + .body() + .raw().stream(this.dbRepository.get() + .flatMap(repository -> repository.getWorld(randomWorldId())) + .map(world -> this.jsonSerializer.get().serialize(world, World.class)) + ); + } + + private static final String PARAMETER_QUERIES = "queries"; + + private int extractQueriesParameter(Exchange exchange) { + try { + return Math.min(500, Math.max(1, exchange.request().queryParameters().get(PARAMETER_QUERIES).map(Parameter::asInteger).orElse(1))); + } + catch (ConverterException e) { + return 1; + } + } + + public void handle_queries(Exchange exchange) throws HttpException { + int queries = this.extractQueriesParameter(exchange); + exchange.response() + .headers(h -> h + .add(HttpHeaderNames.SERVER, STATIC_SERVER) + .add(HttpHeaderNames.DATE, this.date) + .add(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.APPLICATION_JSON) + ) + .body() + .raw().stream(this.dbRepository.get() + .flatMapMany(repository -> ((UnsafeSqlOperations)repository.getSqlClient()) + .batchQueries(ops -> + Flux.range(0, queries) + .map(ign -> ops.queryForObject( + DB_SELECT_WORLD, + row -> new World(row.getInteger(0), row.getInteger(1)), + randomWorldId() + )) + ) + ) + .collectList() + .map(worlds -> this.jsonSerializer.get().serialize(worlds, LIST_WORLD_TYPE)) + ); + } + + public void handle_updates(Exchange exchange) throws HttpException { + int queries = this.extractQueriesParameter(exchange); + exchange.response() + .headers(h -> h + .add(HttpHeaderNames.SERVER, STATIC_SERVER) + .add(HttpHeaderNames.DATE, this.date) + .add(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.APPLICATION_JSON) + ) + .body() + .raw().stream(this.dbRepository.get() + .flatMapMany(repository -> Flux.from(((UnsafeSqlOperations)repository.getSqlClient()) + .batchQueries(ops -> + Flux.range(0, queries) + .map(ign -> ops.queryForObject( + DB_SELECT_WORLD, + row -> new World(row.getInteger(0), randomWorldId()), + randomWorldId() + )) + )) + .collectSortedList() + .delayUntil(repository::updateWorlds) + .map(worlds -> this.jsonSerializer.get().serialize(worlds, LIST_WORLD_TYPE)) + ) + ); + } + + private static final CharSequence MEDIA_TEXT_HTML_UTF8 = AsciiString.cached("text/html; charset=utf-8"); + + private static final FortunesTemplate.Renderer> FORTUNES_RENDERER = FortunesTemplate.bytebuf(Unpooled::buffer); + + public void handle_fortunes(Exchange exchange) throws HttpException { + exchange.response() + .headers(h -> h + .add(HttpHeaderNames.SERVER, STATIC_SERVER) + .add(HttpHeaderNames.DATE, this.date) + .add(HttpHeaderNames.CONTENT_TYPE, MEDIA_TEXT_HTML_UTF8) + ) + .body() + .raw().stream(this.dbRepository.get().flatMapMany(DbRepository::listFortunes) + .collectList() + .flatMap(fortunes -> { + fortunes.add(new Fortune(0, "Additional fortune added at request time.")); + Collections.sort(fortunes); + return Mono.fromFuture(() -> FORTUNES_RENDERER.render(fortunes)); + }) + ); + } +} diff --git a/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/internal/DbRepository.java b/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/internal/DbRepository.java new file mode 100644 index 00000000000..28699e3c1d0 --- /dev/null +++ b/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/internal/DbRepository.java @@ -0,0 +1,132 @@ +package com.techempower.inverno.benchmark.internal; + +import com.techempower.inverno.benchmark.AppConfiguration; +import com.techempower.inverno.benchmark.model.Fortune; +import com.techempower.inverno.benchmark.model.World; +import io.inverno.core.annotation.Bean; +import io.inverno.core.annotation.Destroy; +import io.inverno.core.annotation.Init; +import io.inverno.mod.base.concurrent.Reactor; +import io.inverno.mod.base.concurrent.VertxReactor; +import io.inverno.mod.sql.PreparedStatement; +import io.inverno.mod.sql.SqlClient; +import io.inverno.mod.sql.vertx.ConnectionSqlClient; +import io.vertx.core.Vertx; +import io.vertx.core.VertxOptions; +import io.vertx.pgclient.PgConnectOptions; +import io.vertx.pgclient.PgConnection; +import java.util.ArrayList; +import java.util.List; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +public class DbRepository { + + public static final String DB_SELECT_WORLD = "SELECT id, randomnumber from WORLD where id = $1"; + public static final String DB_SELECT_FORTUNE = "SELECT id, message from FORTUNE"; + + private final SqlClient sqlClient; + + private final PreparedStatement selectWorldByIdQuery; + private final PreparedStatement selectFortuneQuery; + private final PreparedStatement[] updateWorldQueries; + + public DbRepository(SqlClient sqlClient) { + this.sqlClient = sqlClient; + + this.selectWorldByIdQuery = sqlClient.preparedStatement(DB_SELECT_WORLD); + this.selectFortuneQuery = sqlClient.preparedStatement(DB_SELECT_FORTUNE); + this.updateWorldQueries = new PreparedStatement[500]; + for(int i=0;i getWorld(int id) { + return Mono.from(this.selectWorldByIdQuery.bind(id).execute(row -> new World(row.getInteger(0), row.getInteger(1)))); + } + + public Flux listFortunes() { + return Flux.from(this.selectFortuneQuery.execute(row -> new Fortune(row.getInteger(0), row.getString(1)))); + } + + public Mono updateWorlds(List worlds) { + int len = worlds.size(); + List parameters = new ArrayList<>(len * 2); + for(World world : worlds) { + parameters.add(world.getId()); + parameters.add(world.getRandomNumber()); + } + return Mono.when(this.updateWorldQueries[len - 1].bind(parameters).execute()); + } + + @Bean( name = "dbRespository", visibility = Bean.Visibility.PRIVATE ) + public static class ReactorScope extends io.inverno.mod.base.concurrent.ReactorScope> { + + private final AppConfiguration configuration; + private final Reactor reactor; + + private Vertx vertx; + private PgConnectOptions connectOptions; + + public ReactorScope(AppConfiguration configuration, Reactor reactor) { + this.configuration = configuration; + this.reactor = reactor; + } + + @Init + public void init() { + if(this.reactor instanceof VertxReactor) { + this.vertx = ((VertxReactor)this.reactor).getVertx(); + } + else { + this.vertx = Vertx.vertx(new VertxOptions().setPreferNativeTransport(this.configuration.boot().prefer_native_transport())); + } + + this.connectOptions = new PgConnectOptions() + .setHost(this.configuration.db_host()) + .setPort(this.configuration.db_port()) + .setDatabase(this.configuration.db_database()) + .setUser(this.configuration.db_username()) + .setPassword(this.configuration.db_password()) + .setCachePreparedStatements(true) + .setPreparedStatementCacheMaxSize(1024) + .setPipeliningLimit(100_100); + } + + @Destroy + public void destroy() { + if(!(this.reactor instanceof VertxReactor)) { + this.vertx.close(); + } + } + + @Override + protected Mono create() { + return Mono.fromCompletionStage(() -> PgConnection.connect(this.vertx, this.connectOptions).toCompletionStage()) + .map(pgConn -> new DbRepository(new ConnectionSqlClient(pgConn))) + .cacheInvalidateWhen(repository -> ((ConnectionSqlClient)repository.getSqlClient()).onClose()); + } + } +} diff --git a/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/internal/Handler.java b/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/internal/Handler.java deleted file mode 100644 index 1e7052c275e..00000000000 --- a/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/internal/Handler.java +++ /dev/null @@ -1,316 +0,0 @@ -package com.techempower.inverno.benchmark.internal; - -import java.time.ZonedDateTime; -import java.time.format.DateTimeFormatter; -import java.util.Collections; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ThreadLocalRandom; -import java.util.concurrent.TimeUnit; -import java.util.function.Supplier; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.techempower.inverno.benchmark.model.Fortune; -import com.techempower.inverno.benchmark.model.Message; -import com.techempower.inverno.benchmark.model.World; -import com.techempower.inverno.benchmark.templates.FortunesTemplate; - -import io.inverno.core.annotation.Bean; -import io.inverno.core.annotation.Bean.Visibility; -import io.inverno.core.annotation.Destroy; -import io.inverno.core.annotation.Init; -import io.inverno.mod.base.Charsets; -import io.inverno.mod.base.concurrent.Reactor; -import io.inverno.mod.base.concurrent.ReactorScope; -import io.inverno.mod.base.converter.ConverterException; -import io.inverno.mod.http.base.HttpException; -import io.inverno.mod.http.base.InternalServerErrorException; -import io.inverno.mod.http.base.Parameter; -import io.inverno.mod.http.base.Status; -import io.inverno.mod.http.server.Exchange; -import io.inverno.mod.http.server.ExchangeContext; -import io.inverno.mod.http.server.RootExchangeHandler; -import io.inverno.mod.sql.SqlClient; -import io.inverno.mod.sql.UnsafeSqlOperations; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.EventLoopGroup; -import io.netty.handler.codec.http.HttpHeaderNames; -import io.netty.handler.codec.http.HttpHeaderValues; -import io.netty.util.AsciiString; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -@Bean( visibility = Visibility.PRIVATE ) -public class Handler implements RootExchangeHandler> { - - 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"; - - public static final String DB_SELECT_WORLD = "SELECT id, randomnumber from WORLD where id = $1"; - public static final String DB_UPDATE_WORLD = "UPDATE world SET randomnumber=$1 WHERE id=$2"; - public static final String DB_SELECT_FORTUNE = "SELECT id, message from FORTUNE"; - - private static final CharSequence STATIC_SERVER = AsciiString.cached("inverno"); - - private final Reactor reactor; - private final ObjectMapper mapper; - private final ReactorScope> sqlClient; - - private EventLoopGroup dateEventLoopGroup; - - private CharSequence date; - - public Handler(Reactor reactor, - ObjectMapper mapper, - ReactorScope> sqlClient - ) { - this.reactor = reactor; - this.mapper = mapper; - this.sqlClient = sqlClient; - } - - @Init - public void init() { - this.dateEventLoopGroup = this.reactor.createIoEventLoopGroup(1); - this.dateEventLoopGroup.scheduleAtFixedRate(() -> { - this.date = new AsciiString(DateTimeFormatter.RFC_1123_DATE_TIME.format(ZonedDateTime.now())); - }, 0, 1000, TimeUnit.MILLISECONDS); - } - - @Destroy - public void destroy() { - this.dateEventLoopGroup.shutdownGracefully(); - } - - @Override - public void handle(Exchange exchange) throws HttpException { - switch(exchange.request().getPath()) { - case PATH_PLAINTEXT: { - this.handle_plaintext(exchange); - break; - } - case PATH_JSON: { - this.handle_json(exchange); - break; - } - case PATH_DB: { - this.handle_db(exchange); - break; - } - case PATH_FORTUNES: { - this.handle_fortunes(exchange); - break; - } - default: { - switch(exchange.request().getPathAbsolute()) { - case PATH_QUERIES: { - this.handle_queries(exchange); - break; - } - case PATH_UPDATES: { - this.handle_updates(exchange); - break; - } - default: { - exchange.response() - .headers(h -> h.status(Status.NOT_FOUND)) - .body() - .empty(); - } - } - } - } - } - - private static final byte[] STATIC_PLAINTEXT = "Hello, World!".getBytes(Charsets.UTF_8); - private static final int STATIC_PLAINTEXT_LEN = STATIC_PLAINTEXT.length; - - private static final ByteBuf STATIC_PLAINTEXT_BYTEBUF; - static { - ByteBuf tmpBuf = Unpooled.directBuffer(STATIC_PLAINTEXT_LEN); - tmpBuf.writeBytes(STATIC_PLAINTEXT); - STATIC_PLAINTEXT_BYTEBUF = Unpooled.unreleasableBuffer(tmpBuf); - } - - private static final CharSequence STATIC_PLAINTEXT_LEN_VALUE = AsciiString.cached(String.valueOf(STATIC_PLAINTEXT_LEN)); - - private static class PlaintextSupplier implements Supplier { - @Override - public ByteBuf get() { - return STATIC_PLAINTEXT_BYTEBUF.duplicate(); - } - } - - private static final Mono PLAIN_TEXT_MONO = Mono.fromSupplier(new PlaintextSupplier()); - - public void handle_plaintext(Exchange exchange) throws HttpException { - exchange.response() - .headers(h -> h - .add(HttpHeaderNames.SERVER, STATIC_SERVER) - .add(HttpHeaderNames.DATE, date) - .add(HttpHeaderNames.CONTENT_LENGTH, STATIC_PLAINTEXT_LEN_VALUE) - .add(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) - ) - .body() - .raw() - .stream(PLAIN_TEXT_MONO); - } - - public void handle_json(Exchange exchange) throws HttpException { - try { - exchange.response() - .headers(h -> h - .add(HttpHeaderNames.SERVER, STATIC_SERVER) - .add(HttpHeaderNames.DATE, this.date) - .add(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.APPLICATION_JSON) - ) - .body() - .raw() - .value(Unpooled.unreleasableBuffer(Unpooled.wrappedBuffer(this.mapper.writeValueAsBytes(new Message("Hello, World!"))))); - } - catch (JsonProcessingException | IllegalStateException e) { - throw new InternalServerErrorException("Error serializing message as JSON", e); - } - } - - private static int randomWorldId() { - return 1 + ThreadLocalRandom.current().nextInt(10000); - } - - public void handle_db(Exchange exchange) throws HttpException { - exchange.response() - .headers(h -> h - .add(HttpHeaderNames.SERVER, STATIC_SERVER) - .add(HttpHeaderNames.DATE, this.date) - .add(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.APPLICATION_JSON) - ) - .body() - .raw().stream(this.sqlClient.get().flatMap(client -> - client.queryForObject( - DB_SELECT_WORLD, - row -> { - try { - return Unpooled.unreleasableBuffer(Unpooled.wrappedBuffer(this.mapper.writeValueAsBytes(new World(row.getInteger(0), row.getInteger(1))))); - } - catch (JsonProcessingException e) { - throw new InternalServerErrorException(e); - } - }, - randomWorldId() - ) - )); - } - - private static final String PARAMETER_QUERIES = "queries"; - - private int extractQueriesParameter(Exchange exchange) { - try { - return Math.min(500, Math.max(1, exchange.request().queryParameters().get(PARAMETER_QUERIES).map(Parameter::asInteger).orElse(1))); - } - catch (ConverterException e) { - return 1; - } - } - - public void handle_queries(Exchange exchange) throws HttpException { - int queries = this.extractQueriesParameter(exchange); - exchange.response() - .headers(h -> h - .add(HttpHeaderNames.SERVER, STATIC_SERVER) - .add(HttpHeaderNames.DATE, this.date) - .add(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.APPLICATION_JSON) - ) - .body() - .raw().stream(this.sqlClient.get() - .flatMapMany(client -> ((UnsafeSqlOperations)client) - .batchQueries(ops -> - Flux.range(0, queries) - .map(ign -> ops.queryForObject( - DB_SELECT_WORLD, - row -> new World(row.getInteger(0), row.getInteger(1)), - randomWorldId() - )) - ) - ) - .collectList() - .map(worlds -> { - try { - return Unpooled.unreleasableBuffer(Unpooled.wrappedBuffer(this.mapper.writeValueAsBytes(worlds))); - } - catch (JsonProcessingException e) { - throw new InternalServerErrorException(e); - } - }) - ); - } - - public void handle_updates(Exchange exchange) throws HttpException { - int queries = this.extractQueriesParameter(exchange); - - exchange.response() - .headers(h -> h - .add(HttpHeaderNames.SERVER, STATIC_SERVER) - .add(HttpHeaderNames.DATE, this.date) - .add(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.APPLICATION_JSON) - ) - .body() - .raw().stream(this.sqlClient.get() - .flatMapMany(client -> Flux.from(((UnsafeSqlOperations)client) - .batchQueries(ops -> - Flux.range(0, queries) - .map(ign -> ops.queryForObject( - DB_SELECT_WORLD, - row -> new World(row.getInteger(0), randomWorldId()), - randomWorldId() - )) - )) - .collectSortedList() - .delayUntil(worlds -> client.batchUpdate( - DB_UPDATE_WORLD, - worlds.stream().map(world -> new Object[] { world.getRandomNumber(), world.getId() }) - ) - ) - .map(worlds -> { - try { - return Unpooled.unreleasableBuffer(Unpooled.wrappedBuffer(this.mapper.writeValueAsBytes(worlds))); - } - catch (JsonProcessingException e) { - throw new InternalServerErrorException(e); - } - }) - ) - ); - } - - private static final CharSequence MEDIA_TEXT_HTML_UTF8 = AsciiString.cached("text/html; charset=utf-8"); - - private static final FortunesTemplate.Renderer> FORTUNES_RENDERER = FortunesTemplate.bytebuf(() -> Unpooled.unreleasableBuffer(Unpooled.buffer())); - - public void handle_fortunes(Exchange exchange) throws HttpException { - exchange.response() - .headers(h -> h - .add(HttpHeaderNames.SERVER, STATIC_SERVER) - .add(HttpHeaderNames.DATE, this.date) - .add(HttpHeaderNames.CONTENT_TYPE, MEDIA_TEXT_HTML_UTF8) - ) - .body() - .raw().stream(this.sqlClient.get().flatMapMany(client -> - client.query( - DB_SELECT_FORTUNE, - row -> new Fortune(row.getInteger(0), row.getString(1)) - ) - ) - .collectList() - .flatMap(fortunes -> { - fortunes.add(new Fortune(0, "Additional fortune added at request time.")); - Collections.sort(fortunes); - return Mono.fromFuture(() -> FORTUNES_RENDERER.render(fortunes)); - }) - ); - } -} diff --git a/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/internal/JsonSerializer.java b/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/internal/JsonSerializer.java new file mode 100644 index 00000000000..24ce79eedd3 --- /dev/null +++ b/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/internal/JsonSerializer.java @@ -0,0 +1,38 @@ +package com.techempower.inverno.benchmark.internal; + +import com.dslplatform.json.DslJson; +import com.dslplatform.json.JsonWriter; +import io.inverno.core.annotation.Bean; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import java.lang.reflect.Type; + +public class JsonSerializer { + + private static final DslJson DSL_JSON = new DslJson<>(); + + private final JsonWriter jsonWriter; + + public JsonSerializer() { + this.jsonWriter = DSL_JSON.newWriter(); + } + + public ByteBuf serialize(T value, Type type) { + try { + DSL_JSON.serialize(this.jsonWriter, type, value); + return Unpooled.wrappedBuffer(this.jsonWriter.toByteArray()); + } + finally { + this.jsonWriter.reset(); + } + } + + @Bean( name = "jsonSerializer", visibility = Bean.Visibility.PRIVATE ) + public static class ReactorScope extends io.inverno.mod.base.concurrent.ReactorScope { + + @Override + protected JsonSerializer create() { + return new JsonSerializer(); + } + } +} diff --git a/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/internal/SqlClientReactorScope.java b/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/internal/SqlClientReactorScope.java deleted file mode 100644 index 81b30069ec2..00000000000 --- a/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/internal/SqlClientReactorScope.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.techempower.inverno.benchmark.internal; - -import com.techempower.inverno.benchmark.AppConfiguration; - -import io.inverno.core.annotation.Bean; -import io.inverno.core.annotation.Bean.Visibility; -import io.inverno.core.annotation.Destroy; -import io.inverno.core.annotation.Init; -import io.inverno.mod.base.concurrent.Reactor; -import io.inverno.mod.base.concurrent.ReactorScope; -import io.inverno.mod.base.concurrent.VertxReactor; -import io.inverno.mod.sql.SqlClient; -import io.inverno.mod.sql.vertx.ConnectionSqlClient; -import io.vertx.core.Vertx; -import io.vertx.core.VertxOptions; -import io.vertx.pgclient.PgConnectOptions; -import io.vertx.pgclient.PgConnection; -import reactor.core.publisher.Mono; - -@Bean( name = "SqlClient", visibility = Visibility.PRIVATE ) -public class SqlClientReactorScope extends ReactorScope> { - - private final AppConfiguration configuration; - private final Reactor reactor; - - private Vertx vertx; - private PgConnectOptions connectOptions; - - public SqlClientReactorScope(AppConfiguration configuration, Reactor reactor) { - this.configuration = configuration; - this.reactor = reactor; - } - - @Init - public void init() { - if(this.reactor instanceof VertxReactor) { - this.vertx = ((VertxReactor)this.reactor).getVertx(); - } - else { - this.vertx = Vertx.vertx(new VertxOptions().setPreferNativeTransport(this.configuration.boot().prefer_native_transport())); - } - - this.connectOptions = new PgConnectOptions() - .setHost(this.configuration.db_host()) - .setPort(this.configuration.db_port()) - .setDatabase(this.configuration.db_database()) - .setUser(this.configuration.db_username()) - .setPassword(this.configuration.db_password()) - .setCachePreparedStatements(true) - .setPipeliningLimit(100_100); - } - - @Destroy - public void destroy() { - if(!(this.reactor instanceof VertxReactor)) { - this.vertx.close(); - } - } - - @Override - protected Mono create() { - return Mono.fromCompletionStage(PgConnection.connect(this.vertx, this.connectOptions).toCompletionStage()).map(pgConn -> (SqlClient)new ConnectionSqlClient(pgConn)).cache(); - } -} diff --git a/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/model/Fortune.java b/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/model/Fortune.java index de4017c3c0d..b00a8a9df9f 100644 --- a/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/model/Fortune.java +++ b/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/model/Fortune.java @@ -1,5 +1,8 @@ package com.techempower.inverno.benchmark.model; +import com.dslplatform.json.CompiledJson; + +@CompiledJson public final class Fortune implements Comparable { private final int id; diff --git a/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/model/Message.java b/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/model/Message.java index c9d554903d7..306d5c348d6 100644 --- a/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/model/Message.java +++ b/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/model/Message.java @@ -1,5 +1,8 @@ package com.techempower.inverno.benchmark.model; +import com.dslplatform.json.CompiledJson; + +@CompiledJson public final class Message { private final String message; diff --git a/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/model/World.java b/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/model/World.java index f0f1825f3b9..6defeb042a3 100644 --- a/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/model/World.java +++ b/frameworks/Java/inverno/src/main/java/com/techempower/inverno/benchmark/model/World.java @@ -1,14 +1,15 @@ package com.techempower.inverno.benchmark.model; +import com.dslplatform.json.CompiledJson; + +@CompiledJson public final class World implements Comparable { - private final int id; + private int id; private int randomNumber; - public World(int id) { - this.id = id; - } - + public World() {} + public World(int id, int randomNumber) { this.id = id; this.randomNumber = randomNumber; diff --git a/frameworks/Java/inverno/src/main/java/module-info.java b/frameworks/Java/inverno/src/main/java/module-info.java index 7f0f44d7b65..39d0224949b 100644 --- a/frameworks/Java/inverno/src/main/java/module-info.java +++ b/frameworks/Java/inverno/src/main/java/module-info.java @@ -10,16 +10,13 @@ requires io.netty.common; requires io.netty.codec.http; requires unbescape; - + requires static dsl.json; + requires io.vertx.client.sql.pg; requires io.vertx.client.sql; requires io.vertx.core; requires java.sql; - - requires transitive io.netty.transport; - requires static io.netty.transport.unix.common; - requires static io.netty.transport.epoll; - + exports com.techempower.inverno.benchmark; exports com.techempower.inverno.benchmark.model; } diff --git a/frameworks/Java/inverno/src/main/resources/configuration.cprops b/frameworks/Java/inverno/src/main/resources/configuration.cprops index df4680e124b..9fc9d6fddd0 100644 --- a/frameworks/Java/inverno/src/main/resources/configuration.cprops +++ b/frameworks/Java/inverno/src/main/resources/configuration.cprops @@ -6,7 +6,9 @@ com.techempower.inverno.benchmark.appConfiguration { http_server { tls_enabled = false server_port = 8080 - h2c_enabled = false + h2_enabled = false + http1x_validate_headers = false + ws_enabled = false } db_database = "hello_world" db_host = "tfb-database" diff --git a/frameworks/Java/javalin/pom.xml b/frameworks/Java/javalin/pom.xml index 77133c44ab4..f45da15fcaf 100644 --- a/frameworks/Java/javalin/pom.xml +++ b/frameworks/Java/javalin/pom.xml @@ -15,7 +15,7 @@ 2.0.3 2.13.4 5.0.1 - 42.5.1 + 42.7.2 4.7.2 2.2.3 diff --git a/frameworks/Java/jetty/jetty-servlet.dockerfile b/frameworks/Java/jetty/jetty-servlet.dockerfile index 764c2eb58bc..aafe6afc370 100644 --- a/frameworks/Java/jetty/jetty-servlet.dockerfile +++ b/frameworks/Java/jetty/jetty-servlet.dockerfile @@ -1,10 +1,10 @@ -FROM maven:3.6.1-jdk-11-slim as maven +FROM maven:3-eclipse-temurin-24-alpine as maven WORKDIR /jetty COPY pom.xml pom.xml COPY src src RUN mvn compile assembly:single -q -P servlet -FROM openjdk:11.0.3-jdk-slim +FROM amazoncorretto:25 WORKDIR /jetty COPY --from=maven /jetty/target/jetty-example-0.1-jar-with-dependencies.jar app.jar diff --git a/frameworks/Java/jetty/jetty.dockerfile b/frameworks/Java/jetty/jetty.dockerfile index f8ff4d716d2..996ee1627be 100644 --- a/frameworks/Java/jetty/jetty.dockerfile +++ b/frameworks/Java/jetty/jetty.dockerfile @@ -1,10 +1,10 @@ -FROM maven:3.6.1-jdk-11-slim as maven +FROM maven:3-eclipse-temurin-24-alpine as maven WORKDIR /jetty COPY pom.xml pom.xml COPY src src RUN mvn compile assembly:single -q -FROM openjdk:11.0.3-jdk-slim +FROM amazoncorretto:25 WORKDIR /jetty COPY --from=maven /jetty/target/jetty-example-0.1-jar-with-dependencies.jar app.jar diff --git a/frameworks/Java/jetty/pom.xml b/frameworks/Java/jetty/pom.xml index db5ba4a6b7b..ee615b85538 100644 --- a/frameworks/Java/jetty/pom.xml +++ b/frameworks/Java/jetty/pom.xml @@ -9,9 +9,9 @@ UTF-8 - 11 - 11 - 10.0.14 + 21 + 21 + 12.0.22 hello.handler.HelloWebServer @@ -23,8 +23,8 @@ - org.eclipse.jetty - jetty-server + org.eclipse.jetty.ee10 + jetty-ee10-servlet ${jetty.version} @@ -34,7 +34,7 @@ true org.apache.maven.plugins maven-compiler-plugin - 3.8.0 + 3.14.0 hello/servlet/** @@ -52,14 +52,14 @@ - org.eclipse.jetty - jetty-servlet + org.eclipse.jetty.ee10 + jetty-ee10-servlet ${jetty.version} - com.sun.activation - jakarta.activation - 1.2.1 + jakarta.activation + jakarta.activation-api + 2.1.3 diff --git a/frameworks/Java/jetty/src/main/java/hello/handler/HelloWebServer.java b/frameworks/Java/jetty/src/main/java/hello/handler/HelloWebServer.java index 85e63461518..0d76a933bef 100644 --- a/frameworks/Java/jetty/src/main/java/hello/handler/HelloWebServer.java +++ b/frameworks/Java/jetty/src/main/java/hello/handler/HelloWebServer.java @@ -1,29 +1,15 @@ package hello.handler; -import java.io.IOException; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.eclipse.jetty.server.Handler; -import org.eclipse.jetty.server.HttpConfiguration; -import org.eclipse.jetty.server.HttpConnectionFactory; -import org.eclipse.jetty.server.Request; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.ServerConnector; -import org.eclipse.jetty.server.handler.AbstractHandler; -import org.eclipse.jetty.server.handler.AbstractHandlerContainer; +import org.eclipse.jetty.server.*; +import org.eclipse.jetty.util.Callback; /** * An implementation of the TechEmpower benchmark tests using the Jetty web - * server. + * server. */ -public final class HelloWebServer -{ - public static void main(String[] args) throws Exception - { +public final class HelloWebServer { + public static void main(String[] args) throws Exception { Server server = new Server(8080); ServerConnector connector = server.getBean(ServerConnector.class); HttpConfiguration config = connector.getBean(HttpConnectionFactory.class).getHttpConfiguration(); @@ -36,34 +22,33 @@ public static void main(String[] args) throws Exception server.start(); server.join(); } - - public static class PathHandler extends AbstractHandler - { - JsonHandler _jsonHandler=new JsonHandler(); - PlainTextHandler _plainHandler=new PlainTextHandler(); - - public PathHandler() - { + + public static class PathHandler extends Handler.Abstract { + JsonHandler _jsonHandler = new JsonHandler(); + PlainTextHandler _plainHandler = new PlainTextHandler(); + + public PathHandler() { addBean(_jsonHandler); addBean(_plainHandler); } @Override - public void setServer(Server server) - { + public void setServer(Server server) { super.setServer(server); _jsonHandler.setServer(server); _plainHandler.setServer(server); } @Override - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException - { - if ("/plaintext".equals(target)) - _plainHandler.handle(target,baseRequest,request,response); - else if ("/json".equals(target)) - _jsonHandler.handle(target,baseRequest,request,response); + public boolean handle(Request request, Response response, Callback callback) { + String uri = request.getHttpURI().getPath(); + + if ("/plaintext".equals(uri)) + return _plainHandler.handle(request, response, callback); + else if ("/json".equals(uri)) + return _jsonHandler.handle(request, response, callback); + else + return false; } - } } diff --git a/frameworks/Java/jetty/src/main/java/hello/handler/JsonHandler.java b/frameworks/Java/jetty/src/main/java/hello/handler/JsonHandler.java index e99c9790a5f..8a7da96f576 100644 --- a/frameworks/Java/jetty/src/main/java/hello/handler/JsonHandler.java +++ b/frameworks/Java/jetty/src/main/java/hello/handler/JsonHandler.java @@ -1,34 +1,35 @@ package hello.handler; -import java.io.IOException; -import java.util.Collections; -import java.util.Map; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - import org.eclipse.jetty.http.HttpField; -import org.eclipse.jetty.http.HttpHeader; -import org.eclipse.jetty.http.PreEncodedHttpField; +import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.Request; -import org.eclipse.jetty.server.handler.AbstractHandler; -import org.eclipse.jetty.util.ajax.JSON; +import org.eclipse.jetty.server.Response; +import org.eclipse.jetty.util.Callback; + +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +public class JsonHandler extends Handler.Abstract { + + private static final HttpField JSON_HEADER = new HttpField("Content-Type", "application/json"); + private static final String JSON_RESPONSE = "{\"message\": \"Hello, World!\"}"; -public class JsonHandler extends AbstractHandler -{ - private JSON json = new JSON(); - HttpField contentType = new PreEncodedHttpField(HttpHeader.CONTENT_TYPE,"application/json"); @Override - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException - { - baseRequest.setHandled(true); - baseRequest.getResponse().getHttpFields().add(contentType); - Map map = Collections.singletonMap("message","Hello, World!"); - json.append(response.getWriter(),map); + public boolean handle(Request request, Response response, Callback callback) { + try { + response.setStatus(200); + response.getHeaders().add(JSON_HEADER); + + byte[] contentBytes = JSON_RESPONSE.getBytes(StandardCharsets.UTF_8); + ByteBuffer contentBuffer = ByteBuffer.wrap(contentBytes); + response.getHeaders().put("Content-Length", String.valueOf(contentBytes.length)); + + response.write(true, contentBuffer, callback); + } catch (Exception e) { + callback.failed(e); + } + return true; } - -} +} \ No newline at end of file diff --git a/frameworks/Java/jetty/src/main/java/hello/handler/PlainTextHandler.java b/frameworks/Java/jetty/src/main/java/hello/handler/PlainTextHandler.java index fee97b635b9..940110224db 100644 --- a/frameworks/Java/jetty/src/main/java/hello/handler/PlainTextHandler.java +++ b/frameworks/Java/jetty/src/main/java/hello/handler/PlainTextHandler.java @@ -1,31 +1,35 @@ package hello.handler; -import java.io.IOException; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.MimeTypes; import org.eclipse.jetty.http.PreEncodedHttpField; +import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.Request; -import org.eclipse.jetty.server.handler.AbstractHandler; -import org.eclipse.jetty.util.BufferUtil; +import org.eclipse.jetty.server.Response; +import org.eclipse.jetty.util.Callback; -public class PlainTextHandler extends AbstractHandler -{ - ByteBuffer helloWorld = BufferUtil.toBuffer("Hello, World!"); - HttpField contentType = new PreEncodedHttpField(HttpHeader.CONTENT_TYPE,MimeTypes.Type.TEXT_PLAIN.asString()); +public class PlainTextHandler extends Handler.Abstract { + private static final String RESPONSE_BODY = "Hello, World!"; + private static final HttpField contentType = new PreEncodedHttpField(HttpHeader.CONTENT_TYPE, MimeTypes.Type.TEXT_PLAIN.asString()); @Override - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException - { - baseRequest.setHandled(true); - baseRequest.getResponse().getHttpFields().add(contentType); - baseRequest.getResponse().getHttpOutput().sendContent(helloWorld.slice()); + public boolean handle(Request request, Response response, Callback callback) { + try { + response.setStatus(200); + response.getHeaders().put(contentType); + + byte[] contentBytes = RESPONSE_BODY.getBytes(StandardCharsets.UTF_8); + ByteBuffer contentBuffer = ByteBuffer.wrap(contentBytes); + response.getHeaders().put("Content-Length", String.valueOf(contentBytes.length)); + + response.write(true, contentBuffer, callback); + } catch (Exception e) { + callback.failed(e); + } + return true; } } diff --git a/frameworks/Java/jetty/src/main/java/hello/servlet/HelloWebServerServlet.java b/frameworks/Java/jetty/src/main/java/hello/servlet/HelloWebServerServlet.java index b9ab9af85c9..2859edd1aa7 100644 --- a/frameworks/Java/jetty/src/main/java/hello/servlet/HelloWebServerServlet.java +++ b/frameworks/Java/jetty/src/main/java/hello/servlet/HelloWebServerServlet.java @@ -4,14 +4,14 @@ import org.eclipse.jetty.server.HttpConnectionFactory; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; -import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.ee10.servlet.ServletContextHandler; /** * An implementation of the TechEmpower benchmark tests using the Jetty web * server. */ -public final class HelloWebServerServlet +public final class HelloWebServerServlet { public static void main(String[] args) throws Exception @@ -26,7 +26,7 @@ public static void main(String[] args) throws Exception context.setContextPath("/"); server.setHandler(context); - context.addServlet(org.eclipse.jetty.servlet.DefaultServlet.class,"/"); + context.addServlet(org.eclipse.jetty.ee10.servlet.DefaultServlet.class,"/"); context.addServlet(JsonServlet.class,"/json"); context.addServlet(PlaintextServlet.class,"/plaintext"); diff --git a/frameworks/Java/jetty/src/main/java/hello/servlet/JsonServlet.java b/frameworks/Java/jetty/src/main/java/hello/servlet/JsonServlet.java index 9533083c18c..2d374a0a21d 100644 --- a/frameworks/Java/jetty/src/main/java/hello/servlet/JsonServlet.java +++ b/frameworks/Java/jetty/src/main/java/hello/servlet/JsonServlet.java @@ -4,11 +4,10 @@ import java.util.Collections; import java.util.Map; -import javax.servlet.GenericServlet; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.GenericServlet; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; +import jakarta.servlet.http.HttpServletResponse; import org.eclipse.jetty.util.ajax.JSON; @@ -16,16 +15,15 @@ public class JsonServlet extends GenericServlet { - private JSON json = new JSON(); - + private final JSON json = new JSON(); + @Override - public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException + public void service(ServletRequest req, ServletResponse res) throws IOException { HttpServletResponse response= (HttpServletResponse)res; response.setContentType("application/json"); Map map = Collections.singletonMap("message","Hello, World!"); - + json.append(response.getWriter(),map); } - } diff --git a/frameworks/Java/jetty/src/main/java/hello/servlet/PlaintextServlet.java b/frameworks/Java/jetty/src/main/java/hello/servlet/PlaintextServlet.java index 7e72d80b9ad..99b245478f5 100644 --- a/frameworks/Java/jetty/src/main/java/hello/servlet/PlaintextServlet.java +++ b/frameworks/Java/jetty/src/main/java/hello/servlet/PlaintextServlet.java @@ -2,16 +2,11 @@ import java.io.IOException; import java.nio.charset.StandardCharsets; -import java.util.Collections; -import java.util.Map; -import javax.activation.MimeType; -import javax.servlet.GenericServlet; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.GenericServlet; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; +import jakarta.servlet.http.HttpServletResponse; import org.eclipse.jetty.http.MimeTypes; @@ -19,7 +14,7 @@ public class PlaintextServlet extends GenericServlet { byte[] helloWorld = "Hello, World!".getBytes(StandardCharsets.ISO_8859_1); @Override - public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException + public void service(ServletRequest req, ServletResponse res) throws IOException { HttpServletResponse response= (HttpServletResponse)res; response.setContentType(MimeTypes.Type.TEXT_PLAIN.asString()); diff --git a/frameworks/Java/jlhttp/pom.xml b/frameworks/Java/jlhttp/pom.xml index eea865c88aa..af63382cc2b 100644 --- a/frameworks/Java/jlhttp/pom.xml +++ b/frameworks/Java/jlhttp/pom.xml @@ -24,7 +24,7 @@ com.fasterxml.jackson.core jackson-databind - 2.13.4.2 + 2.16.0 com.fasterxml.jackson.module @@ -35,7 +35,7 @@ org.postgresql postgresql - 42.4.3 + 42.7.2 com.zaxxer diff --git a/frameworks/Java/jooby/benchmark_config.json b/frameworks/Java/jooby/benchmark_config.json index 1632b784b4b..2185d0c0fdf 100644 --- a/frameworks/Java/jooby/benchmark_config.json +++ b/frameworks/Java/jooby/benchmark_config.json @@ -60,15 +60,15 @@ "framework": "Jooby", "language": "Java", "flavor": "None", - "platform": "Undertow", + "platform": "Netty", "database": "Postgres", "database_os": "Linux", "orm": "Raw", "webserver": "None", "os": "Linux", - "notes": "Jooby MVC using Undertow", + "notes": "Jooby MVC using Netty", "display_name": "jooby-jaxrs", - "versus": "undertow" + "versus": "netty" }, "jetty": { "json_url": "/json", diff --git a/frameworks/Java/jooby/conf/application.vertx.conf b/frameworks/Java/jooby/conf/application.vertx.conf new file mode 100644 index 00000000000..d3a286c4b71 --- /dev/null +++ b/frameworks/Java/jooby/conf/application.vertx.conf @@ -0,0 +1,6 @@ +# Add/Override some properties to matches Vertx pg Driver properties +db.database = ${db.databaseName} +db.host = ${db.serverName} +db.cachePreparedStatements = true +db.preparedStatementCacheMaxSize = 1024 +db.pipeliningLimit = 256 diff --git a/frameworks/Java/jooby/config.toml b/frameworks/Java/jooby/config.toml index aa7c6edf89f..4929ae1bfc8 100644 --- a/frameworks/Java/jooby/config.toml +++ b/frameworks/Java/jooby/config.toml @@ -80,6 +80,6 @@ database = "Postgres" database_os = "Linux" os = "Linux" orm = "Raw" -platform = "Undertow" +platform = "Netty" webserver = "None" -versus = "undertow" +versus = "netty" diff --git a/frameworks/Java/jooby/jooby-jetty.dockerfile b/frameworks/Java/jooby/jooby-jetty.dockerfile index e832ecc3359..fb23bc745c4 100644 --- a/frameworks/Java/jooby/jooby-jetty.dockerfile +++ b/frameworks/Java/jooby/jooby-jetty.dockerfile @@ -1,4 +1,4 @@ -FROM maven:3.9.0-eclipse-temurin-17 +FROM maven:3.9.11-eclipse-temurin-25-noble as maven WORKDIR /jooby COPY pom.xml pom.xml COPY src src diff --git a/frameworks/Java/jooby/jooby-mvc.dockerfile b/frameworks/Java/jooby/jooby-mvc.dockerfile index 3153f04df69..e88198b64bd 100644 --- a/frameworks/Java/jooby/jooby-mvc.dockerfile +++ b/frameworks/Java/jooby/jooby-mvc.dockerfile @@ -1,4 +1,4 @@ -FROM maven:3.9.0-eclipse-temurin-17 +FROM maven:3.9.11-eclipse-temurin-25-noble as maven WORKDIR /jooby COPY pom.xml pom.xml COPY src src @@ -8,4 +8,4 @@ RUN mvn package -q -P netty EXPOSE 8080 -CMD ["java", "-server", "-Xms2g", "-Xmx2g", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-Dio.netty.disableHttpHeadersValidation=true", "-Dio.netty.buffer.checkBounds=false", "-Dio.netty.buffer.checkAccessible=false", "-cp", "target/jooby.jar", "com.techempower.MvcApp"] +CMD ["java", "-server", "-Xms2g", "-Xmx2g", "-XX:+UseNUMA", "-XX:+UseParallelGC", "--enable-native-access=ALL-UNNAMED", "--add-opens=java.base/java.lang=ALL-UNNAMED", "--sun-misc-unsafe-memory-access=allow", "-Dio.netty.disableHttpHeadersValidation=true", "-Dio.netty.buffer.checkBounds=false", "-Dio.netty.buffer.checkAccessible=false", "-Dio.netty.noUnsafe=false", "-Dio.netty.eventLoopGroup=single", "-cp", "target/jooby.jar", "com.techempower.MvcApp"] diff --git a/frameworks/Java/jooby/jooby-netty.dockerfile b/frameworks/Java/jooby/jooby-netty.dockerfile index 141f166e27c..cee8fa0aef4 100644 --- a/frameworks/Java/jooby/jooby-netty.dockerfile +++ b/frameworks/Java/jooby/jooby-netty.dockerfile @@ -1,4 +1,4 @@ -FROM maven:3.9.0-eclipse-temurin-17 +FROM maven:3.9.11-eclipse-temurin-25-noble as maven WORKDIR /jooby COPY pom.xml pom.xml COPY src src @@ -8,4 +8,4 @@ RUN mvn package -q -P netty EXPOSE 8080 -CMD ["java", "-server", "-Xms2g", "-Xmx2g", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-Dio.netty.disableHttpHeadersValidation=true", "-Dio.netty.buffer.checkBounds=false", "-Dio.netty.buffer.checkAccessible=false", "-jar", "target/jooby.jar"] +CMD ["java", "-server", "-Xms2g", "-Xmx2g", "-XX:+UseNUMA", "-XX:+UseParallelGC", "--enable-native-access=ALL-UNNAMED", "--add-opens=java.base/java.lang=ALL-UNNAMED", "--sun-misc-unsafe-memory-access=allow", "-Dio.netty.disableHttpHeadersValidation=true", "-Dio.netty.buffer.checkBounds=false", "-Dio.netty.buffer.checkAccessible=false", "-Dio.netty.noUnsafe=false", "-Dio.netty.eventLoopGroup=single", "-jar", "target/jooby.jar"] diff --git a/frameworks/Java/jooby/jooby-pgclient.dockerfile b/frameworks/Java/jooby/jooby-pgclient.dockerfile index b4a9ba32aad..e4ddf09382f 100644 --- a/frameworks/Java/jooby/jooby-pgclient.dockerfile +++ b/frameworks/Java/jooby/jooby-pgclient.dockerfile @@ -1,11 +1,11 @@ -FROM maven:3.9.0-eclipse-temurin-17 +FROM maven:3.9.11-eclipse-temurin-25-noble as maven WORKDIR /jooby COPY pom.xml pom.xml COPY src src COPY public public COPY conf conf -RUN mvn package -q -P netty +RUN mvn package -q -P vertx EXPOSE 8080 -CMD ["java", "-server", "-Xms2g", "-Xmx2g", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-Dio.netty.disableHttpHeadersValidation=true", "-Dio.netty.buffer.checkBounds=false", "-Dio.netty.buffer.checkAccessible=false", "-cp", "target/jooby.jar", "com.techempower.ReactivePg"] +CMD ["java", "-server", "-Xms2g", "-Xmx2g", "-XX:+UseNUMA", "-XX:+UseParallelGC", "--enable-native-access=ALL-UNNAMED", "--add-opens=java.base/java.lang=ALL-UNNAMED", "--sun-misc-unsafe-memory-access=allow", "-Dio.netty.disableHttpHeadersValidation=true", "-Dio.netty.buffer.checkBounds=false", "-Dio.netty.buffer.checkAccessible=false", "-Dio.netty.noUnsafe=false", "-Dio.netty.eventLoopGroup=single", "-Djava.lang.Integer.IntegerCache.high=10000", "-Dvertx.disableMetrics=true", "-Dvertx.disableContextTimings=true", "-cp", "target/jooby.jar", "com.techempower.ReactivePg", "vertx"] diff --git a/frameworks/Java/jooby/jooby.dockerfile b/frameworks/Java/jooby/jooby.dockerfile index d262363b076..3170040c2de 100644 --- a/frameworks/Java/jooby/jooby.dockerfile +++ b/frameworks/Java/jooby/jooby.dockerfile @@ -1,4 +1,4 @@ -FROM maven:3.9.0-eclipse-temurin-17 +FROM maven:3.9.11-eclipse-temurin-25-noble as maven WORKDIR /jooby COPY pom.xml pom.xml COPY src src diff --git a/frameworks/Java/jooby/pom.xml b/frameworks/Java/jooby/pom.xml index 975c8359c1e..eef2366bd98 100644 --- a/frameworks/Java/jooby/pom.xml +++ b/frameworks/Java/jooby/pom.xml @@ -6,17 +6,17 @@ jooby com.techempower - 3.0 + 4.0 jooby - 3.0.5 - 1.10.0 - 42.6.0 + 4.0.11 + 2.0.2 + 42.7.7 UTF-8 - 17 - 17 + 25 + 25 com.techempower.App @@ -37,14 +37,6 @@ ${jooby.version} - - - com.mysql - mysql-connector-j - 8.0.33 - - - org.postgresql @@ -52,16 +44,17 @@ ${postgresql.version} + - io.vertx - vertx-pg-client - 4.4.4 + io.jooby + jooby-vertx-pg-client + ${jooby.version} com.dslplatform - dsl-json-java8 + dsl-json ${dsl-json.version} @@ -72,7 +65,7 @@ org.codehaus.mojo build-helper-maven-plugin - 3.3.0 + 3.6.1 add-source @@ -91,7 +84,7 @@ com.fizzed rocker-maven-plugin - 1.3.0 + 2.2.1 generate-rocker-templates @@ -110,7 +103,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.11.0 + 3.14.0 @@ -120,7 +113,7 @@ com.dslplatform - dsl-json-java8 + dsl-json ${dsl-json.version} @@ -130,7 +123,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.4.1 + 3.6.0 uber-jar @@ -166,6 +159,21 @@ + + mac + + + mac + + + + + io.netty + netty-resolver-dns-native-macos + osx-aarch_64 + + + undertow @@ -198,6 +206,17 @@ + + + vertx + + + io.jooby + jooby-vertx + ${jooby.version} + + + diff --git a/frameworks/Java/jooby/src/main/java/com/techempower/App.java b/frameworks/Java/jooby/src/main/java/com/techempower/App.java index 01c3665a76b..0c11074d79f 100644 --- a/frameworks/Java/jooby/src/main/java/com/techempower/App.java +++ b/frameworks/Java/jooby/src/main/java/com/techempower/App.java @@ -1,10 +1,10 @@ package com.techempower; +import static com.techempower.Util.boxedRandomWorld; import static com.techempower.Util.randomWorld; import static io.jooby.ExecutionMode.EVENT_LOOP; import static io.jooby.MediaType.JSON; -import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.sql.Connection; import java.sql.PreparedStatement; @@ -26,24 +26,21 @@ public class App extends Jooby { private static final String MESSAGE = "Hello, World!"; - private static final byte[] MESSAGE_BYTES = MESSAGE.getBytes(StandardCharsets.US_ASCII); - - private static final ByteBuffer MESSAGE_BUFFER = (ByteBuffer) ByteBuffer - .allocateDirect(MESSAGE_BYTES.length) - .put(MESSAGE_BYTES) - .flip(); + private static final byte[] MESSAGE_BYTES = MESSAGE.getBytes(StandardCharsets.UTF_8); { - /** Database: */ install(new HikariModule()); DataSource ds = require(DataSource.class); /** Template engine: */ - install(new RockerModule().reuseBuffer(true)); + install(new RockerModule()); + var outputFactory = getOutputFactory(); + Json.configure(outputFactory); + var message = outputFactory.wrap(MESSAGE_BYTES); get("/plaintext", ctx -> - ctx.send(MESSAGE_BUFFER.duplicate()) + ctx.send(message) ); get("/json", ctx -> ctx @@ -104,7 +101,7 @@ public class App extends Jooby { statement.setInt(1, randomWorld()); try (ResultSet rs = statement.executeQuery()) { rs.next(); - result[i] = new World(rs.getInt("id"), randomWorld()); + result[i] = new World(rs.getInt("id"), boxedRandomWorld()); } // prepare update query updateSql.add("(?, ?)"); diff --git a/frameworks/Java/jooby/src/main/java/com/techempower/Json.java b/frameworks/Java/jooby/src/main/java/com/techempower/Json.java index 87543caec1f..a83db38d49d 100644 --- a/frameworks/Java/jooby/src/main/java/com/techempower/Json.java +++ b/frameworks/Java/jooby/src/main/java/com/techempower/Json.java @@ -6,6 +6,8 @@ import com.dslplatform.json.DslJson; import com.dslplatform.json.JsonWriter; import com.dslplatform.json.runtime.Settings; +import io.jooby.output.Output; +import io.jooby.output.OutputFactory; public class Json { private final static DslJson dslJson = new DslJson<>(Settings.basicSetup()); @@ -15,40 +17,41 @@ public class Json { return dslJson.newWriter(1024); } }; + private static OutputFactory outputFactory; - public static ByteBuffer encode(Message data) { + public static void configure(OutputFactory outputFactory) { + Json.outputFactory =outputFactory.getContextFactory(); + } + + public static Output encode(Message data) { JsonWriter writer = pool.get(); writer.reset(); - _Message_DslJsonConverter.ObjectFormatConverter converter = new _Message_DslJsonConverter.ObjectFormatConverter( - dslJson); + var converter = new _Message_DslJsonConverter.ObjectFormatConverter(dslJson); converter.write(writer, data); - return ByteBuffer.wrap(writer.getByteBuffer(), 0, writer.size()); + return outputFactory.wrap(writer.getByteBuffer(), 0, writer.size()); } - public static ByteBuffer encode(World data) { + public static Output encode(World data) { JsonWriter writer = pool.get(); writer.reset(); - _World_DslJsonConverter.ObjectFormatConverter converter = new _World_DslJsonConverter.ObjectFormatConverter( - dslJson); + var converter = new _World_DslJsonConverter.ObjectFormatConverter(dslJson); converter.write(writer, data); - return ByteBuffer.wrap(writer.getByteBuffer(), 0, writer.size()); + return outputFactory.wrap(writer.getByteBuffer(), 0, writer.size()); } - public static ByteBuffer encode(World[] data) { + public static Output encode(World[] data) { JsonWriter writer = pool.get(); writer.reset(); - _World_DslJsonConverter.ObjectFormatConverter converter = new _World_DslJsonConverter.ObjectFormatConverter( - dslJson); + var converter = new _World_DslJsonConverter.ObjectFormatConverter(dslJson); writer.serialize(data, converter); - return ByteBuffer.wrap(writer.getByteBuffer(), 0, writer.size()); + return outputFactory.wrap(writer.getByteBuffer(), 0, writer.size()); } - public static ByteBuffer encode(List data) { + public static Output encode(List data) { JsonWriter writer = pool.get(); writer.reset(); - _World_DslJsonConverter.ObjectFormatConverter converter = new _World_DslJsonConverter.ObjectFormatConverter( - dslJson); + var converter = new _World_DslJsonConverter.ObjectFormatConverter(dslJson); writer.serialize(data, converter); - return ByteBuffer.wrap(writer.getByteBuffer(), 0, writer.size()); + return outputFactory.wrap(writer.getByteBuffer(), 0, writer.size()); } } diff --git a/frameworks/Java/jooby/src/main/java/com/techempower/MvcApp.java b/frameworks/Java/jooby/src/main/java/com/techempower/MvcApp.java index 68d09e0a472..1b69ad5fc87 100644 --- a/frameworks/Java/jooby/src/main/java/com/techempower/MvcApp.java +++ b/frameworks/Java/jooby/src/main/java/com/techempower/MvcApp.java @@ -17,7 +17,9 @@ public static void main(String[] args) { /** Template engine: */ app.install(new RockerModule()); - app.mvc(new Resource(app.require(DataSource.class))); + Json.configure(app.getOutputFactory()); + + app.mvc(new Resource_(app.require(DataSource.class), app.getOutputFactory())); }); } } diff --git a/frameworks/Java/jooby/src/main/java/com/techempower/PgClient.java b/frameworks/Java/jooby/src/main/java/com/techempower/PgClient.java deleted file mode 100644 index 4847ddab1de..00000000000 --- a/frameworks/Java/jooby/src/main/java/com/techempower/PgClient.java +++ /dev/null @@ -1,144 +0,0 @@ -package com.techempower; - -import java.util.List; -import java.util.concurrent.ExecutionException; -import java.util.function.BiConsumer; - -import com.typesafe.config.Config; -import io.jooby.SneakyThrows; -import io.vertx.core.AsyncResult; -import io.vertx.core.Future; -import io.vertx.core.Handler; -import io.vertx.core.Vertx; -import io.vertx.core.VertxOptions; -import io.vertx.pgclient.PgConnectOptions; -import io.vertx.pgclient.PgConnection; -import io.vertx.sqlclient.PreparedQuery; -import io.vertx.sqlclient.PreparedStatement; -import io.vertx.sqlclient.Row; -import io.vertx.sqlclient.RowSet; -import io.vertx.sqlclient.Tuple; -import io.vertx.sqlclient.impl.SqlClientInternal; - -public class PgClient { - - static { - // Should be all I/O processing for SQL responses - System.setProperty("vertx.nettyIORatio", "100"); - } - - 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 class DbConnection { - private PreparedQuery> SELECT_WORLD_QUERY; - private PreparedQuery> SELECT_FORTUNE_QUERY; - private PreparedQuery> UPDATE_WORLD_QUERY; - private SqlClientInternal connection; - } - - private static class DbConnectionFactory extends ThreadLocal { - - private final PgConnectOptions options; - - public DbConnectionFactory(PgConnectOptions options) { - this.options = options; - } - - private Handler> onSuccess(Handler handler) { - return ar -> { - if (ar.succeeded()) { - handler.handle(ar.result()); - } - }; - } - - @Override protected DbConnection initialValue() { - try { - DbConnection result = new DbConnection(); - Vertx vertx = Vertx.vertx( - new VertxOptions() - .setPreferNativeTransport(true) - .setEventLoopPoolSize(1) - .setWorkerPoolSize(1) - .setInternalBlockingPoolSize(1) - ); - var future = PgConnection.connect(vertx, options) - .flatMap(conn -> { - result.connection = (SqlClientInternal) conn; - Future f1 = conn.prepare(SELECT_WORLD) - .andThen(onSuccess(ps -> result.SELECT_WORLD_QUERY = ps.query())); - Future f2 = conn.prepare(SELECT_FORTUNE) - .andThen(onSuccess(ps -> result.SELECT_FORTUNE_QUERY = ps.query())); - Future f3 = conn.prepare(UPDATE_WORLD) - .andThen(onSuccess(ps -> result.UPDATE_WORLD_QUERY = ps.query())); - return Future.join(f1, f2, f3); - }) - .toCompletionStage() - .toCompletableFuture() - .get(); - - Throwable cause = future.cause(); - if (cause != null) { - throw SneakyThrows.propagate(cause); - } - return result; - } catch (InterruptedException ex) { - Thread.currentThread().interrupt(); - throw SneakyThrows.propagate(ex); - } catch (ExecutionException ex) { - throw SneakyThrows.propagate(ex.getCause()); - } - } - } - - private final ThreadLocal sqlClient; - - public PgClient(Config config) { - this.sqlClient = new DbConnectionFactory(pgPoolOptions(config)); - } - - public void selectWorld(Tuple row, Handler>> handler) { - this.sqlClient.get().SELECT_WORLD_QUERY.execute(row, handler); - } - - public void selectWorlds(int queries, Handler>> handler) { - this.sqlClient.get().connection.group(c -> { - for (int i = 0; i < queries; i++) { - c.preparedQuery(SELECT_WORLD).execute(Tuple.of(Util.randomWorld()), handler); - } - }); - } - - public void fortunes(Handler>> handler) { - this.sqlClient.get().SELECT_FORTUNE_QUERY.execute(handler); - } - - public void selectWorldForUpdate(int queries, - BiConsumer>> consumer) { - this.sqlClient.get().connection.group(c -> { - PreparedQuery> statement = c.preparedQuery(SELECT_WORLD); - for (int i = 0; i < queries; i++) { - consumer.accept(i, statement); - } - }); - } - - public void updateWorld(List batch, Handler>> handler) { - this.sqlClient.get().UPDATE_WORLD_QUERY.executeBatch(batch, handler); - } - - private PgConnectOptions pgPoolOptions(Config config) { - PgConnectOptions options = new PgConnectOptions(); - options.setDatabase(config.getString("databaseName")); - options.setHost(config.getString("serverName")); - options.setPort(config.getInt("portNumber")); - options.setUser(config.getString("user")); - options.setPassword(config.getString("password")); - options.setCachePreparedStatements(true); - // Large pipelining means less flushing and we use a single connection anyway - options.setPipeliningLimit(100_000); - return options; - } -} diff --git a/frameworks/Java/jooby/src/main/java/com/techempower/ReactivePg.java b/frameworks/Java/jooby/src/main/java/com/techempower/ReactivePg.java index bd456dc2824..9123447f1a2 100644 --- a/frameworks/Java/jooby/src/main/java/com/techempower/ReactivePg.java +++ b/frameworks/Java/jooby/src/main/java/com/techempower/ReactivePg.java @@ -1,148 +1,187 @@ package com.techempower; -import static com.techempower.Util.randomWorld; import static io.jooby.ExecutionMode.EVENT_LOOP; import static io.jooby.MediaType.JSON; +import static io.jooby.Reified.getParameterized; +import static java.util.stream.IntStream.range; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -import com.fizzed.rocker.RockerOutputFactory; -import io.jooby.Context; -import io.jooby.Jooby; -import io.jooby.MediaType; -import io.jooby.ServerOptions; -import io.jooby.rocker.ByteBufferOutput; +import java.util.*; +import java.util.function.Consumer; + +import io.jooby.*; import io.jooby.rocker.RockerModule; -import io.vertx.sqlclient.Row; -import io.vertx.sqlclient.RowIterator; -import io.vertx.sqlclient.Tuple; +import io.jooby.vertx.pgclient.VertxPgConnectionModule; +import io.vertx.core.AsyncResult; +import io.vertx.core.Handler; +import io.vertx.sqlclient.*; +import io.vertx.sqlclient.impl.SqlClientInternal; public class ReactivePg extends Jooby { + private final PreparedQuery> selectWorldQuery; + private final PreparedQuery> selectFortuneQuery; + private final List>> updateWorldQuery; + private final SqlClientInternal sqlClient; + + { + /** PG client: */ + install(new VertxPgConnectionModule().prepare(statements())); + + /** Template engine: */ + install(new RockerModule()); + Json.configure(getOutputFactory()); + + this.selectWorldQuery = require(PreparedQueryType, "selectWorld"); + this.selectFortuneQuery = require(PreparedQueryType, "selectFortune"); + this.updateWorldQuery = require(PreparedQueryTypeList, "updateWorld"); + this.sqlClient = require(SqlClientInternal.class); + + /** Single query: */ + get("/db", ctx -> { + selectWorldQuery + .execute(Tuple.of(Util.boxedRandomWorld())) + .onComplete( + rsp -> { + if (rsp.succeeded()) { + var rs = rsp.result().iterator(); + var row = rs.next(); + ctx.setResponseType(JSON) + .send(Json.encode(new World(row.getInteger(0), row.getInteger(1)))); + } else { + ctx.sendError(rsp.cause()); + } + }); + return ctx; + }); + + /** Multiple queries: */ + get("/queries", ctx -> { + int queries = Util.queries(ctx); + selectWorlds(ctx, queries, result -> ctx.setResponseType(JSON).send(Json.encode(result))); + return ctx; + }); + + /** Update queries: */ + get("/updates", ctx -> { + int queries = Util.queries(ctx); + selectWorlds( + ctx, + queries, + result -> { + updateWorld( + result, + ar -> { + if (ar.failed()) { + sendError(ctx, ar.cause()); + } else { + ctx.setResponseType(JSON).send(Json.encode(result)); + } + }); + }); + return ctx; + }); + + /** Fortunes: */ + get("/fortunes", ctx -> { + selectFortuneQuery.execute() + .onComplete(rsp -> { + if (rsp.succeeded()) { + RowIterator rs = rsp.result().iterator(); + List fortunes = new ArrayList<>(); + + while (rs.hasNext()) { + Row row = rs.next(); + fortunes.add(new Fortune(row.getInteger(0), row.getString(1))); + } + + fortunes.add(new Fortune(0, "Additional fortune added at request time.")); + Collections.sort(fortunes); + + /** render view: */ + ctx.setResponseType(MediaType.html) + .render(views.fortunes.template(fortunes)); + } else { + sendError(ctx, rsp.cause()); + } + }); + return ctx; + }); + } + + private void selectWorlds(Context ctx, int queries, Consumer> consumer) { + sqlClient.group( + client -> { + List worlds = new ArrayList<>(queries); + for (int i = 0; i < queries; i++) { + client.preparedQuery(SELECT_WORLD) + .execute(Tuple.of(Util.boxedRandomWorld())) + .map(rs -> new World(rs.iterator().next().getInteger(0), Util.boxedRandomWorld())) + .onComplete( + ar -> { + if (ar.succeeded()) { + worlds.add(ar.result()); + if (worlds.size() == queries) { + consumer.accept(worlds); + } + } else { + sendError(ctx, ar.cause()); + } + }); + } + }); + } - { - /** Reduce the number of resources due we do reactive processing. */ - setServerOptions( - new ServerOptions() - .setIoThreads(Runtime.getRuntime().availableProcessors() + 1) - .setWorkerThreads(Runtime.getRuntime().availableProcessors() + 1) - ); - - /** PG client: */ - PgClient client = new PgClient(getConfig().getConfig("db")); - - /** Template engine: */ - install(new RockerModule().reuseBuffer(true)); - - /** Single query: */ - get("/db", ctx -> { - client.selectWorld(Tuple.of(randomWorld()), rsp -> { - if (rsp.succeeded()) { - RowIterator rs = rsp.result().iterator(); - Row row = rs.next(); - ctx.setResponseType(JSON) - .send(Json.encode(new World(row.getInteger(0), row.getInteger(1)))); - } else { - ctx.sendError(rsp.cause()); + private void updateWorld(List worlds, Handler>> handler) { + Collections.sort(worlds); + int len = worlds.size(); + List arguments = new ArrayList<>(); + for (var world : worlds) { + arguments.add(world.getId()); + arguments.add(world.getRandomNumber()); } - }); - return ctx; - }).setNonBlocking(true); - - /** Multiple queries: */ - get("/queries", ctx -> { - int queries = Util.queries(ctx); - var result = new ArrayList(queries); - client.selectWorlds(queries, rsp -> { - if (rsp.succeeded()) { - RowIterator rs = rsp.result().iterator(); - Row row = rs.next(); - result.add(new World(row.getInteger(0), row.getInteger(1))); - } else { - sendError(ctx, rsp.cause()); + updateWorldQuery.get(len - 1).execute(Tuple.wrap(arguments)).onComplete(handler); + } + + private void sendError(Context ctx, Throwable cause) { + if (!ctx.isResponseStarted()) { + ctx.sendError(cause); } - // ready? - if (result.size() == queries) { - ctx.setResponseType(JSON) - .send(Json.encode(result)); + } + + private Map> statements() { + return Map.of( + "selectWorld", List.of(SELECT_WORLD), + "selectFortune", List.of(SELECT_FORTUNE), + "updateWorld", + range(0, 500).map(i -> i + 1).mapToObj(this::buildAggregatedUpdateQuery).toList()); + } + + private String buildAggregatedUpdateQuery(int len) { + var sql = new StringBuilder(); + 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); } - }); - return ctx; - }).setNonBlocking(true); - - /** Update queries: */ - get("/updates", ctx -> { - int queries = Util.queries(ctx); - World[] result = new World[queries]; - client.selectWorldForUpdate(queries, (index, statement) -> { - int id = randomWorld(); - statement.execute(Tuple.of(id), selectCallback -> { - if (selectCallback.failed()) { - sendError(ctx, selectCallback.cause()); - return; - } - result[index] = new World( - selectCallback.result().iterator().next().getInteger(0), - randomWorld()); - if (index == queries - 1) { - // Sort results... avoid dead locks - Arrays.sort(result); - List batch = new ArrayList<>(queries); - for (World world : result) { - batch.add(Tuple.of(world.getRandomNumber(), world.getId())); - } - - client.updateWorld(batch, updateCallback -> { - if (updateCallback.failed()) { - sendError(ctx, updateCallback.cause()); - } else { - ctx.setResponseType(JSON) - .send(Json.encode(result)); - } - }); - } - }); - }); - return ctx; - }).setNonBlocking(true); - - /** Fortunes: */ - RockerOutputFactory factory = require(RockerOutputFactory.class); - get("/fortunes", ctx -> { - client.fortunes(rsp -> { - if (rsp.succeeded()) { - RowIterator rs = rsp.result().iterator(); - List fortunes = new ArrayList<>(); - - while (rs.hasNext()) { - Row row = rs.next(); - fortunes.add(new Fortune(row.getInteger(0), row.getString(1))); - } - - fortunes.add(new Fortune(0, "Additional fortune added at request time.")); - Collections.sort(fortunes); - - /** render view: */ - views.fortunes template = views.fortunes.template(fortunes); - ctx.setResponseType(MediaType.html) - .send(template.render(factory).toBuffer()); - } else { - sendError(ctx, rsp.cause()); + sql.append(" ELSE RANDOMNUMBER"); + sql.append(" END WHERE ID IN ($1"); + for (int i = 1; i < len; i++) { + int offset = (i * 2) + 1; + sql.append(",$").append(offset); } - }); - return ctx; - }).setNonBlocking(true); - } - - private void sendError(Context ctx, Throwable cause) { - if (!ctx.isResponseStarted()) { - ctx.sendError(cause); + sql.append(")"); + return sql.toString(); } - } - public static void main(String[] args) { - runApp(args, EVENT_LOOP, ReactivePg::new); - } + 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 Reified>> PreparedQueryType = + getParameterized(PreparedQuery.class, getParameterized(RowSet.class, Row.class)); + + private static final Reified>>> PreparedQueryTypeList = + Reified.list(PreparedQueryType); + + public static void main(String[] args) { + runApp(args, EVENT_LOOP, ReactivePg::new); + } } diff --git a/frameworks/Java/jooby/src/main/java/com/techempower/Resource.java b/frameworks/Java/jooby/src/main/java/com/techempower/Resource.java index b6eca3b4d80..30ea59472c8 100644 --- a/frameworks/Java/jooby/src/main/java/com/techempower/Resource.java +++ b/frameworks/Java/jooby/src/main/java/com/techempower/Resource.java @@ -4,6 +4,8 @@ import io.jooby.annotation.GET; import io.jooby.annotation.Path; import io.jooby.annotation.Dispatch; +import io.jooby.output.Output; +import io.jooby.output.OutputFactory; import views.fortunes; import javax.sql.DataSource; @@ -28,14 +30,16 @@ public class Resource { private static final byte[] MESSAGE_BYTES = MESSAGE.getBytes(StandardCharsets.UTF_8); private final DataSource dataSource; + private final Output message; - public Resource(DataSource dataSource) { + public Resource(DataSource dataSource, OutputFactory factory) { this.dataSource = dataSource; + this.message = factory.wrap(MESSAGE_BYTES); } @GET @Path("/plaintext") public void plaintText(Context ctx) { - ctx.send(MESSAGE_BYTES); + ctx.send(message); } @GET @Path("/json") diff --git a/frameworks/Java/jooby/src/main/java/com/techempower/Util.java b/frameworks/Java/jooby/src/main/java/com/techempower/Util.java index 7fcef41d43d..e54ae1074a6 100644 --- a/frameworks/Java/jooby/src/main/java/com/techempower/Util.java +++ b/frameworks/Java/jooby/src/main/java/com/techempower/Util.java @@ -1,11 +1,13 @@ package com.techempower; import io.jooby.Context; -import io.jooby.Value; +import io.jooby.value.Value; import java.util.concurrent.ThreadLocalRandom; +import java.util.stream.IntStream; public class Util { + private static final Integer[] BOXED_RND = IntStream.range(1, 10001).boxed().toArray(Integer[]::new); public static int queries(Context ctx) { try { @@ -21,4 +23,9 @@ public static int queries(Context ctx) { public static int randomWorld() { return 1 + ThreadLocalRandom.current().nextInt(10000); } + + public static Integer boxedRandomWorld() { + final int rndValue = ThreadLocalRandom.current().nextInt(1, 10001); + return BOXED_RND[rndValue - 1]; + } } diff --git a/frameworks/Java/jooby/src/main/java/com/techempower/World.java b/frameworks/Java/jooby/src/main/java/com/techempower/World.java index d525eeee44a..4b4259cab42 100644 --- a/frameworks/Java/jooby/src/main/java/com/techempower/World.java +++ b/frameworks/Java/jooby/src/main/java/com/techempower/World.java @@ -7,9 +7,9 @@ public class World implements Comparable { private int id; - private int randomNumber; + private Integer randomNumber; - public World(int id, int randomNumber) { + public World(int id, Integer randomNumber) { this.id = id; this.randomNumber = randomNumber; } @@ -18,7 +18,7 @@ public int getId() { return id; } - public int getRandomNumber() { + public Integer getRandomNumber() { return randomNumber; } diff --git a/frameworks/Java/light-java/pom.xml b/frameworks/Java/light-java/pom.xml index f0e01ee8518..c4f19482f33 100644 --- a/frameworks/Java/light-java/pom.xml +++ b/frameworks/Java/light-java/pom.xml @@ -25,10 +25,10 @@ 11 2.0.1 1.3.12 - 2.3.5.Final + 2.3.20.Final 3.3.1 8.0.28 - 42.4.1 + 42.7.2 1.8.4 0.9.6 3.8.0 diff --git a/frameworks/Java/microhttp/pom.xml b/frameworks/Java/microhttp/pom.xml index 75501b02275..75ad3849dfb 100644 --- a/frameworks/Java/microhttp/pom.xml +++ b/frameworks/Java/microhttp/pom.xml @@ -24,12 +24,12 @@ com.fasterxml.jackson.core jackson-core - 2.13.3 + 2.15.0 com.fasterxml.jackson.core jackson-databind - 2.13.4.2 + 2.16.0 mysql diff --git a/frameworks/Java/micronaut/benchmark_config.json b/frameworks/Java/micronaut/benchmark_config.json index 215f6a90565..db44857f540 100755 --- a/frameworks/Java/micronaut/benchmark_config.json +++ b/frameworks/Java/micronaut/benchmark_config.json @@ -16,12 +16,12 @@ "framework": "Micronaut", "language": "Java", "flavor": "None", - "orm": "raw", + "orm": "Raw", "platform": "Netty", - "webserver": "None", + "webserver": "Netty", "os": "Linux", "database_os": "Linux", - "display_name": "Micronaut Vertx PG Client", + "display_name": "Micronaut [Vertx PG Client]", "notes": "", "versus": "None" }, @@ -39,12 +39,58 @@ "framework": "Micronaut", "language": "Java", "flavor": "None", - "orm": "raw", + "orm": "Raw", "platform": "Netty", - "webserver": "None", + "webserver": "Netty", "os": "Linux", "database_os": "Linux", - "display_name": "Micronaut Vertx PG Client GraalVM", + "display_name": "Micronaut [Vertx PG Client] [GraalVM]", + "notes": "", + "versus": "None" + }, + "loom-fjp": { + "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": "Micro", + "database": "Postgres", + "framework": "Micronaut", + "language": "Java", + "flavor": "None", + "orm": "Raw", + "platform": "Netty", + "webserver": "Netty", + "os": "Linux", + "database_os": "Linux", + "display_name": "Micronaut [Vertx PG Client] [Virtual Threads FJP]", + "notes": "", + "versus": "None" + }, + "loom-on-netty": { + "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": "Micro", + "database": "Postgres", + "framework": "Micronaut", + "language": "Java", + "flavor": "None", + "orm": "Raw", + "platform": "Netty", + "webserver": "Netty", + "os": "Linux", + "database_os": "Linux", + "display_name": "Micronaut [Vertx PG Client] [Virtual Threads Loom-On-Netty]", "notes": "", "versus": "None" }, @@ -60,12 +106,12 @@ "framework": "Micronaut", "language": "Java", "flavor": "None", - "orm": "raw", + "orm": "Raw", "platform": "Netty", - "webserver": "None", + "webserver": "Netty", "os": "Linux", "database_os": "Linux", - "display_name": "Micronaut JDBC", + "display_name": "Micronaut [JDBC]", "notes": "", "versus": "None" }, @@ -81,12 +127,12 @@ "framework": "Micronaut", "language": "Java", "flavor": "None", - "orm": "raw", + "orm": "Raw", "platform": "Netty", - "webserver": "None", + "webserver": "Netty", "os": "Linux", "database_os": "Linux", - "display_name": "Micronaut JDBC GraalVM", + "display_name": "Micronaut [JDBC] [GraalVM]", "notes": "", "versus": "None" }, @@ -102,12 +148,12 @@ "framework": "Micronaut", "language": "Java", "flavor": "None", - "orm": "raw", + "orm": "Raw", "platform": "Netty", - "webserver": "None", + "webserver": "Netty", "os": "Linux", "database_os": "Linux", - "display_name": "Micronaut R2DBC", + "display_name": "Micronaut [R2DBC]", "notes": "", "versus": "None" }, @@ -123,12 +169,12 @@ "framework": "Micronaut", "language": "Java", "flavor": "None", - "orm": "raw", + "orm": "Raw", "platform": "Netty", - "webserver": "None", + "webserver": "Netty", "os": "Linux", "database_os": "Linux", - "display_name": "Micronaut R2DBC GraalVM", + "display_name": "Micronaut [R2DBC] [GraalVM]", "notes": "", "versus": "None" }, @@ -139,17 +185,17 @@ "update_url": "/updates?queries=", "port": 8080, "approach": "Realistic", - "classification": "Micro", + "classification": "fullstack", "database": "Postgres", "framework": "Micronaut", "language": "Java", "flavor": "None", - "orm": "raw", + "orm": "Micro", "platform": "Netty", - "webserver": "None", + "webserver": "Netty", "os": "Linux", "database_os": "Linux", - "display_name": "Micronaut Data JDBC", + "display_name": "Micronaut [Data JDBC]", "notes": "", "versus": "None" }, @@ -160,17 +206,17 @@ "update_url": "/updates?queries=", "port": 8080, "approach": "Realistic", - "classification": "Micro", + "classification": "fullstack", "database": "Postgres", "framework": "Micronaut", "language": "Java", "flavor": "None", - "orm": "raw", + "orm": "Micro", "platform": "Netty", - "webserver": "None", + "webserver": "Netty", "os": "Linux", "database_os": "Linux", - "display_name": "Micronaut Data JDBC GraalVM", + "display_name": "Micronaut [Data JDBC] [GraalVM]", "notes": "", "versus": "None" }, @@ -181,17 +227,17 @@ "update_url": "/updates?queries=", "port": 8080, "approach": "Realistic", - "classification": "Micro", + "classification": "fullstack", "database": "MongoDB", "framework": "Micronaut", "language": "Java", "flavor": "None", - "orm": "raw", + "orm": "Micro", "platform": "Netty", - "webserver": "None", + "webserver": "Netty", "os": "Linux", "database_os": "Linux", - "display_name": "Micronaut Data MongoDB", + "display_name": "Micronaut [Data MongoDB]", "notes": "", "versus": "None" }, @@ -202,17 +248,17 @@ "update_url": "/updates?queries=", "port": 8080, "approach": "Realistic", - "classification": "Micro", + "classification": "fullstack", "database": "MongoDB", "framework": "Micronaut", "language": "Java", "flavor": "None", - "orm": "raw", + "orm": "Micro", "platform": "Netty", - "webserver": "None", + "webserver": "Netty", "os": "Linux", "database_os": "Linux", - "display_name": "Micronaut Data MongoDB GraalVM", + "display_name": "Micronaut [Data MongoDB] [GraalVM]", "notes": "", "versus": "None" } diff --git a/frameworks/Java/micronaut/buildSrc/build.gradle b/frameworks/Java/micronaut/buildSrc/build.gradle index e15932b65d0..c0dfaa40cbc 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.0.1" - implementation "gradle.plugin.com.github.johnrengelman:shadow:7.1.2" + implementation "io.micronaut.gradle:micronaut-gradle-plugin:4.5.4" + implementation "com.github.johnrengelman.shadow:com.github.johnrengelman.shadow.gradle.plugin:8.1.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 43a854cf848..dcb6b3389fc 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 @@ -28,7 +28,7 @@ dependencies { } graalvmNative.binaries.all { - buildArgs.add("--initialize-at-build-time=views") + buildArgs.add("--initialize-at-build-time=gg.jte.generated.precompiled") } test { diff --git a/frameworks/Java/micronaut/common/build.gradle b/frameworks/Java/micronaut/common/build.gradle index c254fb8e743..ea12d5e8675 100644 --- a/frameworks/Java/micronaut/common/build.gradle +++ b/frameworks/Java/micronaut/common/build.gradle @@ -1,7 +1,7 @@ plugins { id 'java' id "io.micronaut.library" - id "nu.studer.rocker" version "3.0.4" + id "gg.jte.gradle" version "3.1.12" } group 'io.micronaut.benchmark' @@ -16,14 +16,10 @@ micronaut { testRuntime "junit5" } -rocker { - configurations { - main { - templateDir = file('src/main/resources') - outputDir = file('build/generated/rocker') - optimize = true - } - } +jte { + sourceDirectory = file("src/main/jte").toPath() + generate() + binaryStaticContent = true } dependencies { @@ -38,7 +34,9 @@ dependencies { transitive = false } - implementation("com.fizzed:rocker-runtime") + implementation("gg.jte:jte") + + runtimeOnly("io.netty:netty-transport-native-io_uring::linux-x86_64") runtimeOnly("ch.qos.logback:logback-classic") runtimeOnly("org.yaml:snakeyaml") @@ -46,4 +44,11 @@ dependencies { test { useJUnitPlatform() +} + +// Gradle requires that generateJte is run before some tasks +tasks.configureEach { + if (name == "inspectRuntimeClasspath") { + mustRunAfter("generateJte") + } } \ No newline at end of file diff --git a/frameworks/Java/micronaut/common/src/main/java/benchmark/Application.java b/frameworks/Java/micronaut/common/src/main/java/benchmark/Application.java index d3e7dc92125..0623e41085c 100644 --- a/frameworks/Java/micronaut/common/src/main/java/benchmark/Application.java +++ b/frameworks/Java/micronaut/common/src/main/java/benchmark/Application.java @@ -1,10 +1,18 @@ package benchmark; import io.micronaut.runtime.Micronaut; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class Application { + private static final Logger log = LoggerFactory.getLogger(Application.class); + public static void main(String[] args) { + log.info("Runtime.maxMemory: {}", Runtime.getRuntime().maxMemory()); + log.info("Runtime.totalMemory: {}", Runtime.getRuntime().totalMemory()); + log.info("Runtime.availableProcessors: {}", Runtime.getRuntime().availableProcessors()); + Micronaut.build(args).environments("common").classes(Application.class).start(); } diff --git a/frameworks/Java/micronaut/common/src/main/java/benchmark/controller/AbstractBenchmarkController.java b/frameworks/Java/micronaut/common/src/main/java/benchmark/controller/AbstractBenchmarkController.java index 637649b448e..8f595d99931 100644 --- a/frameworks/Java/micronaut/common/src/main/java/benchmark/controller/AbstractBenchmarkController.java +++ b/frameworks/Java/micronaut/common/src/main/java/benchmark/controller/AbstractBenchmarkController.java @@ -5,6 +5,7 @@ import java.util.ArrayList; import java.util.Collections; +import java.util.Comparator; import java.util.List; import java.util.concurrent.ThreadLocalRandom; import java.util.stream.IntStream; @@ -12,6 +13,20 @@ public class AbstractBenchmarkController { protected final Integer[] boxed = IntStream.range(1, 10001).boxed().toArray(Integer[]::new); + private static final Comparator FORTUNES_COMPARATOR = new Comparator<>() { + @Override + public int compare(Fortune o1, Fortune o2) { + return o1.message().compareTo(o2.message()); + } + }; + + protected List prepareFortunes(List fortuneList) { + List all = new ArrayList<>(fortuneList.size() + 1); + all.add(new Fortune(0, "Additional fortune added at request time.")); + all.addAll(fortuneList); + all.sort(FORTUNES_COMPARATOR); + return all; + } protected List createFortunes() { List fortuneMessages = IntStream.range(0, 10).boxed().toList(); diff --git a/frameworks/Java/micronaut/common/src/main/java/benchmark/controller/AsyncBenchmarkController.java b/frameworks/Java/micronaut/common/src/main/java/benchmark/controller/AsyncBenchmarkController.java index df8824142a8..a16ce1933c3 100644 --- a/frameworks/Java/micronaut/common/src/main/java/benchmark/controller/AsyncBenchmarkController.java +++ b/frameworks/Java/micronaut/common/src/main/java/benchmark/controller/AsyncBenchmarkController.java @@ -5,19 +5,14 @@ import benchmark.repository.AsyncFortuneRepository; import benchmark.repository.AsyncWorldRepository; import io.micronaut.context.annotation.Requires; -import io.micronaut.http.HttpResponse; import io.micronaut.http.annotation.Controller; import io.micronaut.http.annotation.Get; import io.micronaut.http.annotation.QueryValue; -import io.micronaut.scheduling.TaskExecutors; -import jakarta.inject.Named; -import views.fortunes; import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.concurrent.CompletionStage; -import java.util.concurrent.Executor; import static java.util.Comparator.comparing; @@ -27,14 +22,11 @@ public class AsyncBenchmarkController extends AbstractBenchmarkController { private final AsyncWorldRepository worldRepository; private final AsyncFortuneRepository fortuneRepository; - private final Executor executor; public AsyncBenchmarkController(AsyncWorldRepository worldRepository, - AsyncFortuneRepository fortuneRepository, - @Named(TaskExecutors.BLOCKING) Executor executor) { + AsyncFortuneRepository fortuneRepository) { this.worldRepository = worldRepository; this.fortuneRepository = fortuneRepository; - this.executor = executor; } @Get("/prepare-data-for-test") @@ -45,7 +37,7 @@ public CompletionStage prepareDataForTest() { // https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview#single-database-query @Get("/db") public CompletionStage db() { - return worldRepository.findById(randomId()).thenApplyAsync(world -> world, executor); + return worldRepository.findById(randomId()); } // https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview#multiple-database-queries @@ -56,20 +48,13 @@ public CompletionStage> queries(@QueryValue String queries) { for (int i = 0; i < count; i++) { ids.add(randomId()); } - return worldRepository.findByIds(ids).thenApplyAsync(worlds -> worlds, executor); + return worldRepository.findByIds(ids); } // https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview#fortunes @Get(value = "/fortunes", produces = "text/html;charset=utf-8") - public CompletionStage> fortune() { - return fortuneRepository.findAll().thenApplyAsync(fortuneList -> { - List all = new ArrayList<>(fortuneList.size() + 1); - all.add(new Fortune(0, "Additional fortune added at request time.")); - all.addAll(fortuneList); - all.sort(comparing(Fortune::message)); - String body = fortunes.template(all).render().toString(); - return HttpResponse.ok(body).contentType("text/html;charset=utf-8"); - }, executor); + public CompletionStage> fortune() { + return fortuneRepository.findAll().thenApply(this::prepareFortunes); } // https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview#database-updates @@ -80,7 +65,7 @@ public CompletionStage> updates(@QueryValue String queries) { world.setRandomNumber(randomWorldNumber()); } worlds.sort(Comparator.comparingInt(World::getId)); // Avoid deadlock - return worldRepository.updateAll(worlds).thenApplyAsync(ignore -> worlds, executor); + return worldRepository.updateAll(worlds).thenApply(ignore -> worlds); }); } diff --git a/frameworks/Java/micronaut/common/src/main/java/benchmark/controller/BenchmarkController.java b/frameworks/Java/micronaut/common/src/main/java/benchmark/controller/BenchmarkController.java index 5f23b1ee017..f38940257d3 100644 --- a/frameworks/Java/micronaut/common/src/main/java/benchmark/controller/BenchmarkController.java +++ b/frameworks/Java/micronaut/common/src/main/java/benchmark/controller/BenchmarkController.java @@ -5,22 +5,14 @@ import benchmark.repository.FortuneRepository; import benchmark.repository.WorldRepository; import io.micronaut.context.annotation.Requires; -import io.micronaut.http.HttpResponse; import io.micronaut.http.annotation.Controller; import io.micronaut.http.annotation.Get; import io.micronaut.http.annotation.QueryValue; -import io.micronaut.scheduling.TaskExecutors; -import io.micronaut.scheduling.annotation.ExecuteOn; -import views.fortunes; import java.util.ArrayList; -import java.util.Collection; import java.util.Comparator; import java.util.List; -import static java.util.Comparator.comparing; - -@ExecuteOn(TaskExecutors.IO) @Requires(beans = {WorldRepository.class, FortuneRepository.class}) @Controller public class BenchmarkController extends AbstractBenchmarkController { @@ -59,14 +51,8 @@ public List queries(@QueryValue String queries) { // https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview#fortunes @Get(value = "/fortunes", produces = "text/html;charset=utf-8") - public HttpResponse fortune() { - Collection all = fortuneRepository.findAll(); - List fortunesList = new ArrayList<>(all.size() + 1); - fortunesList.add(new Fortune(0, "Additional fortune added at request time.")); - fortunesList.addAll(all); - fortunesList.sort(comparing(Fortune::message)); - String body = fortunes.template(fortunesList).render().toString(); - return HttpResponse.ok(body).contentType("text/html;charset=utf-8"); + public List fortune() { + return prepareFortunes(fortuneRepository.findAll()); } // https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview#database-updates @@ -80,5 +66,5 @@ public List updates(@QueryValue String queries) { worldRepository.updateAll(worldList); return worldList; } - + } diff --git a/frameworks/Java/micronaut/common/src/main/java/benchmark/controller/FortunesBodyWriter.java b/frameworks/Java/micronaut/common/src/main/java/benchmark/controller/FortunesBodyWriter.java new file mode 100644 index 00000000000..a7bee37d493 --- /dev/null +++ b/frameworks/Java/micronaut/common/src/main/java/benchmark/controller/FortunesBodyWriter.java @@ -0,0 +1,54 @@ +package benchmark.controller; + +import benchmark.model.Fortune; +import gg.jte.TemplateOutput; +import gg.jte.generated.precompiled.JtefortunesGenerated; +import gg.jte.html.OwaspHtmlTemplateOutput; +import io.micronaut.core.annotation.NonNull; +import io.micronaut.core.type.Argument; +import io.micronaut.core.type.MutableHeaders; +import io.micronaut.http.MediaType; +import io.micronaut.http.body.MessageBodyWriter; +import io.micronaut.http.codec.CodecException; +import io.micronaut.http.netty.NettyHttpHeaders; +import jakarta.inject.Singleton; + +import java.io.IOException; +import java.io.OutputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; + +@Singleton +public class FortunesBodyWriter implements MessageBodyWriter> { + + @Override + public void writeTo(@NonNull Argument> type, + @NonNull MediaType mediaType, + List values, + @NonNull MutableHeaders outgoingHeaders, + @NonNull OutputStream outputStream) throws CodecException { + outgoingHeaders.set(NettyHttpHeaders.CONTENT_TYPE, "text/html;charset=utf-8"); + TemplateOutput output = new TemplateOutput() { + + @Override + public void writeContent(String value) { + writeBinaryContent(value.getBytes(StandardCharsets.UTF_8)); + } + + @Override + public void writeContent(String value, int beginIndex, int endIndex) { + writeBinaryContent(value.substring(beginIndex, endIndex).getBytes(StandardCharsets.UTF_8)); + } + + @Override + public void writeBinaryContent(byte[] value) { + try { + outputStream.write(value); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + }; + JtefortunesGenerated.render(new OwaspHtmlTemplateOutput(output), null, values); + } +} diff --git a/frameworks/Java/micronaut/common/src/main/java/benchmark/controller/ReactiveBenchmarkController.java b/frameworks/Java/micronaut/common/src/main/java/benchmark/controller/ReactiveBenchmarkController.java index 8adbc4c4716..e85d236acee 100644 --- a/frameworks/Java/micronaut/common/src/main/java/benchmark/controller/ReactiveBenchmarkController.java +++ b/frameworks/Java/micronaut/common/src/main/java/benchmark/controller/ReactiveBenchmarkController.java @@ -6,21 +6,17 @@ import benchmark.repository.ReactiveWorldRepository; import io.micronaut.context.annotation.Requires; import io.micronaut.core.async.annotation.SingleResult; -import io.micronaut.http.HttpResponse; import io.micronaut.http.annotation.Controller; import io.micronaut.http.annotation.Get; import io.micronaut.http.annotation.QueryValue; import org.reactivestreams.Publisher; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; -import views.fortunes; import java.util.ArrayList; import java.util.Comparator; import java.util.List; -import static java.util.Comparator.comparing; - @Requires(beans = {ReactiveWorldRepository.class, ReactiveFortuneRepository.class}) @Controller public class ReactiveBenchmarkController extends AbstractBenchmarkController { @@ -61,15 +57,8 @@ public Publisher> queries(@QueryValue String queries) { // https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview#fortunes @Get(value = "/fortunes", produces = "text/html;charset=utf-8") @SingleResult - public Mono> fortune() { - return Mono.from(fortuneRepository.findAll()).map(fortuneList -> { - List all = new ArrayList<>(fortuneList.size() + 1); - all.add(new Fortune(0, "Additional fortune added at request time.")); - all.addAll(fortuneList); - all.sort(comparing(Fortune::message)); - String body = fortunes.template(all).render().toString(); - return HttpResponse.ok(body).contentType("text/html;charset=utf-8"); - }); + public Mono> fortune() { + return Mono.from(fortuneRepository.findAll()).map(this::prepareFortunes); } // https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview#database-updates diff --git a/frameworks/Java/micronaut/common/src/main/java/benchmark/filter/ServerHeaderFilter.java b/frameworks/Java/micronaut/common/src/main/java/benchmark/filter/ServerHeaderFilter.java index 8a20f9c765c..0a89778bfef 100644 --- a/frameworks/Java/micronaut/common/src/main/java/benchmark/filter/ServerHeaderFilter.java +++ b/frameworks/Java/micronaut/common/src/main/java/benchmark/filter/ServerHeaderFilter.java @@ -4,7 +4,9 @@ import io.micronaut.http.annotation.Filter; import io.micronaut.http.annotation.ResponseFilter; import io.micronaut.http.annotation.ServerFilter; +import io.micronaut.http.netty.NettyHttpHeaders; import io.micronaut.scheduling.annotation.Scheduled; +import io.netty.handler.codec.http.HttpHeaderNames; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; @@ -25,7 +27,8 @@ public void setDateHeader() { @ResponseFilter public void addDateHeader(MutableHttpResponse mutableHttpResponse) { - mutableHttpResponse.header("Date", dateHeader); + NettyHttpHeaders nettyHttpHeaders = (NettyHttpHeaders) mutableHttpResponse.getHeaders(); + nettyHttpHeaders.setUnsafe(HttpHeaderNames.DATE, dateHeader); } } \ No newline at end of file diff --git a/frameworks/Java/micronaut/common/src/main/java/benchmark/repository/FortuneRepository.java b/frameworks/Java/micronaut/common/src/main/java/benchmark/repository/FortuneRepository.java index 701f647e384..b1c8fe3989e 100644 --- a/frameworks/Java/micronaut/common/src/main/java/benchmark/repository/FortuneRepository.java +++ b/frameworks/Java/micronaut/common/src/main/java/benchmark/repository/FortuneRepository.java @@ -4,11 +4,12 @@ import org.reactivestreams.Publisher; import java.util.Collection; +import java.util.List; public interface FortuneRepository { void initDb(Collection fortunes); - Collection findAll(); + List findAll(); } diff --git a/frameworks/Java/micronaut/common/src/main/jte/fortunes.jte b/frameworks/Java/micronaut/common/src/main/jte/fortunes.jte new file mode 100644 index 00000000000..7ac61415c99 --- /dev/null +++ b/frameworks/Java/micronaut/common/src/main/jte/fortunes.jte @@ -0,0 +1,4 @@ +@param java.util.List fortunes +Fortunes@for(benchmark.model.Fortune fortune : fortunes) + @endfor +
idmessage
${fortune.id()}${fortune.message()}
\ No newline at end of file diff --git a/frameworks/Java/micronaut/common/src/main/resources/application-benchmark.yml b/frameworks/Java/micronaut/common/src/main/resources/application-benchmark.yml index efff28fbc46..4a1882287dc 100644 --- a/frameworks/Java/micronaut/common/src/main/resources/application-benchmark.yml +++ b/frameworks/Java/micronaut/common/src/main/resources/application-benchmark.yml @@ -5,6 +5,7 @@ micronaut: port: 8080 server-header: Micronaut date-header: false + validate-url: false http: client: read-timeout: 60s diff --git a/frameworks/Java/micronaut/common/src/main/resources/application-common.yml b/frameworks/Java/micronaut/common/src/main/resources/application-common.yml index ab67403287e..852e0fa6079 100644 --- a/frameworks/Java/micronaut/common/src/main/resources/application-common.yml +++ b/frameworks/Java/micronaut/common/src/main/resources/application-common.yml @@ -5,6 +5,21 @@ micronaut: port: 8080 server-header: Micronaut date-header: false + validate-url: false + netty: + parent: + event-loop-group: default + prefer-native-transport: true + worker: + event-loop-group: default + prefer-native-transport: true + http: + client: + event-loop-group: default + netty: + event-loops: + default: + prefer-native-transport: true netty: resource-leak-detector-level: DISABLED @@ -17,7 +32,7 @@ datasources: driverClassName: org.postgresql.Driver db-type: postgresql dialect: POSTGRES - maximum-pool-size: 48 + maximum-pool-size: 512 transaction-per-operation: false allow-connection-per-operation: true @@ -29,7 +44,7 @@ r2dbc: options: protocol: postgres initialSize: 0 # https://github.com/micronaut-projects/micronaut-data/issues/2136 - maxSize: 48 + maxSize: 512 mongodb: package-names: diff --git a/frameworks/Java/micronaut/common/src/main/resources/application-loom-on-netty.yml b/frameworks/Java/micronaut/common/src/main/resources/application-loom-on-netty.yml new file mode 100644 index 00000000000..68a6b805706 --- /dev/null +++ b/frameworks/Java/micronaut/common/src/main/resources/application-loom-on-netty.yml @@ -0,0 +1,8 @@ +micronaut: + netty: + event-loops: + default: + loom-carrier: true + loom-carrier: + work-spill-threshold: 1000000 + throughput-mode-threshold: 1000000 diff --git a/frameworks/Java/micronaut/common/src/main/resources/application-loom.yml b/frameworks/Java/micronaut/common/src/main/resources/application-loom.yml new file mode 100644 index 00000000000..576ea1b8e4e --- /dev/null +++ b/frameworks/Java/micronaut/common/src/main/resources/application-loom.yml @@ -0,0 +1,3 @@ +micronaut: + server: + thread-selection: blocking diff --git a/frameworks/Java/micronaut/common/src/main/resources/logback.xml b/frameworks/Java/micronaut/common/src/main/resources/logback.xml index d15761dd727..0f6f1052520 100644 --- a/frameworks/Java/micronaut/common/src/main/resources/logback.xml +++ b/frameworks/Java/micronaut/common/src/main/resources/logback.xml @@ -12,4 +12,7 @@ + + + \ No newline at end of file diff --git a/frameworks/Java/micronaut/common/src/main/resources/views/fortunes.rocker.html b/frameworks/Java/micronaut/common/src/main/resources/views/fortunes.rocker.html deleted file mode 100644 index c6b9d0124a6..00000000000 --- a/frameworks/Java/micronaut/common/src/main/resources/views/fortunes.rocker.html +++ /dev/null @@ -1,8 +0,0 @@ -@import java.util.* -@import benchmark.model.* -@args(List fortunes) -Fortunes - @for ((ForIterator i, Fortune fortune) : fortunes) { - - } -
idmessage
@fortune.id()@fortune.message()
\ No newline at end of file diff --git a/frameworks/Java/micronaut/gradle.properties b/frameworks/Java/micronaut/gradle.properties index a4d3cd8e470..691f3e86c3c 100644 --- a/frameworks/Java/micronaut/gradle.properties +++ b/frameworks/Java/micronaut/gradle.properties @@ -1 +1 @@ -micronautVersion = 4.2.0 +micronautVersion=4.9.2 diff --git a/frameworks/Java/micronaut/gradle/wrapper/gradle-wrapper.jar b/frameworks/Java/micronaut/gradle/wrapper/gradle-wrapper.jar index 7f93135c49b..9bbc975c742 100644 Binary files a/frameworks/Java/micronaut/gradle/wrapper/gradle-wrapper.jar and b/frameworks/Java/micronaut/gradle/wrapper/gradle-wrapper.jar differ diff --git a/frameworks/Java/micronaut/gradle/wrapper/gradle-wrapper.properties b/frameworks/Java/micronaut/gradle/wrapper/gradle-wrapper.properties index 3fa8f862f75..d4081da476b 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.4-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/frameworks/Java/micronaut/gradlew b/frameworks/Java/micronaut/gradlew index 1aa94a42690..faf93008b77 100755 --- a/frameworks/Java/micronaut/gradlew +++ b/frameworks/Java/micronaut/gradlew @@ -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/. @@ -84,7 +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 "${APP_HOME:-./}" > /dev/null && pwd -P ) || 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 @@ -203,7 +205,7 @@ 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. diff --git a/frameworks/Java/micronaut/gradlew.bat b/frameworks/Java/micronaut/gradlew.bat index 6689b85beec..9b42019c791 100644 --- a/frameworks/Java/micronaut/gradlew.bat +++ b/frameworks/Java/micronaut/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,11 +59,11 @@ 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 diff --git a/frameworks/Java/micronaut/micronaut-data-jdbc-graalvm.dockerfile b/frameworks/Java/micronaut/micronaut-data-jdbc-graalvm.dockerfile index 2057d6d9487..5cd7c898d38 100644 --- a/frameworks/Java/micronaut/micronaut-data-jdbc-graalvm.dockerfile +++ b/frameworks/Java/micronaut/micronaut-data-jdbc-graalvm.dockerfile @@ -1,13 +1,11 @@ -FROM ghcr.io/graalvm/graalvm-community:latest as build +FROM container-registry.oracle.com/graalvm/native-image:24 +RUN microdnf install findutils # Gradle 8.7 requires xargs COPY . /home/gradle/src WORKDIR /home/gradle/src -RUN ./gradlew --no-daemon -RUN ./gradlew micronaut-data-jdbc:nativeBuild -x test --no-daemon +RUN ./gradlew micronaut-data-jdbc:nativeCompile -x test -x internalStartTestResourcesService --no-daemon -FROM frolvlad/alpine-glibc:glibc-2.34 -RUN apk --no-cache update && apk add libstdc++ WORKDIR /micronaut -COPY --from=build /home/gradle/src/micronaut-data-jdbc/build/native/nativeCompile/micronaut-data-jdbc micronaut +RUN mv /home/gradle/src/micronaut-data-jdbc/build/native/nativeCompile/micronaut-data-jdbc micronaut EXPOSE 8080 ENV MICRONAUT_ENVIRONMENTS=benchmark diff --git a/frameworks/Java/micronaut/micronaut-data-jdbc.dockerfile b/frameworks/Java/micronaut/micronaut-data-jdbc.dockerfile index a15705ff470..3f41572b0d1 100644 --- a/frameworks/Java/micronaut/micronaut-data-jdbc.dockerfile +++ b/frameworks/Java/micronaut/micronaut-data-jdbc.dockerfile @@ -1,9 +1,9 @@ -FROM gradle:8.1.0-jdk17 as build +FROM gradle:8.14.3-jdk21 as build COPY --chown=gradle:gradle . /home/gradle/src WORKDIR /home/gradle/src -RUN gradle micronaut-data-jdbc:build -x test --no-daemon +RUN gradle micronaut-data-jdbc:build -x test -x internalStartTestResourcesService --no-daemon -FROM openjdk:21 +FROM openjdk:24 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-jdbc/src/main/java/benchmark/JdbcWorldRepository.java b/frameworks/Java/micronaut/micronaut-data-jdbc/src/main/java/benchmark/JdbcWorldRepository.java index 3b08db89390..89e9a6be895 100644 --- a/frameworks/Java/micronaut/micronaut-data-jdbc/src/main/java/benchmark/JdbcWorldRepository.java +++ b/frameworks/Java/micronaut/micronaut-data-jdbc/src/main/java/benchmark/JdbcWorldRepository.java @@ -2,6 +2,7 @@ import benchmark.model.World; import benchmark.repository.WorldRepository; +import io.micronaut.data.connection.annotation.Connectable; import io.micronaut.data.jdbc.annotation.JdbcRepository; import io.micronaut.data.model.query.builder.sql.Dialect; import io.micronaut.data.repository.GenericRepository; @@ -20,6 +21,7 @@ default void initDb(Collection worlds) { void saveAll(Collection worlds); + @Connectable @Override default List findByIds(List ids) { return WorldRepository.super.findByIds(ids); diff --git a/frameworks/Java/micronaut/micronaut-data-mongodb-graalvm.dockerfile b/frameworks/Java/micronaut/micronaut-data-mongodb-graalvm.dockerfile index 1f090fc4deb..2523f8a8c9d 100644 --- a/frameworks/Java/micronaut/micronaut-data-mongodb-graalvm.dockerfile +++ b/frameworks/Java/micronaut/micronaut-data-mongodb-graalvm.dockerfile @@ -1,13 +1,11 @@ -FROM ghcr.io/graalvm/graalvm-community:latest as build +FROM container-registry.oracle.com/graalvm/native-image:24 +RUN microdnf install findutils # Gradle 8.7 requires xargs COPY . /home/gradle/src WORKDIR /home/gradle/src -RUN ./gradlew --no-daemon -RUN ./gradlew micronaut-data-mongodb:nativeBuild -x test --no-daemon +RUN ./gradlew micronaut-data-mongodb:nativeCompile -x test -x internalStartTestResourcesService --no-daemon -FROM frolvlad/alpine-glibc:glibc-2.34 -RUN apk --no-cache update && apk add libstdc++ WORKDIR /micronaut -COPY --from=build /home/gradle/src/micronaut-data-mongodb/build/native/nativeCompile/micronaut-data-mongodb micronaut +RUN mv /home/gradle/src/micronaut-data-mongodb/build/native/nativeCompile/micronaut-data-mongodb micronaut EXPOSE 8080 ENV MICRONAUT_ENVIRONMENTS=benchmark diff --git a/frameworks/Java/micronaut/micronaut-data-mongodb.dockerfile b/frameworks/Java/micronaut/micronaut-data-mongodb.dockerfile index 3b009baa929..f0265880881 100644 --- a/frameworks/Java/micronaut/micronaut-data-mongodb.dockerfile +++ b/frameworks/Java/micronaut/micronaut-data-mongodb.dockerfile @@ -1,9 +1,9 @@ -FROM gradle:8.1.0-jdk17 as build +FROM gradle:8.14.3-jdk21 as build COPY --chown=gradle:gradle . /home/gradle/src WORKDIR /home/gradle/src -RUN gradle micronaut-data-mongodb:build -x test --no-daemon +RUN gradle micronaut-data-mongodb:build -x test -x internalStartTestResourcesService --no-daemon -FROM openjdk:21 +FROM openjdk:24 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-mongodb/build.gradle b/frameworks/Java/micronaut/micronaut-data-mongodb/build.gradle index a80c5797d38..07cc244708a 100644 --- a/frameworks/Java/micronaut/micronaut-data-mongodb/build.gradle +++ b/frameworks/Java/micronaut/micronaut-data-mongodb/build.gradle @@ -4,6 +4,6 @@ plugins { dependencies { annotationProcessor("io.micronaut.data:micronaut-data-document-processor") - implementation("io.micronaut.data:micronaut-data-mongodb:3.8.1") + implementation("io.micronaut.data:micronaut-data-mongodb") runtimeOnly("io.micronaut.mongodb:micronaut-mongo-sync") } \ No newline at end of file diff --git a/frameworks/Java/micronaut/micronaut-data-r2dbc-graalvm.dockerfile b/frameworks/Java/micronaut/micronaut-data-r2dbc-graalvm.dockerfile index ad20f4f403d..d96f5945b06 100644 --- a/frameworks/Java/micronaut/micronaut-data-r2dbc-graalvm.dockerfile +++ b/frameworks/Java/micronaut/micronaut-data-r2dbc-graalvm.dockerfile @@ -1,13 +1,11 @@ -FROM ghcr.io/graalvm/graalvm-community:latest as build +FROM container-registry.oracle.com/graalvm/native-image:24 +RUN microdnf install findutils # Gradle 8.7 requires xargs COPY . /home/gradle/src WORKDIR /home/gradle/src -RUN ./gradlew --no-daemon -RUN ./gradlew micronaut-data-r2dbc:nativeBuild -x test --no-daemon +RUN ./gradlew micronaut-data-r2dbc:nativeCompile -x test -x internalStartTestResourcesService --no-daemon -FROM frolvlad/alpine-glibc:glibc-2.34 -RUN apk --no-cache update && apk add libstdc++ WORKDIR /micronaut -COPY --from=build /home/gradle/src/micronaut-data-r2dbc/build/native/nativeCompile/micronaut-data-r2dbc micronaut +RUN mv /home/gradle/src/micronaut-data-r2dbc/build/native/nativeCompile/micronaut-data-r2dbc micronaut EXPOSE 8080 ENV MICRONAUT_ENVIRONMENTS=benchmark diff --git a/frameworks/Java/micronaut/micronaut-data-r2dbc.dockerfile b/frameworks/Java/micronaut/micronaut-data-r2dbc.dockerfile index efb48dd3fb1..3caef969781 100644 --- a/frameworks/Java/micronaut/micronaut-data-r2dbc.dockerfile +++ b/frameworks/Java/micronaut/micronaut-data-r2dbc.dockerfile @@ -1,9 +1,9 @@ -FROM gradle:8.1.0-jdk17 as build +FROM gradle:8.14.3-jdk21 as build COPY --chown=gradle:gradle . /home/gradle/src WORKDIR /home/gradle/src -RUN gradle micronaut-data-r2dbc:build -x test --no-daemon +RUN gradle micronaut-data-r2dbc:build -x test -x internalStartTestResourcesService --no-daemon -FROM openjdk:21 +FROM openjdk:24 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 3f364c05edd..5638f4242bb 100644 --- a/frameworks/Java/micronaut/micronaut-graalvm.dockerfile +++ b/frameworks/Java/micronaut/micronaut-graalvm.dockerfile @@ -1,13 +1,11 @@ -FROM ghcr.io/graalvm/graalvm-community:latest as build +FROM container-registry.oracle.com/graalvm/native-image:24 +RUN microdnf install findutils # Gradle 8.7 requires xargs COPY . /home/gradle/src WORKDIR /home/gradle/src -RUN ./gradlew --no-daemon -RUN ./gradlew micronaut-vertx-pg-client:nativeBuild -x test --no-daemon +RUN ./gradlew micronaut-vertx-pg-client:nativeCompile -x test -x internalStartTestResourcesService --no-daemon -FROM frolvlad/alpine-glibc:glibc-2.34 -RUN apk --no-cache update && apk add libstdc++ WORKDIR /micronaut -COPY --from=build /home/gradle/src/micronaut-vertx-pg-client/build/native/nativeCompile/micronaut-vertx-pg-client micronaut +RUN mv /home/gradle/src/micronaut-vertx-pg-client/build/native/nativeCompile/micronaut-vertx-pg-client micronaut EXPOSE 8080 ENV MICRONAUT_ENVIRONMENTS=benchmark diff --git a/frameworks/Java/micronaut/micronaut-jdbc-graalvm.dockerfile b/frameworks/Java/micronaut/micronaut-jdbc-graalvm.dockerfile index 3a35839970c..5defe25a9ad 100644 --- a/frameworks/Java/micronaut/micronaut-jdbc-graalvm.dockerfile +++ b/frameworks/Java/micronaut/micronaut-jdbc-graalvm.dockerfile @@ -1,13 +1,11 @@ -FROM ghcr.io/graalvm/graalvm-community:latest as build +FROM container-registry.oracle.com/graalvm/native-image:24 +RUN microdnf install findutils # Gradle 8.7 requires xargs COPY . /home/gradle/src WORKDIR /home/gradle/src -RUN ./gradlew --no-daemon -RUN ./gradlew micronaut-jdbc:nativeBuild -x test --no-daemon +RUN ./gradlew micronaut-jdbc:nativeCompile -x test -x internalStartTestResourcesService --no-daemon -FROM frolvlad/alpine-glibc:glibc-2.34 -RUN apk --no-cache update && apk add libstdc++ WORKDIR /micronaut -COPY --from=build /home/gradle/src/micronaut-jdbc/build/native/nativeCompile/micronaut-jdbc micronaut +RUN mv /home/gradle/src/micronaut-jdbc/build/native/nativeCompile/micronaut-jdbc micronaut EXPOSE 8080 ENV MICRONAUT_ENVIRONMENTS=benchmark diff --git a/frameworks/Java/micronaut/micronaut-jdbc.dockerfile b/frameworks/Java/micronaut/micronaut-jdbc.dockerfile index 6113f396683..08af177c9e2 100644 --- a/frameworks/Java/micronaut/micronaut-jdbc.dockerfile +++ b/frameworks/Java/micronaut/micronaut-jdbc.dockerfile @@ -1,9 +1,9 @@ -FROM gradle:8.1.0-jdk17 as build +FROM gradle:8.14.3-jdk21 as build COPY --chown=gradle:gradle . /home/gradle/src WORKDIR /home/gradle/src -RUN gradle micronaut-jdbc:build -x test --no-daemon +RUN gradle micronaut-jdbc:build -x test -x internalStartTestResourcesService --no-daemon -FROM openjdk:21 +FROM openjdk:24 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-jdbc/src/main/java/benchmark/JdbcFortuneRepository.java b/frameworks/Java/micronaut/micronaut-jdbc/src/main/java/benchmark/JdbcFortuneRepository.java index 8b07fd1c6fc..2315804f7c2 100644 --- a/frameworks/Java/micronaut/micronaut-jdbc/src/main/java/benchmark/JdbcFortuneRepository.java +++ b/frameworks/Java/micronaut/micronaut-jdbc/src/main/java/benchmark/JdbcFortuneRepository.java @@ -42,7 +42,7 @@ public void initDb(Collection fortunes) { } @Override - public Collection findAll() { + public List findAll() { try (Connection connection = dataSource.getConnection()) { try (PreparedStatement statement = connection.prepareStatement("SELECT id, message FROM fortune", ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY)) { diff --git a/frameworks/Java/micronaut/micronaut-loom-fjp.dockerfile b/frameworks/Java/micronaut/micronaut-loom-fjp.dockerfile new file mode 100644 index 00000000000..29ceea4e896 --- /dev/null +++ b/frameworks/Java/micronaut/micronaut-loom-fjp.dockerfile @@ -0,0 +1,13 @@ +FROM gradle:8.14.3-jdk21 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 +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 + +EXPOSE 8080 +ENV MN_ENV=loom +ENTRYPOINT "./run_benchmark.sh" diff --git a/frameworks/Java/micronaut/micronaut-loom-on-netty.dockerfile b/frameworks/Java/micronaut/micronaut-loom-on-netty.dockerfile new file mode 100644 index 00000000000..76f2cdebfa6 --- /dev/null +++ b/frameworks/Java/micronaut/micronaut-loom-on-netty.dockerfile @@ -0,0 +1,13 @@ +FROM gradle:8.14.3-jdk21 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 +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 + +EXPOSE 8080 +ENV MN_ENV=loom,loom-on-netty +ENTRYPOINT "./run_benchmark.sh" diff --git a/frameworks/Java/micronaut/micronaut-r2dbc-graalvm.dockerfile b/frameworks/Java/micronaut/micronaut-r2dbc-graalvm.dockerfile index 627fd21aba2..32c282bbcd2 100644 --- a/frameworks/Java/micronaut/micronaut-r2dbc-graalvm.dockerfile +++ b/frameworks/Java/micronaut/micronaut-r2dbc-graalvm.dockerfile @@ -1,13 +1,11 @@ -FROM ghcr.io/graalvm/graalvm-community:latest as build +FROM container-registry.oracle.com/graalvm/native-image:24 +RUN microdnf install findutils # Gradle 8.7 requires xargs COPY . /home/gradle/src WORKDIR /home/gradle/src -RUN ./gradlew --no-daemon -RUN ./gradlew micronaut-r2dbc:nativeBuild -x test --no-daemon +RUN ./gradlew micronaut-r2dbc:nativeCompile -x test --no-daemon -FROM frolvlad/alpine-glibc:glibc-2.34 -RUN apk --no-cache update && apk add libstdc++ WORKDIR /micronaut -COPY --from=build /home/gradle/src/micronaut-r2dbc/build/native/nativeCompile/micronaut-r2dbc micronaut +RUN mv /home/gradle/src/micronaut-r2dbc/build/native/nativeCompile/micronaut-r2dbc micronaut EXPOSE 8080 ENV MICRONAUT_ENVIRONMENTS=benchmark diff --git a/frameworks/Java/micronaut/micronaut-r2dbc.dockerfile b/frameworks/Java/micronaut/micronaut-r2dbc.dockerfile index cad08e08d3b..1ddbd04a84c 100644 --- a/frameworks/Java/micronaut/micronaut-r2dbc.dockerfile +++ b/frameworks/Java/micronaut/micronaut-r2dbc.dockerfile @@ -1,9 +1,9 @@ -FROM gradle:8.1.0-jdk17 as build +FROM gradle:8.14.3-jdk21 as build COPY --chown=gradle:gradle . /home/gradle/src WORKDIR /home/gradle/src -RUN gradle micronaut-r2dbc:build -x test --no-daemon +RUN gradle micronaut-r2dbc:build -x test -x internalStartTestResourcesService --no-daemon -FROM openjdk:21 +FROM openjdk:24 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 ce83fa28bf2..fe8dd5d09bf 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") + implementation("io.vertx:vertx-pg-client:5.0.2") implementation('com.ongres.scram:client') } \ No newline at end of file diff --git a/frameworks/Java/micronaut/micronaut-vertx-pg-client/src/main/java/benchmark/AbstractVertxSqlClientRepository.java b/frameworks/Java/micronaut/micronaut-vertx-pg-client/src/main/java/benchmark/AbstractVertxSqlClientRepository.java index 8f76190eaa4..26e993fe9e6 100644 --- a/frameworks/Java/micronaut/micronaut-vertx-pg-client/src/main/java/benchmark/AbstractVertxSqlClientRepository.java +++ b/frameworks/Java/micronaut/micronaut-vertx-pg-client/src/main/java/benchmark/AbstractVertxSqlClientRepository.java @@ -7,6 +7,7 @@ import io.vertx.sqlclient.RowSet; import io.vertx.sqlclient.SqlClient; import io.vertx.sqlclient.Tuple; +import jakarta.inject.Inject; import java.util.ArrayList; import java.util.List; @@ -15,23 +16,20 @@ public class AbstractVertxSqlClientRepository { - protected final Pool client; - - public AbstractVertxSqlClientRepository(Pool client) { - this.client = client; - } + @Inject + protected ConnectionHolder holder; protected CompletionStage execute(String sql) { - return client.preparedQuery(sql).execute().toCompletionStage(); + return holder.get().flatMap(conn->conn.preparedQuery(sql).execute()).toCompletionStage(); } protected CompletionStage executeAndCollectOne(String sql, Tuple tuple, Function mapper) { - return client.preparedQuery(sql).execute(tuple).map(rows -> mapper.apply(rows.iterator().next())) + return holder.get().flatMap(conn->conn.preparedQuery(sql).execute(tuple).map(rows -> mapper.apply(rows.iterator().next()))) .toCompletionStage(); } protected CompletionStage> executeAndCollectList(String sql, Function mapper) { - return client.preparedQuery(sql).execute().map(rows -> { + return holder.get().flatMap(conn->conn.preparedQuery(sql).execute()).map(rows -> { List result = new ArrayList<>(rows.size()); for (Row row : rows) { result.add(mapper.apply(row)); @@ -52,7 +50,7 @@ protected Future> executeMany(SqlClient sqlClient, String sql, List< } protected CompletionStage executeBatch(String sql, List data) { - return client.preparedQuery(sql).executeBatch(data).toCompletionStage(); + return holder.get().flatMap(conn->conn.preparedQuery(sql).executeBatch(data)).toCompletionStage(); } } 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 new file mode 100644 index 00000000000..6d7d91cd3f9 --- /dev/null +++ b/frameworks/Java/micronaut/micronaut-vertx-pg-client/src/main/java/benchmark/ConnectionHolder.java @@ -0,0 +1,219 @@ +package benchmark; + +import io.micronaut.context.annotation.Property; +import io.micronaut.core.util.SupplierUtil; +import io.micronaut.http.netty.channel.loom.EventLoopVirtualThreadScheduler; +import io.micronaut.http.netty.channel.loom.PrivateLoomSupport; +import io.micronaut.scheduling.LoomSupport; +import io.netty.bootstrap.Bootstrap; +import io.netty.bootstrap.ServerBootstrap; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFactory; +import io.netty.channel.EventLoop; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.IoHandlerFactory; +import io.netty.channel.ServerChannel; +import io.netty.channel.socket.DatagramChannel; +import io.netty.channel.socket.InternetProtocolFamily; +import io.netty.util.Attribute; +import io.netty.util.AttributeKey; +import io.netty.util.concurrent.FastThreadLocal; +import io.netty.util.internal.ThreadExecutorMap; +import io.vertx.core.Future; +import io.vertx.core.Vertx; +import io.vertx.core.VertxBuilder; +import io.vertx.core.datagram.DatagramSocketOptions; +import io.vertx.core.net.ClientOptionsBase; +import io.vertx.core.net.NetServerOptions; +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; + +import java.net.SocketAddress; +import java.util.List; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadLocalRandom; +import java.util.function.Supplier; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +@Singleton +public class ConnectionHolder { + private static final Logger log = LoggerFactory.getLogger(ConnectionHolder.class); + private final FastThreadLocal> conn = new FastThreadLocal<>(); + private final AttributeKey> loomConn = AttributeKey.valueOf("vertx-pg-connection"); + + @Property(name = "datasources.default.url") String url; + @Property(name = "datasources.default.username") String user; + @Property(name = "datasources.default.password") String password; + @Property(name = "datasources.default.maximum-pool-size") int maxPoolSize; + + private final Supplier>> pool = SupplierUtil.memoized(() -> { + Vertx vertx = Vertx.builder() + .withTransport(vertxTransport()) + .build(); + return IntStream.range(0, maxPoolSize) + .mapToObj(i -> PgConnection.connect(vertx, connectOptions())) + .toList(); + }); + + public Future get() { + if (PrivateLoomSupport.isSupported() && + LoomSupport.isVirtual(Thread.currentThread()) && + PrivateLoomSupport.getScheduler(Thread.currentThread()) instanceof EventLoopVirtualThreadScheduler sch) { + + Attribute> attr = sch.attributeMap().attr(loomConn); + Future c = attr.get(); + if (c == null) { + c = connect((EventLoop) sch.eventLoop()); + attr.set(c); + } + return c; + } else if (ThreadExecutorMap.currentExecutor() instanceof EventLoop el) { + + Future c = conn.get(); + if (c == null) { + c = connect(el); + conn.set(c); + } + return c; + } else { + List> l = pool.get(); + return l.get(ThreadLocalRandom.current().nextInt(l.size())); + } + } + + private Future connect(EventLoop loop) { + VertxBuilder builder = Vertx.builder(); + + io.vertx.core.transport.Transport original = vertxTransport(); + ExistingTransport mapped = new ExistingTransport(original.implementation(), loop); + io.vertx.core.transport.Transport tr = new io.vertx.core.transport.Transport() { + @Override + public String name() { + return "ExistingTransport"; + } + + @Override + public boolean available() { + return true; + } + + @Override + public Throwable unavailabilityCause() { + return null; + } + + @Override + public Transport implementation() { + return mapped; + } + }; + Vertx vertx = builder + .withTransport(tr) + .build(); + return PgConnection.connect(vertx, connectOptions()); + } + + private static io.vertx.core.transport.Transport vertxTransport() { + return Stream.of(io.vertx.core.transport.Transport.IO_URING, io.vertx.core.transport.Transport.NIO) + .filter(t -> t != null && t.available()) + .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) + .setPassword(password) + .setCachePreparedStatements(true) + .setPipeliningLimit(1024); + } + + private record ExistingTransport(Transport transport, EventLoop loop) implements Transport { + + @Override + public boolean supportsDomainSockets() { + return transport.supportsDomainSockets(); + } + + @Override + public boolean supportFileRegion() { + return transport.supportFileRegion(); + } + + @Override + public boolean isAvailable() { + return transport.isAvailable(); + } + + @Override + public Throwable unavailabilityCause() { + return transport.unavailabilityCause(); + } + + @Override + public SocketAddress convert(io.vertx.core.net.SocketAddress address) { + return transport.convert(address); + } + + @Override + public io.vertx.core.net.SocketAddress convert(SocketAddress address) { + return transport.convert(address); + } + + @Override + public IoHandlerFactory ioHandlerFactory() { + return transport.ioHandlerFactory(); + } + + @Override + public EventLoopGroup eventLoopGroup(int type, int nThreads, ThreadFactory threadFactory, int ignoredIoRatio) { + return loop; + } + + @Override + public DatagramChannel datagramChannel() { + return transport.datagramChannel(); + } + + @Override + public DatagramChannel datagramChannel(InternetProtocolFamily family) { + return transport.datagramChannel(family); + } + + @Override + public ChannelFactory channelFactory(boolean domainSocket) { + return transport.channelFactory(domainSocket); + } + + @Override + public ChannelFactory serverChannelFactory(boolean domainSocket) { + return transport.serverChannelFactory(domainSocket); + } + + @Override + public void configure(DatagramChannel channel, DatagramSocketOptions options) { + transport.configure(channel, options); + } + + @Override + public void configure(ClientOptionsBase options, int connectTimeout, boolean domainSocket, Bootstrap bootstrap) { + transport.configure(options, connectTimeout, domainSocket, bootstrap); + } + + @Override + public void configure(NetServerOptions options, boolean domainSocket, ServerBootstrap bootstrap) { + transport.configure(options, domainSocket, bootstrap); + } + } +} diff --git a/frameworks/Java/micronaut/micronaut-vertx-pg-client/src/main/java/benchmark/PgClientFactory.java b/frameworks/Java/micronaut/micronaut-vertx-pg-client/src/main/java/benchmark/PgClientFactory.java deleted file mode 100644 index 3b10b483c42..00000000000 --- a/frameworks/Java/micronaut/micronaut-vertx-pg-client/src/main/java/benchmark/PgClientFactory.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2017-2020 original authors - * - * 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 - * - * https://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 benchmark; - -import io.micronaut.context.annotation.Bean; -import io.micronaut.context.annotation.Factory; -import io.micronaut.context.annotation.Property; -import io.vertx.core.Vertx; -import io.vertx.core.VertxOptions; -import io.vertx.core.impl.VertxBuilder; -import io.vertx.pgclient.PgConnectOptions; -import io.vertx.pgclient.PgPool; -import io.vertx.sqlclient.PoolOptions; -import jakarta.inject.Singleton; - -/** - * The Factory for creating Vertx PG client. - */ -@Factory -public class PgClientFactory { - - @Singleton - @Bean(preDestroy = "close") - public PgPool client(@Property(name = "datasources.default.url") String url, - @Property(name = "datasources.default.username") String user, - @Property(name = "datasources.default.password") String password, - @Property(name = "datasources.default.maximum-pool-size") int maxPoolSize) { - - VertxOptions vertxOptions = new VertxOptions() - .setPreferNativeTransport(true); - - PgConnectOptions connectOptions = PgConnectOptions.fromUri(url.substring(5)) - .setUser(user) - .setPassword(password) - .setCachePreparedStatements(true) - .setTcpNoDelay(true) - .setTcpQuickAck(true) - .setPipeliningLimit(1024); - PoolOptions poolOptions = new PoolOptions(); - poolOptions.setMaxSize(maxPoolSize); - - Vertx vertx = new VertxBuilder(vertxOptions).init().vertx(); - return PgPool.pool(vertx, connectOptions, poolOptions); - } -} diff --git a/frameworks/Java/micronaut/micronaut-vertx-pg-client/src/main/java/benchmark/VertxPgFortuneRepository.java b/frameworks/Java/micronaut/micronaut-vertx-pg-client/src/main/java/benchmark/VertxPgFortuneRepository.java index 3515f9fc118..1c25569cd0f 100644 --- a/frameworks/Java/micronaut/micronaut-vertx-pg-client/src/main/java/benchmark/VertxPgFortuneRepository.java +++ b/frameworks/Java/micronaut/micronaut-vertx-pg-client/src/main/java/benchmark/VertxPgFortuneRepository.java @@ -2,7 +2,6 @@ import benchmark.model.Fortune; import benchmark.repository.AsyncFortuneRepository; -import io.vertx.sqlclient.Pool; import io.vertx.sqlclient.Tuple; import jakarta.inject.Singleton; @@ -14,10 +13,6 @@ @Singleton public class VertxPgFortuneRepository extends AbstractVertxSqlClientRepository implements AsyncFortuneRepository { - public VertxPgFortuneRepository(Pool client) { - super(client); - } - private CompletionStage createTable() { return execute("DROP TABLE IF EXISTS Fortune;") .thenCompose(ignore -> execute("CREATE TABLE Fortune (id INTEGER NOT NULL,message VARCHAR(255) NOT NULL);")); diff --git a/frameworks/Java/micronaut/micronaut-vertx-pg-client/src/main/java/benchmark/VertxPgWorldRepository.java b/frameworks/Java/micronaut/micronaut-vertx-pg-client/src/main/java/benchmark/VertxPgWorldRepository.java index c584b69d095..b1929d8833c 100644 --- a/frameworks/Java/micronaut/micronaut-vertx-pg-client/src/main/java/benchmark/VertxPgWorldRepository.java +++ b/frameworks/Java/micronaut/micronaut-vertx-pg-client/src/main/java/benchmark/VertxPgWorldRepository.java @@ -2,7 +2,6 @@ import benchmark.model.World; import benchmark.repository.AsyncWorldRepository; -import io.vertx.sqlclient.Pool; import io.vertx.sqlclient.Row; import io.vertx.sqlclient.Tuple; import jakarta.inject.Singleton; @@ -19,10 +18,6 @@ public class VertxPgWorldRepository extends AbstractVertxSqlClientRepository imp private static final Function ROW_TO_WORLD_MAPPER = row -> new World(row.getInteger(0), row.getInteger(1)); - public VertxPgWorldRepository(Pool client) { - super(client); - } - private CompletionStage createTable() { return execute("DROP TABLE IF EXISTS World;").thenCompose(ignore -> execute("CREATE TABLE World (id INTEGER NOT NULL,randomNumber INTEGER NOT NULL);")); } @@ -44,7 +39,7 @@ public CompletionStage> findByIds(List ids) { for (Integer id : ids) { data.add(Tuple.of(id)); } - return client.withConnection(sqlConnection -> + return holder.get().flatMap(sqlConnection -> executeMany(sqlConnection, "SELECT * FROM world WHERE id = $1", data, ROW_TO_WORLD_MAPPER)) .toCompletionStage(); } diff --git a/frameworks/Java/micronaut/micronaut.dockerfile b/frameworks/Java/micronaut/micronaut.dockerfile index 72376d86588..b50cc0fa117 100644 --- a/frameworks/Java/micronaut/micronaut.dockerfile +++ b/frameworks/Java/micronaut/micronaut.dockerfile @@ -1,9 +1,9 @@ -FROM gradle:8.1.0-jdk17 as build +FROM gradle:8.14.3-jdk21 as build COPY --chown=gradle:gradle . /home/gradle/src WORKDIR /home/gradle/src -RUN gradle micronaut-vertx-pg-client:build -x test --no-daemon +RUN gradle micronaut-vertx-pg-client:build -x test -x internalStartTestResourcesService --no-daemon -FROM openjdk:21 +FROM openjdk:24 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/run_benchmark.sh b/frameworks/Java/micronaut/run_benchmark.sh index 4f8fccf3ba4..a5db04ab957 100755 --- a/frameworks/Java/micronaut/run_benchmark.sh +++ b/frameworks/Java/micronaut/run_benchmark.sh @@ -1,17 +1,23 @@ #!/bin/bash -JAVA_OPTIONS="-server \ +if [ -z "$MN_ENV" ]; then + MN_ENV=benchmark +else + MN_ENV=benchmark,$MN_ENV +fi + +JAVA_OPTIONS="$JAVA_OPTIONS -server \ -XX:+UseParallelGC \ -XX:+UseNUMA \ - -XX:+UseStringDeduplication \ - -XX:-StackTraceInThrowable \ + -Djdk.trackAllThreads=false \ -Dio.netty.buffer.checkBounds=false \ -Dio.netty.buffer.checkAccessible=false \ -Dvertx.disableMetrics=true \ -Dvertx.threadChecks=false \ -Dvertx.disableContextTimings=true \ -Dvertx.disableTCCL=true \ - -Dmicronaut.environments=benchmark + -Dmicronaut.environments=$MN_ENV \ + --add-opens=java.base/java.lang=ALL-UNNAMED \ $@" -java $JAVA_OPTIONS -jar micronaut.jar +exec java $JAVA_OPTIONS -jar micronaut.jar diff --git a/frameworks/Java/muserver/README.md b/frameworks/Java/muserver/README.md new file mode 100644 index 00000000000..935dbb5d8c9 --- /dev/null +++ b/frameworks/Java/muserver/README.md @@ -0,0 +1,60 @@ +# muserver Benchmarking Test + +### Test Type Implementation Source Code + +* [JSON](src/main/java/benchmark/TFBBase.java) +* [PLAINTEXT](src/main/java/benchmark/TFBBase.java) +* [DB](src/main/java/benchmark/TFBBase.java) +* [QUERY](src/main/java/benchmark/TFBBase.java) +* [UPDATE](src/main/java/benchmark/TFBBase.java) +* [FORTUNES](src/main/java/benchmark/TFBBase.java) + +## Important Libraries + +The tests were run with: + +* [Java 21](https://jdk.java.net/21/) +* [muserver 2.1.10](https://muserver.io/) +* [Jackson 2.19.0](https://github.com/FasterXML/jackson) +* [Pebble 3.2.4](https://pebbletemplates.io/) +* [Postgres JDBC Driver 42.7.5](https://jdbc.postgresql.org/) +* [HikariCP 6.3.0](https://github.com/brettwooldridge/HikariCP) + +## Test URLs + +For running default test (TFBRest.java), please append "/rest" to the path. + +### JSON + +http://localhost:8080/json + +### PLAINTEXT + +http://localhost:8080/plaintext + +### DB + +http://localhost:8080/db + +### QUERY + +http://localhost:8080/query?queries= + +### CACHED QUERY + +http://localhost:8080/cached_query?queries= + +### UPDATE + +http://localhost:8080/update?queries= + +### FORTUNES + +http://localhost:8080/fortunes + + +## Reference + +The Loom support and IO_URING support are modified from [netty test](https://github.com/TechEmpower/FrameworkBenchmarks/tree/master/frameworks/Java/netty). + +The database connection part is modified from [Javalin test](https://github.com/TechEmpower/FrameworkBenchmarks/tree/master/frameworks/Java/javalin). \ No newline at end of file diff --git a/frameworks/Java/muserver/benchmark_config.json b/frameworks/Java/muserver/benchmark_config.json new file mode 100644 index 00000000000..aad8aa5274b --- /dev/null +++ b/frameworks/Java/muserver/benchmark_config.json @@ -0,0 +1,53 @@ +{ + "framework": "muserver", + "tests": [ + { + "default": { + "json_url": "/rest/json", + "plaintext_url": "/rest/plaintext", + "db_url": "/rest/db", + "query_url": "/rest/queries?queries=", + "update_url": "/rest/updates?queries=", + "fortune_url": "/rest/fortunes", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "Postgres", + "framework": "muserver", + "language": "Java", + "flavor": "None", + "orm": "Raw", + "platform": "Netty", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "mu-rest-pg", + "notes": "Jax-rs rest resource handler implementation", + "versus": "None" + }, + "pg": { + "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": "muserver", + "language": "Java", + "flavor": "None", + "orm": "Raw", + "platform": "Netty", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "mu-pg", + "notes": "MuHandler implementation", + "versus": "None" + } + } + ] +} diff --git a/frameworks/Java/muserver/muserver-pg.dockerfile b/frameworks/Java/muserver/muserver-pg.dockerfile new file mode 100644 index 00000000000..17f20f3874c --- /dev/null +++ b/frameworks/Java/muserver/muserver-pg.dockerfile @@ -0,0 +1,15 @@ +FROM maven:3.9.9-eclipse-temurin-21 as maven +WORKDIR /netty +COPY pom.xml pom.xml +COPY src src +RUN mvn compile assembly:single -q + +FROM maven:3.9.9-eclipse-temurin-21 +WORKDIR /netty +COPY --from=maven /netty/target/app.jar app.jar +COPY run-pg.sh run-pg.sh + +EXPOSE 8080 +# see https://github.com/netty/netty/issues/14942 +# remember to run this with --privileged since https://github.com/TechEmpower/FrameworkBenchmarks/blob/c94f7f95bd751f86a57dea8b63fb8f336bdbbde3/toolset/utils/docker_helper.py#L239 does it +ENTRYPOINT "./run-pg.sh" \ No newline at end of file diff --git a/frameworks/Java/muserver/muserver.dockerfile b/frameworks/Java/muserver/muserver.dockerfile new file mode 100644 index 00000000000..75b9397a253 --- /dev/null +++ b/frameworks/Java/muserver/muserver.dockerfile @@ -0,0 +1,15 @@ +FROM maven:3.9.9-eclipse-temurin-21 as maven +WORKDIR /netty +COPY pom.xml pom.xml +COPY src src +RUN mvn compile assembly:single -q + +FROM maven:3.9.9-eclipse-temurin-21 +WORKDIR /netty +COPY --from=maven /netty/target/app.jar app.jar +COPY run.sh run.sh + +EXPOSE 8080 +# see https://github.com/netty/netty/issues/14942 +# remember to run this with --privileged since https://github.com/TechEmpower/FrameworkBenchmarks/blob/c94f7f95bd751f86a57dea8b63fb8f336bdbbde3/toolset/utils/docker_helper.py#L239 does it +ENTRYPOINT "./run.sh" \ No newline at end of file diff --git a/frameworks/Java/muserver/pom.xml b/frameworks/Java/muserver/pom.xml new file mode 100644 index 00000000000..0b40f7a8b6f --- /dev/null +++ b/frameworks/Java/muserver/pom.xml @@ -0,0 +1,95 @@ + + + 4.0.0 + + tfb.benchmark + muserver + 0.1 + + + 21 + 21 + + + jar + + + + org.slf4j + slf4j-api + 2.0.17 + + + org.slf4j + slf4j-simple + 2.0.17 + provided + + + io.muserver + mu-server + 2.1.10 + + + org.postgresql + postgresql + 42.7.7 + + + com.zaxxer + HikariCP + 6.3.0 + + + io.pebbletemplates + pebble + 3.2.4 + + + com.fasterxml.jackson.jakarta.rs + jackson-jakarta-rs-json-provider + 2.19.0 + + + + + + + true + org.apache.maven.plugins + maven-compiler-plugin + 3.14.0 + + false + + + + maven-assembly-plugin + 3.7.1 + + app + + + hello.HelloWebServer + + + + jar-with-dependencies + + false + + + + make-assembly + package + + single + + + + + + + diff --git a/frameworks/Java/muserver/run-pg.sh b/frameworks/Java/muserver/run-pg.sh new file mode 100755 index 00000000000..68eb89117d6 --- /dev/null +++ b/frameworks/Java/muserver/run-pg.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +# PROFILING: -XX:+UnlockDiagnosticVMOptions -XX:+DebugNonSafepoints +JAVA_OPTIONS="-XX:+UseNUMA \ + -XX:+UseZGC \ + -XX:+ZGenerational \ + $@" + +java $JAVA_OPTIONS -cp app.jar benchmark.TFBPg diff --git a/frameworks/Java/muserver/run.sh b/frameworks/Java/muserver/run.sh new file mode 100755 index 00000000000..2b03ca41371 --- /dev/null +++ b/frameworks/Java/muserver/run.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +# PROFILING: -XX:+UnlockDiagnosticVMOptions -XX:+DebugNonSafepoints +JAVA_OPTIONS="-XX:+UseNUMA \ + -XX:+UseZGC \ + -XX:+ZGenerational \ + $@" + +java $JAVA_OPTIONS -cp app.jar benchmark.TFBRest diff --git a/frameworks/Java/muserver/src/main/java/benchmark/TFBBase.java b/frameworks/Java/muserver/src/main/java/benchmark/TFBBase.java new file mode 100644 index 00000000000..f3da599077d --- /dev/null +++ b/frameworks/Java/muserver/src/main/java/benchmark/TFBBase.java @@ -0,0 +1,179 @@ +package benchmark; + +import benchmark.model.Fortune; +import benchmark.model.World; +import benchmark.repository.DbFactory; +import benchmark.repository.DbService; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.jakarta.rs.json.JacksonJsonProvider; +import io.muserver.Method; +import io.muserver.MuResponse; +import io.muserver.MuServerBuilder; +import io.muserver.Mutils; +import io.muserver.rest.RestHandlerBuilder; +import io.pebbletemplates.pebble.PebbleEngine; +import io.pebbletemplates.pebble.template.PebbleTemplate; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.core.Context; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.util.List; +import java.util.Map; + +import static jakarta.ws.rs.core.MediaType.*; + +public class TFBBase { + public static final Logger LOGGER = LoggerFactory.getLogger(TFBBase.class); + public static PebbleEngine engine = new PebbleEngine.Builder().build(); + public static PebbleTemplate compiledTemplate = engine.getTemplate("templates/fortune.peb"); + + public static MuServerBuilder commonBuilderWithMuHandler() { + var jackson = new ObjectMapper(); + var dbService = DbFactory.INSTANCE.getDbService(DbFactory.DbType.POSTGRES); + return MuServerBuilder.httpServer() + .addHandler((ignore, res) -> { + res.headers().add("Server", "muserver"); + return false; + }) + .addHandler(Method.GET, "/plaintext", (req, res, pp) -> { + var ah = req.handleAsync(); + res.headers().add("content-type", "text/plain"); + ah.write(Mutils.toByteBuffer("Hello, World!"), (optEx) -> ah.complete()); + }) + .addHandler(Method.GET, "/json", (req, res, pp) -> { + res.headers().add("content-type", "application/json"); + jackson.writeValue(res.writer(), Map.of("message", "Hello, World!")); + }) + .addHandler(Method.GET, "/db", (req, res, pp) -> { + res.headers().add("content-type", "application/json"); + jackson.writeValue(res.writer(), dbService.getWorld(1).get(0)); + }) + .addHandler(Method.GET, "/queries", (req, res, pp) -> { + res.headers().add("content-type", "application/json"); + jackson.writeValue( + res.writer(), + dbService.getWorld(getBoundedRowNumber(req.query().get("queries", ""))) + ); + }) + .addHandler(Method.GET, "/fortunes", (req, res, pp) -> { + res.headers().set("content-type", "text/html;charset=utf-8"); + compiledTemplate.evaluate( + res.writer(), + Map.of("fortunes", dbService.getFortune().stream().map(Fortune::toMap).toList())); + }) + .addHandler(Method.GET, "/updates", (req, res, pp) -> { + res.headers().add("content-type", "application/json"); + jackson.writeValue( + res.writer(), + dbService.updateWorld(getBoundedRowNumber(req.query().get("queries", ""))) + ); + }) + .withInterface("0.0.0.0") + .withHttpPort(8080) + .addShutdownHook(true); + } + + public static MuServerBuilder commonBuilderWithRestHandler() { + return MuServerBuilder.httpServer() + .addHandler((req, res) -> { + res.headers().add("Server", "muserver"); + return false; + }) + .addHandler(RestHandlerBuilder.restHandler(new TFBResource( + DbFactory.INSTANCE.getDbService(DbFactory.DbType.POSTGRES), + compiledTemplate + )).addCustomWriter(new JacksonJsonProvider())) + .withInterface("0.0.0.0") + .withHttpPort(8080) + .addShutdownHook(true); + } + + @Path("/rest") + public static class TFBResource { + public final DbService dbService; + public final PebbleTemplate template; + + public TFBResource( + DbService dbService, + PebbleTemplate template + ) { + this.dbService = dbService; + this.template = template; + } + + @GET + @Path("/plaintext") + @Produces(TEXT_PLAIN) + public String plaintext() { + return "Hello, World!"; + } + + @GET + @Path("/json") + @Produces(APPLICATION_JSON) + public Map json() { + return Map.of("message", "Hello, World!"); + } + + @GET + @Path("/db") + @Produces(APPLICATION_JSON) + public World db() { + return dbService.getWorld(1).get(0); + } + + @GET + @Path("/queries") + @Produces(APPLICATION_JSON) + public List queries( + @QueryParam("queries") + String queries + ) { + int num = getBoundedRowNumber(queries); + return dbService.getWorld(num); + } + + + @GET + @Path("/fortunes") + @Produces(TEXT_HTML) + public void fortunes( + @Context MuResponse res + ) throws IOException { + res.headers().set("content-type", "text/html;charset=utf-8"); + List fortuneList = dbService.getFortune(); + var writer = res.writer(); + // writer will be flushed + template.evaluate(writer, Map.of("fortunes", fortuneList.stream().map(Fortune::toMap).toList())); + } + + @GET + @Path("/updates") + @Produces(APPLICATION_JSON) + public List updates( + @QueryParam("queries") + String queries + ) { + return dbService.updateWorld(getBoundedRowNumber(queries)); + } + } + + + private static final int MIN_QUERIES = 1; + private static final int MAX_QUERIES = 500; + + private static int getBoundedRowNumber(String number) { + int num; + try { + num = Integer.parseInt(number); + } catch (NumberFormatException e) { + num = MIN_QUERIES; + } + return Math.max(MIN_QUERIES, Math.min(num, MAX_QUERIES)); + } +} diff --git a/frameworks/Java/muserver/src/main/java/benchmark/TFBPg.java b/frameworks/Java/muserver/src/main/java/benchmark/TFBPg.java new file mode 100644 index 00000000000..d8a369628eb --- /dev/null +++ b/frameworks/Java/muserver/src/main/java/benchmark/TFBPg.java @@ -0,0 +1,8 @@ +package benchmark; + +public class TFBPg extends TFBBase { + public static void main(String[] args) { + var server = commonBuilderWithMuHandler().start(); + LOGGER.info("Server started at {}", server.uri()); + } +} diff --git a/frameworks/Java/muserver/src/main/java/benchmark/TFBRest.java b/frameworks/Java/muserver/src/main/java/benchmark/TFBRest.java new file mode 100644 index 00000000000..09c3ce9423d --- /dev/null +++ b/frameworks/Java/muserver/src/main/java/benchmark/TFBRest.java @@ -0,0 +1,9 @@ +package benchmark; + +public class TFBRest extends TFBBase { + public static void main(String[] args) { + var server = commonBuilderWithRestHandler().start(); + LOGGER.info("Server started at {}", server.uri()); + } + +} diff --git a/frameworks/Java/muserver/src/main/java/benchmark/model/Fortune.java b/frameworks/Java/muserver/src/main/java/benchmark/model/Fortune.java new file mode 100644 index 00000000000..5d1daced647 --- /dev/null +++ b/frameworks/Java/muserver/src/main/java/benchmark/model/Fortune.java @@ -0,0 +1,12 @@ +package benchmark.model; + +import java.util.Map; + +public record Fortune( + int id, + String message +) { + public Map toMap() { + return Map.of("id", id, "message", message); + } +} diff --git a/frameworks/Java/muserver/src/main/java/benchmark/model/World.java b/frameworks/Java/muserver/src/main/java/benchmark/model/World.java new file mode 100644 index 00000000000..3de4ff1c8b5 --- /dev/null +++ b/frameworks/Java/muserver/src/main/java/benchmark/model/World.java @@ -0,0 +1,12 @@ +package benchmark.model; + +import java.util.Objects; + +public record World( + int id, + int randomNumber +) { + public World copy(Integer id, Integer randomNumber) { + return new World(Objects.requireNonNullElse(id, this.id), Objects.requireNonNullElse(randomNumber, this.randomNumber)); + } +} diff --git a/frameworks/Java/muserver/src/main/java/benchmark/repository/DbFactory.java b/frameworks/Java/muserver/src/main/java/benchmark/repository/DbFactory.java new file mode 100644 index 00000000000..9371c498906 --- /dev/null +++ b/frameworks/Java/muserver/src/main/java/benchmark/repository/DbFactory.java @@ -0,0 +1,62 @@ +package benchmark.repository; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; + +public enum DbFactory { + + INSTANCE; + + public enum DbType {POSTGRES} + + public DbService getDbService(DbType type) { + + DbService dbService; + + switch (type) { + case POSTGRES: + dbService = new JDBCDbService(); + break; + default: + dbService = null; + } + + return dbService; + } + + public int getMaxPoolSize(DbType dbType) { + + int maxPoolSize; + String env = System.getenv("BENCHMARK_ENV"); + String propertiesFileName = "/environment.properties"; + File propFile = new File(propertiesFileName); + + try (InputStream is = propFile.isFile() ? + new FileInputStream(propFile) : + this.getClass().getResourceAsStream(propertiesFileName)) { + Properties prop = new Properties(); + prop.load(is); + + switch (dbType) { + case POSTGRES: + if (prop.getProperty("physicalTag").equals(env)) { + maxPoolSize = Integer.parseInt(prop.getProperty("postgresPhysicalPoolSize")); + } else if (prop.getProperty("cloudTag").equals(env)) { + maxPoolSize = Integer.parseInt(prop.getProperty("postgresCloudPoolSize")); + } else { + maxPoolSize = Integer.parseInt(prop.getProperty("postgresDefaultPoolSize")); + } + break; + default: + maxPoolSize = 100; + } + } catch (IOException | NumberFormatException e) { + throw new RuntimeException("Failed to read property file " + propertiesFileName); + } + + return maxPoolSize; + } +} diff --git a/frameworks/Java/muserver/src/main/java/benchmark/repository/DbService.java b/frameworks/Java/muserver/src/main/java/benchmark/repository/DbService.java new file mode 100644 index 00000000000..838359969be --- /dev/null +++ b/frameworks/Java/muserver/src/main/java/benchmark/repository/DbService.java @@ -0,0 +1,33 @@ +package benchmark.repository; + +import benchmark.model.Fortune; +import benchmark.model.World; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.ThreadLocalRandom; + +public interface DbService { + + int MIN_RANDOM_NUMBER = 1; + int MAX_RANDOM_NUMBER_PLUS_ONE = 10001; + int defaultFortuneId = 0; + String defaultFortuneMessage = "Additional fortune added at request time."; + + + List getWorld(int num); + List getFortune(); + List updateWorld(int num); + + default int getRandomNumber() { + return ThreadLocalRandom.current().nextInt(MIN_RANDOM_NUMBER, MAX_RANDOM_NUMBER_PLUS_ONE); + } + + default Set getRandomNumberSet(int num) { + Set set = new HashSet<>(); + while (set.size() < num) + set.add(getRandomNumber()); + return set; + } +} diff --git a/frameworks/Java/muserver/src/main/java/benchmark/repository/JDBCConnectionFactory.java b/frameworks/Java/muserver/src/main/java/benchmark/repository/JDBCConnectionFactory.java new file mode 100644 index 00000000000..195cbd160b3 --- /dev/null +++ b/frameworks/Java/muserver/src/main/java/benchmark/repository/JDBCConnectionFactory.java @@ -0,0 +1,28 @@ +package benchmark.repository; + +import com.zaxxer.hikari.HikariConfig; +import com.zaxxer.hikari.HikariDataSource; + +import java.sql.Connection; +import java.sql.SQLException; + + +public enum JDBCConnectionFactory { + + INSTANCE; + + private final HikariDataSource ds; + + JDBCConnectionFactory() { + String propertiesFileName = "/hikari.properties"; + HikariConfig config = new HikariConfig(propertiesFileName); + int maxPoolSize = DbFactory.INSTANCE.getMaxPoolSize(DbFactory.DbType.POSTGRES); + + ds = new HikariDataSource(config); + ds.setMaximumPoolSize(maxPoolSize); + } + + public Connection getConnection() throws SQLException { + return ds.getConnection(); + } +} diff --git a/frameworks/Java/muserver/src/main/java/benchmark/repository/JDBCDbService.java b/frameworks/Java/muserver/src/main/java/benchmark/repository/JDBCDbService.java new file mode 100644 index 00000000000..5c9278c42c6 --- /dev/null +++ b/frameworks/Java/muserver/src/main/java/benchmark/repository/JDBCDbService.java @@ -0,0 +1,94 @@ +package benchmark.repository; + +import benchmark.model.Fortune; +import benchmark.model.World; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; + +public class JDBCDbService implements DbService { + + @Override + public List getWorld(int num) { + + String select = "select id, randomNumber from World where id = ?"; + List worldList = new ArrayList<>(); + + try (Connection conn = JDBCConnectionFactory.INSTANCE.getConnection(); + PreparedStatement pstm = conn.prepareStatement(select)) { + + for (int randomId : getRandomNumberSet(num)) { + pstm.setInt(1, randomId); + try (ResultSet rs = pstm.executeQuery()) { + rs.next(); + World world = new World(rs.getInt("id"),rs.getInt("randomNumber")); + worldList.add(world); + } + } + } catch (SQLException e) { + throw new RuntimeException(e); + } + + return worldList; + } + + @Override + public List getFortune() { + + String select = "select id, message from Fortune"; + List fortuneList = new ArrayList<>(); + + try (Connection conn = JDBCConnectionFactory.INSTANCE.getConnection(); + PreparedStatement pstm = conn.prepareStatement(select); + ResultSet rs = pstm.executeQuery()) { + + while (rs.next()) { + Fortune fortune = new Fortune(rs.getInt("id"), rs.getString("message")); + fortuneList.add(fortune); + } + fortuneList.add(new Fortune(defaultFortuneId, defaultFortuneMessage)); + } catch (SQLException e) { + throw new RuntimeException(e); + } + + fortuneList.sort(Comparator.comparing(Fortune::message)); + return fortuneList; + } + + @Override + public List updateWorld(int num) { + + String update = "update World set randomNumber = ? where id = ?"; + List worldList = getWorld(num); + List updatedWorldList = new ArrayList<>(num); + + try (Connection conn = JDBCConnectionFactory.INSTANCE.getConnection(); + PreparedStatement pstm = conn.prepareStatement(update)) { + + conn.setAutoCommit(false); + for (World world : worldList) { + int newRandomNumber; + do { + newRandomNumber = getRandomNumber(); + } while (newRandomNumber == world.randomNumber()); + + pstm.setInt(1, newRandomNumber); + pstm.setInt(2, world.id()); + pstm.addBatch(); + + updatedWorldList.add(world.copy(null, newRandomNumber)); + } + pstm.executeBatch(); + conn.commit(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + + return updatedWorldList; + } +} diff --git a/frameworks/Java/muserver/src/main/resources/environment.properties b/frameworks/Java/muserver/src/main/resources/environment.properties new file mode 100644 index 00000000000..2a941e54bf0 --- /dev/null +++ b/frameworks/Java/muserver/src/main/resources/environment.properties @@ -0,0 +1,7 @@ +physicalTag=Citrine +cloudTag=Azure + +postgresPhysicalPoolSize=56 +postgresCloudPoolSize=16 +# test in 2c kvm +postgresDefaultPoolSize=10 diff --git a/frameworks/Java/muserver/src/main/resources/hikari.properties b/frameworks/Java/muserver/src/main/resources/hikari.properties new file mode 100644 index 00000000000..f859c5a8763 --- /dev/null +++ b/frameworks/Java/muserver/src/main/resources/hikari.properties @@ -0,0 +1,7 @@ +dataSourceClassName=org.postgresql.ds.PGSimpleDataSource +dataSource.serverName=tfb-database +dataSource.portNumber=5432 +dataSource.user=benchmarkdbuser +dataSource.password=benchmarkdbpass +dataSource.databaseName=hello_world + diff --git a/frameworks/Java/muserver/src/main/resources/templates/fortune.peb b/frameworks/Java/muserver/src/main/resources/templates/fortune.peb new file mode 100644 index 00000000000..8272a990d66 --- /dev/null +++ b/frameworks/Java/muserver/src/main/resources/templates/fortune.peb @@ -0,0 +1,12 @@ + + +Fortunes + + + +{% for f in fortunes %} + +{% endfor %} +
idmessage
{{f.id}}{{f.message}}
+ + diff --git a/frameworks/Java/nanohttpd/pom.xml b/frameworks/Java/nanohttpd/pom.xml index 5ce138edc23..10538727775 100644 --- a/frameworks/Java/nanohttpd/pom.xml +++ b/frameworks/Java/nanohttpd/pom.xml @@ -23,7 +23,7 @@ com.fasterxml.jackson.core jackson-databind - 2.13.4.2 + 2.16.0 com.fasterxml.jackson.module diff --git a/frameworks/Java/netty/.sdkmanrc b/frameworks/Java/netty/.sdkmanrc new file mode 100644 index 00000000000..2478fa5a19d --- /dev/null +++ b/frameworks/Java/netty/.sdkmanrc @@ -0,0 +1,3 @@ +# Enable auto-env through the sdkman_auto_env config +# Add key=value pairs of SDKs to use below +java=24-oracle diff --git a/frameworks/Java/netty/benchmark_config.json b/frameworks/Java/netty/benchmark_config.json index 0202931297c..79c322fef4e 100644 --- a/frameworks/Java/netty/benchmark_config.json +++ b/frameworks/Java/netty/benchmark_config.json @@ -19,6 +19,25 @@ "display_name": "netty", "notes": "", "versus": "netty" + }, + "loom": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Platform", + "database": "None", + "framework": "netty", + "language": "Java", + "flavor": "None", + "orm": "Raw", + "platform": "Netty", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "netty", + "notes": "", + "versus": "netty" } }] } diff --git a/frameworks/Java/netty/config.toml b/frameworks/Java/netty/config.toml index 3780eace78d..bea6d72db37 100644 --- a/frameworks/Java/netty/config.toml +++ b/frameworks/Java/netty/config.toml @@ -13,3 +13,16 @@ orm = "Raw" platform = "Netty" webserver = "None" versus = "netty" + +[loom] +urls.plaintext = "/plaintext" +urls.json = "/json" +approach = "Realistic" +classification = "Platform" +database = "None" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "Netty" +webserver = "None" +versus = "netty" diff --git a/frameworks/Java/netty/netty-loom.dockerfile b/frameworks/Java/netty/netty-loom.dockerfile new file mode 100644 index 00000000000..1405909b099 --- /dev/null +++ b/frameworks/Java/netty/netty-loom.dockerfile @@ -0,0 +1,15 @@ +FROM maven:3.9.9-eclipse-temurin-24-noble as maven +WORKDIR /netty +COPY pom.xml pom.xml +COPY src src +RUN mvn compile assembly:single -q + +FROM maven:3.9.9-eclipse-temurin-24-noble +WORKDIR /netty +COPY --from=maven /netty/target/app.jar app.jar +COPY run_netty_loom.sh run_netty_loom.sh + +EXPOSE 8080 +# see https://github.com/netty/netty/issues/14942 +# remember to run this with --privileged since https://github.com/TechEmpower/FrameworkBenchmarks/blob/c94f7f95bd751f86a57dea8b63fb8f336bdbbde3/toolset/utils/docker_helper.py#L239 does it +ENTRYPOINT "./run_netty_loom.sh" \ No newline at end of file diff --git a/frameworks/Java/netty/netty.dockerfile b/frameworks/Java/netty/netty.dockerfile index 25636ca4f2f..ecc8cd4269d 100644 --- a/frameworks/Java/netty/netty.dockerfile +++ b/frameworks/Java/netty/netty.dockerfile @@ -1,13 +1,15 @@ -FROM maven:3.6.1-jdk-11-slim as maven +FROM maven:3.9.9-eclipse-temurin-24-noble as maven WORKDIR /netty COPY pom.xml pom.xml COPY src src RUN mvn compile assembly:single -q -FROM openjdk:11.0.3-jdk-slim +FROM maven:3.9.9-eclipse-temurin-24-noble WORKDIR /netty -COPY --from=maven /netty/target/netty-example-0.1-jar-with-dependencies.jar app.jar +COPY --from=maven /netty/target/app.jar app.jar +COPY run_netty.sh run_netty.sh EXPOSE 8080 - -CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AggressiveOpts", "-Dio.netty.buffer.checkBounds=false", "-Dio.netty.buffer.checkAccessible=false", "-Dio.netty.iouring.iosqeAsyncThreshold=32000", "-jar", "app.jar"] +# see https://github.com/netty/netty/issues/14942 +# remember to run this with --privileged since https://github.com/TechEmpower/FrameworkBenchmarks/blob/c94f7f95bd751f86a57dea8b63fb8f336bdbbde3/toolset/utils/docker_helper.py#L239 does it +ENTRYPOINT "./run_netty.sh" \ No newline at end of file diff --git a/frameworks/Java/netty/pom.xml b/frameworks/Java/netty/pom.xml index e11a42ffc60..c9be856b254 100644 --- a/frameworks/Java/netty/pom.xml +++ b/frameworks/Java/netty/pom.xml @@ -9,10 +9,9 @@ 0.1 - 11 - 11 - 4.1.92.Final - 0.0.21.Final + 24 + 24 + 4.2.0.Final jar @@ -21,7 +20,7 @@ io.netty - netty-codec-http + netty-all ${netty.version} @@ -40,9 +39,9 @@ - io.netty.incubator - netty-incubator-transport-native-io_uring - ${io_uring.version} + io.netty + netty-transport-native-io_uring + ${netty.version} linux-x86_64 @@ -74,6 +73,7 @@ maven-assembly-plugin + app hello.HelloWebServer @@ -82,6 +82,7 @@ jar-with-dependencies + false diff --git a/frameworks/Java/netty/run_netty.sh b/frameworks/Java/netty/run_netty.sh new file mode 100755 index 00000000000..413dff9e601 --- /dev/null +++ b/frameworks/Java/netty/run_netty.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +# PROFILING: -XX:+UnlockDiagnosticVMOptions -XX:+DebugNonSafepoints +JAVA_OPTIONS="--enable-native-access=ALL-UNNAMED \ + -Dio.netty.noUnsafe=false \ + --sun-misc-unsafe-memory-access=allow \ + --add-opens=java.base/java.lang=ALL-UNNAMED \ + -XX:+UseNUMA \ + -XX:+UseParallelGC \ + -Dio.netty.buffer.checkBounds=false \ + -Dio.netty.buffer.checkAccessible=false \ + $@" + +java $JAVA_OPTIONS -jar app.jar diff --git a/frameworks/Java/netty/run_netty_loom.sh b/frameworks/Java/netty/run_netty_loom.sh new file mode 100755 index 00000000000..6cc9085441f --- /dev/null +++ b/frameworks/Java/netty/run_netty_loom.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +# PROFILING: -XX:+UnlockDiagnosticVMOptions -XX:+DebugNonSafepoints +JAVA_OPTIONS="--enable-native-access=ALL-UNNAMED \ + -Dio.netty.noUnsafe=false \ + --sun-misc-unsafe-memory-access=allow \ + --add-opens=java.base/java.lang=ALL-UNNAMED \ + -XX:+UseNUMA \ + -XX:+UseParallelGC \ + -Dio.netty.buffer.checkBounds=false \ + -Dio.netty.buffer.checkAccessible=false \ + -Dhello.eventloop.carrier=true \ + -XX:+UnlockExperimentalVMOptions \ + -XX:-DoJVMTIVirtualThreadTransitions \ + -Djdk.trackAllThreads=false \ + $@" + +java $JAVA_OPTIONS -jar app.jar diff --git a/frameworks/Java/netty/src/main/java/hello/Constants.java b/frameworks/Java/netty/src/main/java/hello/Constants.java new file mode 100644 index 00000000000..63da7d66851 --- /dev/null +++ b/frameworks/Java/netty/src/main/java/hello/Constants.java @@ -0,0 +1,24 @@ +package hello; + +import io.netty.util.AsciiString; +import io.netty.util.CharsetUtil; + +public class Constants { + + public static final byte[] STATIC_PLAINTEXT = "Hello, World!".getBytes(CharsetUtil.UTF_8); + public static final int STATIC_PLAINTEXT_LEN = STATIC_PLAINTEXT.length; + + public static final CharSequence PLAINTEXT_CLHEADER_VALUE = AsciiString.cached(String.valueOf(STATIC_PLAINTEXT_LEN)); + public static final int JSON_LEN = jsonLen(); + public static final CharSequence JSON_CLHEADER_VALUE = AsciiString.cached(String.valueOf(JSON_LEN)); + public static final CharSequence SERVER_NAME = AsciiString.cached("Netty"); + + private static int jsonLen() { + return JsonUtils.serializeMsg(newMsg()).length; + } + + public static Message newMsg() { + return new Message("Hello, World!"); + } + +} diff --git a/frameworks/Java/netty/src/main/java/hello/HelloServerHandler.java b/frameworks/Java/netty/src/main/java/hello/HelloServerHandler.java index c82e008c4d6..db3f7896940 100644 --- a/frameworks/Java/netty/src/main/java/hello/HelloServerHandler.java +++ b/frameworks/Java/netty/src/main/java/hello/HelloServerHandler.java @@ -1,89 +1,51 @@ package hello; -import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_LENGTH; -import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_TYPE; -import static io.netty.handler.codec.http.HttpHeaderNames.DATE; -import static io.netty.handler.codec.http.HttpHeaderNames.SERVER; -import static io.netty.handler.codec.http.HttpHeaderValues.APPLICATION_JSON; -import static io.netty.handler.codec.http.HttpHeaderValues.TEXT_PLAIN; +import static hello.HttpResponses.*; +import static hello.JsonUtils.acquireJsonStreamFromEventLoop; +import static hello.JsonUtils.releaseJsonStreamFromEventLoop; import static io.netty.handler.codec.http.HttpResponseStatus.NOT_FOUND; -import static io.netty.handler.codec.http.HttpResponseStatus.OK; import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1; -import java.io.IOException; import java.text.DateFormat; import java.text.SimpleDateFormat; -import java.util.Arrays; import java.util.Date; import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import com.jsoniter.output.JsonStream; -import com.jsoniter.output.JsonStreamPool; -import com.jsoniter.spi.JsonException; -import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; -import io.netty.handler.codec.http.DefaultFullHttpResponse; -import io.netty.handler.codec.http.DefaultHttpRequest; -import io.netty.handler.codec.http.FullHttpResponse; -import io.netty.handler.codec.http.HttpRequest; -import io.netty.handler.codec.http.LastHttpContent; +import io.netty.handler.codec.http.*; import io.netty.util.AsciiString; -import io.netty.util.CharsetUtil; import io.netty.util.ReferenceCountUtil; import io.netty.util.concurrent.FastThreadLocal; public class HelloServerHandler extends ChannelInboundHandlerAdapter { - private static final FastThreadLocal FORMAT = new FastThreadLocal() { - @Override - protected DateFormat initialValue() { - return new SimpleDateFormat("E, dd MMM yyyy HH:mm:ss z"); - } - }; - - private static Message newMsg() { - return new Message("Hello, World!"); - } - - private static byte[] serializeMsg(Message obj) { - JsonStream stream = JsonStreamPool.borrowJsonStream(); - try { - stream.reset(null); - stream.writeVal(Message.class, obj); - return Arrays.copyOfRange(stream.buffer().data(), 0, stream.buffer().tail()); - } catch (IOException e) { - throw new JsonException(e); - } finally { - JsonStreamPool.returnJsonStream(stream); - } - } - - private static int jsonLen() { - return serializeMsg(newMsg()).length; - } - - private static final byte[] STATIC_PLAINTEXT = "Hello, World!".getBytes(CharsetUtil.UTF_8); - private static final int STATIC_PLAINTEXT_LEN = STATIC_PLAINTEXT.length; - - private static final CharSequence PLAINTEXT_CLHEADER_VALUE = AsciiString.cached(String.valueOf(STATIC_PLAINTEXT_LEN)); - private static final int JSON_LEN = jsonLen(); - private static final CharSequence JSON_CLHEADER_VALUE = AsciiString.cached(String.valueOf(JSON_LEN)); - private static final CharSequence SERVER_NAME = AsciiString.cached("Netty"); + private static final FastThreadLocal FORMAT = new FastThreadLocal<>() { + @Override + protected DateFormat initialValue() { + return new SimpleDateFormat("E, dd MMM yyyy HH:mm:ss z"); + } + }; - private volatile CharSequence date = new AsciiString(FORMAT.get().format(new Date())); + private HttpHeaders jsonHeaders = makeJsonHeaders(new AsciiString(FORMAT.get().format(new Date()))); + private HttpHeaders plaintextHeaders = makePlaintextHeaders(new AsciiString(FORMAT.get().format(new Date()))); + private ScheduledFuture refreshHeaders; - HelloServerHandler(ScheduledExecutorService service) { - service.scheduleWithFixedDelay(new Runnable() { + public HelloServerHandler(ScheduledExecutorService service) { + refreshHeaders = service.scheduleWithFixedDelay(new Runnable() { private final DateFormat format = FORMAT.get(); @Override public void run() { - date = new AsciiString(format.format(new Date())); + var date = new AsciiString(format.format(new Date())); + jsonHeaders = makeJsonHeaders(date); + plaintextHeaders = makePlaintextHeaders(date); } }, 1000, 1000, TimeUnit.MILLISECONDS); } @@ -118,42 +80,48 @@ private void process(ChannelHandlerContext ctx, HttpRequest request) throws Exce String uri = request.uri(); switch (uri) { case "/plaintext": - writePlainResponse(ctx, Unpooled.wrappedBuffer(STATIC_PLAINTEXT)); + writePlainResponse(ctx, plaintextHeaders); return; case "/json": - byte[] json = serializeMsg(newMsg()); - writeJsonResponse(ctx, Unpooled.wrappedBuffer(json)); + // even for the virtual thread case we expect virtual threads to be executed inlined! + var stream = acquireJsonStreamFromEventLoop(); + try { + writeJsonResponse(ctx, stream, jsonHeaders); + } finally { + releaseJsonStreamFromEventLoop(stream); + } return; } + // we drain in-flight responses before closing the connection + channelReadComplete(ctx); FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, NOT_FOUND, Unpooled.EMPTY_BUFFER, false); - ctx.write(response).addListener(ChannelFutureListener.CLOSE); - } - - private void writePlainResponse(ChannelHandlerContext ctx, ByteBuf buf) { - ctx.write(makeResponse(buf, TEXT_PLAIN, PLAINTEXT_CLHEADER_VALUE), ctx.voidPromise()); + ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); } - private void writeJsonResponse(ChannelHandlerContext ctx, ByteBuf buf) { - ctx.write(makeResponse(buf, APPLICATION_JSON, JSON_CLHEADER_VALUE), ctx.voidPromise()); + protected void writePlainResponse(ChannelHandlerContext ctx, HttpHeaders plaintextHeaders) { + ctx.write(makePlaintextResponse(plaintextHeaders), ctx.voidPromise()); } - private FullHttpResponse makeResponse(ByteBuf buf, CharSequence contentType, CharSequence contentLength) { - final FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, OK, buf, false); - response.headers() - .set(CONTENT_TYPE, contentType) - .set(SERVER, SERVER_NAME) - .set(DATE, date) - .set(CONTENT_LENGTH, contentLength); - return response; + protected void writeJsonResponse(ChannelHandlerContext ctx, JsonStream stream, HttpHeaders jsonHeaders) { + ctx.write(makeJsonResponse(stream, jsonHeaders), ctx.voidPromise()); } @Override - public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { ctx.close(); } @Override - public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { + public void channelReadComplete(ChannelHandlerContext ctx) { ctx.flush(); } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + super.channelInactive(ctx); + if (refreshHeaders != null) { + refreshHeaders.cancel(false); + refreshHeaders = null; + } + } } diff --git a/frameworks/Java/netty/src/main/java/hello/HelloServerInitializer.java b/frameworks/Java/netty/src/main/java/hello/HelloServerInitializer.java index 060dd49930c..5fc354e61a3 100644 --- a/frameworks/Java/netty/src/main/java/hello/HelloServerInitializer.java +++ b/frameworks/Java/netty/src/main/java/hello/HelloServerInitializer.java @@ -2,28 +2,45 @@ import java.util.concurrent.ScheduledExecutorService; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; import io.netty.channel.ChannelInitializer; import io.netty.channel.socket.SocketChannel; -import io.netty.handler.codec.http.DefaultFullHttpResponse; -import io.netty.handler.codec.http.DefaultHttpRequest; -import io.netty.handler.codec.http.HttpMessage; -import io.netty.handler.codec.http.HttpMethod; -import io.netty.handler.codec.http.HttpRequestDecoder; -import io.netty.handler.codec.http.HttpResponseEncoder; -import io.netty.handler.codec.http.HttpVersion; +import io.netty.handler.codec.http.*; public class HelloServerInitializer extends ChannelInitializer { - private final ScheduledExecutorService service; - - public HelloServerInitializer(ScheduledExecutorService service) { - this.service = service; + public HelloServerInitializer() { } @Override public void initChannel(SocketChannel ch) throws Exception { ch.pipeline() .addLast("encoder", new HttpResponseEncoder() { + + private ByteBuf encodedHeaders; + private HttpHeaders lastSeenHeaders; + + @Override + protected void encodeHeaders(HttpHeaders headers, ByteBuf buf) { + if (lastSeenHeaders != headers) { + updateEncodedHttpHeaders(headers, buf); + } + var encodedHeaders = this.encodedHeaders; + buf.ensureWritable(encodedHeaders.readableBytes()); + encodedHeaders.getBytes(encodedHeaders.readerIndex(), buf, encodedHeaders.readableBytes()); + } + + private void updateEncodedHttpHeaders(HttpHeaders headers, ByteBuf buf) { + if (encodedHeaders == null) { + encodedHeaders = Unpooled.buffer(buf.writableBytes()); + } else { + encodedHeaders.clear().ensureWritable(buf.writableBytes()); + } + super.encodeHeaders(headers, encodedHeaders); + lastSeenHeaders = headers; + } + @Override public boolean acceptOutboundMessage(final Object msg) throws Exception { if (msg.getClass() == DefaultFullHttpResponse.class) { @@ -46,6 +63,10 @@ protected boolean isContentAlwaysEmpty(final HttpMessage msg) { return false; } }) - .addLast("handler", new HelloServerHandler(service)); + .addLast("handler", newHelloServerHandler(ch.eventLoop())); + } + + protected HelloServerHandler newHelloServerHandler(ScheduledExecutorService service) { + return new HelloServerHandler(service); } } diff --git a/frameworks/Java/netty/src/main/java/hello/HelloWebServer.java b/frameworks/Java/netty/src/main/java/hello/HelloWebServer.java index 84cc86ab273..492a44121c9 100644 --- a/frameworks/Java/netty/src/main/java/hello/HelloWebServer.java +++ b/frameworks/Java/netty/src/main/java/hello/HelloWebServer.java @@ -2,30 +2,35 @@ import java.net.InetSocketAddress; +import hello.loom.HelloLoomServerInitializer; +import hello.loom.LoomSupport; +import hello.loom.MultithreadVirtualEventExecutorGroup; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelOption; -import io.netty.channel.EventLoopGroup; -import io.netty.channel.ServerChannel; -import io.netty.channel.epoll.Epoll; import io.netty.channel.epoll.EpollChannelOption; -import io.netty.channel.epoll.EpollEventLoopGroup; -import io.netty.channel.epoll.EpollServerSocketChannel; -import io.netty.channel.kqueue.KQueue; -import io.netty.channel.kqueue.KQueueServerSocketChannel; -import io.netty.channel.nio.NioEventLoopGroup; -import io.netty.channel.socket.nio.NioServerSocketChannel; -import io.netty.incubator.channel.uring.IOUring; -import io.netty.incubator.channel.uring.IOUringChannelOption; -import io.netty.incubator.channel.uring.IOUringEventLoopGroup; -import io.netty.incubator.channel.uring.IOUringServerSocketChannel; +import io.netty.channel.uring.IoUringChannelOption; import io.netty.util.ResourceLeakDetector; import io.netty.util.ResourceLeakDetector.Level; public class HelloWebServer { + private static final boolean EVENT_LOOP_CARRIER = Boolean.getBoolean("hello.eventloop.carrier"); + private static final IoMultiplexer PREFERRED_TRANSPORT; + static { ResourceLeakDetector.setLevel(Level.DISABLED); + String transportName = System.getProperty("hello.transport"); + if (transportName != null) { + try { + PREFERRED_TRANSPORT = IoMultiplexer.valueOf(transportName); + } catch (IllegalArgumentException e) { + System.err.println("Invalid transport name: " + transportName); + throw e; + } + } else { + PREFERRED_TRANSPORT = IoMultiplexer.type(); + } } private final int port; @@ -35,47 +40,46 @@ public HelloWebServer(int port) { } public void run() throws Exception { - // Configure the server. - if (IOUring.isAvailable()) { - doRun(new IOUringEventLoopGroup(Runtime.getRuntime().availableProcessors()), IOUringServerSocketChannel.class, IoMultiplexer.IO_URING); - } else - if (Epoll.isAvailable()) { - doRun(new EpollEventLoopGroup(), EpollServerSocketChannel.class, IoMultiplexer.EPOLL); - } else if (KQueue.isAvailable()) { - doRun(new EpollEventLoopGroup(), KQueueServerSocketChannel.class, IoMultiplexer.KQUEUE); - } else { - doRun(new NioEventLoopGroup(), NioServerSocketChannel.class, IoMultiplexer.JDK); + final var preferredTransport = PREFERRED_TRANSPORT; + System.out.printf("Using %s IoMultiplexer%n", preferredTransport); + final int coreCount = Runtime.getRuntime().availableProcessors(); + final var group = EVENT_LOOP_CARRIER? + preferredTransport.newVirtualEventExecutorGroup(coreCount) : + preferredTransport.newEventLoopGroup(coreCount); + if (EVENT_LOOP_CARRIER) { + LoomSupport.checkSupported(); + System.out.println("Using EventLoop optimized for Loom"); } - } - - private void doRun(EventLoopGroup loupGroup, Class serverChannelClass, IoMultiplexer multiplexer) throws InterruptedException { try { - InetSocketAddress inet = new InetSocketAddress(port); - - System.out.printf("Using %s IoMultiplexer%n", multiplexer); + final var serverChannelClass = preferredTransport.serverChannelClass(); + var inet = new InetSocketAddress(port); + var b = new ServerBootstrap(); - ServerBootstrap b = new ServerBootstrap(); - - if (multiplexer == IoMultiplexer.EPOLL) { - b.option(EpollChannelOption.SO_REUSEPORT, true); - } - - if (multiplexer == IoMultiplexer.IO_URING) { - b.option(IOUringChannelOption.SO_REUSEPORT, true); - } - b.option(ChannelOption.SO_BACKLOG, 8192); b.option(ChannelOption.SO_REUSEADDR, true); - b.group(loupGroup).channel(serverChannelClass).childHandler(new HelloServerInitializer(loupGroup.next())); + switch (preferredTransport) { + case EPOLL: + b.option(EpollChannelOption.SO_REUSEPORT, true); + break; + case IO_URING: + b.option(IoUringChannelOption.SO_REUSEPORT, true); + break; + } + var channelB = b.group(group).channel(serverChannelClass); + if (EVENT_LOOP_CARRIER) { + channelB.childHandler(new HelloLoomServerInitializer((MultithreadVirtualEventExecutorGroup) group)); + } else { + channelB.childHandler(new HelloServerInitializer()); + } b.childOption(ChannelOption.SO_REUSEADDR, true); Channel ch = b.bind(inet).sync().channel(); - System.out.printf("Httpd started. Listening on: %s%n", inet.toString()); + System.out.printf("Httpd started. Listening on: %s%n", inet); ch.closeFuture().sync(); } finally { - loupGroup.shutdownGracefully().sync(); + group.shutdownGracefully().sync(); } } @@ -87,5 +91,7 @@ public static void main(String[] args) throws Exception { port = 8080; } new HelloWebServer(port).run(); + + } } diff --git a/frameworks/Java/netty/src/main/java/hello/HttpResponses.java b/frameworks/Java/netty/src/main/java/hello/HttpResponses.java new file mode 100644 index 00000000000..5e36c43a269 --- /dev/null +++ b/frameworks/Java/netty/src/main/java/hello/HttpResponses.java @@ -0,0 +1,62 @@ +package hello; + +import static hello.Constants.JSON_CLHEADER_VALUE; +import static hello.Constants.PLAINTEXT_CLHEADER_VALUE; +import static hello.Constants.SERVER_NAME; +import static hello.Constants.STATIC_PLAINTEXT; +import static hello.Constants.newMsg; +import static hello.JsonUtils.serializeMsg; +import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_LENGTH; +import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_TYPE; +import static io.netty.handler.codec.http.HttpHeaderNames.DATE; +import static io.netty.handler.codec.http.HttpHeaderNames.SERVER; +import static io.netty.handler.codec.http.HttpHeaderValues.APPLICATION_JSON; +import static io.netty.handler.codec.http.HttpHeaderValues.TEXT_PLAIN; +import static io.netty.handler.codec.http.HttpResponseStatus.OK; +import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1; + +import com.jsoniter.output.JsonStream; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.handler.codec.http.DefaultFullHttpResponse; +import io.netty.handler.codec.http.DefaultHttpHeadersFactory; +import io.netty.handler.codec.http.FullHttpResponse; +import io.netty.handler.codec.http.HttpHeaders; +import io.netty.handler.codec.http.HttpHeadersFactory; +import io.netty.util.AsciiString; + +public class HttpResponses { + + private static final HttpHeadersFactory HEADERS_FACTORY = DefaultHttpHeadersFactory.headersFactory() + .withValidation(false); + + public static HttpHeaders makeJsonHeaders(AsciiString date) { + return HEADERS_FACTORY.newHeaders() + .set(CONTENT_TYPE, APPLICATION_JSON) + .set(SERVER, SERVER_NAME) + .set(DATE, date) + .set(CONTENT_LENGTH, JSON_CLHEADER_VALUE); + } + + + public static HttpHeaders makePlaintextHeaders(AsciiString date) { + return HEADERS_FACTORY.newHeaders() + .set(CONTENT_TYPE, TEXT_PLAIN) + .set(SERVER, SERVER_NAME) + .set(DATE, date) + .set(CONTENT_LENGTH, PLAINTEXT_CLHEADER_VALUE); + } + + public static FullHttpResponse makePlaintextResponse(HttpHeaders plaintextHeaders) { + return makeResponse(Unpooled.wrappedBuffer(STATIC_PLAINTEXT), plaintextHeaders); + } + + public static FullHttpResponse makeJsonResponse(JsonStream stream, HttpHeaders jsonHeaders) { + return makeResponse(Unpooled.wrappedBuffer(serializeMsg(newMsg(), stream)), jsonHeaders); + } + + private static FullHttpResponse makeResponse(ByteBuf buf, HttpHeaders headers) { + return new DefaultFullHttpResponse(HTTP_1_1, OK, buf, headers, HttpHeaders.EMPTY_HEADERS); + } +} diff --git a/frameworks/Java/netty/src/main/java/hello/IoMultiplexer.java b/frameworks/Java/netty/src/main/java/hello/IoMultiplexer.java index 4a58e4f01b5..d50d5e13464 100644 --- a/frameworks/Java/netty/src/main/java/hello/IoMultiplexer.java +++ b/frameworks/Java/netty/src/main/java/hello/IoMultiplexer.java @@ -1,5 +1,59 @@ package hello; +import hello.loom.MultithreadVirtualEventExecutorGroup; +import io.netty.channel.IoHandlerFactory; +import io.netty.channel.MultiThreadIoEventLoopGroup; +import io.netty.channel.ServerChannel; +import io.netty.channel.epoll.Epoll; +import io.netty.channel.epoll.EpollIoHandler; +import io.netty.channel.epoll.EpollServerSocketChannel; +import io.netty.channel.kqueue.KQueue; +import io.netty.channel.kqueue.KQueueIoHandler; +import io.netty.channel.kqueue.KQueueServerSocketChannel; +import io.netty.channel.nio.NioIoHandler; +import io.netty.channel.socket.nio.NioServerSocketChannel; +import io.netty.channel.uring.IoUring; +import io.netty.channel.uring.IoUringIoHandler; +import io.netty.channel.uring.IoUringServerSocketChannel; + public enum IoMultiplexer { - EPOLL, KQUEUE, JDK, IO_URING + EPOLL, KQUEUE, JDK, IO_URING; + + public Class serverChannelClass() { + return switch (this) { + case EPOLL -> EpollServerSocketChannel.class; + case KQUEUE -> KQueueServerSocketChannel.class; + case JDK -> NioServerSocketChannel.class; + case IO_URING -> IoUringServerSocketChannel.class; + }; + } + + public IoHandlerFactory newIoHandlerFactory() { + return switch (this) { + case EPOLL -> EpollIoHandler.newFactory(); + case KQUEUE -> KQueueIoHandler.newFactory(); + case JDK -> NioIoHandler.newFactory(); + case IO_URING -> IoUringIoHandler.newFactory(); + }; + } + + public MultiThreadIoEventLoopGroup newEventLoopGroup(int nThreads) { + return new MultiThreadIoEventLoopGroup(nThreads, newIoHandlerFactory()); + } + + public MultithreadVirtualEventExecutorGroup newVirtualEventExecutorGroup(int nThreads) { + return new MultithreadVirtualEventExecutorGroup(nThreads, newIoHandlerFactory()); + } + + public static IoMultiplexer type() { + if (IoUring.isAvailable()) { + return IO_URING; + } else if (Epoll.isAvailable()) { + return EPOLL; + } else if (KQueue.isAvailable()) { + return KQUEUE; + } else { + return JDK; + } + } } \ No newline at end of file diff --git a/frameworks/Java/netty/src/main/java/hello/JsonUtils.java b/frameworks/Java/netty/src/main/java/hello/JsonUtils.java new file mode 100644 index 00000000000..4b7ca5723ed --- /dev/null +++ b/frameworks/Java/netty/src/main/java/hello/JsonUtils.java @@ -0,0 +1,78 @@ +package hello; + +import java.io.IOException; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.VarHandle; +import java.util.Arrays; + +import com.jsoniter.output.JsonStream; +import com.jsoniter.output.JsonStreamPool; +import com.jsoniter.spi.Config; +import com.jsoniter.spi.JsonException; + +import io.netty.util.concurrent.FastThreadLocal; + +public class JsonUtils { + + private static final VarHandle INDENTATION; + + static { + try { + var lookup = MethodHandles.privateLookupIn(JsonStream.class, MethodHandles.lookup()); + INDENTATION = lookup.findVarHandle(JsonStream.class, "indention", int.class); + var dummy = new JsonStream(null, 32); + INDENTATION.set(dummy, 4); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private static void setIndentation(JsonStream stream, int value) { + INDENTATION.set(stream, value); // Plain store + } + + private static final FastThreadLocal JSON_STREAM = new FastThreadLocal<>(); + + public static JsonStream acquireJsonStreamFromEventLoop() { + var stream = JSON_STREAM.get(); + if (stream == null) { + stream = new JsonStream(null, 512) { + // this is to save virtual threads to use thread locals + @Override + public Config currentConfig() { + return Config.INSTANCE; + } + }; + } else { + stream.reset(null); + JSON_STREAM.set(null); + } + return stream; + } + + public static JsonStream releaseJsonStreamFromEventLoop(JsonStream jsonStream) { + jsonStream.configCache = null; + setIndentation(jsonStream, 0); + JSON_STREAM.set(jsonStream); + return jsonStream; + } + + public static byte[] serializeMsg(Message message) { + var stream = JsonStreamPool.borrowJsonStream(); + try { + return serializeMsg(message, stream); + } finally { + // Reset the stream to avoid memory leaks + JsonStreamPool.returnJsonStream(stream); + } + } + + public static byte[] serializeMsg(Message obj, JsonStream stream) { + try { + stream.writeVal(Message.class, obj); + return Arrays.copyOfRange(stream.buffer().data(), 0, stream.buffer().tail()); + } catch (IOException e) { + throw new JsonException(e); + } + } +} diff --git a/frameworks/Java/netty/src/main/java/hello/loom/HelloLoomServerInitializer.java b/frameworks/Java/netty/src/main/java/hello/loom/HelloLoomServerInitializer.java new file mode 100644 index 00000000000..ab407b4ffc5 --- /dev/null +++ b/frameworks/Java/netty/src/main/java/hello/loom/HelloLoomServerInitializer.java @@ -0,0 +1,20 @@ +package hello.loom; + +import java.util.concurrent.ScheduledExecutorService; + +import hello.HelloServerHandler; +import hello.HelloServerInitializer; + +public class HelloLoomServerInitializer extends HelloServerInitializer { + + private final MultithreadVirtualEventExecutorGroup group; + + public HelloLoomServerInitializer(MultithreadVirtualEventExecutorGroup group) { + this.group = group; + } + + @Override + protected HelloServerHandler newHelloServerHandler(ScheduledExecutorService service) { + return new VirtualThreadHelloServerHandler(service, group); + } +} diff --git a/frameworks/Java/netty/src/main/java/hello/loom/LoomSupport.java b/frameworks/Java/netty/src/main/java/hello/loom/LoomSupport.java new file mode 100644 index 00000000000..2349072bbd2 --- /dev/null +++ b/frameworks/Java/netty/src/main/java/hello/loom/LoomSupport.java @@ -0,0 +1,71 @@ +package hello.loom; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.reflect.Field; +import java.util.concurrent.Executor; + +public final class LoomSupport { + private static final boolean SUPPORTED; + private static Throwable FAILURE; + + private static final MethodHandle SCHEDULER; + + static { + boolean sup; + MethodHandle scheduler; + try { + // this is required to override the default scheduler + MethodHandles.Lookup lookup = MethodHandles.lookup(); + Field schedulerField = Class.forName("java.lang.ThreadBuilders$VirtualThreadBuilder") + .getDeclaredField("scheduler"); + schedulerField.setAccessible(true); + scheduler = lookup.unreflectSetter(schedulerField); + + // this is to make sure we fail earlier! + var builder = Thread.ofVirtual(); + scheduler.invoke(builder, new Executor() { + @Override + public void execute(Runnable command) { + + } + }); + + FAILURE = null; + + sup = true; + } catch (Throwable e) { + scheduler = null; + sup = false; + FAILURE = e; + } + + SCHEDULER = scheduler; + SUPPORTED = sup; + } + + private LoomSupport() { + } + + public static boolean isSupported() { + return SUPPORTED; + } + + public static void checkSupported() { + if (!isSupported()) { + throw new UnsupportedOperationException(FAILURE); + } + } + + + public static Thread.Builder.OfVirtual setVirtualThreadFactoryScheduler(Thread.Builder.OfVirtual builder, + Executor vthreadScheduler) { + checkSupported(); + try { + SCHEDULER.invoke(builder, vthreadScheduler); + return builder; + } catch (Throwable e) { + throw new RuntimeException(e); + } + } +} diff --git a/frameworks/Java/netty/src/main/java/hello/loom/MultithreadVirtualEventExecutorGroup.java b/frameworks/Java/netty/src/main/java/hello/loom/MultithreadVirtualEventExecutorGroup.java new file mode 100644 index 00000000000..bd099534700 --- /dev/null +++ b/frameworks/Java/netty/src/main/java/hello/loom/MultithreadVirtualEventExecutorGroup.java @@ -0,0 +1,56 @@ +package hello.loom; + +import java.util.IdentityHashMap; +import java.util.concurrent.Executor; +import java.util.concurrent.ThreadFactory; + +import io.netty.channel.IoEventLoop; +import io.netty.channel.IoHandlerFactory; +import io.netty.channel.MultiThreadIoEventLoopGroup; +import io.netty.util.concurrent.FastThreadLocal; +import io.netty.util.concurrent.FastThreadLocalThread; + +public class MultithreadVirtualEventExecutorGroup extends MultiThreadIoEventLoopGroup { + + public static final int RESUMED_CONTINUATIONS_EXPECTED_COUNT = Integer.getInteger("io.netty.loom.resumed.continuations", 1024); + private ThreadFactory threadFactory; + private IdentityHashMap schedulers; + private final FastThreadLocal v_thread_factory = new FastThreadLocal<>() { + @Override + protected ThreadFactory initialValue() { + var scheduler = schedulers.get(Thread.currentThread()); + if (scheduler == null) { + return null; + } + return LoomSupport.setVirtualThreadFactoryScheduler(Thread.ofVirtual(), scheduler).factory(); + } + }; + + public MultithreadVirtualEventExecutorGroup(int nThreads, IoHandlerFactory ioHandlerFactory) { + super(nThreads, (Executor) command -> { + throw new UnsupportedOperationException("this executor is not supposed to be used"); + }, ioHandlerFactory); + } + + public ThreadFactory eventLoopVirtualThreadFactory() { + if (!(Thread.currentThread() instanceof FastThreadLocalThread)) { + throw new IllegalStateException("this method should be called from event loop fast thread local threads"); + } + return v_thread_factory.get(); + } + + @Override + protected IoEventLoop newChild(Executor executor, IoHandlerFactory ioHandlerFactory, + @SuppressWarnings("unused") Object... args) { + if (threadFactory == null) { + threadFactory = newDefaultThreadFactory(); + } + var scheduler = new VirtualThreadNettyScheduler(this, threadFactory, ioHandlerFactory, RESUMED_CONTINUATIONS_EXPECTED_COUNT); + if (schedulers == null) { + schedulers = new IdentityHashMap<>(); + } + schedulers.put(scheduler.getCarrierThread(), scheduler); + return scheduler.ioEventLoop(); + } + +} diff --git a/frameworks/Java/netty/src/main/java/hello/loom/VirtualThreadHelloServerHandler.java b/frameworks/Java/netty/src/main/java/hello/loom/VirtualThreadHelloServerHandler.java new file mode 100644 index 00000000000..9da17a24adb --- /dev/null +++ b/frameworks/Java/netty/src/main/java/hello/loom/VirtualThreadHelloServerHandler.java @@ -0,0 +1,47 @@ +package hello.loom; + +import java.util.ArrayDeque; +import java.util.concurrent.ScheduledExecutorService; + +import com.jsoniter.output.JsonStream; + +import hello.HelloServerHandler; +import hello.HttpResponses; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http.FullHttpResponse; +import io.netty.handler.codec.http.HttpHeaders; +import io.netty.util.AsciiString; + +public class VirtualThreadHelloServerHandler extends HelloServerHandler { + + private final ArrayDeque responses = new ArrayDeque<>(); + private final MultithreadVirtualEventExecutorGroup group; + + public VirtualThreadHelloServerHandler(ScheduledExecutorService service, MultithreadVirtualEventExecutorGroup group) { + super(service); + this.group = group; + } + + @Override + protected void writePlainResponse(ChannelHandlerContext ctx, HttpHeaders plainTextHeaders) { + group.eventLoopVirtualThreadFactory().newThread(() -> { + responses.add(HttpResponses.makePlaintextResponse(plainTextHeaders)); + }).start(); + } + + @Override + protected void writeJsonResponse(ChannelHandlerContext ctx, JsonStream stream, HttpHeaders jsonHeaders) { + group.eventLoopVirtualThreadFactory().newThread(() -> { + responses.add(HttpResponses.makeJsonResponse(stream, jsonHeaders)); + }).start(); + } + + @Override + public void channelReadComplete(ChannelHandlerContext ctx) { + var responses = this.responses; + for (int i = 0, count = responses.size(); i < count; i++) { + ctx.write(responses.poll()); + } + ctx.flush(); + } +} diff --git a/frameworks/Java/netty/src/main/java/hello/loom/VirtualThreadNettyScheduler.java b/frameworks/Java/netty/src/main/java/hello/loom/VirtualThreadNettyScheduler.java new file mode 100644 index 00000000000..8a6f59ca346 --- /dev/null +++ b/frameworks/Java/netty/src/main/java/hello/loom/VirtualThreadNettyScheduler.java @@ -0,0 +1,95 @@ +package hello.loom; + +import java.util.concurrent.Executor; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; + +import io.netty.channel.IoEventLoopGroup; +import io.netty.channel.IoHandlerFactory; +import io.netty.channel.ManualIoEventLoop; +import io.netty.util.internal.shaded.org.jctools.queues.MpscUnboundedArrayQueue; + +public class VirtualThreadNettyScheduler implements Executor { + + private static final long MAX_WAIT_TASKS_NS = TimeUnit.SECONDS.toNanos(1); + private static final long MAX_RUN_CONTINUATIONS_NS = TimeUnit.SECONDS.toNanos(1); + + private final MpscUnboundedArrayQueue externalContinuations; + private final ManualIoEventLoop ioEventLoop; + private final Thread carrierThread; + + + public VirtualThreadNettyScheduler(IoEventLoopGroup parent, ThreadFactory threadFactory, IoHandlerFactory ioHandlerFactory, int resumedContinuationsExpectedCount) { + this.externalContinuations = new MpscUnboundedArrayQueue<>(resumedContinuationsExpectedCount); + this.carrierThread = threadFactory.newThread(this::internalRun); + this.ioEventLoop = new ManualIoEventLoop(parent, carrierThread, ioHandlerFactory); + // we can start the carrier only after all the fields are initialized + carrierThread.start(); + } + + public Thread getCarrierThread() { + return carrierThread; + } + + public ManualIoEventLoop ioEventLoop() { + return ioEventLoop; + } + + private void internalRun() { + var ioEventLoop = this.ioEventLoop; + while (!ioEventLoop.isShuttingDown()) { + // runnning I/O and async tasks within Netty without blocking + int workDone = ioEventLoop.runNow(); + workDone += runExternalContinuations(MAX_RUN_CONTINUATIONS_NS); + if (workDone == 0 && externalContinuations.isEmpty()) { + ioEventLoop.run(MAX_WAIT_TASKS_NS); + } + } + while (!ioEventLoop.isTerminated()) { + ioEventLoop.runNow(); + runExternalContinuations(MAX_RUN_CONTINUATIONS_NS); + } + while (!externalContinuations.isEmpty()) { + runExternalContinuations(MAX_RUN_CONTINUATIONS_NS); + } + } + + private int runExternalContinuations(long deadlineNs) { + final long startDrainingNs = System.nanoTime(); + int executed = 0; + for (; ; ) { + var continuation = this.externalContinuations.poll(); + if (continuation == null) { + break; + } + try { + continuation.run(); + } catch (Throwable t) { + // this shouldn't really happen + } + executed++; + long elapsedNs = System.nanoTime() - startDrainingNs; + if (elapsedNs >= deadlineNs) { + return executed; + } + } + return executed; + } + + @Override + public void execute(Runnable command) { + // TODO improve it using a reject handler? It's not too strict!? + if (ioEventLoop.isShuttingDown()) { + throw new RejectedExecutionException("event loop is shutting down"); + } + if (ioEventLoop.inEventLoop(Thread.currentThread())) { + command.run(); + } else { + externalContinuations.offer(command); + // wakeup won't happen if we're shutting down! + ioEventLoop.wakeup(); + } + } + +} diff --git a/frameworks/Java/ninja-standalone/pom.xml b/frameworks/Java/ninja-standalone/pom.xml index b4af584038f..080be7a670b 100644 --- a/frameworks/Java/ninja-standalone/pom.xml +++ b/frameworks/Java/ninja-standalone/pom.xml @@ -20,7 +20,7 @@ 2.2.220 5.4.24.Final - 6.0.20.Final + 6.2.0.Final 2.3.0 9.4.18.v20190429 8.0.28 @@ -51,7 +51,7 @@ com.fasterxml.jackson.core jackson-core - 2.9.9 + 2.15.0 com.fasterxml.jackson.module diff --git a/frameworks/Java/officefloor/benchmark_config.json b/frameworks/Java/officefloor/benchmark_config.json index 1a309d4ccbd..d90efc51b9d 100755 --- a/frameworks/Java/officefloor/benchmark_config.json +++ b/frameworks/Java/officefloor/benchmark_config.json @@ -47,6 +47,7 @@ "os": "Linux", "database_os": "Linux", "display_name": "OfficeFloor-r2dbc", + "tags": ["broken"], "notes": "" }, "sqlclient": { @@ -69,6 +70,7 @@ "os": "Linux", "database_os": "Linux", "display_name": "OfficeFloor-sqlclient", + "tags": ["broken"], "notes": "" }, "rawsqlclient": { @@ -91,6 +93,7 @@ "os": "Linux", "database_os": "Linux", "display_name": "OfficeFloor-rawsqlclient", + "tags": ["broken"], "notes": "" }, "async": { @@ -162,6 +165,7 @@ "database_os": "Linux", "display_name": "OfficeFloor-thread_affinity", "notes": "", + "tags": ["broken"], "versus": "OfficeFloor-r2dbc" }, "netty": { diff --git a/frameworks/Java/play1/README.md b/frameworks/Java/play1/README.md deleted file mode 100644 index 7cf95274bd7..00000000000 --- a/frameworks/Java/play1/README.md +++ /dev/null @@ -1,31 +0,0 @@ -# Play 1 framework Benchmarking Test - -[Play 1 framework](https://www.playframework.com/) - the high velocity web framework for Java and Scala. This is the old version - it's not Play 2. - -### Test sources - -This is the list: - - * [Plaintext](app/controllers/Application.java#L24) - * [JSON](app/controllers/Application.java#L28) - * [DB](app/controllers/Application.java#L39) - * [Queries](app/controllers/Application.java#L45) - -## Software Versions - -The tests were run with: - - * [Oracle Java 10](https://www.oracle.com/java/) - * [MySQL 5.7](http://www.mysql.com/) - -Please check the versions in the install and build scripts of TFB project. - -## Test URLs - -All implementations use the same URLs. - - * Plaintext - `http://localhost:8080/plaintext` - * JSON - `http://localhost:8080/json` - * DB - `http://localhost:8080/db` - * Queries - `http://localhost:8080/query?queries=` - diff --git a/frameworks/Java/play1/app/controllers/Application.java b/frameworks/Java/play1/app/controllers/Application.java deleted file mode 100644 index f2424d15b15..00000000000 --- a/frameworks/Java/play1/app/controllers/Application.java +++ /dev/null @@ -1,132 +0,0 @@ -package controllers; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ThreadLocalRandom; - -import models.World; -import play.db.jpa.JPAPlugin; -import play.jobs.Job; -import play.libs.F.Promise; -import play.mvc.Controller; - -public class Application extends Controller { - - private static final int TEST_DATABASE_ROWS = 10000; - - public static void index() { - render(); - } - - public static void hello() { - renderText("Hello, world!"); - } - - public static void json() { - Map result = new HashMap(); - result.put("message", "Hello, World!"); - renderJSON(result); - } - - /** - * this version is used in the tests. it is the simplest and fastest. - * - * @param queries - */ - public static void dbSync() { - Long id = Long.valueOf(ThreadLocalRandom.current().nextInt(TEST_DATABASE_ROWS) + 1); - World result = World.findById(id); - renderJSON(result); - } - - public static void dbQueries(int queries) { - if (queries == 0) { - queries = 1; - } else if (queries > 500) { - queries = 500; - } - final List worlds = new ArrayList(); - for (int i = 0; i < queries; ++i) { - Long id = Long.valueOf(ThreadLocalRandom.current().nextInt(TEST_DATABASE_ROWS) + 1); - World result = World.findById(id); - worlds.add(result); - } - renderJSON(worlds); - } - - @play.db.jpa.NoTransaction - public static void setup() { - JPAPlugin plugin = play.Play.plugin(JPAPlugin.class); - plugin.startTx(true); - - // clean out the old - World.deleteAll(); - System.out.println("DELETED"); - // in with the new - for (long i = 0; i <= TEST_DATABASE_ROWS; i++) { - int randomNumber = ThreadLocalRandom.current().nextInt(TEST_DATABASE_ROWS) + 1; - new World(i, randomNumber).save(); - if (i % 100 == 0) { - - World.em().flush(); - World.em().clear(); - System.out.println("FLUSHED : " + i + "/" + TEST_DATABASE_ROWS); - - } - } - System.out.println("ADDED"); - plugin.closeTx(false); - } - - /** - * note this is method is much slower than the synchronous version - */ - public static void dbAsyncEachQuery(int queries) - throws InterruptedException, ExecutionException { - if (queries == 0) - queries = 1; - final int queryCount = queries; - List> promises = new ArrayList>(); - for (int i = 0; i < queryCount; ++i) { - final Long id = Long - .valueOf(ThreadLocalRandom.current().nextInt(TEST_DATABASE_ROWS) + 1); - Job job = new Job() { - public World doJobWithResult() throws Exception { - World result = World.findById(id); - return result; - }; - }; - promises.add(job.now()); - } - List result = await(Promise.waitAll(promises)); - renderJSON(result); - } - - /** - * note this is method is a bit slower than the synchronous version - */ - public static void dbAsyncAllQueries(int queries) - throws InterruptedException, ExecutionException { - if (queries == 0) - queries = 1; - final int queryCount = queries; - final List worlds = new ArrayList(); - Job> job = new Job>() { - public java.util.List doJobWithResult() throws Exception { - for (int i = 0; i < queryCount; ++i) { - Long id = Long - .valueOf(ThreadLocalRandom.current().nextInt(TEST_DATABASE_ROWS) + 1); - World result = World.findById(id); - worlds.add(result); - } - return worlds; - }; - }; - List result = job.now().get(); - renderJSON(result); - } - -} diff --git a/frameworks/Java/play1/app/models/World.java b/frameworks/Java/play1/app/models/World.java deleted file mode 100644 index c1337dd9c6c..00000000000 --- a/frameworks/Java/play1/app/models/World.java +++ /dev/null @@ -1,30 +0,0 @@ -package models; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Id; - -import play.db.jpa.GenericModel; -import play.db.jpa.Model; - -import com.google.gson.annotations.SerializedName; - -/** - * use a generic model as we want to explicitly define the id - * - * @author tom - * - */ -@Entity -public class World extends GenericModel { - - public World(long i, long number) { - id = i; - randomNumber = number ; - } - - @Id - public Long id; - - public Long randomNumber; -} \ No newline at end of file diff --git a/frameworks/Java/play1/app/views/Application/index.html b/frameworks/Java/play1/app/views/Application/index.html deleted file mode 100644 index c614df6bffb..00000000000 --- a/frameworks/Java/play1/app/views/Application/index.html +++ /dev/null @@ -1,8 +0,0 @@ - - - diff --git a/frameworks/Java/play1/app/views/errors/404.html b/frameworks/Java/play1/app/views/errors/404.html deleted file mode 100644 index eb0b00e5421..00000000000 --- a/frameworks/Java/play1/app/views/errors/404.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - - Not found - - - - #{if play.mode.name() == 'DEV'} - #{404 result /} - #{/if} - #{else} -

Not found

-

- ${result.message} -

- #{/else} - - diff --git a/frameworks/Java/play1/app/views/errors/500.html b/frameworks/Java/play1/app/views/errors/500.html deleted file mode 100644 index a898cb77e48..00000000000 --- a/frameworks/Java/play1/app/views/errors/500.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - Application error - - - - #{if play.mode.name() == 'DEV'} - #{500 exception /} - #{/if} - #{else} -

Oops, an error occured

- #{if exception instanceof play.exceptions.PlayException} -

- This exception has been logged with id ${exception.id}. -

- #{/if} - #{/else} - - diff --git a/frameworks/Java/play1/app/views/main.html b/frameworks/Java/play1/app/views/main.html deleted file mode 100644 index 92e03f87d7a..00000000000 --- a/frameworks/Java/play1/app/views/main.html +++ /dev/null @@ -1,16 +0,0 @@ - - - - - #{get 'title' /} - - - #{get 'moreStyles' /} - - - #{get 'moreScripts' /} - - - #{doLayout /} - - diff --git a/frameworks/Java/play1/benchmark_config.json b/frameworks/Java/play1/benchmark_config.json deleted file mode 100644 index dddee2bca86..00000000000 --- a/frameworks/Java/play1/benchmark_config.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "framework": "play1", - "tests": [{ - "default": { - "json_url": "/json", - "plaintext_url": "/plaintext", - "db_url": "/db", - "query_url": "/query?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "MySQL", - "framework": "play1", - "language": "Java", - "flavor": "None", - "orm": "Full", - "platform": "Netty", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "play1", - "notes": "", - "versus": "netty" - } - }] -} diff --git a/frameworks/Java/play1/conf/application.conf b/frameworks/Java/play1/conf/application.conf deleted file mode 100644 index 02d35c1cde6..00000000000 --- a/frameworks/Java/play1/conf/application.conf +++ /dev/null @@ -1,236 +0,0 @@ -# This is the main configuration file for the application. -# ~~~~~ -application.name=play-1.2.5 - -# Application mode -# ~~~~~ -# Set to dev to enable instant reloading and other development help. -# Otherwise set to prod. -application.mode=dev -%prod.application.mode=prod - -# Secret key -# ~~~~~ -# The secret key is used to secure cryptographics functions -# If you deploy your application to several instances be sure to use the same key ! -application.secret=p7Abj8rpexZmmC8iPsY2PlXSo1xtHFhLKHRCHpE1ZqEgRU5TIHPcEbaryoj16vi8 - -# i18n -# ~~~~~ -# Define locales used by your application. -# You can then place localized messages in conf/messages.{locale} files -# application.langs=fr,en,ja - -# Date format -# ~~~~~ -date.format=yyyy-MM-dd -# date.format.fr=dd/MM/yyyy - -# Server configuration -# ~~~~~ -# If you need to change the HTTP port, uncomment this (default is set to 9000) -# http.port=9000 - -#modified to match previous port on test -http.port=8080 - -# -# By default the server listen for HTTP on the wilcard address. -# You can restrict this. -# http.address=127.0.0.1 -# -# Use this if you don't host your Play application at the root of the domain -# you're serving it from. This parameter has no effect when deployed as a -# war, because the path will be handled by the application server. -# http.path=/ - -# Session configuration -# ~~~~~~~~~~~~~~~~~~~~~~ -# By default, session will be written to the transient PLAY_SESSION cookie. -# The cookies are not secured by default, only set it to true -# if you're serving your pages through https. -# application.session.cookie=PLAY -# application.session.maxAge=1h -# application.session.secure=false - -# Session/Cookie sharing between subdomain -# ~~~~~~~~~~~~~~~~~~~~~~ -# By default a cookie is only valid for a specific domain. By setting -# application.defaultCookieDomain to '.example.com', the cookies -# will be valid for all domains ending with '.example.com', ie: -# foo.example.com and bar.example.com -# application.defaultCookieDomain=.example.com - -# JVM configuration -# ~~~~~ -# Define which port is used by JPDA when application is in debug mode (default is set to 8000) -# jpda.port=8000 -# -# Java source level => 1.5, 1.6 or 1.7 (experimental) -# java.source=1.5 - -# Log level -# ~~~~~ -# Specify log level for your application. -# If you want a very customized log, create a log4j.properties file in the conf directory -# application.log=INFO -# -# More logging configuration -# application.log.path=/log4j.properties -# application.log.system.out=off - -# Database configuration -# ~~~~~ -# Enable a database engine if needed. -# -# To quickly set up a development database, use either: -# - mem : for a transient in memory database (H2 in memory) -# - fs : for a simple file written database (H2 file stored) -# db=mem -# -# To connect to a local MySQL5 database, use: -# db=mysql://user:pwd@host/database -# -# To connect to a local PostgreSQL9 database, use: -# db=postgres://user:pwd@host/database -# -# If you need a full JDBC configuration use the following : -# db.url=jdbc:postgresql:database_name -# db.driver=org.postgresql.Driver -# db.user=root -# db.pass=secret -# -# Connections pool configuration : -db.pool.timeout=1000 -db.pool.maxSize=30 -db.pool.minSize=10 - - -# -# If you want to reuse an existing Datasource from your application server, use: -# db=java:/comp/env/jdbc/myDatasource -# -# When using an existing Datasource, it's sometimes needed to destroy it when -# the application is stopped. Depending on the datasource, you can define a -# generic "destroy" method : -# db.destroyMethod=close -db.driver= com.mysql.jdbc.Driver -db.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&cacheRSMetadata=true&useSSL=false -#db.url=jdbc:mysql://tfb-database:3306/hello_world -db.user=benchmarkdbuser -db.pass=benchmarkdbpass -#db.jndiName=DefaultDS - -#db.default.driver= com.mysql.jdbc.Driver -#db.default.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&cacheRSMetadata=true -#db.default.user=benchmarkdbuser -#db.default.pass=benchmarkdbpass -#db.default.jndiName=DefaultDS - - -# JPA Configuration (Hibernate) -# ~~~~~ -# -# Specify the custom JPA dialect to use here (default to guess): -# jpa.dialect=org.hibernate.dialect.PostgreSQLDialect -# -# Specify the ddl generation pattern to use. Set to none to disable it -# (default to update in DEV mode, and none in PROD mode): -# jpa.ddl=update -# -# Debug SQL statements (logged using DEBUG level): -# jpa.debugSQL=true -# -# You can even specify additional hibernate properties here: -# hibernate.use_sql_comments=true -# ... -# -# Store path for Blob content -attachments.path=data/attachments - -# Memcached configuration -# ~~~~~ -# Enable memcached if needed. Otherwise a local cache is used. -# memcached=enabled -# -# Specify memcached host (default to 127.0.0.1:11211) -# memcached.host=127.0.0.1:11211 -# -# Or you can specify multiple host to build a distributed cache -# memcached.1.host=127.0.0.1:11211 -# memcached.2.host=127.0.0.1:11212 -# -# Use plain SASL to authenticate for memcached -# memcached.user= -# memcached.password= - -# HTTP Response headers control for static files -# ~~~~~ -# Set the default max-age, telling the user's browser how long it should cache the page. -# Default is 3600 (one hour). Set it to 0 to send no-cache. -# This is only read in prod mode, in dev mode the cache is disabled. -# http.cacheControl=3600 - -# If enabled, Play will generate entity tags automatically and send a 304 when needed. -# Default is true, set it to false to deactivate use of entity tags. -# http.useETag=true - -# Custom mime types -# mimetype.xpi=application/x-xpinstall - -# WS configuration -# ~~~~~ -# Default engine is Async Http Client, uncomment to use -# the JDK's internal implementation -# webservice = urlfetch -# If you need to set proxy params for WS requests -# http.proxyHost = localhost -# http.proxyPort = 3128 -# http.proxyUser = jojo -# http.proxyPassword = jojo - -# Mail configuration -# ~~~~~ -# Default is to use a mock Mailer -mail.smtp=mock - -# Or, specify mail host configuration -# mail.smtp.host=127.0.0.1 -# mail.smtp.user=admin -# mail.smtp.pass= -# mail.smtp.channel=ssl - -# Url-resolving in Jobs -# ~~~~~~ -# When rendering templates with reverse-url-resoling (@@{..}) in Jobs (which do not have an inbound Http.Request), -# ie if sending a HtmlMail, Play need to know which url your users use when accessing your app. -# %test.application.baseUrl=http://localhost:9000/ -# %prod.application.baseUrl=http://www.yourdomain.com/ - -# Jobs executor -# ~~~~~~ -# Size of the Jobs pool -# play.jobs.pool=10 - - -# Execution pool -# ~~~~~ -# Default to 1 thread in DEV mode or (nb processors + 1) threads in PROD mode. -# Try to keep a low as possible. 1 thread will serialize all requests (very useful for debugging purpose) -# play.pool=3 - -# Open file from errors pages -# ~~~~~ -# If your text editor supports opening files by URL, Play! will -# dynamically link error pages to files -# -# Example, for textmate: -# play.editor=txmt://open?url=file://%s&line=%s - -# Testing. Set up a custom configuration for test mode -# ~~~~~ -#%test.module.cobertura=${play.path}/modules/cobertura -%test.application.mode=dev -%test.db.url=jdbc:h2:mem:play;MODE=MYSQL;LOCK_MODE=0 -%test.jpa.ddl=create -%test.mail.smtp=mock diff --git a/frameworks/Java/play1/conf/dependencies.yml b/frameworks/Java/play1/conf/dependencies.yml deleted file mode 100644 index d86de2e46ea..00000000000 --- a/frameworks/Java/play1/conf/dependencies.yml +++ /dev/null @@ -1,4 +0,0 @@ -# Application dependencies - -require: - - play \ No newline at end of file diff --git a/frameworks/Java/play1/conf/messages b/frameworks/Java/play1/conf/messages deleted file mode 100644 index b51f29459d1..00000000000 --- a/frameworks/Java/play1/conf/messages +++ /dev/null @@ -1,3 +0,0 @@ -# You can specialize this file for each language. -# For example, for French create a messages.fr file -# diff --git a/frameworks/Java/play1/conf/routes b/frameworks/Java/play1/conf/routes deleted file mode 100644 index 5f33cf52b6c..00000000000 --- a/frameworks/Java/play1/conf/routes +++ /dev/null @@ -1,15 +0,0 @@ -# Routes -# This file defines all application routes (Higher priority routes first) -# ~~~~ - - -# Home page -GET /json Application.json -GET /db Application.dbSync -GET /query Application.dbQueries -GET /plaintext Application.hello -GET /db2 Application.dbAsyncAllQueries -GET /db3 Application.dbAsyncEachQuery -GET /setup Application.setup -GET / Application.index - diff --git a/frameworks/Java/play1/config.toml b/frameworks/Java/play1/config.toml deleted file mode 100644 index 7e774fff5de..00000000000 --- a/frameworks/Java/play1/config.toml +++ /dev/null @@ -1,17 +0,0 @@ -[framework] -name = "play1" - -[main] -urls.plaintext = "/plaintext" -urls.json = "/json" -urls.db = "/db" -urls.query = "/query?queries=" -approach = "Realistic" -classification = "Fullstack" -database = "MySQL" -database_os = "Linux" -os = "Linux" -orm = "Full" -platform = "Netty" -webserver = "None" -versus = "netty" diff --git a/frameworks/Java/play1/play1.dockerfile b/frameworks/Java/play1/play1.dockerfile deleted file mode 100644 index 090a8ff77a5..00000000000 --- a/frameworks/Java/play1/play1.dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM openjdk:10-jdk -WORKDIR /play1 -COPY app app -COPY conf conf -COPY public public -COPY test test -RUN wget -nv https://downloads.typesafe.com/play/1.5.2/play-1.5.2.zip -RUN unzip -q play-1.5.2.zip -RUN apt-get install -yqq python - -EXPOSE 8080 - -CMD ["play-1.5.2/play", "run", "--%prod"] diff --git a/frameworks/Java/play1/public/images/favicon.png b/frameworks/Java/play1/public/images/favicon.png deleted file mode 100644 index c7d92d2ae47..00000000000 Binary files a/frameworks/Java/play1/public/images/favicon.png and /dev/null differ diff --git a/frameworks/Java/play1/public/javascripts/jquery-1.6.4.min.js b/frameworks/Java/play1/public/javascripts/jquery-1.6.4.min.js deleted file mode 100644 index 628ed9b3160..00000000000 --- a/frameworks/Java/play1/public/javascripts/jquery-1.6.4.min.js +++ /dev/null @@ -1,4 +0,0 @@ -/*! jQuery v1.6.4 http://jquery.com/ | http://jquery.org/license */ -(function(a,b){function cu(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cr(a){if(!cg[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){ch||(ch=c.createElement("iframe"),ch.frameBorder=ch.width=ch.height=0),b.appendChild(ch);if(!ci||!ch.createElement)ci=(ch.contentWindow||ch.contentDocument).document,ci.write((c.compatMode==="CSS1Compat"?"":"")+""),ci.close();d=ci.createElement(a),ci.body.appendChild(d),e=f.css(d,"display"),b.removeChild(ch)}cg[a]=e}return cg[a]}function cq(a,b){var c={};f.each(cm.concat.apply([],cm.slice(0,b)),function(){c[this]=a});return c}function cp(){cn=b}function co(){setTimeout(cp,0);return cn=f.now()}function cf(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ce(){try{return new a.XMLHttpRequest}catch(b){}}function b$(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g0){c!=="border"&&f.each(e,function(){c||(d-=parseFloat(f.css(a,"padding"+this))||0),c==="margin"?d+=parseFloat(f.css(a,c+this))||0:d-=parseFloat(f.css(a,"border"+this+"Width"))||0});return d+"px"}d=bv(a,b,b);if(d<0||d==null)d=a.style[b]||0;d=parseFloat(d)||0,c&&f.each(e,function(){d+=parseFloat(f.css(a,"padding"+this))||0,c!=="padding"&&(d+=parseFloat(f.css(a,"border"+this+"Width"))||0),c==="margin"&&(d+=parseFloat(f.css(a,c+this))||0)});return d+"px"}function bl(a,b){b.src?f.ajax({url:b.src,async:!1,dataType:"script"}):f.globalEval((b.text||b.textContent||b.innerHTML||"").replace(bd,"/*$0*/")),b.parentNode&&b.parentNode.removeChild(b)}function bk(a){f.nodeName(a,"input")?bj(a):"getElementsByTagName"in a&&f.grep(a.getElementsByTagName("input"),bj)}function bj(a){if(a.type==="checkbox"||a.type==="radio")a.defaultChecked=a.checked}function bi(a){return"getElementsByTagName"in a?a.getElementsByTagName("*"):"querySelectorAll"in a?a.querySelectorAll("*"):[]}function bh(a,b){var c;if(b.nodeType===1){b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase();if(c==="object")b.outerHTML=a.outerHTML;else if(c!=="input"||a.type!=="checkbox"&&a.type!=="radio"){if(c==="option")b.selected=a.defaultSelected;else if(c==="input"||c==="textarea")b.defaultValue=a.defaultValue}else a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value);b.removeAttribute(f.expando)}}function bg(a,b){if(b.nodeType===1&&!!f.hasData(a)){var c=f.expando,d=f.data(a),e=f.data(b,d);if(d=d[c]){var g=d.events;e=e[c]=f.extend({},d);if(g){delete e.handle,e.events={};for(var h in g)for(var i=0,j=g[h].length;i=0===c})}function U(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function M(a,b){return(a&&a!=="*"?a+".":"")+b.replace(y,"`").replace(z,"&")}function L(a){var b,c,d,e,g,h,i,j,k,l,m,n,o,p=[],q=[],r=f._data(this,"events");if(!(a.liveFired===this||!r||!r.live||a.target.disabled||a.button&&a.type==="click")){a.namespace&&(n=new RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)")),a.liveFired=this;var s=r.live.slice(0);for(i=0;ic)break;a.currentTarget=e.elem,a.data=e.handleObj.data,a.handleObj=e.handleObj,o=e.handleObj.origHandler.apply(e.elem,arguments);if(o===!1||a.isPropagationStopped()){c=e.level,o===!1&&(b=!1);if(a.isImmediatePropagationStopped())break}}return b}}function J(a,c,d){var e=f.extend({},d[0]);e.type=a,e.originalEvent={},e.liveFired=b,f.event.handle.call(c,e),e.isDefaultPrevented()&&d[0].preventDefault()}function D(){return!0}function C(){return!1}function m(a,c,d){var e=c+"defer",g=c+"queue",h=c+"mark",i=f.data(a,e,b,!0);i&&(d==="queue"||!f.data(a,g,b,!0))&&(d==="mark"||!f.data(a,h,b,!0))&&setTimeout(function(){!f.data(a,g,b,!0)&&!f.data(a,h,b,!0)&&(f.removeData(a,e,!0),i.resolve())},0)}function l(a){for(var b in a)if(b!=="toJSON")return!1;return!0}function k(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(j,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNaN(d)?i.test(d)?f.parseJSON(d):d:parseFloat(d)}catch(g){}f.data(a,c,d)}else d=b}return d}var c=a.document,d=a.navigator,e=a.location,f=function(){function K(){if(!e.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(K,1);return}e.ready()}}var e=function(a,b){return new e.fn.init(a,b,h)},f=a.jQuery,g=a.$,h,i=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/\d/,n=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,o=/^[\],:{}\s]*$/,p=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,q=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,r=/(?:^|:|,)(?:\s*\[)+/g,s=/(webkit)[ \/]([\w.]+)/,t=/(opera)(?:.*version)?[ \/]([\w.]+)/,u=/(msie) ([\w.]+)/,v=/(mozilla)(?:.*? rv:([\w.]+))?/,w=/-([a-z]|[0-9])/ig,x=/^-ms-/,y=function(a,b){return(b+"").toUpperCase()},z=d.userAgent,A,B,C,D=Object.prototype.toString,E=Object.prototype.hasOwnProperty,F=Array.prototype.push,G=Array.prototype.slice,H=String.prototype.trim,I=Array.prototype.indexOf,J={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=n.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.6.4",length:0,size:function(){return this.length},toArray:function(){return G.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?F.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),B.done(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(G.apply(this,arguments),"slice",G.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:F,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;B.resolveWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").unbind("ready")}},bindReady:function(){if(!B){B=e._Deferred();if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",C,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",C),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&K()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNaN:function(a){return a==null||!m.test(a)||isNaN(a)},type:function(a){return a==null?String(a):J[D.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!E.call(a,"constructor")&&!E.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||E.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw a},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(o.test(b.replace(p,"@").replace(q,"]").replace(r,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(c){var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&e.error("Invalid XML: "+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(x,"ms-").replace(w,y)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i1?h.call(arguments,0):c,--e||g.resolveWith(g,h.call(b,0))}}var b=arguments,c=0,d=b.length,e=d,g=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred();if(d>1){for(;c
a",d=a.getElementsByTagName("*"),e=a.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=a.getElementsByTagName("input")[0],k={leadingWhitespace:a.firstChild.nodeType===3,tbody:!a.getElementsByTagName("tbody").length,htmlSerialize:!!a.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55$/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:a.className!=="t",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,k.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,k.optDisabled=!h.disabled;try{delete a.test}catch(v){k.deleteExpando=!1}!a.addEventListener&&a.attachEvent&&a.fireEvent&&(a.attachEvent("onclick",function(){k.noCloneEvent=!1}),a.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),k.radioValue=i.value==="t",i.setAttribute("checked","checked"),a.appendChild(i),l=c.createDocumentFragment(),l.appendChild(a.firstChild),k.checkClone=l.cloneNode(!0).cloneNode(!0).lastChild.checked,a.innerHTML="",a.style.width=a.style.paddingLeft="1px",m=c.getElementsByTagName("body")[0],o=c.createElement(m?"div":"body"),p={visibility:"hidden",width:0,height:0,border:0,margin:0,background:"none"},m&&f.extend(p,{position:"absolute",left:"-1000px",top:"-1000px"});for(t in p)o.style[t]=p[t];o.appendChild(a),n=m||b,n.insertBefore(o,n.firstChild),k.appendChecked=i.checked,k.boxModel=a.offsetWidth===2,"zoom"in a.style&&(a.style.display="inline",a.style.zoom=1,k.inlineBlockNeedsLayout=a.offsetWidth===2,a.style.display="",a.innerHTML="
",k.shrinkWrapBlocks=a.offsetWidth!==2),a.innerHTML="
t
",q=a.getElementsByTagName("td"),u=q[0].offsetHeight===0,q[0].style.display="",q[1].style.display="none",k.reliableHiddenOffsets=u&&q[0].offsetHeight===0,a.innerHTML="",c.defaultView&&c.defaultView.getComputedStyle&&(j=c.createElement("div"),j.style.width="0",j.style.marginRight="0",a.appendChild(j),k.reliableMarginRight=(parseInt((c.defaultView.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0),o.innerHTML="",n.removeChild(o);if(a.attachEvent)for(t in{submit:1,change:1,focusin:1})s="on"+t,u=s in a,u||(a.setAttribute(s,"return;"),u=typeof a[s]=="function"),k[t+"Bubbles"]=u;o=l=g=h=m=j=a=i=null;return k}(),f.boxModel=f.support.boxModel;var i=/^(?:\{.*\}|\[.*\])$/,j=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!l(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i=f.expando,j=typeof c=="string",k=a.nodeType,l=k?f.cache:a,m=k?a[f.expando]:a[f.expando]&&f.expando;if((!m||e&&m&&l[m]&&!l[m][i])&&j&&d===b)return;m||(k?a[f.expando]=m=++f.uuid:m=f.expando),l[m]||(l[m]={},k||(l[m].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?l[m][i]=f.extend(l[m][i],c):l[m]=f.extend(l[m],c);g=l[m],e&&(g[i]||(g[i]={}),g=g[i]),d!==b&&(g[f.camelCase(c)]=d);if(c==="events"&&!g[c])return g[i]&&g[i].events;j?(h=g[c],h==null&&(h=g[f.camelCase(c)])):h=g;return h}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e=f.expando,g=a.nodeType,h=g?f.cache:a,i=g?a[f.expando]:f.expando;if(!h[i])return;if(b){d=c?h[i][e]:h[i];if(d){d[b]||(b=f.camelCase(b)),delete d[b];if(!l(d))return}}if(c){delete h[i][e];if(!l(h[i]))return}var j=h[i][e];f.support.deleteExpando||!h.setInterval?delete h[i]:h[i]=null,j?(h[i]={},g||(h[i].toJSON=f.noop),h[i][e]=j):g&&(f.support.deleteExpando?delete a[f.expando]:a.removeAttribute?a.removeAttribute(f.expando):a[f.expando]=null)}},_data:function(a,b,c){return f.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=f.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),f.fn.extend({data:function(a,c){var d=null;if(typeof a=="undefined"){if(this.length){d=f.data(this[0]);if(this[0].nodeType===1){var e=this[0].attributes,g;for(var h=0,i=e.length;h-1)return!0;return!1},val:function(a){var c,d,e=this[0];if(!arguments.length){if(e){c=f.valHooks[e.nodeName.toLowerCase()]||f.valHooks[e.type];if(c&&"get"in c&&(d=c.get(e,"value"))!==b)return d;d=e.value;return typeof d=="string"?d.replace(p,""):d==null?"":d}return b}var g=f.isFunction(a);return this.each(function(d){var e=f(this),h;if(this.nodeType===1){g?h=a.call(this,d,e.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c=a.selectedIndex,d=[],e=a.options,g=a.type==="select-one";if(c<0)return null;for(var h=g?c:0,i=g?c+1:e.length;h=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attrFix:{tabindex:"tabIndex"},attr:function(a,c,d,e){var g=a.nodeType;if(!a||g===3||g===8||g===2)return b;if(e&&c in f.attrFn)return f(a)[c](d);if(!("getAttribute"in a))return f.prop(a,c,d);var h,i,j=g!==1||!f.isXMLDoc(a);j&&(c=f.attrFix[c]||c,i=f.attrHooks[c],i||(t.test(c)?i=v:u&&(i=u)));if(d!==b){if(d===null){f.removeAttr(a,c);return b}if(i&&"set"in i&&j&&(h=i.set(a,d,c))!==b)return h;a.setAttribute(c,""+d);return d}if(i&&"get"in i&&j&&(h=i.get(a,c))!==null)return h;h=a.getAttribute(c);return h===null?b:h},removeAttr:function(a,b){var c;a.nodeType===1&&(b=f.attrFix[b]||b,f.attr(a,b,""),a.removeAttribute(b),t.test(b)&&(c=f.propFix[b]||b)in a&&(a[c]=!1))},attrHooks:{type:{set:function(a,b){if(q.test(a.nodeName)&&a.parentNode)f.error("type property can't be changed");else if(!f.support.radioValue&&b==="radio"&&f.nodeName(a,"input")){var c=a.value;a.setAttribute("type",b),c&&(a.value=c);return b}}},value:{get:function(a,b){if(u&&f.nodeName(a,"button"))return u.get(a,b);return b in a?a.value:null},set:function(a,b,c){if(u&&f.nodeName(a,"button"))return u.set(a,b,c);a.value=b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e=a.nodeType;if(!a||e===3||e===8||e===2)return b;var g,h,i=e!==1||!f.isXMLDoc(a);i&&(c=f.propFix[c]||c,h=f.propHooks[c]);return d!==b?h&&"set"in h&&(g=h.set(a,d,c))!==b?g:a[c]=d:h&&"get"in h&&(g=h.get(a,c))!==null?g:a[c]},propHooks:{tabIndex:{get:function(a){var c=a.getAttributeNode("tabindex");return c&&c.specified?parseInt(c.value,10):r.test(a.nodeName)||s.test(a.nodeName)&&a.href?0:b}}}}),f.attrHooks.tabIndex=f.propHooks.tabIndex,v={get:function(a,c){var d;return f.prop(a,c)===!0||(d=a.getAttributeNode(c))&&d.nodeValue!==!1?c.toLowerCase():b},set:function(a,b,c){var d;b===!1?f.removeAttr(a,c):(d=f.propFix[c]||c,d in a&&(a[d]=!0),a.setAttribute(c,c.toLowerCase()));return c}},f.support.getSetAttribute||(u=f.valHooks.button={get:function(a,c){var d;d=a.getAttributeNode(c);return d&&d.nodeValue!==""?d.nodeValue:b},set:function(a,b,d){var e=a.getAttributeNode(d);e||(e=c.createAttribute(d),a.setAttributeNode(e));return e.nodeValue=b+""}},f.each(["width","height"],function(a,b){f.attrHooks[b]=f.extend(f.attrHooks[b],{set:function(a,c){if(c===""){a.setAttribute(b,"auto");return c}}})})),f.support.hrefNormalized||f.each(["href","src","width","height"],function(a,c){f.attrHooks[c]=f.extend(f.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),f.support.style||(f.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=""+b}}),f.support.optSelected||(f.propHooks.selected=f.extend(f.propHooks.selected,{get:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex);return null}})),f.support.checkOn||f.each(["radio","checkbox"],function(){f.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),f.each(["radio","checkbox"],function(){f.valHooks[this]=f.extend(f.valHooks[this],{set:function(a,b){if(f.isArray(b))return a.checked=f.inArray(f(a).val(),b)>=0}})});var w=/\.(.*)$/,x=/^(?:textarea|input|select)$/i,y=/\./g,z=/ /g,A=/[^\w\s.|`]/g,B=function(a){return a.replace(A,"\\$&")};f.event={add:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){if(d===!1)d=C;else if(!d)return;var g,h;d.handler&&(g=d,d=g.handler),d.guid||(d.guid=f.guid++);var i=f._data(a);if(!i)return;var j=i.events,k=i.handle;j||(i.events=j={}),k||(i.handle=k=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.handle.apply(k.elem,arguments):b}),k.elem=a,c=c.split(" ");var l,m=0,n;while(l=c[m++]){h=g?f.extend({},g):{handler:d,data:e},l.indexOf(".")>-1?(n=l.split("."),l=n.shift(),h.namespace=n.slice(0).sort().join(".")):(n=[],h.namespace=""),h.type=l,h.guid||(h.guid=d.guid);var o=j[l],p=f.event.special[l]||{};if(!o){o=j[l]=[];if(!p.setup||p.setup.call(a,e,n,k)===!1)a.addEventListener?a.addEventListener(l,k,!1):a.attachEvent&&a.attachEvent("on"+l,k)}p.add&&(p.add.call(a,h),h.handler.guid||(h.handler.guid=d.guid)),o.push(h),f.event.global[l]=!0}a=null}},global:{},remove:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){d===!1&&(d=C);var g,h,i,j,k=0,l,m,n,o,p,q,r,s=f.hasData(a)&&f._data(a),t=s&&s.events;if(!s||!t)return;c&&c.type&&(d=c.handler,c=c.type);if(!c||typeof c=="string"&&c.charAt(0)==="."){c=c||"";for(h in t)f.event.remove(a,h+c);return}c=c.split(" ");while(h=c[k++]){r=h,q=null,l=h.indexOf(".")<0,m=[],l||(m=h.split("."),h=m.shift(),n=new RegExp("(^|\\.)"+f.map(m.slice(0).sort(),B).join("\\.(?:.*\\.)?")+"(\\.|$)")),p=t[h];if(!p)continue;if(!d){for(j=0;j=0&&(h=h.slice(0,-1),j=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if(!!e&&!f.event.customEvent[h]||!!f.event.global[h]){c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.exclusive=j,c.namespace=i.join("."),c.namespace_re=new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)");if(g||!e)c.preventDefault(),c.stopPropagation();if(!e){f.each(f.cache,function(){var a=f.expando,b=this[a];b&&b.events&&b.events[h]&&f.event.trigger(c,d,b.handle.elem)});return}if(e.nodeType===3||e.nodeType===8)return;c.result=b,c.target=e,d=d!=null?f.makeArray(d):[],d.unshift(c);var k=e,l=h.indexOf(":")<0?"on"+h:"";do{var m=f._data(k,"handle");c.currentTarget=k,m&&m.apply(k,d),l&&f.acceptData(k)&&k[l]&&k[l].apply(k,d)===!1&&(c.result=!1,c.preventDefault()),k=k.parentNode||k.ownerDocument||k===c.target.ownerDocument&&a}while(k&&!c.isPropagationStopped());if(!c.isDefaultPrevented()){var n,o=f.event.special[h]||{};if((!o._default||o._default.call(e.ownerDocument,c)===!1)&&(h!=="click"||!f.nodeName(e,"a"))&&f.acceptData(e)){try{l&&e[h]&&(n=e[l],n&&(e[l]=null),f.event.triggered=h,e[h]())}catch(p){}n&&(e[l]=n),f.event.triggered=b}}return c.result}},handle:function(c){c=f.event.fix(c||a.event);var d=((f._data(this,"events")||{})[c.type]||[]).slice(0),e=!c.exclusive&&!c.namespace,g=Array.prototype.slice.call(arguments,0);g[0]=c,c.currentTarget=this;for(var h=0,i=d.length;h-1?f.map(a.options,function(a){return a.selected}).join("-"):"":f.nodeName(a,"select")&&(c=a.selectedIndex);return c},I=function(c){var d=c.target,e,g;if(!!x.test(d.nodeName)&&!d.readOnly){e=f._data(d,"_change_data"),g=H(d),(c.type!=="focusout"||d.type!=="radio")&&f._data(d,"_change_data",g);if(e===b||g===e)return;if(e!=null||g)c.type="change",c.liveFired=b,f.event.trigger(c,arguments[1],d)}};f.event.special.change={filters:{focusout:I,beforedeactivate:I,click:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(c==="radio"||c==="checkbox"||f.nodeName(b,"select"))&&I.call(this,a)},keydown:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(a.keyCode===13&&!f.nodeName(b,"textarea")||a.keyCode===32&&(c==="checkbox"||c==="radio")||c==="select-multiple")&&I.call(this,a)},beforeactivate:function(a){var b=a.target;f._data(b,"_change_data",H(b))}},setup:function(a,b){if(this.type==="file")return!1;for(var c in G)f.event.add(this,c+".specialChange",G[c]);return x.test(this.nodeName)},teardown:function(a){f.event.remove(this,".specialChange");return x.test(this.nodeName)}},G=f.event.special.change.filters,G.focus=G.beforeactivate}f.support.focusinBubbles||f.each({focus:"focusin",blur:"focusout"},function(a,b){function e(a){var c=f.event.fix(a);c.type=b,c.originalEvent={},f.event.trigger(c,null,c.target),c.isDefaultPrevented()&&a.preventDefault()}var d=0;f.event.special[b]={setup:function(){d++===0&&c.addEventListener(a,e,!0)},teardown:function(){--d===0&&c.removeEventListener(a,e,!0)}}}),f.each(["bind","one"],function(a,c){f.fn[c]=function(a,d,e){var g;if(typeof a=="object"){for(var h in a)this[c](h,d,a[h],e);return this}if(arguments.length===2||d===!1)e=d,d=b;c==="one"?(g=function(a){f(this).unbind(a,g);return e.apply(this,arguments)},g.guid=e.guid||f.guid++):g=e;if(a==="unload"&&c!=="one")this.one(a,d,e);else for(var i=0,j=this.length;i0?this.bind(b,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0)}),function(){function u(a,b,c,d,e,f){for(var g=0,h=d.length;g0){j=i;break}}i=i[a]}d[g]=j}}}function t(a,b,c,d,e,f){for(var g=0,h=d.length;g+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d=0,e=Object.prototype.toString,g=!1,h=!0,i=/\\/g,j=/\W/;[0,0].sort(function(){h=!1;return 0});var k=function(b,d,f,g){f=f||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return f;var i,j,n,o,q,r,s,t,u=!0,w=k.isXML(d),x=[],y=b;do{a.exec(""),i=a.exec(y);if(i){y=i[3],x.push(i[1]);if(i[2]){o=i[3];break}}}while(i);if(x.length>1&&m.exec(b))if(x.length===2&&l.relative[x[0]])j=v(x[0]+x[1],d);else{j=l.relative[x[0]]?[d]:k(x.shift(),d);while(x.length)b=x.shift(),l.relative[b]&&(b+=x.shift()),j=v(b,j)}else{!g&&x.length>1&&d.nodeType===9&&!w&&l.match.ID.test(x[0])&&!l.match.ID.test(x[x.length-1])&&(q=k.find(x.shift(),d,w),d=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]);if(d){q=g?{expr:x.pop(),set:p(g)}:k.find(x.pop(),x.length===1&&(x[0]==="~"||x[0]==="+")&&d.parentNode?d.parentNode:d,w),j=q.expr?k.filter(q.expr,q.set):q.set,x.length>0?n=p(j):u=!1;while(x.length)r=x.pop(),s=r,l.relative[r]?s=x.pop():r="",s==null&&(s=d),l.relative[r](n,s,w)}else n=x=[]}n||(n=j),n||k.error(r||b);if(e.call(n)==="[object Array]")if(!u)f.push.apply(f,n);else if(d&&d.nodeType===1)for(t=0;n[t]!=null;t++)n[t]&&(n[t]===!0||n[t].nodeType===1&&k.contains(d,n[t]))&&f.push(j[t]);else for(t=0;n[t]!=null;t++)n[t]&&n[t].nodeType===1&&f.push(j[t]);else p(n,f);o&&(k(o,h,f,g),k.uniqueSort(f));return f};k.uniqueSort=function(a){if(r){g=h,a.sort(r);if(g)for(var b=1;b0},k.find=function(a,b,c){var d;if(!a)return[];for(var e=0,f=l.order.length;e":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!j.test(b)){b=b.toLowerCase();for(;e=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(i,"")},TAG:function(a,b){return a[1].replace(i,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||k.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&k.error(a[0]);a[0]=d++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(i,"");!f&&l.attrMap[g]&&(a[1]=l.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(i,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=k(b[3],null,null,c);else{var g=k.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(l.match.POS.test(b[0])||l.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!k(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return bc[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=l.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||k.getText([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=l.attrHandle[c]?l.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=l.setFilters[e];if(f)return f(a,c,b,d)}}},m=l.match.POS,n=function(a,b){return"\\"+(b-0+1)};for(var o in l.match)l.match[o]=new RegExp(l.match[o].source+/(?![^\[]*\])(?![^\(]*\))/.source),l.leftMatch[o]=new RegExp(/(^(?:.|\r|\n)*?)/.source+l.match[o].source.replace(/\\(\d+)/g,n));var p=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(q){p=function(a,b){var c=0,d=b||[];if(e.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var f=a.length;c",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(l.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},l.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(l.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(l.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=k,b=c.createElement("div"),d="__sizzle__";b.innerHTML="

";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){k=function(b,e,f,g){e=e||c;if(!g&&!k.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return p(e.getElementsByTagName(b),f);if(h[2]&&l.find.CLASS&&e.getElementsByClassName)return p(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return p([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return p([],f);if(i.id===h[3])return p([i],f)}try{return p(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var m=e,n=e.getAttribute("id"),o=n||d,q=e.parentNode,r=/^\s*[+~]/.test(b);n?o=o.replace(/'/g,"\\$&"):e.setAttribute("id",o),r&&q&&(e=e.parentNode);try{if(!r||q)return p(e.querySelectorAll("[id='"+o+"'] "+b),f)}catch(s){}finally{n||m.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)k[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}k.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(a))try{if(e||!l.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return k(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="
";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;l.order.splice(1,0,"CLASS"),l.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?k.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?k.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:k.contains=function(){return!1},k.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var v=function(a,b){var c,d=[],e="",f=b.nodeType?[b]:b;while(c=l.match.PSEUDO.exec(a))e+=c[0],a=a.replace(l.match.PSEUDO,"");a=l.relative[a]?a+"*":a;for(var g=0,h=f.length;g0)for(h=g;h0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h,i,j={},k=1;if(g&&a.length){for(d=0,e=a.length;d-1:f(g).is(h))&&c.push({selector:i,elem:g,level:k});g=g.parentNode,k++}}return c}var l=S.test(a)||typeof a!="string"?f(a,b||this.context):0;for(d=0,e=this.length;d-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a=="string")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(U(c[0])||U(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c),g=R.call(arguments);N.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!T[a]?f.unique(e):e,(this.length>1||P.test(d))&&O.test(a)&&(e=e.reverse());return this.pushStack(e,a,g.join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var W=/ jQuery\d+="(?:\d+|null)"/g,X=/^\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Z=/<([\w:]+)/,$=/",""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]};be.optgroup=be.option,be.tbody=be.tfoot=be.colgroup=be.caption=be.thead,be.th=be.td,f.support.htmlSerialize||(be._default=[1,"div
","
"]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){f(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f(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,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f(arguments[0]).toArray());return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!be[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1>");try{for(var c=0,d=this.length;c1&&l0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d=a.cloneNode(!0),e,g,h;if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bh(a,d),e=bi(a),g=bi(d);for(h=0;e[h];++h)g[h]&&bh(e[h],g[h])}if(b){bg(a,d);if(c){e=bi(a),g=bi(d);for(h=0;e[h];++h)bg(e[h],g[h])}}e=g=null;return d},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!_.test(k))k=b.createTextNode(k);else{k=k.replace(Y,"<$1>");var l=(Z.exec(k)||["",""])[1].toLowerCase(),m=be[l]||be._default,n=m[0],o=b.createElement("div");o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=$.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]===""&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&X.test(k)&&o.insertBefore(b.createTextNode(X.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return bn.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNaN(b)?"":"alpha(opacity="+b*100+")",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bm,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bm.test(g)?g.replace(bm,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bv(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bw=function(a,c){var d,e,g;c=c.replace(bo,"-$1").toLowerCase();if(!(e=a.ownerDocument.defaultView))return b;if(g=e.getComputedStyle(a,null))d=g.getPropertyValue(c),d===""&&!f.contains(a.ownerDocument.documentElement,a)&&(d=f.style(a,c));return d}),c.documentElement.currentStyle&&(bx=function(a,b){var c,d=a.currentStyle&&a.currentStyle[b],e=a.runtimeStyle&&a.runtimeStyle[b],f=a.style;!bp.test(d)&&bq.test(d)&&(c=f.left,e&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":d||0,d=f.pixelLeft+"px",f.left=c,e&&(a.runtimeStyle.left=e));return d===""?"auto":d}),bv=bw||bx,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bz=/%20/g,bA=/\[\]$/,bB=/\r?\n/g,bC=/#.*$/,bD=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bE=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bF=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bG=/^(?:GET|HEAD)$/,bH=/^\/\//,bI=/\?/,bJ=/)<[^<]*)*<\/script>/gi,bK=/^(?:select|textarea)/i,bL=/\s+/,bM=/([?&])_=[^&]*/,bN=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bO=f.fn.load,bP={},bQ={},bR,bS,bT=["*/"]+["*"];try{bR=e.href}catch(bU){bR=c.createElement("a"),bR.href="",bR=bR.href}bS=bN.exec(bR.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bO)return bO.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("
").append(c.replace(bJ,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bK.test(this.nodeName)||bE.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bB,"\r\n")}}):{name:b.name,value:c.replace(bB,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.bind(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?bX(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),bX(a,b);return a},ajaxSettings:{url:bR,isLocal:bF.test(bS[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":bT},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:bV(bP),ajaxTransport:bV(bQ),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?bZ(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader("Last-Modified"))f.lastModified[k]=y;if(z=v.getResponseHeader("Etag"))f.etag[k]=z}if(a===304)w="notmodified",o=!0;else try{r=b$(d,x),w="success",o=!0}catch(A){w="parsererror",u=A}}else{u=w;if(!w||a)w="error",a<0&&(a=0)}v.status=a,v.statusText=""+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.resolveWith(e,[v,w]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f._Deferred(),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bD.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.done,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bC,"").replace(bH,bS[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bL),d.crossDomain==null&&(r=bN.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bS[1]&&r[2]==bS[2]&&(r[3]||(r[1]==="http:"?80:443))==(bS[3]||(bS[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),bW(bP,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bG.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bI.test(d.url)?"&":"?")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bM,"$1_="+x);d.url=y+(y===d.url?(bI.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", "+bT+"; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=bW(bQ,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){s<2?w(-1,z):f.error(z)}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)bY(g,a[g],c,e);return d.join("&").replace(bz,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var b_=f.now(),ca=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+b_++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(ca.test(b.url)||e&&ca.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(ca,l),b.url===j&&(e&&(k=k.replace(ca,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var cb=a.ActiveXObject?function(){for(var a in cd)cd[a](0,1)}:!1,cc=0,cd;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ce()||cf()}:ce,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,cb&&delete cd[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cc,cb&&(cd||(cd={},f(a).unload(cb)),cd[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var cg={},ch,ci,cj=/^(?:toggle|show|hide)$/,ck=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,cl,cm=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cn;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cq("show",3),a,b,c);for(var g=0,h=this.length;g=e.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),e.animatedProperties[this.prop]=!0;for(g in e.animatedProperties)e.animatedProperties[g]!==!0&&(c=!1);if(c){e.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){d.style["overflow"+b]=e.overflow[a]}),e.hide&&f(d).hide();if(e.hide||e.show)for(var i in e.animatedProperties)f.style(d,i,e.orig[i]);e.complete.call(d)}return!1}e.duration==Infinity?this.now=b:(h=b-this.startTime,this.state=h/e.duration,this.pos=f.easing[e.animatedProperties[this.prop]](this.state,h,0,1,e.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){for(var a=f.timers,b=0;b
";f.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"}),b.innerHTML=j,a.insertBefore(b,a.firstChild),d=b.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,this.doesNotAddBorder=e.offsetTop!==5,this.doesAddBorderForTableAndCells=h.offsetTop===5,e.style.position="fixed",e.style.top="20px",this.supportsFixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top="",d.style.overflow="hidden",d.style.position="relative",this.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==i,a.removeChild(b),f.offset.initialize=f.noop},bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;f.offset.initialize(),f.offset.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(f.css(a,"marginTop"))||0,c+=parseFloat(f.css(a,"marginLeft"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var d=f.css(a,"position");d==="static"&&(a.style.position="relative");var e=f(a),g=e.offset(),h=f.css(a,"top"),i=f.css(a,"left"),j=(d==="absolute"||d==="fixed")&&f.inArray("auto",[h,i])>-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=ct.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!ct.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cu(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cu(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){var a=this[0];return a&&a.style?parseFloat(f.css(a,d,"padding")):null},f.fn["outer"+c]=function(a){var b=this[0];return b&&b.style?parseFloat(f.css(b,d,a?"margin":"border")):null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c],h=e.document.body;return e.document.compatMode==="CSS1Compat"&&g||h&&h["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var i=f.css(e,d),j=parseFloat(i);return f.isNaN(j)?i:j}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f})(window); \ No newline at end of file diff --git a/frameworks/Java/play1/test/Application.test.html b/frameworks/Java/play1/test/Application.test.html deleted file mode 100644 index 2b0ad094b67..00000000000 --- a/frameworks/Java/play1/test/Application.test.html +++ /dev/null @@ -1,7 +0,0 @@ -*{ You can use plain selenium command using the selenium tag }* - -#{selenium} - // Open the home page, and check that no error occured - open('/') - assertNotTitle('Application error') -#{/selenium} \ No newline at end of file diff --git a/frameworks/Java/play1/test/ApplicationTest.java b/frameworks/Java/play1/test/ApplicationTest.java deleted file mode 100644 index f1501cbbdba..00000000000 --- a/frameworks/Java/play1/test/ApplicationTest.java +++ /dev/null @@ -1,17 +0,0 @@ -import org.junit.*; -import play.test.*; -import play.mvc.*; -import play.mvc.Http.*; -import models.*; - -public class ApplicationTest extends FunctionalTest { - - @Test - public void testThatIndexPageWorks() { - Response response = GET("/"); - assertIsOk(response); - assertContentType("text/html", response); - assertCharset(play.Play.defaultWebEncoding, response); - } - -} \ No newline at end of file diff --git a/frameworks/Java/play1/test/BasicTest.java b/frameworks/Java/play1/test/BasicTest.java deleted file mode 100644 index d039860fa30..00000000000 --- a/frameworks/Java/play1/test/BasicTest.java +++ /dev/null @@ -1,13 +0,0 @@ -import org.junit.*; -import java.util.*; -import play.test.*; -import models.*; - -public class BasicTest extends UnitTest { - - @Test - public void aVeryImportantThingToTest() { - assertEquals(2, 1 + 1); - } - -} diff --git a/frameworks/Java/play1/test/data.yml b/frameworks/Java/play1/test/data.yml deleted file mode 100644 index 77b04bb14b2..00000000000 --- a/frameworks/Java/play1/test/data.yml +++ /dev/null @@ -1,7 +0,0 @@ -# you describe your data using the YAML notation here -# and then load them using Fixtures.load("data.yml") - -# User(bob): -# email: bob@gmail.com -# password: secret -# fullname: Bob \ No newline at end of file diff --git a/frameworks/Java/proteus/pom.xml b/frameworks/Java/proteus/pom.xml index cb4a0fe1a90..6840966094d 100644 --- a/frameworks/Java/proteus/pom.xml +++ b/frameworks/Java/proteus/pom.xml @@ -252,7 +252,7 @@ org.postgresql postgresql - 42.4.3 + 42.7.2 diff --git a/frameworks/Java/quarkus/benchmark_config.json b/frameworks/Java/quarkus/benchmark_config.json index 9b838d3e98a..dd7fa017935 100644 --- a/frameworks/Java/quarkus/benchmark_config.json +++ b/frameworks/Java/quarkus/benchmark_config.json @@ -1,5 +1,6 @@ { "framework": "quarkus", + "maintainers": ["franz1981", "Sanne", "geoand"], "tests": [ { "default": { @@ -21,7 +22,7 @@ "webserver": "Vert.x", "os": "Linux", "database_os": "Linux", - "display_name": "Quarkus, Hibernate ORM", + "display_name": "Quarkus, Hibernate", "notes": "", "versus": "Netty" }, @@ -44,9 +45,55 @@ "webserver": "Vert.x", "os": "Linux", "database_os": "Linux", - "display_name": "Quarkus, Hibernate Reactive", + "display_name": "Quarkus, Reactive", "notes": "", "versus": "Netty" + }, + "vertx": { + "json_url": "/json", + "db_url": "/db", + "query_url": "/queries?queries=", + "update_url": "/updates?queries=", + "fortune_url": "/fortunes", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "Postgres", + "framework": "Quarkus", + "language": "Java", + "flavor": "None", + "orm": "Raw", + "platform": "Vert.x", + "webserver": "Vert.x", + "os": "Linux", + "database_os": "Linux", + "display_name": "Quarkus, Vert.x", + "notes": "", + "versus": "Vert.x" + }, + "reactive-routes-pgclient": { + "json_url": "/json", + "db_url": "/db", + "query_url": "/queries?queries=", + "update_url": "/updates?queries=", + "fortune_url": "/fortunes", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "fullstack", + "database": "Postgres", + "framework": "Quarkus", + "language": "Java", + "flavor": "None", + "orm": "Raw", + "platform": "Vert.x", + "webserver": "Vert.x", + "os": "Linux", + "database_os": "Linux", + "display_name": "Quarkus, PostgreSQL", + "notes": "", + "versus": "Vert.x" } } ] diff --git a/frameworks/Java/quarkus/config.toml b/frameworks/Java/quarkus/config.toml index f6281628ac5..a11c64b4d76 100644 --- a/frameworks/Java/quarkus/config.toml +++ b/frameworks/Java/quarkus/config.toml @@ -34,3 +34,37 @@ orm = "Full" platform = "RESTEasy Reactive" webserver = "Vert.x" versus = "Netty" + +[vertx] +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 = "Vert.x" +webserver = "Vert.x" +versus = "Vert.x" + +[reactive-routes-pgclient] +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 = "Raw" +platform = "Vert.x" +webserver = "Vert.x" +versus = "Vert.x" diff --git a/frameworks/Java/quarkus/pom.xml b/frameworks/Java/quarkus/pom.xml index b0d16552e18..26dcb870c26 100644 --- a/frameworks/Java/quarkus/pom.xml +++ b/frameworks/Java/quarkus/pom.xml @@ -8,26 +8,26 @@ pom - 3.11.0 - 17 + 3.14.0 + 21 UTF-8 UTF-8 quarkus-bom io.quarkus - 3.2.0.Final + 3.21.2 true - 3.0.0 - 0.0.21.Final - 4.4.4 + 3.5.2 + + 0.0.26.Final 1.3.0 - 6.2.6.Final - 2.0.2.Final quarkus-benchmark-common resteasy-reactive-hibernate resteasy-reactive-hibernate-reactive + vertx + reactive-routes-pgclient @@ -40,17 +40,10 @@ org.hibernate.orm hibernate-core - ${hibernate-orm.version} org.hibernate.reactive hibernate-reactive-core - ${hibernate-reactive.version} - - - io.vertx - vertx-core - ${vertx.version} ${quarkus.platform.group-id} @@ -149,7 +142,6 @@ io.vertx vertx-io_uring-incubator - ${vertx.version} io.netty.incubator diff --git a/frameworks/Java/quarkus/quarkus-hibernate-reactive.dockerfile b/frameworks/Java/quarkus/quarkus-hibernate-reactive.dockerfile index 8e671d7d02f..861dd3b042a 100644 --- a/frameworks/Java/quarkus/quarkus-hibernate-reactive.dockerfile +++ b/frameworks/Java/quarkus/quarkus-hibernate-reactive.dockerfile @@ -1,4 +1,4 @@ -FROM registry.access.redhat.com/ubi8/openjdk-17:1.15 as maven +FROM registry.access.redhat.com/ubi9/openjdk-21:1.22 as maven ENV LANGUAGE='en_US:en' WORKDIR /quarkus @@ -8,6 +8,8 @@ COPY --chown=185 pom.xml pom.xml COPY --chown=185 quarkus-benchmark-common quarkus-benchmark-common/ COPY --chown=185 resteasy-reactive-hibernate resteasy-reactive-hibernate/ COPY --chown=185 resteasy-reactive-hibernate-reactive resteasy-reactive-hibernate-reactive/ +COPY --chown=185 vertx vertx/ +COPY --chown=185 reactive-routes-pgclient reactive-routes-pgclient/ # Uncomment to test pre-release quarkus #RUN mkdir -p /root/.m2/repository/io @@ -27,7 +29,7 @@ WORKDIR /quarkus/$MODULE RUN mvn package -B -q WORKDIR /quarkus -FROM registry.access.redhat.com/ubi8/openjdk-17-runtime:1.15 +FROM registry.access.redhat.com/ubi9/openjdk-21-runtime:1.22 ENV LANGUAGE='en_US:en' WORKDIR /quarkus ENV MODULE=resteasy-reactive-hibernate-reactive diff --git a/frameworks/Java/quarkus/quarkus-reactive-routes-pgclient.dockerfile b/frameworks/Java/quarkus/quarkus-reactive-routes-pgclient.dockerfile new file mode 100644 index 00000000000..21e918be45c --- /dev/null +++ b/frameworks/Java/quarkus/quarkus-reactive-routes-pgclient.dockerfile @@ -0,0 +1,45 @@ +FROM registry.access.redhat.com/ubi9/openjdk-21:1.22 as maven +ENV LANGUAGE='en_US:en' + +WORKDIR /quarkus +ENV MODULE=reactive-routes-pgclient + +COPY --chown=185 pom.xml pom.xml +COPY --chown=185 quarkus-benchmark-common quarkus-benchmark-common/ +COPY --chown=185 resteasy-reactive-hibernate resteasy-reactive-hibernate/ +COPY --chown=185 resteasy-reactive-hibernate-reactive resteasy-reactive-hibernate-reactive/ +COPY --chown=185 vertx vertx/ +COPY --chown=185 reactive-routes-pgclient reactive-routes-pgclient/ + +# Uncomment to test pre-release quarkus +#RUN mkdir -p /root/.m2/repository/io +#COPY m2-quarkus /root/.m2/repository/io/quarkus + +USER 185 +WORKDIR /quarkus +RUN mvn -DskipTests install -pl :benchmark,:quarkus-benchmark-common -B -q + +WORKDIR /quarkus/$MODULE +RUN mvn dependency:go-offline -B -q +WORKDIR /quarkus + +COPY $MODULE/src $MODULE/src + +WORKDIR /quarkus/$MODULE +RUN mvn package -B -q +WORKDIR /quarkus + +FROM registry.access.redhat.com/ubi9/openjdk-21-runtime:1.22 +ENV LANGUAGE='en_US:en' +WORKDIR /quarkus +ENV MODULE=reactive-routes-pgclient + +COPY --chown=185 --from=maven /quarkus/$MODULE/target/quarkus-app/lib/ lib +COPY --chown=185 --from=maven /quarkus/$MODULE/target/quarkus-app/app/ app +COPY --chown=185 --from=maven /quarkus/$MODULE/target/quarkus-app/quarkus/ quarkus +COPY --chown=185 --from=maven /quarkus/$MODULE/target/quarkus-app/quarkus-run.jar quarkus-run.jar +COPY --chown=185 run_quarkus.sh run_quarkus.sh + +EXPOSE 8080 +USER 185 +ENTRYPOINT "./run_quarkus.sh" diff --git a/frameworks/Java/quarkus/quarkus-vertx.dockerfile b/frameworks/Java/quarkus/quarkus-vertx.dockerfile new file mode 100644 index 00000000000..6969bc6d7ba --- /dev/null +++ b/frameworks/Java/quarkus/quarkus-vertx.dockerfile @@ -0,0 +1,45 @@ +FROM registry.access.redhat.com/ubi9/openjdk-21:1.22 as maven +ENV LANGUAGE='en_US:en' + +WORKDIR /quarkus +ENV MODULE=vertx + +COPY --chown=185 pom.xml pom.xml +COPY --chown=185 quarkus-benchmark-common quarkus-benchmark-common/ +COPY --chown=185 resteasy-reactive-hibernate resteasy-reactive-hibernate/ +COPY --chown=185 resteasy-reactive-hibernate-reactive resteasy-reactive-hibernate-reactive/ +COPY --chown=185 vertx vertx/ +COPY --chown=185 reactive-routes-pgclient reactive-routes-pgclient/ + +# Uncomment to test pre-release quarkus +#RUN mkdir -p /root/.m2/repository/io +#COPY m2-quarkus /root/.m2/repository/io/quarkus + +USER 185 +WORKDIR /quarkus +RUN mvn -DskipTests install -pl :benchmark,:quarkus-benchmark-common -B -q + +WORKDIR /quarkus/$MODULE +RUN mvn dependency:go-offline -B -q +WORKDIR /quarkus + +COPY $MODULE/src $MODULE/src + +WORKDIR /quarkus/$MODULE +RUN mvn package -B -q +WORKDIR /quarkus + +FROM registry.access.redhat.com/ubi9/openjdk-21-runtime:1.22 +ENV LANGUAGE='en_US:en' +WORKDIR /quarkus +ENV MODULE=vertx + +COPY --chown=185 --from=maven /quarkus/$MODULE/target/quarkus-app/lib/ lib +COPY --chown=185 --from=maven /quarkus/$MODULE/target/quarkus-app/app/ app +COPY --chown=185 --from=maven /quarkus/$MODULE/target/quarkus-app/quarkus/ quarkus +COPY --chown=185 --from=maven /quarkus/$MODULE/target/quarkus-app/quarkus-run.jar quarkus-run.jar +COPY --chown=185 run_quarkus.sh run_quarkus.sh + +EXPOSE 8080 +USER 185 +ENTRYPOINT "./run_quarkus.sh" diff --git a/frameworks/Java/quarkus/quarkus.dockerfile b/frameworks/Java/quarkus/quarkus.dockerfile index 05ad3c1896e..40ec7a4ded7 100644 --- a/frameworks/Java/quarkus/quarkus.dockerfile +++ b/frameworks/Java/quarkus/quarkus.dockerfile @@ -1,4 +1,4 @@ -FROM registry.access.redhat.com/ubi8/openjdk-17:1.15 as maven +FROM registry.access.redhat.com/ubi9/openjdk-21:1.22 as maven ENV LANGUAGE='en_US:en' WORKDIR /quarkus @@ -8,6 +8,8 @@ COPY --chown=185 pom.xml pom.xml COPY --chown=185 quarkus-benchmark-common quarkus-benchmark-common/ COPY --chown=185 resteasy-reactive-hibernate resteasy-reactive-hibernate/ COPY --chown=185 resteasy-reactive-hibernate-reactive resteasy-reactive-hibernate-reactive/ +COPY --chown=185 vertx vertx/ +COPY --chown=185 reactive-routes-pgclient reactive-routes-pgclient/ # Uncomment to test pre-release quarkus #RUN mkdir -p /root/.m2/repository/io @@ -27,7 +29,7 @@ WORKDIR /quarkus/$MODULE RUN mvn package -B -q WORKDIR /quarkus -FROM registry.access.redhat.com/ubi8/openjdk-17-runtime:1.15 +FROM registry.access.redhat.com/ubi9/openjdk-21-runtime:1.22 ENV LANGUAGE='en_US:en' WORKDIR /quarkus ENV MODULE=resteasy-reactive-hibernate diff --git a/frameworks/Java/quarkus/reactive-routes-pgclient/pom.xml b/frameworks/Java/quarkus/reactive-routes-pgclient/pom.xml new file mode 100644 index 00000000000..599183b4656 --- /dev/null +++ b/frameworks/Java/quarkus/reactive-routes-pgclient/pom.xml @@ -0,0 +1,86 @@ + + + 4.0.0 + + io.quarkus + benchmark + 1.0-SNAPSHOT + + + reactive-routes-pgclient + + + + io.quarkus + quarkus-benchmark-common + + + io.quarkus + quarkus-reactive-pg-client + + + io.quarkus + quarkus-scheduler + + + io.quarkus + quarkus-reactive-routes + + + io.vertx + vertx-web + + + io.vertx + vertx-web-templ-rocker + + + + com.google.guava + guava + 32.0.0-jre + + + io.netty + netty-transport-native-epoll + linux-x86_64 + + + + + + + com.fizzed + rocker-maven-plugin + 1.3.0 + + + generate-rocker-templates + generate-sources + + generate + + + ${project.basedir}/src/main/resources + true + true + false + + + + + + + com.google.guava + guava + 32.0.0-jre + + + + + + + + \ No newline at end of file diff --git a/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/java/io/quarkus/benchmark/filter/ServerHeaderFilter.java b/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/java/io/quarkus/benchmark/filter/ServerHeaderFilter.java new file mode 100644 index 00000000000..d9bc3ce8a66 --- /dev/null +++ b/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/java/io/quarkus/benchmark/filter/ServerHeaderFilter.java @@ -0,0 +1,36 @@ +package io.quarkus.benchmark.filter; + +import io.quarkus.scheduler.Scheduled; +import io.quarkus.vertx.web.RouteFilter; +import io.vertx.core.http.HttpHeaders; +import io.vertx.ext.web.RoutingContext; +import jakarta.annotation.PostConstruct; +import jakarta.inject.Singleton; + +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; + +@Singleton +public class ServerHeaderFilter { + + private static final CharSequence SERVER_HEADER_VALUE = HttpHeaders.createOptimized("Quarkus"); + private CharSequence date; + + @PostConstruct + public void init() { + updateDate(); + } + + @Scheduled(every = "1s") + void updateDate() { + date = HttpHeaders.createOptimized(DateTimeFormatter.RFC_1123_DATE_TIME.format(ZonedDateTime.now())); + } + + @RouteFilter(100) + void addDefaultHeaders(final RoutingContext rc) { + final var headers = rc.response().headers(); + headers.add(HttpHeaders.SERVER, SERVER_HEADER_VALUE); + headers.add(HttpHeaders.DATE, date); + rc.next(); + } +} \ No newline at end of file diff --git a/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/java/io/quarkus/benchmark/model/Fortune.java b/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/java/io/quarkus/benchmark/model/Fortune.java new file mode 100644 index 00000000000..ed941d8b505 --- /dev/null +++ b/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/java/io/quarkus/benchmark/model/Fortune.java @@ -0,0 +1,25 @@ +package io.quarkus.benchmark.model; + +public class Fortune implements Comparable { + + private final int id; + private final String message; + + public Fortune(final int id, final String message) { + this.id = id; + this.message = message; + } + + public int getId() { + return id; + } + + public String getMessage() { + return message; + } + + @Override + public int compareTo(final Fortune other) { + return message.compareTo(other.message); + } +} \ No newline at end of file diff --git a/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/java/io/quarkus/benchmark/model/World.java b/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/java/io/quarkus/benchmark/model/World.java new file mode 100644 index 00000000000..f56b7dd0850 --- /dev/null +++ b/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/java/io/quarkus/benchmark/model/World.java @@ -0,0 +1,29 @@ +package io.quarkus.benchmark.model; + +public class World implements Comparable { + + private final Integer id; + private Integer randomNumber; + + public World(final Integer id, final Integer randomNumber) { + this.id = id; + this.randomNumber = randomNumber; + } + + public Integer getId() { + return id; + } + + public int getRandomNumber() { + return randomNumber; + } + + public void setRandomNumber(final Integer randomNumber) { + this.randomNumber = randomNumber; + } + + @Override + public int compareTo(final World o) { + return id.compareTo(o.id); + } +} \ No newline at end of file diff --git a/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/java/io/quarkus/benchmark/repository/FortuneRepository.java b/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/java/io/quarkus/benchmark/repository/FortuneRepository.java new file mode 100644 index 00000000000..bba1ae2e4c7 --- /dev/null +++ b/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/java/io/quarkus/benchmark/repository/FortuneRepository.java @@ -0,0 +1,29 @@ +package io.quarkus.benchmark.repository; + +import java.util.ArrayList; +import java.util.List; + +import io.quarkus.benchmark.model.Fortune; +import io.smallrye.mutiny.Uni; +import io.vertx.mutiny.sqlclient.Row; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; + +@Singleton +public class FortuneRepository { + + @Inject + PgClients clients; + + public Uni> findAll() { + return clients.getClient().preparedQuery("SELECT * FROM Fortune") + .execute() + .map(rowset -> { + final List ret = new ArrayList<>(rowset.size() + 1); + for (final Row r : rowset) { + ret.add(new Fortune(r.getInteger(0), r.getString(1))); + } + return ret; + }); + } +} \ No newline at end of file diff --git a/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/java/io/quarkus/benchmark/repository/PgClientFactory.java b/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/java/io/quarkus/benchmark/repository/PgClientFactory.java new file mode 100644 index 00000000000..77297726a79 --- /dev/null +++ b/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/java/io/quarkus/benchmark/repository/PgClientFactory.java @@ -0,0 +1,58 @@ +package io.quarkus.benchmark.repository; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import io.vertx.mutiny.sqlclient.SqlClient; +import jakarta.enterprise.inject.Produces; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; +import org.eclipse.microprofile.config.inject.ConfigProperty; + +import io.vertx.mutiny.core.Vertx; +import io.vertx.mutiny.pgclient.PgPool; +import io.vertx.pgclient.PgConnectOptions; +import io.vertx.sqlclient.PoolOptions; + +@Singleton +public class PgClientFactory { + + // vertx-reactive:postgresql://tfb-database:5432/hello_world + private static final String PG_URI_MATCHER = "vertx-reactive:postgresql://([-a-zA-Z]+):([0-9]+)/(.*)"; + + @ConfigProperty(name = "quarkus.datasource.url") + String url; + + @ConfigProperty(name = "quarkus.datasource.username") + String user; + + @ConfigProperty(name = "quarkus.datasource.password") + String pass; + + @Inject + Vertx vertx; + + @Produces + @Singleton + public PgClients pgClients() { + return new PgClients(this); + } + + + SqlClient sqlClient(final int size) { + final PoolOptions options = new PoolOptions(); + final PgConnectOptions connectOptions = new PgConnectOptions(); + final Matcher matcher = Pattern.compile(PG_URI_MATCHER).matcher(url); + matcher.matches(); + connectOptions.setDatabase(matcher.group(3)); + connectOptions.setHost(matcher.group(1)); + connectOptions.setPort(Integer.parseInt(matcher.group(2))); + connectOptions.setUser(user); + connectOptions.setPassword(pass); + connectOptions.setCachePreparedStatements(true); + // Large pipelining means less flushing and we use a single connection anyway + connectOptions.setPipeliningLimit(100_000); + options.setMaxSize(size); + return PgPool.client(vertx, connectOptions, options); + } +} \ No newline at end of file diff --git a/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/java/io/quarkus/benchmark/repository/PgClients.java b/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/java/io/quarkus/benchmark/repository/PgClients.java new file mode 100644 index 00000000000..8b54a9cab24 --- /dev/null +++ b/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/java/io/quarkus/benchmark/repository/PgClients.java @@ -0,0 +1,33 @@ +package io.quarkus.benchmark.repository; + +import io.netty.util.concurrent.FastThreadLocal; +import io.vertx.mutiny.sqlclient.SqlClient; + +class PgClients { + private final FastThreadLocal sqlClient = new FastThreadLocal<>() { + @Override + protected void onRemoval(final SqlClient value) { + if (value != null) { + value.close(); + } + } + }; + private PgClientFactory pgClientFactory; + + // for ArC + public PgClients() { + } + + public PgClients(final PgClientFactory pgClientFactory) { + this.pgClientFactory = pgClientFactory; + } + + SqlClient getClient() { + SqlClient ret = sqlClient.get(); + if (ret == null) { + ret = pgClientFactory.sqlClient(1); + sqlClient.set(ret); + } + return ret; + } +} \ No newline at end of file diff --git a/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/java/io/quarkus/benchmark/repository/WorldRepository.java b/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/java/io/quarkus/benchmark/repository/WorldRepository.java new file mode 100644 index 00000000000..630be2b3861 --- /dev/null +++ b/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/java/io/quarkus/benchmark/repository/WorldRepository.java @@ -0,0 +1,59 @@ +package io.quarkus.benchmark.repository; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import io.quarkus.benchmark.model.World; +import io.smallrye.mutiny.Uni; +import io.vertx.core.json.JsonObject; +import io.vertx.mutiny.sqlclient.Row; +import io.vertx.mutiny.sqlclient.Tuple; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; + +@Singleton +public class WorldRepository { + + //like muggle's JsonWorld + public static class JsonWorld extends JsonObject { + public JsonWorld(final Integer id, final Integer randomNumber) { + super(Map.of("id", id, "randomNumber", randomNumber)); + } + } + + + @Inject + PgClients clients; + + + public Uni findAsJsonWorld(final Integer id) { + return clients.getClient().preparedQuery("SELECT id, randomNumber FROM World WHERE id = $1") + .execute(Tuple.of(id)) + .map(rowset -> { + final Row row = rowset.iterator().next(); + return new JsonWorld(row.getInteger(0), row.getInteger(1)); + }); + } + + public Uni find(final Integer id) { + return clients.getClient().preparedQuery("SELECT id, randomNumber FROM World WHERE id = $1") + .execute(Tuple.of(id)) + .map(rowset -> { + final Row row = rowset.iterator().next(); + return new World(row.getInteger(0), row.getInteger(1)); + }); + } + + public Uni update(final World[] worlds) { + Arrays.sort(worlds); + final List args = new ArrayList<>(worlds.length); + for (final World world : worlds) { + args.add(Tuple.of(world.getId(), world.getRandomNumber())); + } + return clients.getClient().preparedQuery("UPDATE World SET randomNumber = $2 WHERE id = $1") + .executeBatch(args) + .map(v -> null); + } +} diff --git a/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/java/io/quarkus/benchmark/resource/BaseResource.java b/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/java/io/quarkus/benchmark/resource/BaseResource.java new file mode 100644 index 00000000000..13a14912ce2 --- /dev/null +++ b/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/java/io/quarkus/benchmark/resource/BaseResource.java @@ -0,0 +1,32 @@ +package io.quarkus.benchmark.resource; + +import io.netty.handler.codec.http.HttpHeaderValues; +import io.vertx.core.http.HttpHeaders; +import io.vertx.core.json.JsonArray; +import io.vertx.core.json.JsonObject; +import io.vertx.core.json.jackson.JacksonCodec; +import io.vertx.ext.web.RoutingContext; + +public abstract class BaseResource { + + // TODO verify how to override/replace io.quarkus.vertx.runtime.jackson.QuarkusJacksonFactory in io.vertx.core.spi.JsonFactory + private static final JacksonCodec JACKSON_CODEC = new JacksonCodec(); + + void sendJson(final RoutingContext rc, final JsonObject json) { + var response = rc.response(); + response.headers().add(HttpHeaders.CONTENT_TYPE, HttpHeaderValues.APPLICATION_JSON); + response.end(JACKSON_CODEC.toBuffer(json, false), null); + } + + void sendJson(final RoutingContext rc, final JsonArray json) { + var response = rc.response(); + response.headers().add(HttpHeaders.CONTENT_TYPE, HttpHeaderValues.APPLICATION_JSON); + response.end(JACKSON_CODEC.toBuffer(json, false), null); + } + + Void handleFail(final RoutingContext rc, final Throwable t) { + rc.response().setStatusCode(500).end(t.toString()); + return null; + } + +} \ No newline at end of file diff --git a/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/java/io/quarkus/benchmark/resource/DbResource.java b/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/java/io/quarkus/benchmark/resource/DbResource.java new file mode 100644 index 00000000000..4237a81f8dc --- /dev/null +++ b/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/java/io/quarkus/benchmark/resource/DbResource.java @@ -0,0 +1,102 @@ +package io.quarkus.benchmark.resource; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.concurrent.ThreadLocalRandom; +import java.util.stream.IntStream; + +import io.quarkus.benchmark.model.World; +import io.quarkus.benchmark.repository.WorldRepository; +import io.quarkus.benchmark.repository.WorldRepository.JsonWorld; +import io.quarkus.vertx.web.Route; +import io.smallrye.mutiny.Uni; +import io.vertx.core.json.JsonArray; +import io.vertx.ext.web.RoutingContext; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; + + +@Singleton +public class DbResource extends BaseResource { + + @Inject + WorldRepository worldRepository; + + @Route(path = "db") + public void db(final RoutingContext rc) { + worldRepository.findAsJsonWorld(boxedRandomWorldNumber()) + .subscribe().with(world -> sendJson(rc, world), + t -> handleFail(rc, t)); + } + + @Route(path = "queries") + public void queries(final RoutingContext rc) { + final var queries = rc.request().getParam("queries"); + final var worlds = new Uni[parseQueryCount(queries)]; + final var ret = new JsonWorld[worlds.length]; + // replace below with a for loop + Arrays.setAll(worlds, i -> { + return worldRepository.findAsJsonWorld(boxedRandomWorldNumber()).map(w -> ret[i] = w); + }); + + Uni.combine().all().unis(worlds) + .with(v -> Arrays.asList(ret)) + .subscribe().with(list -> { + sendJson(rc, new JsonArray(list)); + }, + t -> handleFail(rc, t)); + } + + @Route(path = "updates") + public void updates(final RoutingContext rc) { + final var queries = rc.request().getParam("queries"); + final var worlds = new Uni[parseQueryCount(queries)]; + final var wordsToUpdate = new World[worlds.length]; + Arrays.setAll(worlds, i -> { + return randomWorld().map(w -> { + w.setRandomNumber(boxedRandomWorldNumber()); + wordsToUpdate[i] = w; + return w; + }); + }); + + Uni.combine().all().unis(worlds) + .with(v -> null) + .flatMap(v -> worldRepository.update(wordsToUpdate)) + .map(updated -> wordsToUpdate) + .subscribe().with(updatedWordsOrderedById -> { + final var jsonWorlds = new JsonArray(new ArrayList<>(updatedWordsOrderedById.length)); + for (final World world : updatedWordsOrderedById) { + jsonWorlds.add(new JsonWorld(world.getId(), world.getRandomNumber())); + } + sendJson(rc, jsonWorlds); + }, + t -> handleFail(rc, t)); + } + + private Uni randomWorld() { + return worldRepository.find(boxedRandomWorldNumber()); + } + + private static final Integer[] BOXED_RND = IntStream.range(1, 10001).boxed().toArray(Integer[]::new); + + private static Integer boxedRandomWorldNumber() { + final int rndValue = ThreadLocalRandom.current().nextInt(1, 10001); + final var boxedRnd = BOXED_RND[rndValue - 1]; + assert boxedRnd.intValue() == rndValue; + return boxedRnd; + } + + private static int parseQueryCount(final String textValue) { + if (textValue == null) { + return 1; + } + final int parsedValue; + try { + parsedValue = Integer.parseInt(textValue); + } catch (final NumberFormatException e) { + return 1; + } + return Math.min(500, Math.max(1, parsedValue)); + } +} \ No newline at end of file diff --git a/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/java/io/quarkus/benchmark/resource/FortuneResource.java b/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/java/io/quarkus/benchmark/resource/FortuneResource.java new file mode 100644 index 00000000000..5289a52a194 --- /dev/null +++ b/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/java/io/quarkus/benchmark/resource/FortuneResource.java @@ -0,0 +1,43 @@ +package io.quarkus.benchmark.resource; + +import java.util.Collections; + +import io.quarkus.benchmark.model.Fortune; +import io.quarkus.benchmark.rocker.VertxRawRockerOutputFactories; +import io.quarkus.benchmark.repository.FortuneRepository; +import io.quarkus.vertx.web.Route; +import io.vertx.core.http.HttpHeaders; +import io.vertx.ext.web.RoutingContext; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; +import views.Fortunes; + +@Singleton +public class FortuneResource extends BaseResource { + + private static final CharSequence HTML_UTF8_CONTENT_TYPE = HttpHeaders.createOptimized("text/html; charset=UTF-8"); + + @Inject + FortuneRepository repository; + @Inject + VertxRawRockerOutputFactories factories; + + public FortuneResource() { + + } + + @Route(path = "fortunes") + public void fortunes(final RoutingContext rc) { + repository.findAll() + .subscribe() + .with(fortunes -> { + fortunes.add(new Fortune(0, "Additional fortune added at request time.")); + Collections.sort(fortunes); + final var vertxRockerOutput = Fortunes.template(fortunes).render(factories.ioFactory()); + var res = rc.response(); + res.headers().add(HttpHeaders.CONTENT_TYPE, HTML_UTF8_CONTENT_TYPE); + res.end(vertxRockerOutput.buffer(), null); + }, + t -> handleFail(rc, t)); + } +} \ No newline at end of file diff --git a/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/java/io/quarkus/benchmark/resource/JsonMessage.java b/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/java/io/quarkus/benchmark/resource/JsonMessage.java new file mode 100644 index 00000000000..5a2b743a19b --- /dev/null +++ b/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/java/io/quarkus/benchmark/resource/JsonMessage.java @@ -0,0 +1,12 @@ +package io.quarkus.benchmark.resource; + +import io.vertx.core.json.JsonObject; + +import java.util.Map; + +public class JsonMessage extends JsonObject { + + public JsonMessage(final String message) { + super(Map.of("message", message)); + } +} diff --git a/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/java/io/quarkus/benchmark/resource/JsonResource.java b/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/java/io/quarkus/benchmark/resource/JsonResource.java new file mode 100644 index 00000000000..d53a821b1d3 --- /dev/null +++ b/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/java/io/quarkus/benchmark/resource/JsonResource.java @@ -0,0 +1,17 @@ +package io.quarkus.benchmark.resource; + + +import io.quarkus.vertx.web.Route; +import io.vertx.ext.web.RoutingContext; +import jakarta.inject.Singleton; + +@Singleton +public class JsonResource extends BaseResource { + + private static final String HELLO = "Hello, World!"; + + @Route(path = "json") + public void json(final RoutingContext rc) { + sendJson(rc, new JsonMessage(HELLO)); + } +} diff --git a/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/java/io/quarkus/benchmark/resource/PlaintextResource.java b/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/java/io/quarkus/benchmark/resource/PlaintextResource.java new file mode 100644 index 00000000000..fcd24cadcfd --- /dev/null +++ b/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/java/io/quarkus/benchmark/resource/PlaintextResource.java @@ -0,0 +1,24 @@ +package io.quarkus.benchmark.resource; + +import io.netty.handler.codec.http.HttpHeaderValues; +import io.quarkus.vertx.web.Route; +import io.vertx.core.buffer.Buffer; +import io.vertx.core.http.HttpHeaders; +import io.vertx.ext.web.RoutingContext; +import jakarta.inject.Singleton; + +@Singleton +public class PlaintextResource { + 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 HELLO_WORLD_LENGTH = HttpHeaders.createOptimized("" + HELLO_WORLD.length()); + + @Route(path = "plaintext") + public void plaintext(final RoutingContext rc) { + final var response = rc.response(); + final var headers = response.headers(); + headers.add(HttpHeaders.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN); + headers.add(HttpHeaders.CONTENT_LENGTH, HELLO_WORLD_LENGTH); + response.end(HELLO_WORLD_BUFFER, null); + } +} \ No newline at end of file diff --git a/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/java/io/quarkus/benchmark/rocker/RawRockerOutput.java b/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/java/io/quarkus/benchmark/rocker/RawRockerOutput.java new file mode 100644 index 00000000000..8dd5bec161b --- /dev/null +++ b/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/java/io/quarkus/benchmark/rocker/RawRockerOutput.java @@ -0,0 +1,65 @@ +package io.quarkus.benchmark.rocker; + +import com.fizzed.rocker.ContentType; +import com.fizzed.rocker.RockerOutputFactory; +import io.netty.buffer.ByteBuf; +import io.vertx.core.buffer.Buffer; +import io.vertx.core.buffer.impl.PartialPooledByteBufAllocator; + +import java.io.IOException; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; + +final class RawRockerOutput implements VertxRawRockerOutput { + + private final ByteBuf buff = PartialPooledByteBufAllocator.INSTANCE.directBuffer(); + private final Buffer buffer = Buffer.buffer(buff); + + RawRockerOutput() { + } + + public static RockerOutputFactory raw() { + final RawRockerOutput output = new RawRockerOutput(); + return (_contentType, charsetName) -> { + output.reset(); + return output; + }; + } + + private void reset() { + buff.resetReaderIndex(); + buff.resetWriterIndex(); + } + + @Override + public RawRockerOutput w(final byte[] bytes) throws IOException { + buffer.appendBytes(bytes); + return this; + } + + @Override + public RawRockerOutput w(final String s) throws IOException { + buffer.appendString(s); + return this; + } + + @Override + public ContentType getContentType() { + return ContentType.RAW; + } + + @Override + public Charset getCharset() { + return StandardCharsets.UTF_8; + } + + @Override + public int getByteLength() { + return buffer.length(); + } + + @Override + public Buffer buffer() { + return buffer; + } +} diff --git a/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/java/io/quarkus/benchmark/rocker/VertxRawRockerOutput.java b/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/java/io/quarkus/benchmark/rocker/VertxRawRockerOutput.java new file mode 100644 index 00000000000..ada27e4e4bf --- /dev/null +++ b/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/java/io/quarkus/benchmark/rocker/VertxRawRockerOutput.java @@ -0,0 +1,15 @@ +package io.quarkus.benchmark.rocker; + +import com.fizzed.rocker.RockerOutputFactory; +import io.vertx.core.buffer.Buffer; + +public interface VertxRawRockerOutput extends com.fizzed.rocker.RockerOutput { + + // factory + static RockerOutputFactory factory() { + return RawRockerOutput.raw(); + } + + Buffer buffer(); + +} diff --git a/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/java/io/quarkus/benchmark/rocker/VertxRawRockerOutputFactories.java b/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/java/io/quarkus/benchmark/rocker/VertxRawRockerOutputFactories.java new file mode 100644 index 00000000000..faf834738c4 --- /dev/null +++ b/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/java/io/quarkus/benchmark/rocker/VertxRawRockerOutputFactories.java @@ -0,0 +1,29 @@ +package io.quarkus.benchmark.rocker; + +import com.fizzed.rocker.RockerOutputFactory; +import io.netty.util.concurrent.FastThreadLocal; +import io.vertx.core.Context; +import jakarta.inject.Singleton; + +@Singleton +public class VertxRawRockerOutputFactories { + + private final FastThreadLocal> ioPool; + + VertxRawRockerOutputFactories() { + ioPool = new FastThreadLocal<>() { + @Override + protected RockerOutputFactory initialValue() { + if (!Context.isOnEventLoopThread()) { + return null; + } + return VertxRawRockerOutput.factory(); + } + }; + } + + public RockerOutputFactory ioFactory() { + return ioPool.get(); + } + +} diff --git a/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/resources/application.properties b/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/resources/application.properties new file mode 100644 index 00000000000..1175db6f746 --- /dev/null +++ b/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/resources/application.properties @@ -0,0 +1,11 @@ +quarkus.datasource.url=vertx-reactive:postgresql://tfb-database:5432/hello_world +quarkus.datasource.username=benchmarkdbuser +quarkus.datasource.password=benchmarkdbpass +quarkus.datasource.reactive.max-size=64 +quarkus.log.console.enable=true +quarkus.log.console.level=INFO +quarkus.log.file.enable=false +quarkus.log.level=INFO +quarkus.vertx.prefer-native-transport=true + +quarkus.arc.context-propagation.enabled=false diff --git a/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/resources/import.sql b/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/resources/import.sql new file mode 100644 index 00000000000..f76881b4287 --- /dev/null +++ b/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/resources/import.sql @@ -0,0 +1 @@ +INSERT INTO Fortune(id, message) VALUES (1, 'Test value One'); \ No newline at end of file diff --git a/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/resources/views/Fortunes.rocker.html b/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/resources/views/Fortunes.rocker.html new file mode 100644 index 00000000000..cfa4f8341e2 --- /dev/null +++ b/frameworks/Java/quarkus/reactive-routes-pgclient/src/main/resources/views/Fortunes.rocker.html @@ -0,0 +1,8 @@ +@import java.util.* +@import io.quarkus.benchmark.model.* +@args(List fortunes) +Fortunes +@for ((ForIterator i, Fortune fortune) : fortunes) { + +} +
idmessage
@fortune.getId()@fortune.getMessage()
\ No newline at end of file diff --git a/frameworks/Java/quarkus/resteasy-reactive-hibernate-reactive/pom.xml b/frameworks/Java/quarkus/resteasy-reactive-hibernate-reactive/pom.xml index c036d06258d..8948c5ffb06 100644 --- a/frameworks/Java/quarkus/resteasy-reactive-hibernate-reactive/pom.xml +++ b/frameworks/Java/quarkus/resteasy-reactive-hibernate-reactive/pom.xml @@ -30,11 +30,11 @@
io.quarkus - quarkus-resteasy-reactive + quarkus-rest io.quarkus - quarkus-resteasy-reactive-jackson + quarkus-rest-jackson io.vertx diff --git a/frameworks/Java/quarkus/resteasy-reactive-hibernate-reactive/src/main/java/io/quarkus/benchmark/repository/WorldRepository.java b/frameworks/Java/quarkus/resteasy-reactive-hibernate-reactive/src/main/java/io/quarkus/benchmark/repository/WorldRepository.java index 6aba8d45b00..90130a91022 100644 --- a/frameworks/Java/quarkus/resteasy-reactive-hibernate-reactive/src/main/java/io/quarkus/benchmark/repository/WorldRepository.java +++ b/frameworks/Java/quarkus/resteasy-reactive-hibernate-reactive/src/main/java/io/quarkus/benchmark/repository/WorldRepository.java @@ -31,7 +31,7 @@ public Uni createData() { world.setRandomNumber(random.getNextRandom()); unis[i] = s.persist(world).map(v -> null); } - return Uni.combine().all().unis(unis).combinedWith(l -> null) + return Uni.combine().all().unis(unis).with(l -> null) .flatMap(v -> s.flush()) .map(v -> null); }); diff --git a/frameworks/Java/quarkus/resteasy-reactive-hibernate/pom.xml b/frameworks/Java/quarkus/resteasy-reactive-hibernate/pom.xml index 3f75ad69d45..5cd634dbea5 100644 --- a/frameworks/Java/quarkus/resteasy-reactive-hibernate/pom.xml +++ b/frameworks/Java/quarkus/resteasy-reactive-hibernate/pom.xml @@ -26,11 +26,11 @@ io.quarkus - quarkus-resteasy-reactive + quarkus-rest io.quarkus - quarkus-resteasy-reactive-jackson + quarkus-rest-jackson io.quarkus diff --git a/frameworks/Java/quarkus/run_quarkus.sh b/frameworks/Java/quarkus/run_quarkus.sh index 7f8bc785fd1..e93ef48f616 100755 --- a/frameworks/Java/quarkus/run_quarkus.sh +++ b/frameworks/Java/quarkus/run_quarkus.sh @@ -10,6 +10,7 @@ # Consider using -Dquarkus.http.io-threads=$((`grep --count ^processor /proc/cpuinfo`)) \ JAVA_OPTIONS="-server \ + -Dquarkus.http.limits.max-body-size= \ -Dquarkus.vertx.prefer-native-transport=true \ -XX:-StackTraceInThrowable \ -Dquarkus.http.accept-backlog=-1 \ diff --git a/frameworks/Java/quarkus/vertx/pom.xml b/frameworks/Java/quarkus/vertx/pom.xml new file mode 100644 index 00000000000..1414a21df4a --- /dev/null +++ b/frameworks/Java/quarkus/vertx/pom.xml @@ -0,0 +1,82 @@ + + + 4.0.0 + + + io.quarkus + benchmark + 1.0-SNAPSHOT + + + io.quarkus.benchmark + vertx + + + + io.quarkus + quarkus-benchmark-common + + + io.quarkus + quarkus-arc + + + io.vertx + vertx-pg-client + + + io.quarkus + quarkus-vertx + + + io.vertx + vertx-web-templ-rocker + + + + com.google.guava + guava + 32.0.0-jre + + + io.netty + netty-transport-native-epoll + linux-x86_64 + + + + + + + com.fizzed + rocker-maven-plugin + 1.3.0 + + + generate-rocker-templates + generate-sources + + generate + + + ${project.basedir}/src/main/resources + true + true + false + + + + + + + com.google.guava + guava + 32.0.0-jre + + + + + + + + diff --git a/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/filter/HttpResponseDecorator.java b/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/filter/HttpResponseDecorator.java new file mode 100644 index 00000000000..8fedfd8fe6b --- /dev/null +++ b/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/filter/HttpResponseDecorator.java @@ -0,0 +1,40 @@ +package io.quarkus.benchmark.filter; + +import io.vertx.core.Vertx; +import io.vertx.core.http.HttpHeaders; +import io.vertx.core.http.HttpServerResponse; +import jakarta.annotation.PreDestroy; +import jakarta.inject.Singleton; + +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; + +@Singleton +public class HttpResponseDecorator { + private static final CharSequence HEADER_DATE = HttpHeaders.createOptimized("date"); + private static final CharSequence QUARKUS_SERVER = HttpHeaders.createOptimized("quarkus"); + private final Vertx vertx; + private CharSequence date; + private final long timerId; + + public HttpResponseDecorator(final Vertx vertx) { + this.vertx = vertx; + date = createDateHeader(); + timerId = vertx.setPeriodic(1000, ignore -> date = createDateHeader()); + } + + public static CharSequence createDateHeader() { + return HttpHeaders.createOptimized(DateTimeFormatter.RFC_1123_DATE_TIME.format(ZonedDateTime.now())); + } + + @PreDestroy + public void destroy() { + vertx.cancelTimer(timerId); + } + + public void decorate(final HttpServerResponse response) { + final var headers = response.headers(); + headers.add(HttpHeaders.SERVER, QUARKUS_SERVER); + headers.add(HEADER_DATE, date); + } +} diff --git a/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/model/Fortune.java b/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/model/Fortune.java new file mode 100644 index 00000000000..a8a56cc71b9 --- /dev/null +++ b/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/model/Fortune.java @@ -0,0 +1,24 @@ +package io.quarkus.benchmark.model; + +public class Fortune implements Comparable { + private final int id; + private final String message; + + public Fortune(final int id, final String message) { + this.id = id; + this.message = message; + } + + public int getId() { + return id; + } + + public String getMessage() { + return message; + } + + @Override + public int compareTo(final Fortune other) { + return message.compareTo(other.message); + } +} \ No newline at end of file diff --git a/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/model/JsonMessage.java b/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/model/JsonMessage.java new file mode 100644 index 00000000000..db58d8e1da4 --- /dev/null +++ b/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/model/JsonMessage.java @@ -0,0 +1,12 @@ +package io.quarkus.benchmark.model; + +import io.vertx.core.json.JsonObject; + +import java.util.Map; + +public class JsonMessage extends JsonObject { + + public JsonMessage(final String message) { + super(Map.of("message", message)); + } +} diff --git a/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/model/World.java b/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/model/World.java new file mode 100644 index 00000000000..07f0b4f972e --- /dev/null +++ b/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/model/World.java @@ -0,0 +1,24 @@ +package io.quarkus.benchmark.model; + +public final class World implements Comparable { + private final Integer id; + private final Integer randomNumber; + + public World(final Integer id, final Integer randomNumber) { + this.id = id; + this.randomNumber = randomNumber; + } + + public Integer getId() { + return id; + } + + public Integer getRandomNumber() { + return randomNumber; + } + + @Override + public int compareTo(final World o) { + return id.compareTo(o.id); + } +} \ No newline at end of file diff --git a/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/repository/FortuneRepository.java b/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/repository/FortuneRepository.java new file mode 100644 index 00000000000..4130f1f3cbd --- /dev/null +++ b/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/repository/FortuneRepository.java @@ -0,0 +1,44 @@ +package io.quarkus.benchmark.repository; + +import io.quarkus.benchmark.model.Fortune; +import io.vertx.core.AsyncResult; +import io.vertx.core.Future; +import io.vertx.core.Handler; +import io.vertx.sqlclient.Row; +import io.vertx.sqlclient.RowIterator; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +@Singleton +public class FortuneRepository { + + @Inject + PgConnectionPool pgConnectionPool; + + public void findAllSortedFortunes(final Handler>> resultHandler) { + pgConnectionPool.pgConnection().selectFortuneQuery() + .execute(fortuneRows -> { + if (fortuneRows.succeeded()) { + final List fortunes = new ArrayList<>(fortuneRows.result().size() + 1); + final RowIterator resultSet = fortuneRows.result().iterator(); + if (!resultSet.hasNext()) { + resultHandler.handle(Future.succeededFuture(List.of())); + return; + } + while (resultSet.hasNext()) { + final Row row = resultSet.next(); + fortunes.add(new Fortune(row.getInteger(0), row.getString(1))); + } + fortunes.add(new Fortune(0, "Additional fortune added at request time.")); + Collections.sort(fortunes); + resultHandler.handle(Future.succeededFuture(fortunes)); + } else { + resultHandler.handle(Future.failedFuture(fortuneRows.cause())); + } + }); + } +} 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 new file mode 100644 index 00000000000..4289a644669 --- /dev/null +++ b/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/repository/PgClientFactory.java @@ -0,0 +1,67 @@ +package io.quarkus.benchmark.repository; + +import io.vertx.core.Vertx; +import io.vertx.pgclient.PgConnectOptions; +import jakarta.annotation.PreDestroy; +import jakarta.enterprise.inject.Produces; +import jakarta.inject.Singleton; +import org.eclipse.microprofile.config.inject.ConfigProperty; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +@Singleton +public class PgClientFactory { + + // vertx-reactive:postgresql://tfb-database:5432/hello_world + private static final String PG_URI_MATCHER = "vertx-reactive:postgresql://([-a-zA-Z]+):([0-9]+)/(.*)"; + @ConfigProperty(name = "quarkus.datasource.url") + String url; + @ConfigProperty(name = "quarkus.datasource.username") + String user; + @ConfigProperty(name = "quarkus.datasource.password") + String pass; + + private final Vertx vertx; + private PgConnectionPool pgConnectionPool; + + public PgClientFactory(final Vertx vertx) { + this.vertx = vertx; + } + + @Produces + @Singleton + PgConnectionPool connectionPool() { + PgConnectionPool pgConnectionPool = null; + try { + pgConnectionPool = new PgConnectionPool(vertx, pgConnectOptions()); + } catch (final Exception e) { + // TODO LOG ME: usually means inability to connect to the database + } finally { + this.pgConnectionPool = pgConnectionPool; + return pgConnectionPool; + } + } + + @PreDestroy + public void closeConnectionPool() { + if (pgConnectionPool != null) { + pgConnectionPool.close(); + } + } + + private PgConnectOptions pgConnectOptions() { + final PgConnectOptions options = new PgConnectOptions(); + final Matcher matcher = Pattern.compile(PG_URI_MATCHER).matcher(url); + matcher.matches(); + options.setDatabase(matcher.group(3)); + options.setHost(matcher.group(1)); + options.setPort(Integer.parseInt(matcher.group(2))); + options.setUser(user); + options.setPassword(pass); + options.setCachePreparedStatements(true); + // Large pipelining means less flushing and we use a single connection anyway + options.setPipeliningLimit(100_000); + return options; + } +} \ No newline at end of file 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 new file mode 100644 index 00000000000..0a04a9fde25 --- /dev/null +++ b/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/repository/PgConnectionPool.java @@ -0,0 +1,208 @@ +package io.quarkus.benchmark.repository; + +import io.netty.util.concurrent.EventExecutor; +import io.netty.util.concurrent.FastThreadLocal; +import io.vertx.core.AsyncResult; +import io.vertx.core.Future; +import io.vertx.core.Handler; +import io.vertx.core.Promise; +import io.vertx.core.Vertx; +import io.vertx.pgclient.PgConnectOptions; +import io.vertx.pgclient.PgConnection; +import io.vertx.sqlclient.PreparedQuery; +import io.vertx.sqlclient.PreparedStatement; +import io.vertx.sqlclient.Row; +import io.vertx.sqlclient.RowSet; +import io.vertx.sqlclient.impl.SqlClientInternal; + +import java.util.ArrayList; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReferenceArray; + +public class PgConnectionPool implements AutoCloseable { + + static final String SELECT_WORLD = "SELECT id, randomnumber from WORLD where id=$1"; + static final String SELECT_FORTUNE = "SELECT id, message from FORTUNE"; + private final FastThreadLocal pgConnectionPool; + private final AtomicReferenceArray pgConnections; + + public PgConnectionPool(final Vertx vertx, final PgConnectOptions options) { + final var executors = new ArrayList(Runtime.getRuntime().availableProcessors()); + vertx.nettyEventLoopGroup().forEach(executors::add); + final var connectionsCompleted = new CompletableFuture<>(); + final var completedConnections = new AtomicReferenceArray>(executors.size()); + final var allCompleted = new AtomicInteger(executors.size()); + final var connectionAffinityMap = new ConcurrentHashMap(executors.size()); + for (int i = 0; i < executors.size(); i++) { + final int executorId = i; + executors.get(i).execute(() -> connect(vertx, options) + .onComplete(ar -> { + final boolean lastCompleted = allCompleted.decrementAndGet() == 0; + if (!completedConnections.compareAndSet(executorId, null, ar)) { + if (ar.succeeded()) { + ar.result().connection.close(); + } + } else if (ar.succeeded()) { + // assign the executorId to the connection + ar.result().executorId = executorId; + connectionAffinityMap.put(Thread.currentThread(), ar.result()); + } + if (lastCompleted) { + connectionsCompleted.complete(null); + } + })); + } + // TODO make the global timeout to be configurable + try { + connectionsCompleted.join(); + } catch (final Throwable t) { + // let's forcibly close all completed connections + forceCloseEstablishedConnections(completedConnections); + throw new IllegalStateException("cannot establish all connections", t); + } + // let's fast-fail if we cannot establish all connections + pgConnections = new AtomicReferenceArray<>(completedConnections.length()); + for (int i = 0; i < completedConnections.length(); i++) { + final AsyncResult ar = completedConnections.get(i); + if (ar == null || ar.failed()) { + forceCloseEstablishedConnections(completedConnections); + throw new IllegalStateException("cannot establish all connections"); + } else { + pgConnections.set(i, ar.result()); + } + } + pgConnectionPool = new FastThreadLocal<>() { + @Override + protected PgClientConnection initialValue() { + return connectionAffinityMap.get(Thread.currentThread()); + } + + @Override + protected void onRemoval(final PgClientConnection value) { + final PgClientConnection removed = connectionAffinityMap.remove(Thread.currentThread()); + if (removed != null) { + final var connectionToClose = pgConnections.getAndSet(removed.executorId, null); + if (connectionToClose != null) { + assert connectionToClose == removed; + connectionToClose.connection.close(); + } + } + } + }; + } + + private static Handler> onSuccess(final Handler handler) { + return ar -> { + if (ar.succeeded()) { + handler.handle(ar.result()); + } + }; + } + + private static Future connect(final Vertx vertx, final PgConnectOptions options) { + final PgClientConnection result = new PgClientConnection(); + final Promise connectionEstablished = Promise.promise(); + final var future = PgConnection.connect(vertx, options) + .flatMap(conn -> { + result.connection = (SqlClientInternal) conn; + final Future f1 = conn.prepare(SELECT_WORLD) + .andThen(onSuccess(ps -> result.SELECT_WORLD_QUERY = ps.query())); + final Future f2 = conn.prepare(SELECT_FORTUNE) + .andThen(onSuccess(ps -> result.SELECT_FORTUNE_QUERY = ps.query())); + + final int QUERIES = 500; + result.UPDATE_WORLD_QUERY = new PreparedQuery[QUERIES]; + var updateWorldQueries = new ArrayList>(QUERIES); + for (int queryCount = 1; queryCount <= QUERIES; queryCount++) { + updateWorldQueries.add(result.prepareUpdateQueryFor(conn, queryCount)); + } + return Future.join(f1, f2, Future.join(updateWorldQueries)); + }).onComplete(ar -> { + if (ar.failed() && result.connection != null) { + result.connection.close(); + } + }); + future.onComplete(ar -> { + if (ar.succeeded()) { + connectionEstablished.complete(result); + } else { + connectionEstablished.fail(ar.cause()); + } + }); + return connectionEstablished.future(); + } + + private static void forceCloseEstablishedConnections(final AtomicReferenceArray> completedConnections) { + final AsyncResult noResult = Future.succeededFuture(); + for (int i = 0; i < completedConnections.length(); i++) { + final AsyncResult ar = completedConnections.getAndSet(i, noResult); + if (ar != null && ar.succeeded() && ar.result() != null && ar.result().connection != null) { + try { + ar.result().connection.close(); + } catch (final Throwable t2) { + // ignore + } + } + } + } + + public PgClientConnection pgConnection() { + return pgConnectionPool.get(); + } + + @Override + public void close() { + for (int i = 0; i < pgConnections.length(); i++) { + final var connection = pgConnections.getAndSet(i, null); + if (connection != null) { + connection.connection.close(); + } + } + } + + public static class PgClientConnection { + private int executorId; + private PreparedQuery> SELECT_WORLD_QUERY; + private PreparedQuery> SELECT_FORTUNE_QUERY; + private PreparedQuery>[] UPDATE_WORLD_QUERY; + private SqlClientInternal connection; + + public PreparedQuery> selectWorldQuery() { + return SELECT_WORLD_QUERY; + } + + public PreparedQuery> selectFortuneQuery() { + return SELECT_FORTUNE_QUERY; + } + + public PreparedQuery> updateWorldQuery(int queryCount) { + return UPDATE_WORLD_QUERY[queryCount - 1]; + } + + private Future prepareUpdateQueryFor(PgConnection connection, int queryCount) { + return connection.prepare(updateQueryFor(queryCount)).andThen(onSuccess(ps -> UPDATE_WORLD_QUERY[queryCount - 1] = ps.query())); + } + private static String updateQueryFor(int queryCount) { + StringBuilder sql = new StringBuilder(); + sql.append("UPDATE WORLD SET RANDOMNUMBER = CASE ID"); + for (int i = 0; i < queryCount; i++) { + int offset = (i * 2) + 1; + sql.append(" WHEN $" + offset + " THEN $" + (offset + 1)); + } + sql.append(" ELSE RANDOMNUMBER"); + sql.append(" END WHERE ID IN ($1"); + for (int i = 1; i < queryCount; i++) { + int offset = (i * 2) + 1; + sql.append(",$" + offset); + } + sql.append(")"); + return sql.toString(); + } + + public SqlClientInternal rawConnection() { + return connection; + } + } +} \ No newline at end of file diff --git a/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/repository/WorldRepository.java b/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/repository/WorldRepository.java new file mode 100644 index 00000000000..3095137ae5e --- /dev/null +++ b/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/repository/WorldRepository.java @@ -0,0 +1,187 @@ +package io.quarkus.benchmark.repository; + +import io.quarkus.benchmark.model.World; +import io.vertx.core.AsyncResult; +import io.vertx.core.Future; +import io.vertx.core.Handler; +import io.vertx.core.json.JsonArray; +import io.vertx.core.json.JsonObject; +import io.vertx.sqlclient.PreparedQuery; +import io.vertx.sqlclient.Row; +import io.vertx.sqlclient.RowIterator; +import io.vertx.sqlclient.RowSet; +import io.vertx.sqlclient.Tuple; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ThreadLocalRandom; +import java.util.stream.IntStream; + +@Singleton +public class WorldRepository { + + @Inject + private PgConnectionPool connectionPool; + + private static final Integer[] BOXED_RND = IntStream.range(1, 10001).boxed().toArray(Integer[]::new); + + private static Integer boxedRandomWorldNumber() { + final int rndValue = ThreadLocalRandom.current().nextInt(1, 10001); + final var boxedRnd = BOXED_RND[rndValue - 1]; + assert boxedRnd.intValue() == rndValue; + return boxedRnd; + } + + public void loadRandomJsonWorld(final Handler> worldHandler) { + connectionPool.pgConnection().selectWorldQuery().execute(Tuple.of(boxedRandomWorldNumber()), randomWorldRow -> { + if (randomWorldRow.succeeded()) { + final RowIterator resultSet = randomWorldRow.result().iterator(); + if (!resultSet.hasNext()) { + worldHandler.handle(Future.succeededFuture()); + return; + } + final Row row = resultSet.next(); + worldHandler.handle(Future.succeededFuture(new JsonWorld(row.getInteger(0), row.getInteger(1)))); + } else { + worldHandler.handle(Future.failedFuture(randomWorldRow.cause())); + } + }); + } + + public void loadNJsonWorlds(final int count, final Handler> worldsHandler) { + FindRandomWorldsCommand.execute(connectionPool, count, worldsHandler); + } + + public void updateNJsonWorlds(final int count, final Handler> worldsHandler) { + UpdateWorldsCommand.execute(connectionPool, count, worldsHandler); + } + + public static class JsonWorlds extends JsonArray { + private JsonWorlds(final int capacity) { + super(new ArrayList(capacity)); + } + + private JsonWorlds(final World[] worlds) { + this(worlds.length); + for (final World world : worlds) { + add(new JsonWorld(world.getId(), world.getRandomNumber())); + } + } + } + + public static class JsonWorld extends JsonObject { + private JsonWorld(final Integer id, final Integer random) { + super(Map.of("id", id, "randomNumber", random)); + } + } + + private static final class UpdateWorldsCommand { + private final PgConnectionPool.PgClientConnection connection; + private final World[] worldsToUpdate; + private final Handler> resultHandler; + private boolean failed; + private int selectWorldCompletedCount; + + private UpdateWorldsCommand(final PgConnectionPool.PgClientConnection connection, final int queries, final Handler> resultHandler) { + this.connection = connection; + this.worldsToUpdate = new World[queries]; + this.resultHandler = resultHandler; + } + + // execute + public static void execute(final PgConnectionPool connectionPool, final int count, final Handler> resultHandler) { + new UpdateWorldsCommand(connectionPool.pgConnection(), count, resultHandler).run(); + } + + private void run() { + connection.rawConnection().group(c -> { + final PreparedQuery> preparedQuery = c.preparedQuery(PgConnectionPool.SELECT_WORLD); + for (int i = 0; i < worldsToUpdate.length; i++) { + final Integer id = boxedRandomWorldNumber(); + final int index = i; + preparedQuery.execute(Tuple.of(id), worldId -> { + if (!failed) { + if (worldId.failed()) { + failed = true; + resultHandler.handle(Future.failedFuture(worldId.cause())); + return; + } + worldsToUpdate[index] = new World(worldId.result().iterator().next().getInteger(0), boxedRandomWorldNumber()); + if (++selectWorldCompletedCount == worldsToUpdate.length) { + randomWorldsQueryCompleted(); + } + } + }); + } + }); + } + + private void randomWorldsQueryCompleted() { + Arrays.sort(worldsToUpdate); + final List params = new ArrayList<>(worldsToUpdate.length * 2); + for (int i = 0, count = worldsToUpdate.length; i < count; i++) { + var world = worldsToUpdate[i]; + params.add(world.getId()); + params.add(world.getRandomNumber()); + } + connection.updateWorldQuery(worldsToUpdate.length).execute(Tuple.wrap(params), updateResult -> { + if (updateResult.failed()) { + resultHandler.handle(Future.failedFuture(updateResult.cause())); + return; + } + resultHandler.handle(Future.succeededFuture(new JsonWorlds(worldsToUpdate))); + }); + } + } + + private static final class FindRandomWorldsCommand implements Handler>> { + private final Handler> resultHandler; + private final int count; + private final JsonWorlds jsonWorlds; + private final PgConnectionPool.PgClientConnection connection; + private boolean failed; + + private FindRandomWorldsCommand(final PgConnectionPool.PgClientConnection connection, final int count, final Handler> resultHandler) { + this.connection = connection; + this.count = count; + this.jsonWorlds = new JsonWorlds(count); + this.resultHandler = resultHandler; + } + + public static void execute(final PgConnectionPool connectionPool, final int queries, final Handler> resultHandler) { + new FindRandomWorldsCommand(connectionPool.pgConnection(), queries, resultHandler).run(); + } + + private void run() { + connection.rawConnection().group(c -> { + for (int i = 0; i < count; i++) { + c.preparedQuery(PgConnectionPool.SELECT_WORLD).execute(Tuple.of(boxedRandomWorldNumber()), this); + } + }); + } + + @Override + public void handle(final AsyncResult> ar) { + if (!failed) { + if (ar.failed()) { + failed = true; + resultHandler.handle(Future.failedFuture(ar.cause())); + return; + } + + final Tuple row = ar.result().iterator().next(); + jsonWorlds.add(new JsonWorld(row.getInteger(0), row.getInteger(1))); + + // stop condition + if (jsonWorlds.size() == count) { + resultHandler.handle(Future.succeededFuture(jsonWorlds)); + } + } + } + } + +} diff --git a/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/resource/DbHttpHandler.java b/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/resource/DbHttpHandler.java new file mode 100644 index 00000000000..01f5b1253ca --- /dev/null +++ b/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/resource/DbHttpHandler.java @@ -0,0 +1,30 @@ +package io.quarkus.benchmark.resource; + +import io.netty.handler.codec.http.HttpHeaderValues; +import io.quarkus.benchmark.repository.WorldRepository; +import io.vertx.core.http.HttpHeaders; +import io.vertx.core.http.HttpServerRequest; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; + +@Singleton +public class DbHttpHandler { + + @Inject + WorldRepository worldRepository; + + // write handle + public void handle(final HttpServerRequest request) { + worldRepository.loadRandomJsonWorld(jsonWorld -> { + if (jsonWorld.succeeded()) { + var res = request.response(); + res.headers().add(HttpHeaders.CONTENT_TYPE, HttpHeaderValues.APPLICATION_JSON); + res.end(jsonWorld.result().toBuffer(), null); + } else { + request.response().setStatusCode(500).end(); + } + }); + } + + +} diff --git a/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/resource/FortunesHttpHandler.java b/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/resource/FortunesHttpHandler.java new file mode 100644 index 00000000000..4735a3729bd --- /dev/null +++ b/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/resource/FortunesHttpHandler.java @@ -0,0 +1,34 @@ +package io.quarkus.benchmark.resource; + +import io.quarkus.benchmark.repository.FortuneRepository; +import io.quarkus.benchmark.rocker.VertxRawRockerOutputFactories; +import io.vertx.core.http.HttpHeaders; +import io.vertx.core.http.HttpServerRequest; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; +import views.Fortunes; + +@Singleton +public class FortunesHttpHandler { + + private static final CharSequence HTML_UTF8_CONTENT_TYPE = HttpHeaders.createOptimized("text/html; charset=UTF-8"); + + @Inject + VertxRawRockerOutputFactories factories; + + @Inject + FortuneRepository fortuneRepository; + + public void handle(final HttpServerRequest request) { + fortuneRepository.findAllSortedFortunes(fortunes -> { + if (fortunes.succeeded()) { + final var vertxRockerOutput = Fortunes.template(fortunes.result()).render(factories.ioFactory()); + var res = request.response(); + res.headers().add(HttpHeaders.CONTENT_TYPE, HTML_UTF8_CONTENT_TYPE); + res.end(vertxRockerOutput.buffer(), null); + } else { + request.response().setStatusCode(500).end(fortunes.cause().getMessage()); + } + }); + } +} diff --git a/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/resource/HttpQueryParameterUtils.java b/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/resource/HttpQueryParameterUtils.java new file mode 100644 index 00000000000..dbebbcb7e6a --- /dev/null +++ b/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/resource/HttpQueryParameterUtils.java @@ -0,0 +1,20 @@ +package io.quarkus.benchmark.resource; + +import io.vertx.core.http.HttpServerRequest; + +public class HttpQueryParameterUtils { + + public static int queriesFrom(final HttpServerRequest request) { + final String param = request.getParam("queries"); + + if (param == null) { + return 1; + } + try { + final int parsedValue = Integer.parseInt(param); + return Math.min(500, Math.max(1, parsedValue)); + } catch (final NumberFormatException e) { + return 1; + } + } +} diff --git a/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/resource/HttpRoutes.java b/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/resource/HttpRoutes.java new file mode 100644 index 00000000000..8ab91bf7648 --- /dev/null +++ b/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/resource/HttpRoutes.java @@ -0,0 +1,109 @@ +package io.quarkus.benchmark.resource; + +import io.netty.handler.codec.http.HttpResponseStatus; +import io.netty.util.concurrent.EventExecutor; +import io.quarkus.benchmark.filter.HttpResponseDecorator; +import io.quarkus.runtime.StartupEvent; +import io.vertx.core.Future; +import io.vertx.core.Handler; +import io.vertx.core.Promise; +import io.vertx.core.Vertx; +import io.vertx.core.http.HttpServer; +import io.vertx.core.http.HttpServerOptions; +import io.vertx.core.http.HttpServerRequest; +import jakarta.annotation.PreDestroy; +import jakarta.enterprise.event.Observes; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; + +import java.util.ArrayList; +import java.util.List; + +@Singleton +public class HttpRoutes { + private static final int PORT = 8080; + 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 HttpServer[] servers; + @Inject + private HttpResponseDecorator responseDecorator; + @Inject + private PlaintextHttpHandler plaintextHttpHandler; + @Inject + private JsonHttpHandler jsonHandler; + @Inject + private DbHttpHandler dbHandler; + @Inject + private UpdateHttpHandler updateHandler; + @Inject + private QueriesHttpHandler queriesHandler; + @Inject + private FortunesHttpHandler fortunesHandler; + + private static HttpServer[] createAndStartHttpServers(final Vertx vertx, final Handler requestHandler) { + final var executors = new ArrayList(Runtime.getRuntime().availableProcessors()); + vertx.nettyEventLoopGroup().forEach(executors::add); + final HttpServer[] servers = new HttpServer[executors.size()]; + final List> allHttpServerListening = new ArrayList<>(servers.length); + for (int i = 0; i < servers.length; i++) { + final int executorId = i; + final var done = Promise.promise(); + allHttpServerListening.add(done.future()); + executors.get(executorId).execute(() -> { + servers[executorId] = vertx.createHttpServer(new HttpServerOptions()); + servers[executorId] + .requestHandler(requestHandler) + .listen(PORT); + done.complete(); + }); + } + Future.join(allHttpServerListening).toCompletionStage().toCompletableFuture().join(); + return servers; + } + + public void init(@Observes final StartupEvent startupEvent, final Vertx vertx) { + servers = createAndStartHttpServers(vertx, this::handle); + } + + @PreDestroy + public void shutdown() { + for (final HttpServer server : servers) { + server.close(); + } + } + + private void handle(final HttpServerRequest request) { + try { + responseDecorator.decorate(request.response()); + switch (request.path()) { + case PATH_PLAINTEXT: + plaintextHttpHandler.handle(request); + break; + case PATH_JSON: + jsonHandler.handle(request); + break; + case PATH_DB: + dbHandler.handle(request); + break; + case PATH_QUERIES: + queriesHandler.handle(request); + break; + case PATH_UPDATES: + updateHandler.handle(request); + break; + case PATH_FORTUNES: + fortunesHandler.handle(request); + break; + default: + request.response().setStatusCode(HttpResponseStatus.NOT_FOUND.code()).end(); + break; + } + } catch (final Exception e) { + request.response().setStatusCode(HttpResponseStatus.INTERNAL_SERVER_ERROR.code()).end(); + } + } +} diff --git a/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/resource/JsonHttpHandler.java b/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/resource/JsonHttpHandler.java new file mode 100644 index 00000000000..23f686d6850 --- /dev/null +++ b/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/resource/JsonHttpHandler.java @@ -0,0 +1,21 @@ +package io.quarkus.benchmark.resource; + +import io.netty.handler.codec.http.HttpHeaderValues; +import io.quarkus.benchmark.model.JsonMessage; +import io.vertx.core.MultiMap; +import io.vertx.core.http.HttpHeaders; +import io.vertx.core.http.HttpServerRequest; +import io.vertx.core.http.HttpServerResponse; +import jakarta.inject.Singleton; + +@Singleton +public class JsonHttpHandler { + + public void handle(final HttpServerRequest request) { + final HttpServerResponse response = request.response(); + final MultiMap headers = response.headers(); + headers.add(HttpHeaders.CONTENT_TYPE, HttpHeaderValues.APPLICATION_JSON); + response.end(new JsonMessage("Hello, World!").toBuffer(), null); + } + +} diff --git a/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/resource/PlaintextHttpHandler.java b/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/resource/PlaintextHttpHandler.java new file mode 100644 index 00000000000..52f23fc9d18 --- /dev/null +++ b/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/resource/PlaintextHttpHandler.java @@ -0,0 +1,24 @@ +package io.quarkus.benchmark.resource; + +import io.netty.handler.codec.http.HttpHeaderValues; +import io.vertx.core.MultiMap; +import io.vertx.core.buffer.Buffer; +import io.vertx.core.http.HttpHeaders; +import io.vertx.core.http.HttpServerRequest; +import io.vertx.core.http.HttpServerResponse; +import jakarta.inject.Singleton; + +@Singleton +public class PlaintextHttpHandler { + 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 HELLO_WORLD_LENGTH = HttpHeaders.createOptimized("" + HELLO_WORLD.length()); + + public void handle(final HttpServerRequest request) { + final HttpServerResponse response = request.response(); + final MultiMap headers = response.headers(); + headers.add(HttpHeaders.CONTENT_LENGTH, HELLO_WORLD_LENGTH); + headers.add(HttpHeaders.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN); + response.end(HELLO_WORLD_BUFFER, null); + } +} diff --git a/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/resource/QueriesHttpHandler.java b/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/resource/QueriesHttpHandler.java new file mode 100644 index 00000000000..5e1ec023fac --- /dev/null +++ b/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/resource/QueriesHttpHandler.java @@ -0,0 +1,28 @@ +package io.quarkus.benchmark.resource; + +import io.netty.handler.codec.http.HttpHeaderValues; +import io.quarkus.benchmark.repository.WorldRepository; +import io.vertx.core.http.HttpHeaders; +import io.vertx.core.http.HttpServerRequest; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; + +import static io.quarkus.benchmark.resource.HttpQueryParameterUtils.queriesFrom; + +@Singleton +public class QueriesHttpHandler { + @Inject + WorldRepository worldRepository; + + public void handle(final HttpServerRequest request) { + worldRepository.loadNJsonWorlds(queriesFrom(request), jsonWorlds -> { + if (jsonWorlds.succeeded()) { + var res = request.response(); + res.headers().add(HttpHeaders.CONTENT_TYPE, HttpHeaderValues.APPLICATION_JSON); + res.end(jsonWorlds.result().toBuffer(), null); + } else { + request.response().setStatusCode(500).end(); + } + }); + } +} diff --git a/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/resource/UpdateHttpHandler.java b/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/resource/UpdateHttpHandler.java new file mode 100644 index 00000000000..789accc48f0 --- /dev/null +++ b/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/resource/UpdateHttpHandler.java @@ -0,0 +1,29 @@ +package io.quarkus.benchmark.resource; + +import io.netty.handler.codec.http.HttpHeaderValues; +import io.quarkus.benchmark.repository.WorldRepository; +import io.vertx.core.http.HttpHeaders; +import io.vertx.core.http.HttpServerRequest; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; + +import static io.quarkus.benchmark.resource.HttpQueryParameterUtils.queriesFrom; + +@Singleton +public class UpdateHttpHandler { + + @Inject + WorldRepository worldRepository; + + public void handle(final HttpServerRequest request) { + worldRepository.updateNJsonWorlds(queriesFrom(request), jsonWorlds -> { + if (jsonWorlds.succeeded()) { + var res = request.response(); + res.headers().add(HttpHeaders.CONTENT_TYPE, HttpHeaderValues.APPLICATION_JSON); + res.end(jsonWorlds.result().toBuffer(), null); + } else { + request.response().setStatusCode(500).end(); + } + }); + } +} diff --git a/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/rocker/RawRockerOutput.java b/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/rocker/RawRockerOutput.java new file mode 100644 index 00000000000..8dd5bec161b --- /dev/null +++ b/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/rocker/RawRockerOutput.java @@ -0,0 +1,65 @@ +package io.quarkus.benchmark.rocker; + +import com.fizzed.rocker.ContentType; +import com.fizzed.rocker.RockerOutputFactory; +import io.netty.buffer.ByteBuf; +import io.vertx.core.buffer.Buffer; +import io.vertx.core.buffer.impl.PartialPooledByteBufAllocator; + +import java.io.IOException; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; + +final class RawRockerOutput implements VertxRawRockerOutput { + + private final ByteBuf buff = PartialPooledByteBufAllocator.INSTANCE.directBuffer(); + private final Buffer buffer = Buffer.buffer(buff); + + RawRockerOutput() { + } + + public static RockerOutputFactory raw() { + final RawRockerOutput output = new RawRockerOutput(); + return (_contentType, charsetName) -> { + output.reset(); + return output; + }; + } + + private void reset() { + buff.resetReaderIndex(); + buff.resetWriterIndex(); + } + + @Override + public RawRockerOutput w(final byte[] bytes) throws IOException { + buffer.appendBytes(bytes); + return this; + } + + @Override + public RawRockerOutput w(final String s) throws IOException { + buffer.appendString(s); + return this; + } + + @Override + public ContentType getContentType() { + return ContentType.RAW; + } + + @Override + public Charset getCharset() { + return StandardCharsets.UTF_8; + } + + @Override + public int getByteLength() { + return buffer.length(); + } + + @Override + public Buffer buffer() { + return buffer; + } +} diff --git a/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/rocker/VertxRawRockerOutput.java b/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/rocker/VertxRawRockerOutput.java new file mode 100644 index 00000000000..ada27e4e4bf --- /dev/null +++ b/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/rocker/VertxRawRockerOutput.java @@ -0,0 +1,15 @@ +package io.quarkus.benchmark.rocker; + +import com.fizzed.rocker.RockerOutputFactory; +import io.vertx.core.buffer.Buffer; + +public interface VertxRawRockerOutput extends com.fizzed.rocker.RockerOutput { + + // factory + static RockerOutputFactory factory() { + return RawRockerOutput.raw(); + } + + Buffer buffer(); + +} diff --git a/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/rocker/VertxRawRockerOutputFactories.java b/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/rocker/VertxRawRockerOutputFactories.java new file mode 100644 index 00000000000..faf834738c4 --- /dev/null +++ b/frameworks/Java/quarkus/vertx/src/main/java/io/quarkus/benchmark/rocker/VertxRawRockerOutputFactories.java @@ -0,0 +1,29 @@ +package io.quarkus.benchmark.rocker; + +import com.fizzed.rocker.RockerOutputFactory; +import io.netty.util.concurrent.FastThreadLocal; +import io.vertx.core.Context; +import jakarta.inject.Singleton; + +@Singleton +public class VertxRawRockerOutputFactories { + + private final FastThreadLocal> ioPool; + + VertxRawRockerOutputFactories() { + ioPool = new FastThreadLocal<>() { + @Override + protected RockerOutputFactory initialValue() { + if (!Context.isOnEventLoopThread()) { + return null; + } + return VertxRawRockerOutput.factory(); + } + }; + } + + public RockerOutputFactory ioFactory() { + return ioPool.get(); + } + +} diff --git a/frameworks/Java/quarkus/vertx/src/main/resources/application.properties b/frameworks/Java/quarkus/vertx/src/main/resources/application.properties new file mode 100644 index 00000000000..a439fe7208a --- /dev/null +++ b/frameworks/Java/quarkus/vertx/src/main/resources/application.properties @@ -0,0 +1,10 @@ +quarkus.datasource.url=vertx-reactive:postgresql://tfb-database:5432/hello_world +%dev.quarkus.datasource.url=vertx-reactive:postgresql://localhost:5432/hello_world +quarkus.datasource.username=benchmarkdbuser +quarkus.datasource.password=benchmarkdbpass + +quarkus.log.console.enable=true +quarkus.log.console.level=INFO +quarkus.log.file.enable=false +quarkus.log.level=INFO + diff --git a/frameworks/Java/quarkus/vertx/src/main/resources/import.sql b/frameworks/Java/quarkus/vertx/src/main/resources/import.sql new file mode 100644 index 00000000000..f76881b4287 --- /dev/null +++ b/frameworks/Java/quarkus/vertx/src/main/resources/import.sql @@ -0,0 +1 @@ +INSERT INTO Fortune(id, message) VALUES (1, 'Test value One'); \ No newline at end of file diff --git a/frameworks/Java/quarkus/vertx/src/main/resources/views/Fortunes.rocker.html b/frameworks/Java/quarkus/vertx/src/main/resources/views/Fortunes.rocker.html new file mode 100644 index 00000000000..cfa4f8341e2 --- /dev/null +++ b/frameworks/Java/quarkus/vertx/src/main/resources/views/Fortunes.rocker.html @@ -0,0 +1,8 @@ +@import java.util.* +@import io.quarkus.benchmark.model.* +@args(List fortunes) +Fortunes +@for ((ForIterator i, Fortune fortune) : fortunes) { + +} +
idmessage
@fortune.getId()@fortune.getMessage()
\ No newline at end of file diff --git a/frameworks/Java/rapidoid/pom.xml b/frameworks/Java/rapidoid/pom.xml index 0a016c06467..e9d05ef289a 100644 --- a/frameworks/Java/rapidoid/pom.xml +++ b/frameworks/Java/rapidoid/pom.xml @@ -28,7 +28,7 @@ org.postgresql postgresql - 42.4.3 + 42.7.2 com.zaxxer diff --git a/frameworks/Java/ratpack/benchmark_config.json b/frameworks/Java/ratpack/benchmark_config.json index c3a755d87ab..85d054fed35 100755 --- a/frameworks/Java/ratpack/benchmark_config.json +++ b/frameworks/Java/ratpack/benchmark_config.json @@ -19,6 +19,7 @@ "database_os": "Linux", "display_name": "Ratpack", "notes": "", + "tags": ["broken"], "versus": "Netty" }, "jdbc": { @@ -40,6 +41,7 @@ "database_os": "Linux", "display_name": "Ratpack-jdbc", "notes": "", + "tags": ["broken"], "versus": "Netty" }, "pgclient": { @@ -61,6 +63,7 @@ "database_os": "Linux", "display_name": "Ratpack-pgclient", "notes": "", + "tags": ["broken"], "versus": "Netty" } } diff --git a/frameworks/Java/redkale/benchmark_config.json b/frameworks/Java/redkale/benchmark_config.json index 86b2fb08d30..52f8550ce9f 100644 --- a/frameworks/Java/redkale/benchmark_config.json +++ b/frameworks/Java/redkale/benchmark_config.json @@ -26,30 +26,6 @@ "notes": "", "versus": "Redkale" }, - "graalvm": { - "plaintext_url": "/plaintext", - "json_url": "/json", - "db_url": "/db", - "query_url": "/queries?q=", - "fortune_url": "/fortunes", - "update_url": "/updates?q=", - "cached_query_url": "/cached-worlds?q=", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "Postgres", - "framework": "Redkale", - "language": "Java", - "flavor": "None", - "orm": "Raw", - "platform": "Redkale", - "webserver": "Redkale", - "os": "Linux", - "database_os": "Linux", - "display_name": "redkale-graalvm", - "notes": "", - "versus": "Redkale" - }, "native": { "plaintext_url": "/plaintext", "json_url": "/json", @@ -95,7 +71,7 @@ "notes": "", "versus": "Redkale" }, - "vertx": { + "pgclient": { "db_url": "/db", "query_url": "/queries?q=", "fortune_url": "/fortunes", @@ -112,7 +88,7 @@ "webserver": "Redkale", "os": "Linux", "database_os": "Linux", - "display_name": "redkale-vertx", + "display_name": "redkale-pgclient", "notes": "", "versus": "Redkale" } diff --git a/frameworks/Java/redkale/conf/application.xml b/frameworks/Java/redkale/conf/application.xml index 3589ce9f086..642b3da5928 100644 --- a/frameworks/Java/redkale/conf/application.xml +++ b/frameworks/Java/redkale/conf/application.xml @@ -3,21 +3,20 @@ - - - + - + - - + + + diff --git a/frameworks/Java/redkale/conf/source.properties b/frameworks/Java/redkale/conf/source.properties index 9efb8cd4158..f88e22a2a12 100644 --- a/frameworks/Java/redkale/conf/source.properties +++ b/frameworks/Java/redkale/conf/source.properties @@ -4,5 +4,6 @@ redkale.datasource[].url = jdbc:postgresql://tfb-database:5432/hello_world redkale.datasource[].user = benchmarkdbuser redkale.datasource[].password = benchmarkdbpass -redkale.datasource[].warnslowms = 0 -redkale.datasource[].errorslowms = 0 +redkale.datasource[].non-blocking = true +redkale.datasource[].warn-slowms = 0 +redkale.datasource[].error-slowms = 0 diff --git a/frameworks/Java/redkale/config.toml b/frameworks/Java/redkale/config.toml index 19eba869560..149aaad007e 100644 --- a/frameworks/Java/redkale/config.toml +++ b/frameworks/Java/redkale/config.toml @@ -19,24 +19,6 @@ platform = "Redkale" webserver = "Redkale" versus = "Redkale" -[graalvm] -urls.plaintext = "/plaintext" -urls.json = "/json" -urls.db = "/db" -urls.fortune = "/fortunes" -urls.query = "/queries?q=" -urls.update = "/updates?q=" -urls.cached_query = "/cached-worlds?q=" -approach = "Realistic" -classification = "Fullstack" -database = "Postgres" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "Redkale" -webserver = "Redkale" -versus = "Redkale" - [native] urls.plaintext = "/plaintext" urls.json = "/json" @@ -70,7 +52,7 @@ platform = "Redkale" webserver = "Redkale" versus = "Redkale" -[vertx] +[pgclient] urls.db = "/db" urls.fortune = "/fortunes" urls.query = "/queries?q=" diff --git a/frameworks/Java/redkale/pom-jdbc.xml b/frameworks/Java/redkale/pom-jdbc.xml index 43ce0fa4e0f..8483c39801d 100644 --- a/frameworks/Java/redkale/pom-jdbc.xml +++ b/frameworks/Java/redkale/pom-jdbc.xml @@ -7,11 +7,12 @@ org.redkale.boot.Application - 2.8.0-SNAPSHOT - 42.6.0 + 2.8.1-SNAPSHOT + 1.2.0 + 42.7.2 UTF-8 - 18 - 18 + 21 + 21 @@ -76,7 +77,6 @@ UTF-8 -parameters - --enable-preview true @@ -85,7 +85,7 @@ org.redkale.maven.plugins redkale-maven-plugin - 1.2.0-SNAPSHOT + ${redkale-maven.version} --no-fallback diff --git a/frameworks/Java/redkale/pom-pgclient.xml b/frameworks/Java/redkale/pom-pgclient.xml new file mode 100644 index 00000000000..10ee48261f9 --- /dev/null +++ b/frameworks/Java/redkale/pom-pgclient.xml @@ -0,0 +1,136 @@ + + 4.0.0 + org.redkalex + redkale-benchmark + 1.0.0 + + + org.redkale.boot.Application + 2.8.1-SNAPSHOT + 1.2.0 + 4.5.8 + 2.1 + UTF-8 + 21 + 21 + + + + + org.redkale + redkale + ${redkale.version} + + + + org.redkalex + redkale-plugins + ${redkale.version} + + + + io.vertx + vertx-pg-client + ${vertx.version} + + + + com.ongres.scram + client + ${vertx-scram.version} + + + + + + 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 + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.10.0 + + UTF-8 + + -parameters + + true + + + + + org.redkale.maven.plugins + redkale-maven-plugin + ${redkale-maven.version} + + + --no-fallback + + + + + redkale-compile + process-classes + + compile + + + + + + + org.apache.maven.plugins + maven-shade-plugin + 3.3.0 + + + package + + shade + + + + + ${main.class} + + + + + + + + + + + diff --git a/frameworks/Java/redkale/pom-vertx.xml b/frameworks/Java/redkale/pom-vertx.xml deleted file mode 100644 index 4d0ffa06212..00000000000 --- a/frameworks/Java/redkale/pom-vertx.xml +++ /dev/null @@ -1,136 +0,0 @@ - - 4.0.0 - org.redkalex - redkale-benchmark - 1.0.0 - - - org.redkale.boot.Application - 2.8.0-SNAPSHOT - 4.4.4 - 2.1 - UTF-8 - 18 - 18 - - - - - org.redkale - redkale - ${redkale.version} - - - - org.redkalex - redkale-plugins - ${redkale.version} - - - - io.vertx - vertx-pg-client - ${vertx.version} - - - - com.ongres.scram - client - ${vertx-scram.version} - - - - - - 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 - - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.10.0 - - UTF-8 - - -parameters - --enable-preview - - true - - - - - org.redkale.maven.plugins - redkale-maven-plugin - 1.2.0-SNAPSHOT - - - --no-fallback - - - - - redkale-compile - process-classes - - compile - - - - - - - org.apache.maven.plugins - maven-shade-plugin - 3.3.0 - - - package - - shade - - - - - ${main.class} - - - - - - - - - - - diff --git a/frameworks/Java/redkale/pom.xml b/frameworks/Java/redkale/pom.xml index 8e6fa747ac0..c8ef3afb031 100644 --- a/frameworks/Java/redkale/pom.xml +++ b/frameworks/Java/redkale/pom.xml @@ -7,10 +7,11 @@ org.redkale.boot.Application - 2.8.0-SNAPSHOT + 2.8.1-SNAPSHOT + 1.2.0 UTF-8 - 11 - 11 + 21 + 21 @@ -74,10 +75,12 @@ org.redkale.maven.plugins redkale-maven-plugin - 1.2.0-SNAPSHOT + ${redkale-maven.version} --no-fallback + -J-XX:+UseNUMA + -J-XX:+UseParallelGC diff --git a/frameworks/Java/redkale/redkale-graalvm.dockerfile b/frameworks/Java/redkale/redkale-graalvm.dockerfile deleted file mode 100644 index 25ad428f6c8..00000000000 --- a/frameworks/Java/redkale/redkale-graalvm.dockerfile +++ /dev/null @@ -1,16 +0,0 @@ -FROM maven:3.8.6-openjdk-18-slim as maven -WORKDIR /redkale -COPY src src -COPY conf conf -COPY pom.xml pom.xml -RUN mvn package -q - - -FROM ghcr.io/graalvm/jdk-community:21.0.0 -WORKDIR /redkale -COPY conf conf -COPY --from=maven /redkale/target/redkale-benchmark-1.0.0.jar redkale-benchmark.jar - -EXPOSE 8080 - -CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-DAPP_HOME=./", "-jar", "redkale-benchmark.jar"] diff --git a/frameworks/Java/redkale/redkale-jdbc.dockerfile b/frameworks/Java/redkale/redkale-jdbc.dockerfile index 5b621e47179..ac3a85bec8b 100644 --- a/frameworks/Java/redkale/redkale-jdbc.dockerfile +++ b/frameworks/Java/redkale/redkale-jdbc.dockerfile @@ -1,15 +1,15 @@ -FROM maven:3.8.6-openjdk-18-slim as maven +FROM maven:3.9.6-amazoncorretto-21-debian as maven WORKDIR /redkale COPY src src COPY conf conf COPY pom-jdbc.xml pom.xml RUN mvn package -q -FROM openjdk:21-jdk-slim +FROM openjdk:23-jdk-slim WORKDIR /redkale COPY conf conf COPY --from=maven /redkale/target/redkale-benchmark-1.0.0.jar redkale-benchmark.jar EXPOSE 8080 -CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-DAPP_HOME=./", "-jar", "redkale-benchmark.jar"] \ No newline at end of file +CMD ["java", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-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 ae8e0cd7895..56fa1921f96 100644 --- a/frameworks/Java/redkale/redkale-native.dockerfile +++ b/frameworks/Java/redkale/redkale-native.dockerfile @@ -1,4 +1,4 @@ -FROM maven:3.8.6-openjdk-18-slim as maven +FROM maven:3.9.6-amazoncorretto-21-debian as maven WORKDIR /redkale COPY src src COPY conf conf @@ -6,15 +6,15 @@ COPY pom.xml pom.xml RUN mvn package -q -FROM ghcr.io/graalvm/graalvm-ce:ol9-java17-22.3.3 -RUN gu install native-image +FROM ghcr.io/graalvm/native-image-community:22.0.2 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 -RUN ls -lh +FROM ghcr.io/graalvm/jdk-community:22.0.2 +WORKDIR /redkale +COPY --from=native /redkale/redkale-benchmark redkale-benchmark EXPOSE 8080 diff --git a/frameworks/Java/redkale/redkale-pgclient.dockerfile b/frameworks/Java/redkale/redkale-pgclient.dockerfile new file mode 100644 index 00000000000..761368ba604 --- /dev/null +++ b/frameworks/Java/redkale/redkale-pgclient.dockerfile @@ -0,0 +1,15 @@ +FROM maven:3.9.6-amazoncorretto-21-debian as maven +WORKDIR /redkale +COPY src src +COPY conf conf +COPY pom-pgclient.xml pom.xml +RUN mvn package -q + +FROM openjdk:23-jdk-slim +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 diff --git a/frameworks/Java/redkale/redkale-vertx.dockerfile b/frameworks/Java/redkale/redkale-vertx.dockerfile deleted file mode 100644 index f4099b6a776..00000000000 --- a/frameworks/Java/redkale/redkale-vertx.dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -FROM maven:3.8.6-openjdk-18-slim as maven -WORKDIR /redkale -COPY src src -COPY conf conf -COPY pom-vertx.xml pom.xml -RUN mvn package -q - -FROM openjdk:21-jdk-slim -WORKDIR /redkale -COPY conf conf -COPY --from=maven /redkale/target/redkale-benchmark-1.0.0.jar redkale-benchmark.jar - -EXPOSE 8080 - -CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-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 d7878808a4b..79ec585c205 100644 --- a/frameworks/Java/redkale/redkale.dockerfile +++ b/frameworks/Java/redkale/redkale.dockerfile @@ -1,15 +1,15 @@ -FROM maven:3.8.6-openjdk-18-slim as maven +FROM maven:3.9.6-amazoncorretto-21-debian as maven WORKDIR /redkale COPY src src COPY conf conf COPY pom.xml pom.xml RUN mvn package -q -FROM openjdk:21-jdk-slim +FROM openjdk:23-jdk-slim WORKDIR /redkale COPY conf conf COPY --from=maven /redkale/target/redkale-benchmark-1.0.0.jar redkale-benchmark.jar EXPOSE 8080 -CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-DAPP_HOME=./", "-jar", "redkale-benchmark.jar"] +CMD ["java", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-DAPP_HOME=./", "-jar", "redkale-benchmark.jar"] diff --git a/frameworks/Java/redkale/src/main/java/org/redkalex/benchmark/BenchmarkService.java b/frameworks/Java/redkale/src/main/java/org/redkalex/benchmark/BenchmarkService.java index 1e48ee8e9b9..e2ebc7b8aad 100644 --- a/frameworks/Java/redkale/src/main/java/org/redkalex/benchmark/BenchmarkService.java +++ b/frameworks/Java/redkale/src/main/java/org/redkalex/benchmark/BenchmarkService.java @@ -7,7 +7,7 @@ import java.util.*; import java.util.concurrent.*; -import java.util.stream.IntStream; +import java.util.stream.*; import org.redkale.annotation.*; import org.redkale.net.http.*; import org.redkale.service.AbstractService; @@ -43,9 +43,7 @@ public CompletableFuture db() { @RestMapping(auth = false) public CompletableFuture> queries(int q) { - int size = Math.min(500, Math.max(1, q)); - IntStream ids = ThreadLocalRandom.current().ints(size, 1, 10001); - return source.findsListAsync(World.class, ids.boxed()); + return source.findsListAsync(World.class, random(q)); } @RestMapping(auth = false) @@ -54,8 +52,8 @@ public CompletableFuture> updates(int q) { IntStream ids = ThreadLocalRandom.current().ints(size, 1, 10001); int[] newNumbers = ThreadLocalRandom.current().ints(size, 1, 10001).toArray(); return source.findsListAsync(World.class, ids.boxed()) - .thenCompose(words -> source.updateAsync(World.updateNewNumbers(words, newNumbers)) - .thenApply(v -> words)); + .thenCompose(words -> source.updateAsync(World.updateNewNumbers(words, newNumbers)) + .thenApply(v -> words)); } @RestMapping(auth = false) @@ -69,8 +67,11 @@ public CompletableFuture fortunes() { @RestMapping(name = "cached-worlds", auth = false) public CachedWorld[] cachedWorlds(int q) { + return source.finds(CachedWorld.class, random(q)); + } + + private Stream random(int q) { int size = Math.min(500, Math.max(1, q)); - IntStream ids = ThreadLocalRandom.current().ints(size, 1, 10001); - return source.finds(CachedWorld.class, ids.boxed()); + return ThreadLocalRandom.current().ints(size, 1, 10001).boxed(); } } diff --git a/frameworks/Java/redkale/src/main/java/org/redkalex/benchmark/CachedWorld.java b/frameworks/Java/redkale/src/main/java/org/redkalex/benchmark/CachedWorld.java index 65dc5b8cf6d..ec2c0f1e0b2 100644 --- a/frameworks/Java/redkale/src/main/java/org/redkalex/benchmark/CachedWorld.java +++ b/frameworks/Java/redkale/src/main/java/org/redkalex/benchmark/CachedWorld.java @@ -10,9 +10,8 @@ * * @author zhangjx */ -@Entity @Table(name = "world") -@Cacheable(direct = true) +@Entity(cacheable = true, cacheDirect = true) public final class CachedWorld { @Id diff --git a/frameworks/Java/redkale/src/main/java/org/redkalex/benchmark/FortuneRender.java b/frameworks/Java/redkale/src/main/java/org/redkalex/benchmark/FortuneRender.java index 201c58bc741..651864d0da5 100644 --- a/frameworks/Java/redkale/src/main/java/org/redkalex/benchmark/FortuneRender.java +++ b/frameworks/Java/redkale/src/main/java/org/redkalex/benchmark/FortuneRender.java @@ -7,6 +7,7 @@ import java.nio.charset.StandardCharsets; import java.util.List; +import java.util.function.Function; import org.redkale.convert.Convert; import org.redkale.net.http.*; import org.redkale.util.*; @@ -19,7 +20,9 @@ public class FortuneRender implements org.redkale.net.http.HttpRender { private static final String contentType = "text/html; charset=utf-8"; - private static final byte[] text1 = "Fortunes".getBytes(StandardCharsets.UTF_8); + private static final byte[] text1 = + "Fortunes
idmessage
" + .getBytes(StandardCharsets.UTF_8); private static final byte[] text2 = "
idmessage
".getBytes(StandardCharsets.UTF_8); @@ -29,9 +32,9 @@ public class FortuneRender implements org.redkale.net.http.HttpRender { private static final byte[] text5 = "
".getBytes(StandardCharsets.UTF_8); - private final ThreadLocal localByteArray = ThreadLocal.withInitial(() -> new ByteArray(1280)); + private static final String arrayName = "fortuneByteArray"; - private final ThreadLocal localTmpArray = ThreadLocal.withInitial(() -> new ByteArray(128)); + private static final Function arrayFunc = s -> new ByteArray(1280); private byte[][] idBytesCache; @@ -53,12 +56,11 @@ public void init(HttpContext context, AnyValue config) { @Override public void renderTo(HttpRequest request, HttpResponse response, Convert convert, HttpScope scope) { - ByteArray array = localByteArray.get().clear(); + ByteArray array = request.getSubobjectIfAbsent(arrayName, arrayFunc).clear(); array.put(text1); - ByteArray tmp = localTmpArray.get(); for (Fortune item : (List) scope.getReferObj()) { - array.put(text2).put(escapeId(item.getId())) - .put(text3).put(escapeMessage(tmp, item.getMessage())).put(text4); + ByteArray msg = request.getSubobjectIfAbsent(item.getMessage(), this::escapeMessage); + array.put(text2).put(escapeId(item.getId())).put(text3).put(msg).put(text4); } array.put(text5); response.finish(contentType, array); @@ -72,23 +74,22 @@ private byte[] escapeId(int id) { } } - private ByteArray escapeMessage(ByteArray tmp, String message) { - tmp.clear(); + private ByteArray escapeMessage(String message) { + ByteArray array = new ByteArray(128); CharSequence cs = message; for (int i = 0; i < cs.length(); i++) { char c = cs.charAt(i); byte[] bs = c < escapeCache.length ? escapeCache[c] : null; if (bs != null) { - tmp.put(bs); + array.put(bs); } else if (c < 0x80) { - tmp.put((byte) c); + array.put((byte) c); } else if (c < 0x800) { - tmp.put((byte) (0xc0 | (c >> 6)), (byte) (0x80 | (c & 0x3f))); + array.put((byte) (0xc0 | (c >> 6)), (byte) (0x80 | (c & 0x3f))); } else { - tmp.put((byte) (0xe0 | ((c >> 12))), (byte) (0x80 | ((c >> 6) & 0x3f)), (byte) (0x80 | (c & 0x3f))); + array.put((byte) (0xe0 | (c >> 12)), (byte) (0x80 | ((c >> 6) & 0x3f)), (byte) (0x80 | (c & 0x3f))); } } - return tmp; + return array; } - } diff --git a/frameworks/Java/redkale/src/main/java/org/redkalex/benchmark/Message.java b/frameworks/Java/redkale/src/main/java/org/redkalex/benchmark/Message.java index 73cbe2c2afd..a5e7aed358d 100644 --- a/frameworks/Java/redkale/src/main/java/org/redkalex/benchmark/Message.java +++ b/frameworks/Java/redkale/src/main/java/org/redkalex/benchmark/Message.java @@ -1,41 +1,40 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package org.redkalex.benchmark; - -import org.redkale.annotation.Bean; -import org.redkale.convert.ConvertSmallString; -import org.redkale.convert.json.JsonConvert; - -/** - * - * @author zhangjx - */ -@Bean -public final class Message { - - @ConvertSmallString - 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; - } - - @Override - public String toString() { - return JsonConvert.root().convertTo(this); - } -} +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.redkalex.benchmark; + +import org.redkale.annotation.Serial; +import org.redkale.convert.ConvertStandardString; +import org.redkale.convert.json.JsonConvert; + +/** + * + * @author zhangjx + */ +@Serial +public final class Message { + + @ConvertStandardString + 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; + } + + @Override + public String toString() { + return JsonConvert.root().convertTo(this); + } +} diff --git a/frameworks/Java/revenj-jvm/benchmark_config.json b/frameworks/Java/revenj-jvm/benchmark_config.json index 4187598430b..ffc6b919ca6 100644 --- a/frameworks/Java/revenj-jvm/benchmark_config.json +++ b/frameworks/Java/revenj-jvm/benchmark_config.json @@ -22,6 +22,7 @@ "database_os": "Linux", "display_name": "Revenj.JVM", "notes": "", + "tags": ["broken"], "versus": "servlet" } }] diff --git a/frameworks/Java/servlet/pom.xml b/frameworks/Java/servlet/pom.xml index b038c8549c2..6f08f65c22a 100644 --- a/frameworks/Java/servlet/pom.xml +++ b/frameworks/Java/servlet/pom.xml @@ -13,7 +13,7 @@ 11 11 1.2.3.Final - 2.13.4.2 + 2.16.0 src/main/webapp/WEB-INF/web.xml @@ -108,7 +108,7 @@ org.postgresql postgresql - 42.4.3 + 42.7.2
diff --git a/frameworks/Java/servlet3/benchmark_config.json b/frameworks/Java/servlet3/benchmark_config.json index b6e4d1b5400..cd2a050e174 100644 --- a/frameworks/Java/servlet3/benchmark_config.json +++ b/frameworks/Java/servlet3/benchmark_config.json @@ -17,6 +17,7 @@ "database_os": "Linux", "display_name": "servlet3", "notes": "Servlet 3.1 Async I/O", + "tags": ["broken"], "versus": "servlet" }, "sync": { @@ -35,6 +36,7 @@ "database_os": "Linux", "display_name": "servlet3", "notes": "", + "tags": ["broken"], "versus": "servlet" } }] diff --git a/frameworks/Java/servlet3/pom.xml b/frameworks/Java/servlet3/pom.xml index e424796691b..d48a9d90723 100644 --- a/frameworks/Java/servlet3/pom.xml +++ b/frameworks/Java/servlet3/pom.xml @@ -80,7 +80,7 @@ com.fasterxml.jackson.core jackson-databind - 2.13.4.2 + 2.16.0 @@ -93,7 +93,7 @@ ch.qos.logback logback-classic - 1.3.0-alpha4 + 1.3.12 org.slf4j diff --git a/frameworks/Java/smart-socket/benchmark_config.json b/frameworks/Java/smart-socket/benchmark_config.json index f69d7a43eb7..040fb6bdee9 100755 --- a/frameworks/Java/smart-socket/benchmark_config.json +++ b/frameworks/Java/smart-socket/benchmark_config.json @@ -1,13 +1,10 @@ { - "framework": "smart-socket", + "framework": "feat", "tests": [ { "default": { "json_url": "/json", "plaintext_url": "/plaintext", - "db_url": "/db", - "query_url": "/queries?queries=", - "update_url": "/updates?queries=", "port": 8080, "approach": "Realistic", "classification": "Platform", @@ -20,9 +17,9 @@ "webserver": "None", "os": "Linux", "database_os": "Linux", - "display_name": "smart-socket", + "display_name": "feat", "notes": "", - "versus": "smart-socket" + "versus": "feat" }, "smart-servlet": { "json_url": "/json", diff --git a/frameworks/Java/smart-socket/config.toml b/frameworks/Java/smart-socket/config.toml index fbebc43a6a3..54e7e13d9d7 100644 --- a/frameworks/Java/smart-socket/config.toml +++ b/frameworks/Java/smart-socket/config.toml @@ -1,12 +1,12 @@ [framework] -name = "smart-socket" +name = "feat" [main] urls.plaintext = "/plaintext" urls.json = "/json" -urls.db = "/db" -urls.query = "/queries?queries=" -urls.update = "/updates?queries=" +#urls.db = "/db" +#urls.query = "/queries?queries=" +#urls.update = "/updates?queries=" approach = "Realistic" classification = "Platform" database = "Postgres" @@ -15,7 +15,7 @@ os = "Linux" orm = "Raw" platform = "smartboot" webserver = "None" -versus = "smart-socket" +versus = "feat" [smart-servlet] urls.plaintext = "/plaintext" diff --git a/frameworks/Java/smart-socket/feat-smart-servlet.dockerfile b/frameworks/Java/smart-socket/feat-smart-servlet.dockerfile new file mode 100644 index 00000000000..7ec765572a8 --- /dev/null +++ b/frameworks/Java/smart-socket/feat-smart-servlet.dockerfile @@ -0,0 +1,13 @@ +FROM maven:3.9.7-amazoncorretto-21 as maven +WORKDIR /smart-socket +COPY pom.xml pom.xml +COPY src src +RUN mvn install -q + +FROM amazoncorretto:25.0.1-alpine +WORKDIR /smart-socket +COPY --from=maven /smart-socket/target/smart-socket-benchmark-1.0.jar app.jar + +EXPOSE 8080 + +CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-cp", "app.jar", "org.smartboot.servlet.Bootstrap"] diff --git a/frameworks/Java/smart-socket/feat.dockerfile b/frameworks/Java/smart-socket/feat.dockerfile new file mode 100644 index 00000000000..e21235baa58 --- /dev/null +++ b/frameworks/Java/smart-socket/feat.dockerfile @@ -0,0 +1,13 @@ +FROM maven:3.9.7-amazoncorretto-21 as maven +WORKDIR /smart-socket +COPY pom.xml pom.xml +COPY src src +RUN mvn install -q + +FROM amazoncorretto:25.0.1-alpine +WORKDIR /smart-socket +COPY --from=maven /smart-socket/target/smart-socket-benchmark-1.0.jar app.jar + +EXPOSE 8080 + +CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-cp", "app.jar", "org.smartboot.http.Bootstrap"] diff --git a/frameworks/Java/smart-socket/pom.xml b/frameworks/Java/smart-socket/pom.xml index 81fbc295b98..171f036e654 100644 --- a/frameworks/Java/smart-socket/pom.xml +++ b/frameworks/Java/smart-socket/pom.xml @@ -8,24 +8,35 @@ jar UTF-8 - 17 - 17 + 21 + 21 2.17.1 - 0.6-SNAPSHOT + 3.1-SNAPSHOT 5.0.0 0.9.23 - io.edap - edapx-json - 0.1-SNAPSHOT + tech.smartboot.feat + feat-cloud-starter + 1.3.2-SNAPSHOT + + + + + - org.smartboot.servlet + tech.smartboot.servlet servlet-core ${smartservlet.version} + + + tech.smartboot.feat + feat-core + + com.zaxxer @@ -56,7 +67,7 @@ org.postgresql postgresql - 42.4.3 + 42.7.2 @@ -77,9 +88,15 @@ https://repo.maven.apache.org/maven2 - sonatype-nexus-snapshots - Sonatype Nexus Snapshots - https://oss.sonatype.org/content/repositories/snapshots + Central Portal Snapshots + central-portal-snapshots + https://central.sonatype.com/repository/maven-snapshots/ + + false + + + true +
@@ -114,20 +131,24 @@
- maven-assembly-plugin - 3.1.0 - - - jar-with-dependencies - - + maven-shade-plugin + 3.3.0 - make-assembly package - single + shade + + false + + + + META-INF/services/tech.smartboot.feat.core.apt.AptLoader + + + diff --git a/frameworks/Java/smart-socket/smart-socket-smart-servlet.dockerfile b/frameworks/Java/smart-socket/smart-socket-smart-servlet.dockerfile deleted file mode 100644 index 8b1cbe79930..00000000000 --- a/frameworks/Java/smart-socket/smart-socket-smart-servlet.dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM maven:3.8.6-openjdk-18-slim as maven -WORKDIR /smart-socket -COPY pom.xml pom.xml -COPY src src -RUN mvn compile assembly:single -q - -FROM openjdk:21-jdk-slim -WORKDIR /smart-socket -COPY --from=maven /smart-socket/target/smart-socket-benchmark-1.0-jar-with-dependencies.jar app.jar - -EXPOSE 8080 - -CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-cp", "app.jar", "org.smartboot.servlet.Bootstrap"] diff --git a/frameworks/Java/smart-socket/smart-socket.dockerfile b/frameworks/Java/smart-socket/smart-socket.dockerfile deleted file mode 100644 index b40ad2c8d43..00000000000 --- a/frameworks/Java/smart-socket/smart-socket.dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM maven:3.8.6-openjdk-18-slim as maven -WORKDIR /smart-socket -COPY pom.xml pom.xml -COPY src src -RUN mvn compile assembly:single -q - -FROM openjdk:21-jdk-slim -WORKDIR /smart-socket -COPY --from=maven /smart-socket/target/smart-socket-benchmark-1.0-jar-with-dependencies.jar app.jar - -EXPOSE 8080 - -CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-cp", "app.jar", "org.smartboot.http.Bootstrap"] diff --git a/frameworks/Java/smart-socket/src/main/java/org/smartboot/http/Bootstrap.java b/frameworks/Java/smart-socket/src/main/java/org/smartboot/http/Bootstrap.java index 3d26a672e59..80fe3131706 100755 --- a/frameworks/Java/smart-socket/src/main/java/org/smartboot/http/Bootstrap.java +++ b/frameworks/Java/smart-socket/src/main/java/org/smartboot/http/Bootstrap.java @@ -8,74 +8,39 @@ package org.smartboot.http; -import com.zaxxer.hikari.HikariConfig; -import com.zaxxer.hikari.HikariDataSource; -import org.smartboot.Message; -import org.smartboot.http.server.HttpBootstrap; -import org.smartboot.http.server.HttpRequest; -import org.smartboot.http.server.HttpResponse; -import org.smartboot.http.server.HttpServerHandler; -import org.smartboot.http.server.handler.HttpRouteHandler; -import javax.sql.DataSource; -import java.io.IOException; +import tech.smartboot.feat.cloud.FeatCloud; public class Bootstrap { - static byte[] body = "Hello, World!".getBytes(); public static void main(String[] args) { - HttpRouteHandler routeHandle = new HttpRouteHandler(); - routeHandle - .route("/plaintext", new HttpServerHandler() { - - - @Override - public void handle(HttpRequest request, HttpResponse response) throws IOException { - response.setContentLength(body.length); - response.setContentType("text/plain; charset=UTF-8"); - response.write(body); - } - }) - .route("/json", new HttpServerHandler() { - - @Override - public void handle(HttpRequest request, HttpResponse response) throws IOException { - - response.setContentType("application/json"); - JsonUtil.writeJsonBytes(response, new Message("Hello, World!")); - } - }); - initDB(routeHandle); int cpuNum = Runtime.getRuntime().availableProcessors(); - // 定义服务器接受的消息类型以及各类消息对应的处理器 - HttpBootstrap bootstrap = new HttpBootstrap(); - bootstrap.configuration() - .threadNum(cpuNum) - .readBufferSize(1024 * 4) - .writeBufferSize(1024 * 4) - .readMemoryPool(16384 * 1024 * 4) - .writeMemoryPool(10 * 1024 * 1024 * cpuNum, cpuNum); - bootstrap.httpHandler(routeHandle).setPort(8080).start(); + FeatCloud.cloudServer(options -> { + options.threadNum(cpuNum + 1) + .headerLimiter(0) + .readBufferSize(1024 * 4) + .writeBufferSize(1024 * 4); + }).listen(8080); } - private static void initDB(HttpRouteHandler routeHandle) { - try { - Class.forName("org.postgresql.Driver"); - } catch (ClassNotFoundException e) { - e.printStackTrace(); - } - HikariConfig config = new HikariConfig(); - config.setJdbcUrl("jdbc:postgresql://tfb-database:5432/hello_world"); - config.setUsername("benchmarkdbuser"); - config.setPassword("benchmarkdbpass"); - config.setMaximumPoolSize(64); - config.addDataSourceProperty("cachePrepStmts", "true"); - config.addDataSourceProperty("prepStmtCacheSize", "250"); - config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048"); - DataSource dataSource = new HikariDataSource(config); - routeHandle.route("/db", new SingleQueryHandler(dataSource)) - .route("/queries", new MultipleQueriesHandler(dataSource)) - .route("/updates", new UpdateHandler(dataSource)); -// .route("/fortunes", new FortunesHandler(dataSource)); - } +// private static void initDB(HttpRouteHandler routeHandle) { +// try { +// Class.forName("org.postgresql.Driver"); +// } catch (ClassNotFoundException e) { +// e.printStackTrace(); +// } +// HikariConfig config = new HikariConfig(); +// config.setJdbcUrl("jdbc:postgresql://tfb-database:5432/hello_world"); +// config.setUsername("benchmarkdbuser"); +// config.setPassword("benchmarkdbpass"); +// config.setMaximumPoolSize(64); +// config.addDataSourceProperty("cachePrepStmts", "true"); +// config.addDataSourceProperty("prepStmtCacheSize", "250"); +// config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048"); +// DataSource dataSource = new HikariDataSource(config); +// routeHandle.route("/db", new SingleQueryHandler(dataSource)) +// .route("/queries", new MultipleQueriesHandler(dataSource)) +// .route("/updates", new UpdateHandler(dataSource)); +//// .route("/fortunes", new FortunesHandler(dataSource)); +// } } diff --git a/frameworks/Java/smart-socket/src/main/java/org/smartboot/http/FeatController.java b/frameworks/Java/smart-socket/src/main/java/org/smartboot/http/FeatController.java new file mode 100644 index 00000000000..2973f2861e5 --- /dev/null +++ b/frameworks/Java/smart-socket/src/main/java/org/smartboot/http/FeatController.java @@ -0,0 +1,24 @@ +package org.smartboot.http; + +import org.smartboot.Message; +import tech.smartboot.feat.cloud.annotation.Controller; +import tech.smartboot.feat.cloud.annotation.RequestMapping; +import tech.smartboot.feat.core.common.HeaderValue; +import tech.smartboot.feat.core.server.HttpResponse; + +@Controller +public class FeatController { + static byte[] body = "Hello, World!".getBytes(); + + @RequestMapping("/plaintext") + public byte[] plaintext(HttpResponse response) { + response.setContentType(HeaderValue.ContentType.TEXT_PLAIN_UTF8); + return body; + } + + @RequestMapping("/json") + public Message json(HttpResponse response) { + response.setContentType(HeaderValue.ContentType.APPLICATION_JSON_UTF8); + return new Message("Hello, World!"); + } +} diff --git a/frameworks/Java/smart-socket/src/main/java/org/smartboot/http/JsonUtil.java b/frameworks/Java/smart-socket/src/main/java/org/smartboot/http/JsonUtil.java index b20525ec571..31a7d546119 100644 --- a/frameworks/Java/smart-socket/src/main/java/org/smartboot/http/JsonUtil.java +++ b/frameworks/Java/smart-socket/src/main/java/org/smartboot/http/JsonUtil.java @@ -5,7 +5,7 @@ import com.jsoniter.spi.JsonException; import com.jsoniter.spi.Slice; import jakarta.servlet.http.HttpServletResponse; -import org.smartboot.http.server.HttpResponse; +import tech.smartboot.feat.core.server.HttpResponse; import java.io.IOException; diff --git a/frameworks/Java/smart-socket/src/main/java/org/smartboot/http/MultipleQueriesHandler.java b/frameworks/Java/smart-socket/src/main/java/org/smartboot/http/MultipleQueriesHandler.java index d623f3bf1de..07147048a34 100644 --- a/frameworks/Java/smart-socket/src/main/java/org/smartboot/http/MultipleQueriesHandler.java +++ b/frameworks/Java/smart-socket/src/main/java/org/smartboot/http/MultipleQueriesHandler.java @@ -1,9 +1,10 @@ package org.smartboot.http; -import org.smartboot.http.common.utils.NumberUtils; -import org.smartboot.http.server.HttpRequest; -import org.smartboot.http.server.HttpResponse; -import org.smartboot.http.server.HttpServerHandler; + +import tech.smartboot.feat.core.common.FeatUtils; +import tech.smartboot.feat.core.server.HttpHandler; +import tech.smartboot.feat.core.server.HttpRequest; +import tech.smartboot.feat.core.server.HttpResponse; import javax.sql.DataSource; import java.io.IOException; @@ -11,13 +12,14 @@ import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.ThreadLocalRandom; /** * @author 三刀 * @version V1.0 , 2020/6/16 */ -public class MultipleQueriesHandler extends HttpServerHandler { +public class MultipleQueriesHandler implements HttpHandler { private DataSource dataSource; public MultipleQueriesHandler(DataSource dataSource) { @@ -25,28 +27,41 @@ public MultipleQueriesHandler(DataSource dataSource) { } @Override - public void handle(HttpRequest httpRequest, HttpResponse response) throws IOException { - int queries = Math.min(Math.max(NumberUtils.toInt(httpRequest.getParameter("queries"), 1), 1), 500); - World[] worlds = new World[queries]; - try (Connection connection = dataSource.getConnection(); - PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM World WHERE id=?");) { - - for (int i = 0; i < queries; i++) { - preparedStatement.setInt(1, getRandomNumber()); - ResultSet resultSet = preparedStatement.executeQuery(); - resultSet.next(); - World world = new World(); - world.setId(resultSet.getInt(1)); - world.setRandomNumber(resultSet.getInt(2)); - worlds[i] = world; - preparedStatement.clearParameters(); + public void handle(HttpRequest httpRequest, CompletableFuture completableFuture) throws IOException { + HttpResponse response = httpRequest.getResponse(); + Thread.startVirtualThread(() -> { + try { + int queries = Math.min(Math.max(FeatUtils.toInt(httpRequest.getParameter("queries"), 1), 1), 500); + World[] worlds = new World[queries]; + try (Connection connection = dataSource.getConnection(); + PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM World WHERE id=?");) { + + for (int i = 0; i < queries; i++) { + preparedStatement.setInt(1, getRandomNumber()); + ResultSet resultSet = preparedStatement.executeQuery(); + resultSet.next(); + World world = new World(); + world.setId(resultSet.getInt(1)); + world.setRandomNumber(resultSet.getInt(2)); + worlds[i] = world; + preparedStatement.clearParameters(); + } + + } catch (SQLException throwables) { + throwables.printStackTrace(); + } + response.setContentType("application/json"); + JsonUtil.writeJsonBytes(response, worlds); + } finally { + completableFuture.complete(null); } + }); + + } + + @Override + public void handle(HttpRequest request) throws Throwable { - } catch (SQLException throwables) { - throwables.printStackTrace(); - } - response.setContentType("application/json"); - JsonUtil.writeJsonBytes(response, worlds); } protected int getRandomNumber() { diff --git a/frameworks/Java/smart-socket/src/main/java/org/smartboot/http/SingleQueryHandler.java b/frameworks/Java/smart-socket/src/main/java/org/smartboot/http/SingleQueryHandler.java index e72f4b06433..c6f9f78b263 100644 --- a/frameworks/Java/smart-socket/src/main/java/org/smartboot/http/SingleQueryHandler.java +++ b/frameworks/Java/smart-socket/src/main/java/org/smartboot/http/SingleQueryHandler.java @@ -1,8 +1,9 @@ package org.smartboot.http; -import org.smartboot.http.server.HttpRequest; -import org.smartboot.http.server.HttpResponse; -import org.smartboot.http.server.HttpServerHandler; + +import tech.smartboot.feat.core.server.HttpHandler; +import tech.smartboot.feat.core.server.HttpRequest; +import tech.smartboot.feat.core.server.HttpResponse; import javax.sql.DataSource; import java.io.IOException; @@ -10,13 +11,14 @@ import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.ThreadLocalRandom; /** * @author 三刀 * @version V1.0 , 2020/6/16 */ -public class SingleQueryHandler extends HttpServerHandler { +public class SingleQueryHandler implements HttpHandler { private DataSource dataSource; public SingleQueryHandler(DataSource dataSource) { @@ -24,20 +26,32 @@ public SingleQueryHandler(DataSource dataSource) { } @Override - public void handle(HttpRequest httpRequest, HttpResponse response) throws IOException { - World world = new World(); - try (Connection connection = dataSource.getConnection(); - PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM World WHERE id=?");) { - preparedStatement.setInt(1, getRandomNumber()); - ResultSet resultSet = preparedStatement.executeQuery(); - resultSet.next(); - world.setId(resultSet.getInt(1)); - world.setRandomNumber(resultSet.getInt(2)); - } catch (SQLException throwables) { - throwables.printStackTrace(); - } - response.setContentType("application/json"); - JsonUtil.writeJsonBytes(response, world); + public void handle(HttpRequest httpRequest, CompletableFuture completableFuture) throws IOException { + HttpResponse response = httpRequest.getResponse(); + Thread.startVirtualThread(() -> { + try { + World world = new World(); + try (Connection connection = dataSource.getConnection(); PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM World WHERE id=?");) { + preparedStatement.setInt(1, getRandomNumber()); + ResultSet resultSet = preparedStatement.executeQuery(); + resultSet.next(); + world.setId(resultSet.getInt(1)); + world.setRandomNumber(resultSet.getInt(2)); + } catch (SQLException throwables) { + throwables.printStackTrace(); + } + response.setContentType("application/json"); + JsonUtil.writeJsonBytes(response, world); + } finally { + completableFuture.complete(null); + } + }); + + } + + @Override + public void handle(HttpRequest request) throws Throwable { + } protected int getRandomNumber() { diff --git a/frameworks/Java/smart-socket/src/main/java/org/smartboot/http/UpdateHandler.java b/frameworks/Java/smart-socket/src/main/java/org/smartboot/http/UpdateHandler.java index 065bed5a9a6..85d990a71b4 100644 --- a/frameworks/Java/smart-socket/src/main/java/org/smartboot/http/UpdateHandler.java +++ b/frameworks/Java/smart-socket/src/main/java/org/smartboot/http/UpdateHandler.java @@ -1,9 +1,10 @@ package org.smartboot.http; -import org.smartboot.http.common.utils.NumberUtils; -import org.smartboot.http.server.HttpRequest; -import org.smartboot.http.server.HttpResponse; -import org.smartboot.http.server.HttpServerHandler; + +import tech.smartboot.feat.core.common.FeatUtils; +import tech.smartboot.feat.core.server.HttpHandler; +import tech.smartboot.feat.core.server.HttpRequest; +import tech.smartboot.feat.core.server.HttpResponse; import javax.sql.DataSource; import java.io.IOException; @@ -18,7 +19,7 @@ * @author 三刀 * @version V1.0 , 2020/6/16 */ -public class UpdateHandler extends HttpServerHandler { +public class UpdateHandler implements HttpHandler { private DataSource dataSource; public UpdateHandler(DataSource dataSource) { @@ -26,8 +27,9 @@ public UpdateHandler(DataSource dataSource) { } @Override - public void handle(HttpRequest httpRequest, HttpResponse response) throws IOException { - int queries = Math.min(Math.max(NumberUtils.toInt(httpRequest.getParameter("queries"), 1), 1), 500); + public void handle(HttpRequest request) throws IOException { + HttpResponse response = request.getResponse(); + int queries = Math.min(Math.max(FeatUtils.toInt(request.getParameter("queries"), 1), 1), 500); World[] worlds = new World[queries]; StringJoiner updateSql = new StringJoiner( ", ", diff --git a/frameworks/Java/smart-socket/src/main/java/org/smartboot/servlet/Bootstrap.java b/frameworks/Java/smart-socket/src/main/java/org/smartboot/servlet/Bootstrap.java index 681ad1a7593..0ff24d1cbfa 100644 --- a/frameworks/Java/smart-socket/src/main/java/org/smartboot/servlet/Bootstrap.java +++ b/frameworks/Java/smart-socket/src/main/java/org/smartboot/servlet/Bootstrap.java @@ -1,12 +1,9 @@ package org.smartboot.servlet; -import org.smartboot.http.server.HttpBootstrap; -import org.smartboot.http.server.HttpRequest; -import org.smartboot.http.server.HttpResponse; -import org.smartboot.http.server.HttpServerHandler; -import org.smartboot.servlet.conf.ServletInfo; -import java.util.concurrent.CompletableFuture; +import tech.smartboot.servlet.Container; +import tech.smartboot.servlet.ServletContextRuntime; +import tech.smartboot.servlet.conf.ServletInfo; /** * @author 三刀(zhengjunweimail@163.com) @@ -15,41 +12,34 @@ public class Bootstrap { public static void main(String[] args) throws Throwable { - ContainerRuntime containerRuntime = new ContainerRuntime(); + System.setProperty("smart-servlet-spring-boot-starter", "true"); + Container containerRuntime = new Container(); // plaintext - ServletContextRuntime applicationRuntime = new ServletContextRuntime("/"); + ServletContextRuntime applicationRuntime = new ServletContextRuntime(null, Thread.currentThread().getContextClassLoader(), "/"); + applicationRuntime.setVendorProvider(response -> { + + }); ServletInfo plainTextServletInfo = new ServletInfo(); plainTextServletInfo.setServletName("plaintext"); plainTextServletInfo.setServletClass(HelloWorldServlet.class.getName()); - plainTextServletInfo.addMapping("/plaintext"); + plainTextServletInfo.addServletMapping("/plaintext", applicationRuntime); applicationRuntime.getDeploymentInfo().addServlet(plainTextServletInfo); // json ServletInfo jsonServletInfo = new ServletInfo(); jsonServletInfo.setServletName("json"); jsonServletInfo.setServletClass(JsonServlet.class.getName()); - jsonServletInfo.addMapping("/json"); + jsonServletInfo.addServletMapping("/json", applicationRuntime); applicationRuntime.getDeploymentInfo().addServlet(jsonServletInfo); containerRuntime.addRuntime(applicationRuntime); - int cpuNum = Runtime.getRuntime().availableProcessors(); // 定义服务器接受的消息类型以及各类消息对应的处理器 - HttpBootstrap bootstrap = new HttpBootstrap(); - bootstrap.configuration() - .threadNum(cpuNum) - .bannerEnabled(false) - .readBufferSize(1024 * 4) - .writeBufferSize(1024 * 4) - .readMemoryPool(16384 * 1024 * 4) - .writeMemoryPool(10 * 1024 * 1024 * cpuNum, cpuNum); - containerRuntime.start(bootstrap.configuration()); - bootstrap.setPort(8080) - .httpHandler(new HttpServerHandler() { - @Override - public void handle(HttpRequest request, HttpResponse response, CompletableFuture completableFuture) throws Throwable { - containerRuntime.doHandle(request, response, completableFuture); - } - }) - .start(); + containerRuntime.getConfiguration() + .setThreadNum(cpuNum) + .setHeaderLimiter(0) + .setReadBufferSize(1024 * 4); + containerRuntime.initialize(); + containerRuntime.start(); + } } diff --git a/frameworks/Java/smart-socket/src/main/java/org/smartboot/servlet/HelloWorldServlet.java b/frameworks/Java/smart-socket/src/main/java/org/smartboot/servlet/HelloWorldServlet.java index c3900de716c..3d0d8bd1d2a 100644 --- a/frameworks/Java/smart-socket/src/main/java/org/smartboot/servlet/HelloWorldServlet.java +++ b/frameworks/Java/smart-socket/src/main/java/org/smartboot/servlet/HelloWorldServlet.java @@ -1,5 +1,6 @@ package org.smartboot.servlet; + import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; diff --git a/frameworks/Java/smart-socket/src/main/resources/smart-servlet/License.shield b/frameworks/Java/smart-socket/src/main/resources/smart-servlet/License.shield new file mode 100644 index 00000000000..866f59ca2b9 Binary files /dev/null and b/frameworks/Java/smart-socket/src/main/resources/smart-servlet/License.shield differ diff --git a/frameworks/Java/smart-socket/src/main/resources/smart-servlet/smart-servlet.pem b/frameworks/Java/smart-socket/src/main/resources/smart-servlet/smart-servlet.pem new file mode 100644 index 00000000000..38a0a7c0ec9 --- /dev/null +++ b/frameworks/Java/smart-socket/src/main/resources/smart-servlet/smart-servlet.pem @@ -0,0 +1,55 @@ +-----BEGIN CERTIFICATE----- +MIIEhTCCAu2gAwIBAgIQF5C4/s1tNk9arohyD4J2UDANBgkqhkiG9w0BAQsFADCB +nzEeMBwGA1UEChMVbWtjZXJ0IGRldmVsb3BtZW50IENBMTowOAYDVQQLDDF6aGVu +Z2p3MjJtYWMxMjNAemhlbmdqdzIyTWFjMTIzLmxvY2FsICh6aGVuZ2p3MjIpMUEw +PwYDVQQDDDhta2NlcnQgemhlbmdqdzIybWFjMTIzQHpoZW5nancyMk1hYzEyMy5s +b2NhbCAoemhlbmdqdzIyKTAeFw0yNDAyMTUwNzU3NTNaFw0yNjA1MTUwNzU3NTNa +MGUxJzAlBgNVBAoTHm1rY2VydCBkZXZlbG9wbWVudCBjZXJ0aWZpY2F0ZTE6MDgG +A1UECwwxemhlbmdqdzIybWFjMTIzQHpoZW5nancyMk1hYzEyMy5sb2NhbCAoemhl +bmdqdzIyKTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALvMsE1RIalU +Kzy+4U+Ixw+Z8FL3KHiKLk1513qsn40Po4bsE8zgsrd4lLx1lHpEkmKK3dpHREP1 +a1goi8Jqypmiz4oBUzrBMKBVo60wom3Al/XslgiZdzrhtFMOhwcjfGhkthq3ps5q +wHyqRneijfeB/YICfF+e0K6fnbiSPd8rBJP6F7de2oafawIV9jNtIpqUQpfk+b+F +Y3oDE2xCiz1chx/AfY6CaSICHYoHR9beugnm9RO45mjw/84Fs5AnneTUkZbeozYo +I0FyqplhfExglU3k/S0Fvkbd+GT5RPkhwwC3SQGldORHR9/+yoAsNjKlrLMD+aTo +5G618AEldr0CAwEAAaN2MHQwDgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsG +AQUFBwMBMB8GA1UdIwQYMBaAFDnyay2H0T65/ghxa7Ap7kKXyEefMCwGA1UdEQQl +MCOCCWxvY2FsaG9zdIcEfwAAAYcQAAAAAAAAAAAAAAAAAAAAATANBgkqhkiG9w0B +AQsFAAOCAYEAu31uRYtB+5dYbtOTVJDNw94nRXNkkh/u1Gv/WcEaauwsgoaeyy6P +kIavx1RiNrCkAO5aYIVCF407OadMzixRurvc4hVatAJVaj6zNfSs4HCViB7BCfLu +oYmqEYwjaPdqLq04uA/ZEeklqeKRJ0gzKXToaoQ8xcxIJcCjojaSi4usqSI5bi4y +Md79AtB3fxv+RipaHOPAqs2i2Eo7wCENEnUs8Uqu/VI3hZEljVOOFHbak33iFdwM +Gg4NfE3QSxVOctseB+2lcNjuk8Wxee1CIvH/imskgZl25dg4B2nHG9TEiYbabJ7/ +K5MOWg81lNAF+pmUJ01OaoFcXyDPc5hh5Unv3zHJrhRc86JwxqwhThkXRwAgh8fA +gjQIfE9byUD9o/HTeTdC7B8Tb3EnvYxkj83fi0fDj90022sjsRD/JMLfigx+T4rA +C4FKqpXgqfry0QUfibX6sxRWw7QwWtf9AInAEVgukx2ollxLGoVeK6hYG26d94YE +QtxEn3cOVqU+ +-----END CERTIFICATE----- +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC7zLBNUSGpVCs8 +vuFPiMcPmfBS9yh4ii5Nedd6rJ+ND6OG7BPM4LK3eJS8dZR6RJJiit3aR0RD9WtY +KIvCasqZos+KAVM6wTCgVaOtMKJtwJf17JYImXc64bRTDocHI3xoZLYat6bOasB8 +qkZ3oo33gf2CAnxfntCun524kj3fKwST+he3XtqGn2sCFfYzbSKalEKX5Pm/hWN6 +AxNsQos9XIcfwH2OgmkiAh2KB0fW3roJ5vUTuOZo8P/OBbOQJ53k1JGW3qM2KCNB +cqqZYXxMYJVN5P0tBb5G3fhk+UT5IcMAt0kBpXTkR0ff/sqALDYypayzA/mk6ORu +tfABJXa9AgMBAAECggEAHGOV5yozj3hUzOsB/lbr2JTpunD4YjhpRXb8tuOvftB1 +ZOj9GUSCX6/PtCmGF3GUO2dIoD2TuT45SuteLTadh9oPy4nlvgUER8iKZJzsgPDT +R+7Kw2QHnRQPgVq52L9piBJpYOKQSbXjgTTwUBd3pIm2+9dKW94TJ8KjQgqBZeHF +jBFrqqAVLvgRm5nOeNx98H6bhLd/GoB1RSj61jIcNNpDRnPxzq3IYLgv2zjXWasJ ++IvVCTlxapbVBgzvp6burmJ8eYBruW3FAR0tGBJi3imySDLs3EbB1F2ox0pOJjOw +c2bdZVgPdKY2wbmk+/2pyG4le5/64ByLxqX7Gux9dQKBgQDT/25SzZF9sVGkOo0u +5WUYqBA0ni2O7mFJR9KdHKrEeN6IcvPL+ttp92ESBAZf/rxN4KZs1OPeg7MABN/3 +caQQIqQNaFBdPrX0E5fs+gTKb38r1hXxpsCEhDjxMXroBen2RaTf7Q7AyxQFKFXZ +wjFyOWHR0tL1pO+O7dt3YgMB7wKBgQDix3pisWzUAeXOVVXRzfe9H9n5KmY0rnmC +raXa00Aq2RnBxtdIDf2whX6wOBOz3cHxsFMSDOVy36DfzGeBjMJjhvwq4Mdzu9HV +fYqUJHQBGdK/wGOMOto32E/hbIVhWwxsPZvpeb3h8lhOHVTJN0HbqrZbDLPObjlE +Dlx67ILOEwKBgB4CUV6dRNQTDqh9tVCHHllwKOMZ5P8PlWvnI9Qjo7SuG2obQ5GD +UB3e67m+IhzilUs82rIbLKpp4CPHjOCdEIlMLgbL1lxsrRsAzwe3mIgDYnAVHQQZ +A7V+dgUGaQyBEc5Pq3gbOXRnCs10GTr69z7hCozGGCC3mUWVO/TZRe23AoGBAOFI +y0LaAUPHstS8H2oyU8a0qqSFQ01YemugN+Bf9iHa1GSVNO5mv7upkkZbHu+TAAUq +ZgvLdfEdSUKqW7Tt8XpP8Zhi/qDxV63fblhmsjsZvSwyYnI/UOMjZ4+IcCRb/8ZT +mdxhzYl1Z9YJ+119IFapi0h+IO2UwBzkq2iOJg+zAoGBALJSi+nD7/lhA/HKu8Nr +sh4G6tczLMOHN+jvngf5WoGEnBM1ENUtmMiH0YvBIpyHSHgyKwq+H29fgA5f42Eb +xe7HfOye3a3OmmJvzkckEs5Ms1J4ahErwRUvM5+xsCG5bdpA/p61sy14W3eYyA/r +tSSrxN4ernLg7k/vNHB0NIjK +-----END PRIVATE KEY----- diff --git a/frameworks/Java/smart-socket/src/main/resources/smart-servlet/smart-servlet.properties b/frameworks/Java/smart-socket/src/main/resources/smart-servlet/smart-servlet.properties new file mode 100644 index 00000000000..2df513cd3ae --- /dev/null +++ b/frameworks/Java/smart-socket/src/main/resources/smart-servlet/smart-servlet.properties @@ -0,0 +1,15 @@ +# +# Copyright (c) 2017-2020, org.smartboot. All rights reserved. +# project name: smart-servlet +# file name: smart-servlet.properties +# Date: 2020-12-10 +# Author: sandao (zhengjunweimail@163.com) +# +# +http.port=8080 +http.readBufferSize=8192 +#http.threadNum=10 +root.context=ROOT +## tls/ssl +ssl.enable=false +ssl.port=443 diff --git a/frameworks/Java/solon/README.md b/frameworks/Java/solon/README.md index 0824b5effd9..49d4aef9fe8 100644 --- a/frameworks/Java/solon/README.md +++ b/frameworks/Java/solon/README.md @@ -4,13 +4,13 @@ This is the solon portion of a [benchmarking test suite](../) comparing a variety of web development platforms. ### JSON Encoding Test -* [JSON test source](src/main/java/pmg/Main.java) -* [Plaintext test source](src/main/java/pmg/Main.java) +* [JSON test source](src/main/java/hello/Main.java) +* [Plaintext test source](src/main/java/hello/Main.java) ## Versions -* [Java OpenJDK 1.8](http://openjdk.java.net/) -* [solon 2.0.0](https://github.com/noear/solon) +* [Java OpenJDK 21](http://openjdk.java.net/) +* [solon 3.0.2](https://github.com/noear/solon) ## Test URLs diff --git a/frameworks/Java/solon/benchmark_config.json b/frameworks/Java/solon/benchmark_config.json index 70a0c1cfc10..52c9fd8be8c 100644 --- a/frameworks/Java/solon/benchmark_config.json +++ b/frameworks/Java/solon/benchmark_config.json @@ -3,16 +3,16 @@ "tests": [ { "default": { - "json_url": "/json", "plaintext_url": "/plaintext", + "json_url": "/json", "port": 8080, "approach": "Realistic", "classification": "Fullstack", - "database": "None", + "database": "Postgres", "framework": "solon", "language": "Java", "flavor": "None", - "orm": "Full", + "orm": "Micro", "platform": "solon", "webserver": "smarthttp", "os": "Linux", diff --git a/frameworks/Java/solon/config.toml b/frameworks/Java/solon/config.toml index c806ddfb0bf..83bd6e72946 100644 --- a/frameworks/Java/solon/config.toml +++ b/frameworks/Java/solon/config.toml @@ -6,10 +6,10 @@ urls.plaintext = "/plaintext" urls.json = "/json" approach = "Realistic" classification = "Platform" -database = "None" +database = "Postgres" database_os = "Linux" os = "Linux" -orm = "Raw" +orm = "Micro" platform = "solon" webserver = "smarthttp" versus = "None" diff --git a/frameworks/Java/solon/pom.xml b/frameworks/Java/solon/pom.xml index 58e7d792301..bd21bbd75df 100644 --- a/frameworks/Java/solon/pom.xml +++ b/frameworks/Java/solon/pom.xml @@ -2,62 +2,69 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - org.noear.solon - solon-benchmark + + org.noear + solon-parent + 3.0.5 + + + hello + hello-solon 1.0 jar - UTF-8 - 11 - 11 - 2.0.0 + 21 + 1.3.6 org.noear - solon.boot.smarthttp - ${solon.version} + solon-lib + org.noear - solon.serialization.snack3 - ${solon.version} + solon-boot-smarthttp + + + + org.noear + solon-serialization-jackson + + + + org.noear + solon-data-sqlutils - - - - central - Central Repository - https://repo.maven.apache.org/maven2 - - - sonatype-nexus-snapshots - Sonatype Nexus Snapshots - https://oss.sonatype.org/content/repositories/snapshots - - + + io.jstach + jstachio + ${jstachio.version} + + + + io.jstach + jstachio-apt + ${jstachio.version} + provided + true + - - - central - Central Repository - https://repo.maven.apache.org/maven2 - - - sonatype-nexus-snapshots - Sonatype Nexus Snapshots - https://oss.sonatype.org/content/repositories/snapshots - - false - - - true - - - + + com.zaxxer + HikariCP + 6.0.0 + + + + org.postgresql + postgresql + 42.7.7 + + ${project.artifactId} @@ -66,27 +73,27 @@ org.apache.maven.plugins maven-compiler-plugin - 3.8.1 - -parameters - 1.8 - 1.8 - UTF-8 - false + + + io.jstach + jstachio-apt + ${jstachio.version} + + org.apache.maven.plugins maven-assembly-plugin - 3.3.0 jar-with-dependencies - pmg.Main + hello.Main diff --git a/frameworks/Java/solon/solon.dockerfile b/frameworks/Java/solon/solon.dockerfile index 21d7f50d8a8..c387938661c 100644 --- a/frameworks/Java/solon/solon.dockerfile +++ b/frameworks/Java/solon/solon.dockerfile @@ -1,13 +1,13 @@ -FROM maven:3.6.1-jdk-11-slim as maven +FROM maven:3.9.7-amazoncorretto-21 as maven WORKDIR /solon COPY pom.xml pom.xml COPY src src RUN mvn compile assembly:single -q -FROM openjdk:11.0.3-jdk-slim +FROM openjdk:21-jdk-slim WORKDIR /solon -COPY --from=maven /solon/target/solon-benchmark-jar-with-dependencies.jar app.jar +COPY --from=maven /solon/target/hello-solon.jar app.jar EXPOSE 8080 -CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AggressiveOpts", "-cp", "app.jar", "pmg.Main"] +CMD ["java", "-server", "-cp", "app.jar", "hello.Main"] \ No newline at end of file diff --git a/frameworks/Java/solon/src/main/java/hello/Main.java b/frameworks/Java/solon/src/main/java/hello/Main.java new file mode 100644 index 00000000000..75fd11bfc36 --- /dev/null +++ b/frameworks/Java/solon/src/main/java/hello/Main.java @@ -0,0 +1,9 @@ +package hello; + +import org.noear.solon.Solon; + +public class Main { + public static void main(String[] args) { + Solon.start(Main.class, args); + } +} diff --git a/frameworks/Java/solon/src/main/java/hello/Utils.java b/frameworks/Java/solon/src/main/java/hello/Utils.java new file mode 100644 index 00000000000..162f89cc79c --- /dev/null +++ b/frameworks/Java/solon/src/main/java/hello/Utils.java @@ -0,0 +1,17 @@ +package hello; + +import java.util.concurrent.ThreadLocalRandom; +import java.util.stream.IntStream; + +abstract public 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/solon/src/main/java/hello/model/Fortune.java b/frameworks/Java/solon/src/main/java/hello/model/Fortune.java new file mode 100644 index 00000000000..f7b5769ef28 --- /dev/null +++ b/frameworks/Java/solon/src/main/java/hello/model/Fortune.java @@ -0,0 +1,16 @@ +package hello.model; + +public final class Fortune implements Comparable{ + public final int id; + public final String message; + + 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/solon/src/main/java/hello/model/World.java b/frameworks/Java/solon/src/main/java/hello/model/World.java new file mode 100644 index 00000000000..ec6fc5b3abf --- /dev/null +++ b/frameworks/Java/solon/src/main/java/hello/model/World.java @@ -0,0 +1,12 @@ +package hello.model; + + +public final class World { + public int id; + public int randomNumber; + public World(int id, int randomNumber) { + this.id = id; + this.randomNumber = randomNumber; + } + +} \ No newline at end of file diff --git a/frameworks/Java/solon/src/main/java/hello/repository/DbRepository.java b/frameworks/Java/solon/src/main/java/hello/repository/DbRepository.java new file mode 100644 index 00000000000..e5445184077 --- /dev/null +++ b/frameworks/Java/solon/src/main/java/hello/repository/DbRepository.java @@ -0,0 +1,15 @@ +package hello.repository; + +import hello.model.Fortune; +import hello.model.World; + +import java.util.List; + +public interface DbRepository { + + World getWorld(int id) throws Exception; + + void updateWorlds(List worlds) throws Exception; + + List fortunes() throws Exception; +} diff --git a/frameworks/Java/solon/src/main/java/hello/repository/JdbcDbRepository.java b/frameworks/Java/solon/src/main/java/hello/repository/JdbcDbRepository.java new file mode 100644 index 00000000000..5fb83f9a68e --- /dev/null +++ b/frameworks/Java/solon/src/main/java/hello/repository/JdbcDbRepository.java @@ -0,0 +1,41 @@ +package hello.repository; + +import hello.model.Fortune; +import hello.model.World; +import org.noear.solon.annotation.Component; +import org.noear.solon.annotation.Inject; +import org.noear.solon.data.sql.SqlUtils; + +import java.sql.SQLException; +import java.util.List; + +@Component +public class JdbcDbRepository implements DbRepository { + @Inject + SqlUtils sqlUtils; + + @Override + public World getWorld(int id) { + try { + return sqlUtils.sql("SELECT id, randomnumber FROM world WHERE id = ?", id) + .queryRow((rs) -> new World(rs.getInt(1), rs.getInt(2))); + } catch (Exception e) { + return null; + } + } + + @Override + public void updateWorlds(List worlds) throws SQLException { + sqlUtils.sql("UPDATE world SET randomnumber = ? WHERE id = ?") + .updateBatch(worlds, (ps, w) -> { + ps.setInt(1, w.randomNumber); + ps.setInt(2, w.id); + }); + } + + @Override + public List fortunes() throws SQLException { + return sqlUtils.sql("SELECT id, message FROM fortune") + .queryRowList((r) -> new Fortune(r.getInt(1), r.getString(2))); + } +} diff --git a/frameworks/Java/solon/src/main/java/hello/web/DbHandler.java b/frameworks/Java/solon/src/main/java/hello/web/DbHandler.java new file mode 100644 index 00000000000..9163c94e3c9 --- /dev/null +++ b/frameworks/Java/solon/src/main/java/hello/web/DbHandler.java @@ -0,0 +1,61 @@ +package hello.web; + +import hello.Utils; +import hello.model.Fortune; +import hello.model.World; +import hello.repository.JdbcDbRepository; +import org.noear.solon.annotation.Component; +import org.noear.solon.annotation.Inject; +import org.noear.solon.core.handle.Context; + +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +@Component +public class DbHandler { + @Inject + JdbcDbRepository dbRepository; + + public void db(Context ctx) throws Throwable { + ctx.render(dbRepository.getWorld(Utils.randomWorldNumber())); + } + + public void queries(Context ctx) throws Throwable { + int queries = ctx.paramAsInt("queries", 0); + + World[] worlds = Utils.randomWorldNumbers() + .mapToObj(dbRepository::getWorld).limit(queries) + .toArray(World[]::new); + + ctx.render(worlds); + } + + public void updates(Context ctx) throws Throwable { + int queries = ctx.paramAsInt("queries", 0); + + List worlds = Utils.randomWorldNumbers() + .mapToObj(id -> { + World world = dbRepository.getWorld(id); + int randomNumber; + do { + randomNumber = Utils.randomWorldNumber(); + } while (randomNumber == world.randomNumber); + world.randomNumber = randomNumber; + return world; + }).limit(queries) + .sorted(Comparator.comparingInt(w -> w.id)) + .toList(); + dbRepository.updateWorlds(worlds); + + ctx.render(worlds); + } + + public void fortunes(Context ctx) throws Throwable { + List fortunes = dbRepository.fortunes(); + fortunes.add(new Fortune(0, "Additional fortune added at request time.")); + Collections.sort(fortunes); + + ctx.render(new Fortunes(fortunes)); + } +} diff --git a/frameworks/Java/solon/src/main/java/hello/web/Fortunes.java b/frameworks/Java/solon/src/main/java/hello/web/Fortunes.java new file mode 100644 index 00000000000..a5416ec07bc --- /dev/null +++ b/frameworks/Java/solon/src/main/java/hello/web/Fortunes.java @@ -0,0 +1,10 @@ +package hello.web; + +import hello.model.Fortune; +import io.jstach.jstache.JStache; + +import java.util.List; + +@JStache(path = "fortunes.mustache") +public record Fortunes(List fortunes) { +} diff --git a/frameworks/Java/solon/src/main/java/hello/web/JsonHandler.java b/frameworks/Java/solon/src/main/java/hello/web/JsonHandler.java new file mode 100644 index 00000000000..c65bb73ab74 --- /dev/null +++ b/frameworks/Java/solon/src/main/java/hello/web/JsonHandler.java @@ -0,0 +1,27 @@ +package hello.web; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectWriter; +import org.noear.solon.annotation.Component; +import org.noear.solon.boot.web.MimeType; +import org.noear.solon.core.handle.Context; +import org.noear.solon.core.handle.Handler; + +import java.util.Map; + +@Component +public class JsonHandler implements Handler { + private final ObjectWriter writer; + + public JsonHandler() { + this.writer = new ObjectMapper().writerFor(Map.class); + } + + @Override + public void handle(Context ctx) throws Throwable { + byte[] body = this.writer.writeValueAsBytes(Map.of("message", "Hello, world!")); + ctx.contentLength(body.length); + ctx.contentType(MimeType.APPLICATION_JSON_VALUE); + ctx.output(body); + } +} diff --git a/frameworks/Java/solon/src/main/java/hello/web/TextHandler.java b/frameworks/Java/solon/src/main/java/hello/web/TextHandler.java new file mode 100644 index 00000000000..96d68e6e7df --- /dev/null +++ b/frameworks/Java/solon/src/main/java/hello/web/TextHandler.java @@ -0,0 +1,25 @@ +package hello.web; + +import org.noear.solon.annotation.Component; +import org.noear.solon.boot.web.MimeType; +import org.noear.solon.core.handle.Context; +import org.noear.solon.core.handle.Handler; + +import java.nio.charset.StandardCharsets; + +@Component +public class TextHandler implements Handler { + private static final byte[] TEXT_BODY = "Hello, World!".getBytes(StandardCharsets.UTF_8); + + private static final String TEXT_BODY_LENGTH = String.valueOf(TEXT_BODY.length); + private static final String CONTENT_LENGTH = "Content-Length"; + private static final String CONTENT_TYPE = "Content-Type"; + + @Override + public void handle(Context ctx) throws Throwable { + ctx.headerSet(CONTENT_LENGTH, TEXT_BODY_LENGTH); + ctx.headerSet(CONTENT_TYPE, MimeType.TEXT_PLAIN_VALUE); + ctx.output("Hello, World!".getBytes()); + } +} + diff --git a/frameworks/Java/solon/src/main/java/hello/web/WebmvcRouter.java b/frameworks/Java/solon/src/main/java/hello/web/WebmvcRouter.java new file mode 100644 index 00000000000..6024ddcc548 --- /dev/null +++ b/frameworks/Java/solon/src/main/java/hello/web/WebmvcRouter.java @@ -0,0 +1,29 @@ +package hello.web; + +import org.noear.solon.SolonApp; +import org.noear.solon.annotation.Bean; +import org.noear.solon.annotation.Configuration; + +@Configuration +public class WebmvcRouter { + @Bean + public void initRouter(SolonApp app, + DbHandler dbHandler, + JsonHandler jsonHandler, + TextHandler textHandler) { + app.handler().prev(ctx -> { + ctx.setHandled(true); + ctx.headerSet("Server", "Solon"); + + switch (ctx.path()) { + case "/plaintext" -> textHandler.handle(ctx); + case "/json" -> jsonHandler.handle(ctx); + case "/db" -> dbHandler.db(ctx); + case "/queries" -> dbHandler.queries(ctx); + case "/updates" -> dbHandler.updates(ctx); + case "/fortunes" -> dbHandler.fortunes(ctx); + default -> ctx.status(404); + } + }); + } +} diff --git a/frameworks/Java/solon/src/main/java/pmg/Main.java b/frameworks/Java/solon/src/main/java/pmg/Main.java deleted file mode 100644 index b4b7b651797..00000000000 --- a/frameworks/Java/solon/src/main/java/pmg/Main.java +++ /dev/null @@ -1,13 +0,0 @@ -package pmg; - -import org.noear.solon.Solon; - -/** - * @author pmg1991 - * @version V1.0 - */ -public class Main { - public static void main(String[] args) { - Solon.start(Main.class, args); - } -} diff --git a/frameworks/Java/solon/src/main/java/pmg/controller/HelloController.java b/frameworks/Java/solon/src/main/java/pmg/controller/HelloController.java deleted file mode 100644 index fe9a1b43e3a..00000000000 --- a/frameworks/Java/solon/src/main/java/pmg/controller/HelloController.java +++ /dev/null @@ -1,25 +0,0 @@ -package pmg.controller; - -import org.noear.solon.annotation.Controller; -import org.noear.solon.annotation.Get; -import org.noear.solon.annotation.Mapping; -import pmg.model.Message; - -/** - * @author noear - * @version V1.0 - */ -@Controller -public class HelloController { - @Get - @Mapping("plaintext") - public String plaintext() { - return "Hello, World!"; - } - - @Get - @Mapping("json") - public Message json() { - return new Message("Hello, World!"); - } -} diff --git a/frameworks/Java/solon/src/main/java/pmg/model/Message.java b/frameworks/Java/solon/src/main/java/pmg/model/Message.java deleted file mode 100644 index f88b9b1a8d4..00000000000 --- a/frameworks/Java/solon/src/main/java/pmg/model/Message.java +++ /dev/null @@ -1,21 +0,0 @@ -package pmg.model; - -/** - * @author pmg1991 - * @version V1.0 - */ -public class Message { - private String 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/solon/src/main/resources/app.properties b/frameworks/Java/solon/src/main/resources/app.properties deleted file mode 100644 index 26a5df70351..00000000000 --- a/frameworks/Java/solon/src/main/resources/app.properties +++ /dev/null @@ -1 +0,0 @@ -server.http.ioBound=false \ No newline at end of file diff --git a/frameworks/Java/solon/src/main/resources/app.yml b/frameworks/Java/solon/src/main/resources/app.yml new file mode 100644 index 00000000000..cbd9e850625 --- /dev/null +++ b/frameworks/Java/solon/src/main/resources/app.yml @@ -0,0 +1,23 @@ +database: + name: hello_world + host: tfb-database + port: 5432 + username: benchmarkdbuser + password: benchmarkdbpass + +server.http: + ioBound: false + +solon.threads: + virtual: + enabled: true + +solon.dataSources: + test!: + class: "com.zaxxer.hikari.HikariDataSource" + driverClassName: "org.postgresql.Driver" + url: jdbc:postgresql://${database.host}:${database.port}/${database.name}?loggerLevel=OFF&disableColumnSanitiser=true&assumeMinServerVersion=16&sslmode=disable + username: ${database.username} + password: ${database.password} + hikari: + maximum-pool-size: 256 \ No newline at end of file diff --git a/frameworks/Java/spring-webflux/src/main/resources/templates/fortunes.mustache b/frameworks/Java/solon/src/main/resources/fortunes.mustache similarity index 100% rename from frameworks/Java/spring-webflux/src/main/resources/templates/fortunes.mustache rename to frameworks/Java/solon/src/main/resources/fortunes.mustache diff --git a/frameworks/Java/spring-webflux/README.md b/frameworks/Java/spring-webflux/README.md index 91e18bc9ceb..74297391137 100755 --- a/frameworks/Java/spring-webflux/README.md +++ b/frameworks/Java/spring-webflux/README.md @@ -37,15 +37,6 @@ For mongoDB access, spring-data-mongodb with reactive support is used. See [Mong * [Template rendering test source](src/main/java/benchmark/web/WebfluxRouter.java) -## Versions - -* [Java OpenJDK 10](http://openjdk.java.net/) -* [Spring boot 2.1.0.RELEASE](https://spring.io/projects/spring-boot) -* [Spring data mongodb 2.1.0.RELEASE](https://projects.spring.io/spring-data-mongodb/) -* [reactive-pg-client 0.10.6](https://github.com/reactiverse/reactive-pg-client) -* [rxjava2-jdbc 0.2.0](https://github.com/davidmoten/rxjava2-jdbc) -* [r2dbc-postgresql 1.0.0.BUILD-SNAPSHOT](https://github.com/r2dbc/r2dbc-postgresql) - ## Test URLs ### Plaintext Test diff --git a/frameworks/Java/spring-webflux/benchmark_config.json b/frameworks/Java/spring-webflux/benchmark_config.json index e5c13f8e292..d3d0746d448 100644 --- a/frameworks/Java/spring-webflux/benchmark_config.json +++ b/frameworks/Java/spring-webflux/benchmark_config.json @@ -2,9 +2,11 @@ "framework": "spring-webflux", "tests": [{ "default": { + "json_url": "/json", "db_url": "/db", "query_url": "/queries?queries=", "fortune_url": "/fortunes", + "plaintext_url": "/plaintext", "update_url": "/updates?queries=", "port": 8080, "approach": "Realistic", @@ -20,13 +22,14 @@ "database_os": "Linux", "display_name": "spring-webflux-r2dbc", "notes": "", - "versus": "spring", - "tags": ["broken"] + "versus": "spring" }, "mongo": { + "json_url": "/json", "db_url": "/db", "query_url": "/queries?queries=", "fortune_url": "/fortunes", + "plaintext_url": "/plaintext", "port": 8080, "approach": "Realistic", "classification": "Fullstack", @@ -41,74 +44,7 @@ "database_os": "Linux", "display_name": "spring-webflux-mongo", "notes": "", - "versus": "spring", - "tags": ["broken"] - }, - "pgclient": { - "db_url": "/db", - "query_url": "/queries?queries=", - "fortune_url": "/fortunes", - "update_url": "/updates?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "Postgres", - "framework": "spring", - "language": "Java", - "flavor": "None", - "orm": "Micro", - "platform": "Netty", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "spring-webflux-pgclient", - "notes": "", - "versus": "spring", - "tags": ["broken"] - }, - "rxjdbc": { - "db_url": "/db", - "query_url": "/queries?queries=", - "fortune_url": "/fortunes", - "update_url": "/updates?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "Postgres", - "framework": "spring", - "language": "Java", - "flavor": "None", - "orm": "Micro", - "platform": "Netty", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "spring-webflux-rxjdbc", - "notes": "", - "versus": "spring", - "tags": ["broken"] - }, - "jdbc": { - "db_url": "/db", - "query_url": "/queries?queries=", - "fortune_url": "/fortunes", - "update_url": "/updates?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "Postgres", - "framework": "spring", - "language": "Java", - "flavor": "None", - "orm": "Micro", - "platform": "Netty", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "spring-webflux-jdbc", - "notes": "", - "versus": "spring", - "tags": ["broken"] + "versus": "spring" } }] } diff --git a/frameworks/Java/spring-webflux/config.toml b/frameworks/Java/spring-webflux/config.toml index 0cf76705159..806591a8384 100644 --- a/frameworks/Java/spring-webflux/config.toml +++ b/frameworks/Java/spring-webflux/config.toml @@ -16,36 +16,6 @@ platform = "Netty" webserver = "None" versus = "spring" -[pgclient] -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 = "None" -versus = "spring" - -[jdbc] -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 = "None" -versus = "spring" - [mongo] urls.db = "/db" urls.query = "/queries?queries=" @@ -59,18 +29,3 @@ orm = "Full" platform = "Netty" webserver = "None" versus = "spring" - -[rxjdbc] -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 = "None" -versus = "spring" diff --git a/frameworks/Java/spring-webflux/pom.xml b/frameworks/Java/spring-webflux/pom.xml index 701d1348d47..af60e1f7c7e 100644 --- a/frameworks/Java/spring-webflux/pom.xml +++ b/frameworks/Java/spring-webflux/pom.xml @@ -8,24 +8,17 @@ benchmark spring-webflux-benchmark - 1.1-SNAPSHOT + 1.0-SNAPSHOT org.springframework.boot spring-boot-starter-parent - 2.2.0.M2 + 3.3.5 - 11 - 11 - UTF-8 - 1.0.0.M2 - 42.4.3 - 0.11.4 - 0.2.4 - 1.0.0.M7 - 1.0.0.BUILD-SNAPSHOT + 21 + 1.3.6 @@ -35,112 +28,30 @@ org.springframework.boot - spring-boot-starter-jdbc - - - org.springframework.boot - spring-boot-starter-mustache - - - org.springframework.boot - spring-boot-starter-data-mongodb-reactive + spring-boot-starter-data-r2dbc org.postgresql - postgresql - ${postgresql.version} - - - io.reactiverse - reactive-pg-client - ${pgclient.version} - - - com.github.davidmoten - rxjava2-jdbc - ${rxjava2-jdbc.version} - - - - io.r2dbc r2dbc-postgresql - ${r2dbc-postgresql.version} - - - io.r2dbc - r2dbc-pool - ${r2dbc-pool.version} - - - org.springframework.data - spring-data-r2dbc - ${spring-data-r2dbc.version} - - - - org.springframework - spring-tx - - - org.springframework - spring-context - - - org.springframework - spring-core - - - org.springframework - spring-beans - - - org.springframework - spring-tx - 5.2.0.M2 + io.jstach + jstachio + ${jstachio.version} - org.springframework - spring-context - 5.2.0.M2 + io.jstach + jstachio-apt + ${jstachio.version} + provided + true - org.springframework - spring-core - 5.2.24.RELEASE - - - org.springframework - spring-beans - 5.2.21.BUILD-SNAPSHOT + org.springframework.boot + spring-boot-starter-data-mongodb-reactive - - - - spring-libs-snapshot - Spring Snapshots - https://repo.spring.io/libs-snapshot - - - spring-snapshots - Spring Snapshots - https://repo.spring.io/snapshot - - true - - - - - - spring-libs-snapshot - Spring Snapshots - https://repo.spring.io/libs-snapshot - - - ${project.artifactId} @@ -151,9 +62,14 @@ org.apache.maven.plugins maven-compiler-plugin - 3.8.0 - false + + + io.jstach + jstachio-apt + ${jstachio.version} + + diff --git a/frameworks/Java/spring-webflux/spring-webflux-jdbc.dockerfile b/frameworks/Java/spring-webflux/spring-webflux-jdbc.dockerfile deleted file mode 100644 index 89f1ba40f89..00000000000 --- a/frameworks/Java/spring-webflux/spring-webflux-jdbc.dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM maven:3.8.5-openjdk-17-slim as maven -WORKDIR /spring -COPY src src -COPY pom.xml pom.xml -RUN mvn package -q - -FROM openjdk:17.0-jdk-slim -WORKDIR /spring -COPY --from=maven /spring/target/spring-webflux-benchmark.jar app.jar - -EXPOSE 8080 - -CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-Dlogging.level.root=OFF", "-jar", "app.jar", "--spring.profiles.active=jdbc,postgres"] diff --git a/frameworks/Java/spring-webflux/spring-webflux-mongo.dockerfile b/frameworks/Java/spring-webflux/spring-webflux-mongo.dockerfile index 95d24ac6003..514a1db96df 100644 --- a/frameworks/Java/spring-webflux/spring-webflux-mongo.dockerfile +++ b/frameworks/Java/spring-webflux/spring-webflux-mongo.dockerfile @@ -1,13 +1,16 @@ -FROM maven:3.8.5-openjdk-17-slim as maven +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 openjdk:17.0-jdk-slim +FROM bellsoft/liberica-openjre-debian:23 WORKDIR /spring COPY --from=maven /spring/target/spring-webflux-benchmark.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", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-Dlogging.level.root=OFF", "-jar", "app.jar", "--spring.profiles.active=mongo"] +CMD ["java", "-Dlogging.level.root=OFF", "-Dio.netty.leakDetection.level=disabled", "-Dreactor.netty.http.server.lastFlushWhenNoRead=true", "-jar", "app/app.jar", "--spring.profiles.active=mongo"] \ No newline at end of file diff --git a/frameworks/Java/spring-webflux/spring-webflux-pgclient.dockerfile b/frameworks/Java/spring-webflux/spring-webflux-pgclient.dockerfile deleted file mode 100644 index 0c03140d05a..00000000000 --- a/frameworks/Java/spring-webflux/spring-webflux-pgclient.dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM maven:3.8.5-openjdk-17-slim as maven -WORKDIR /spring -COPY src src -COPY pom.xml pom.xml -RUN mvn package -q - -FROM openjdk:17.0-jdk-slim -WORKDIR /spring -COPY --from=maven /spring/target/spring-webflux-benchmark.jar app.jar - -EXPOSE 8080 - -CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-Dlogging.level.root=OFF", "-jar", "app.jar", "--spring.profiles.active=pgclient,postgres"] diff --git a/frameworks/Java/spring-webflux/spring-webflux-rxjdbc.dockerfile b/frameworks/Java/spring-webflux/spring-webflux-rxjdbc.dockerfile deleted file mode 100644 index 05aacc1a8f1..00000000000 --- a/frameworks/Java/spring-webflux/spring-webflux-rxjdbc.dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM maven:3.8.5-openjdk-17-slim as maven -WORKDIR /spring -COPY src src -COPY pom.xml pom.xml -RUN mvn package -q - -FROM openjdk:17.0-jdk-slim -WORKDIR /spring -COPY --from=maven /spring/target/spring-webflux-benchmark.jar app.jar - -EXPOSE 8080 - -CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-Dlogging.level.root=OFF", "-jar", "app.jar", "--spring.profiles.active=rxjdbc,postgres"] diff --git a/frameworks/Java/spring-webflux/spring-webflux.dockerfile b/frameworks/Java/spring-webflux/spring-webflux.dockerfile index 3d41fc1ecbe..60c2229b795 100644 --- a/frameworks/Java/spring-webflux/spring-webflux.dockerfile +++ b/frameworks/Java/spring-webflux/spring-webflux.dockerfile @@ -1,13 +1,15 @@ -FROM maven:3.8.5-openjdk-17-slim as maven +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 openjdk:17.0-jdk-slim +FROM bellsoft/liberica-openjre-debian:23 WORKDIR /spring COPY --from=maven /spring/target/spring-webflux-benchmark.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", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-Dlogging.level.root=OFF", "-jar", "app.jar", "--spring.profiles.active=r2dbc,postgres"] +CMD ["java", "-Dlogging.level.root=OFF", "-Dio.netty.leakDetection.level=disabled", "-Dreactor.netty.http.server.lastFlushWhenNoRead=true", "-jar", "app/app.jar", "--spring.profiles.active=r2dbc"] diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/App.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/App.java old mode 100755 new mode 100644 index e33025461c6..3ba49056611 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/App.java +++ b/frameworks/Java/spring-webflux/src/main/java/benchmark/App.java @@ -1,53 +1,31 @@ package benchmark; -import org.springframework.beans.factory.annotation.Autowired; +import benchmark.web.ServerFilter; + import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.boot.web.reactive.result.view.MustacheViewResolver; import org.springframework.context.annotation.Bean; +import org.springframework.http.server.reactive.HttpHandler; import org.springframework.scheduling.annotation.EnableScheduling; -import org.springframework.web.reactive.config.EnableWebFlux; -import org.springframework.web.reactive.config.ViewResolverRegistry; -import org.springframework.web.reactive.config.WebFluxConfigurer; -import reactor.core.scheduler.Scheduler; -import reactor.core.scheduler.Schedulers; - -import java.util.concurrent.Executors; - -@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class, MongoReactiveDataAutoConfiguration.class }) -@EnableWebFlux +import org.springframework.web.reactive.function.server.HandlerStrategies; +import org.springframework.web.reactive.function.server.RouterFunction; +import org.springframework.web.reactive.function.server.RouterFunctions; +import org.springframework.web.reactive.function.server.ServerResponse; +import org.springframework.web.server.WebHandler; +import org.springframework.web.server.adapter.WebHttpHandlerBuilder; + +@SpringBootApplication @EnableScheduling -@EnableConfigurationProperties -public class App implements WebFluxConfigurer { - - @Autowired - private MustacheViewResolver mustacheViewResolver; - - public static void main(String[] args) { - SpringApplication.run(App.class, args); - } +public class App { @Bean - public ServerFilter serverFilter() { - return new ServerFilter(); + public HttpHandler httpHandler(RouterFunction route, ServerFilter serverFilter) { + WebHandler webHandler = RouterFunctions.toWebHandler(route, HandlerStrategies.builder().build()); + return WebHttpHandlerBuilder.webHandler(webHandler).filter(serverFilter).build(); } - @Bean - public DateHandler dateHandler() { - return new DateHandler(); - } - - @Bean - public Scheduler ioScheduler() { - return Schedulers.fromExecutor(Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2)); - } - - @Override - public void configureViewResolvers(ViewResolverRegistry registry) { - registry.viewResolver(mustacheViewResolver); + public static void main(String[] args) { + SpringApplication.run(App.class, args); } } \ No newline at end of file diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/DateHandler.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/DateHandler.java deleted file mode 100644 index fdaab4a2209..00000000000 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/DateHandler.java +++ /dev/null @@ -1,19 +0,0 @@ -package benchmark; - -import org.springframework.scheduling.annotation.Scheduled; - -import java.util.Date; - -public class DateHandler { - - private Date date = new Date(); - - @Scheduled(fixedRate = 1000) - public void update() { - this.date = new Date(); - } - - public Date getDate() { - return date; - } -} diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/PgClients.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/PgClients.java deleted file mode 100644 index 902478447c6..00000000000 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/PgClients.java +++ /dev/null @@ -1,19 +0,0 @@ -package benchmark; - -import io.reactiverse.pgclient.PgClient; - -import java.util.Collection; -import java.util.Iterator; -import java.util.stream.Stream; - -public class PgClients { - private final Iterator iterator; - - public PgClients(Collection clients) { - iterator = Stream.generate(() -> clients).flatMap(Collection::stream).iterator(); - } - - public synchronized PgClient getOne() { - return iterator.next(); - } -} \ No newline at end of file diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/ServerFilter.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/ServerFilter.java deleted file mode 100644 index 40cc32ff9a7..00000000000 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/ServerFilter.java +++ /dev/null @@ -1,20 +0,0 @@ -package benchmark; - -import io.netty.handler.codec.http.HttpHeaderNames; -import org.springframework.http.HttpHeaders; -import org.springframework.web.server.ServerWebExchange; -import org.springframework.web.server.WebFilter; -import org.springframework.web.server.WebFilterChain; -import reactor.core.publisher.Mono; - -public class ServerFilter implements WebFilter { - private static final String SERVER_NAME = "spring-webflux"; - - @Override - public Mono filter(ServerWebExchange exchange, WebFilterChain chain) { - HttpHeaders headers = exchange.getResponse().getHeaders(); - headers.add(HttpHeaderNames.SERVER.toString(), SERVER_NAME); - headers.add(HttpHeaderNames.DATE.toString(), java.time.format.DateTimeFormatter.RFC_1123_DATE_TIME.format(java.time.ZonedDateTime.now())); - return chain.filter(exchange); - } -} diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/Utils.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/Utils.java new file mode 100644 index 00000000000..4631be27f11 --- /dev/null +++ b/frameworks/Java/spring-webflux/src/main/java/benchmark/Utils.java @@ -0,0 +1,19 @@ +package benchmark; + +import java.util.concurrent.ThreadLocalRandom; +import java.util.stream.IntStream; + +abstract public 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/spring-webflux/src/main/java/benchmark/config/JdbcConfig.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/config/JdbcConfig.java deleted file mode 100644 index cd97d6e9708..00000000000 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/config/JdbcConfig.java +++ /dev/null @@ -1,22 +0,0 @@ -package benchmark.config; - -import com.zaxxer.hikari.HikariDataSource; -import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Profile; - -import javax.sql.DataSource; - -@Configuration -@Profile("jdbc") -public class JdbcConfig { - - @Bean - public DataSource datasource(DataSourceProperties dataSourceProperties) { - HikariDataSource dataSource = dataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource.class).build(); - dataSource.setMaximumPoolSize(Runtime.getRuntime().availableProcessors() * 2); - - return dataSource; - } -} \ No newline at end of file diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/config/PgClientConfig.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/config/PgClientConfig.java deleted file mode 100644 index ebcbc732d67..00000000000 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/config/PgClientConfig.java +++ /dev/null @@ -1,94 +0,0 @@ -package benchmark.config; - -import benchmark.PgClients; -import io.reactiverse.pgclient.PgClient; -import io.reactiverse.pgclient.PgPool; -import io.reactiverse.pgclient.PgPoolOptions; -import io.vertx.core.Vertx; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Profile; - -import java.util.ArrayList; -import java.util.List; - -@Configuration -@Profile("pgclient") -@ConfigurationProperties(prefix = "database") -public class PgClientConfig { - private String name; - private String host; - private int port; - private String username; - private String password; - - @Bean - public Vertx vertx() { - return Vertx.vertx(); - } - - @Bean - public PgClients pgClients(Vertx vertx) { - List clients = new ArrayList<>(); - - for (int i = 0; i < Runtime.getRuntime().availableProcessors(); i++) { - clients.add(pgClient(vertx)); - } - - return new PgClients(clients); - } - - - public PgPool pgClient(Vertx vertx) { - PgPoolOptions options = new PgPoolOptions(); - options.setDatabase(name); - options.setHost(host); - options.setPort(port); - options.setUser(username); - options.setPassword(password); - options.setCachePreparedStatements(true); - options.setMaxSize(1); - return PgClient.pool(vertx, options); - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getHost() { - return host; - } - - public void setHost(String host) { - this.host = host; - } - - public int getPort() { - return port; - } - - public void setPort(int port) { - this.port = port; - } - - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - - public String getPassword() { - return password; - } - - public void setPassword(String password) { - this.password = password; - } -} diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/config/R2dbcConfig.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/config/R2dbcConfig.java deleted file mode 100644 index 60e006cc80f..00000000000 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/config/R2dbcConfig.java +++ /dev/null @@ -1,63 +0,0 @@ -package benchmark.config; - - -import io.r2dbc.spi.ConnectionFactories; -import io.r2dbc.spi.ConnectionFactory; - -import io.r2dbc.spi.ConnectionFactoryOptions; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Profile; -import org.springframework.data.r2dbc.core.DatabaseClient; - -import static io.r2dbc.spi.ConnectionFactoryOptions.*; - -@Configuration -@Profile("r2dbc") -@ConfigurationProperties(prefix = "database") -public class R2dbcConfig { - private String name; - private String host; - private int port; - private String username; - private String password; - - public void setName(String name) { - this.name = name; - } - - public void setHost(String host) { - this.host = host; - } - - public void setPort(int port) { - this.port = port; - } - - public void setUsername(String username) { - this.username = username; - } - - public void setPassword(String password) { - this.password = password; - } - - @Bean - public ConnectionFactory connectionFactory() { - return ConnectionFactories.get(ConnectionFactoryOptions.builder() - .option(DRIVER,"pool") - .option(PROTOCOL,"postgresql") - .option(HOST, host) - .option(PORT, port) - .option(USER, username) - .option(PASSWORD, password) - .option(DATABASE, name) - .build()); - } - - @Bean - public DatabaseClient databaseClient(ConnectionFactory connectionFactory) { - return DatabaseClient.create(connectionFactory); - } -} \ No newline at end of file diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/config/ReactiveMongoConfig.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/config/ReactiveMongoConfig.java deleted file mode 100644 index ee80f0fd87b..00000000000 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/config/ReactiveMongoConfig.java +++ /dev/null @@ -1,53 +0,0 @@ -package benchmark.config; - -import com.mongodb.reactivestreams.client.MongoClient; -import com.mongodb.reactivestreams.client.MongoClients; -import org.slf4j.LoggerFactory; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Profile; -import org.springframework.data.mongodb.config.AbstractReactiveMongoConfiguration; -import org.springframework.data.mongodb.core.ReactiveMongoTemplate; -import org.springframework.data.mongodb.repository.config.EnableReactiveMongoRepositories; - -@Configuration -@EnableReactiveMongoRepositories -@Profile("mongo") -@ConfigurationProperties(prefix = "database") -public class ReactiveMongoConfig extends AbstractReactiveMongoConfiguration { - private String url; - private String name; - - @Bean - public MongoClient reactiveMongoClient() { - LoggerFactory.getLogger(getClass()).info("Connecting to mongo url: {}/{}", url, name); - return MongoClients.create(url); - } - - @Override - protected String getDatabaseName() { - return name; - } - - @Bean - public ReactiveMongoTemplate reactiveMongoTemplate() { - return new ReactiveMongoTemplate(reactiveMongoClient(), getDatabaseName()); - } - - public String getUrl() { - return url; - } - - public void setUrl(String url) { - this.url = url; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } -} diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/config/RxJdbcConfig.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/config/RxJdbcConfig.java deleted file mode 100644 index 23b7d200cca..00000000000 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/config/RxJdbcConfig.java +++ /dev/null @@ -1,29 +0,0 @@ -package benchmark.config; - -import org.davidmoten.rx.jdbc.ConnectionProvider; -import org.davidmoten.rx.jdbc.Database; -import org.davidmoten.rx.jdbc.pool.NonBlockingConnectionPool; -import org.davidmoten.rx.jdbc.pool.Pools; -import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Profile; - -import java.sql.SQLException; - -@Configuration -@Profile("rxjdbc") -public class RxJdbcConfig { - @Bean - public Database database(DataSourceProperties dsProps) throws SQLException { - NonBlockingConnectionPool pool = - Pools.nonBlocking() - .maxPoolSize(Runtime.getRuntime().availableProcessors() * 2) - .connectionProvider(ConnectionProvider.from(dsProps.getUrl(), dsProps.getUsername(), dsProps.getPassword())) - .build(); - - Database db = Database.from(pool); - - return db; - } -} \ No newline at end of file diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/model/Fortune.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/model/Fortune.java index 12ae17e0448..d66f56215fc 100644 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/model/Fortune.java +++ b/frameworks/Java/spring-webflux/src/main/java/benchmark/model/Fortune.java @@ -4,9 +4,11 @@ import org.springframework.data.mongodb.core.mapping.Document; @Document -public final class Fortune { +public final class Fortune implements Comparable { + @Id public int id; + public String message; public Fortune(int id, String message) { @@ -14,11 +16,8 @@ public Fortune(int id, String message) { this.message = message; } - public int getId() { - return id; - } - - public String getMessage() { - return message; + @Override + public int compareTo(final Fortune other) { + return message.compareTo(other.message); } } diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/model/World.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/model/World.java index 612c7fef03a..ab096a1e313 100644 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/model/World.java +++ b/frameworks/Java/spring-webflux/src/main/java/benchmark/model/World.java @@ -9,6 +9,7 @@ public final class World { @Id public int id; + @Field("randomNumber") public int randomnumber; diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/repository/DbRepository.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/repository/DbRepository.java index 20e753e317e..2eea6d41049 100644 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/repository/DbRepository.java +++ b/frameworks/Java/spring-webflux/src/main/java/benchmark/repository/DbRepository.java @@ -1,14 +1,17 @@ package benchmark.repository; +import java.util.List; + import benchmark.model.Fortune; import benchmark.model.World; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; public interface DbRepository { + Mono getWorld(int id); - Mono findAndUpdateWorld(int id, int randomNumber); + Mono updateWorlds(List worlds); Flux fortunes(); } \ No newline at end of file diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/repository/JdbcDbRepository.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/repository/JdbcDbRepository.java deleted file mode 100644 index 5e159f816ed..00000000000 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/repository/JdbcDbRepository.java +++ /dev/null @@ -1,63 +0,0 @@ -package benchmark.repository; - -import benchmark.model.Fortune; -import benchmark.model.World; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.context.annotation.Profile; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.stereotype.Component; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; -import reactor.core.scheduler.Scheduler; - -@Component -@Profile("jdbc") -public class JdbcDbRepository implements DbRepository { - private final Logger log = LoggerFactory.getLogger(getClass()); - private final JdbcTemplate jdbcTemplate; - private final Scheduler scheduler; - - public JdbcDbRepository(JdbcTemplate jdbcTemplate, Scheduler scheduler) { - this.jdbcTemplate = jdbcTemplate; - this.scheduler = scheduler; - } - - @Override - public Mono getWorld(int id) { - log.debug("getWorld({})", id); - return Mono.fromCallable(() -> { - return jdbcTemplate.queryForObject( - "SELECT * FROM world WHERE id = ?", - (rs, rn) -> new World(rs.getInt("id"), rs.getInt("randomnumber")), - id); - }).subscribeOn(scheduler); - } - - private Mono updateWorld(World world) { - return Mono.fromCallable(() -> { - jdbcTemplate.update( - "UPDATE world SET randomnumber = ? WHERE id = ?", - world.randomnumber, - world.id); - return world; - }).subscribeOn(scheduler); - } - - @Override - public Mono findAndUpdateWorld(int id, int randomNumber) { - return getWorld(id).flatMap(world -> { - world.randomnumber = randomNumber; - return updateWorld(world); - }); - } - - @Override - public Flux fortunes() { - return Mono.fromCallable(() -> { - return jdbcTemplate.query( - "SELECT * FROM fortune", - (rs, rn) -> new Fortune(rs.getInt("id"), rs.getString("message"))); - }).subscribeOn(scheduler).flatMapIterable(fortunes -> fortunes); - } -} \ No newline at end of file diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/repository/MongoDbRepository.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/repository/MongoDbRepository.java index 7e6b51ff39a..4fff0eb2c5d 100644 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/repository/MongoDbRepository.java +++ b/frameworks/Java/spring-webflux/src/main/java/benchmark/repository/MongoDbRepository.java @@ -1,16 +1,16 @@ package benchmark.repository; +import java.util.List; + import benchmark.model.Fortune; import benchmark.model.World; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; + import org.springframework.context.annotation.Profile; -import org.springframework.data.mongodb.core.ReactiveMongoTemplate; +import org.springframework.data.mongodb.core.ReactiveMongoOperations; import org.springframework.stereotype.Component; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; -import static org.springframework.data.mongodb.core.FindAndModifyOptions.options; import static org.springframework.data.mongodb.core.query.Criteria.where; import static org.springframework.data.mongodb.core.query.Query.query; import static org.springframework.data.mongodb.core.query.Update.update; @@ -18,30 +18,28 @@ @Component @Profile("mongo") public class MongoDbRepository implements DbRepository { - private final Logger log = LoggerFactory.getLogger(getClass()); - private final ReactiveMongoTemplate mongoTemplate; - public MongoDbRepository(ReactiveMongoTemplate mongoTemplate) { - this.mongoTemplate = mongoTemplate; + private final ReactiveMongoOperations operations; + + public MongoDbRepository(ReactiveMongoOperations operations) { + this.operations = operations; } @Override public Mono getWorld(int id) { - log.debug("getWorld({})", id); - return mongoTemplate.findById(id, World.class); + return operations.findById(id, World.class); } @Override - public Mono findAndUpdateWorld(int id, int randomNumber) { - return mongoTemplate.findAndModify( - query(where("id").is(id)), - update("randomNumber", randomNumber), - options().returnNew(true), - World.class); + public Mono updateWorlds(List worlds) { + return Flux.fromIterable(worlds).flatMap(world -> operations.findAndModify( + query(where("id").is(world.id)), + update("randomNumber", world.randomnumber), + World.class)).then(); } @Override public Flux fortunes() { - return mongoTemplate.findAll(Fortune.class); + return operations.findAll(Fortune.class); } } \ No newline at end of file diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/repository/PgClientDbRepository.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/repository/PgClientDbRepository.java deleted file mode 100644 index 50dc6286ea1..00000000000 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/repository/PgClientDbRepository.java +++ /dev/null @@ -1,79 +0,0 @@ -package benchmark.repository; - -import benchmark.PgClients; -import benchmark.model.Fortune; -import benchmark.model.World; -import io.reactiverse.pgclient.PgIterator; -import io.reactiverse.pgclient.Row; -import io.reactiverse.pgclient.Tuple; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.context.annotation.Profile; -import org.springframework.stereotype.Component; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -@Component -@Profile("pgclient") -public class PgClientDbRepository implements DbRepository { - private final Logger log = LoggerFactory.getLogger(getClass()); - private final PgClients pgClients; - - public PgClientDbRepository(PgClients pgClients) { - this.pgClients = pgClients; - } - - @Override - public Mono getWorld(int id) { - return Mono.create(sink -> - pgClients.getOne().preparedQuery("SELECT * FROM world WHERE id = $1", Tuple.of(id), ar -> { - if (ar.failed()) { - sink.error(ar.cause()); - } else { - - final Row row = ar.result().iterator().next(); - - World world = new World(row.getInteger(0), row.getInteger(1)); - sink.success(world); - } - })); - } - - private Mono updateWorld(World world) { - return Mono.create(sink -> { - pgClients.getOne().preparedQuery("UPDATE world SET randomnumber = $1 WHERE id = $2", Tuple.of(world.randomnumber, world.id), ar -> { - if (ar.failed()) { - sink.error(ar.cause()); - } else { - sink.success(world); - } - }); - }); - } - - @Override - public Mono findAndUpdateWorld(int id, int randomNumber) { - return getWorld(id).flatMap(world -> { - world.randomnumber = randomNumber; - return updateWorld(world); - }); - } - - @Override - public Flux fortunes() { - return Flux.create(sink -> - pgClients.getOne().preparedQuery("SELECT * FROM fortune", ar -> { - if (ar.failed()) { - sink.error(ar.cause()); - return; - } - - PgIterator resultSet = ar.result().iterator(); - while (resultSet.hasNext()) { - Tuple row = resultSet.next(); - sink.next(new Fortune(row.getInteger(0), row.getString(1))); - } - sink.complete(); - })); - } -} \ No newline at end of file diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/repository/R2dbcDbRepository.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/repository/R2dbcDbRepository.java index a6979ffb058..c8f1cdbc0c2 100644 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/repository/R2dbcDbRepository.java +++ b/frameworks/Java/spring-webflux/src/main/java/benchmark/repository/R2dbcDbRepository.java @@ -1,16 +1,24 @@ package benchmark.repository; -import benchmark.model.Fortune; -import benchmark.model.World; +import java.util.List; + import org.springframework.context.annotation.Profile; -import org.springframework.data.r2dbc.core.DatabaseClient; +import org.springframework.r2dbc.core.DatabaseClient; import org.springframework.stereotype.Component; + +import benchmark.model.Fortune; +import benchmark.model.World; +import io.r2dbc.spi.Connection; +import io.r2dbc.spi.ConnectionFactory; +import io.r2dbc.spi.Result; +import io.r2dbc.spi.Statement; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @Component @Profile("r2dbc") public class R2dbcDbRepository implements DbRepository { + private final DatabaseClient databaseClient; public R2dbcDbRepository(DatabaseClient databaseClient) { @@ -19,38 +27,35 @@ public R2dbcDbRepository(DatabaseClient databaseClient) { @Override public Mono getWorld(int id) { - return databaseClient.execute() + return databaseClient .sql("SELECT id, randomnumber FROM world WHERE id = $1") - .bind("$1", id) - .as(World.class) - .fetch() + .bind(0, id) + .mapProperties(World.class) .first(); - - } - - public Mono updateWorld(World world) { - return databaseClient.execute() - .sql("UPDATE world SET randomnumber=$2 WHERE id = $1") - .bind("$1", world.id) - .bind("$2", world.randomnumber) - .fetch() - .rowsUpdated() - .map(count -> world); } - public Mono findAndUpdateWorld(int id, int randomNumber) { - return getWorld(id).flatMap(world -> { - world.randomnumber = randomNumber; - return updateWorld(world); - }); + @Override + public Mono updateWorlds(List worlds) { + return databaseClient.inConnectionMany(con -> { + Statement statement = con.createStatement("UPDATE world SET randomnumber=$2 WHERE id = $1"); + for (int i = 0; i < worlds.size(); i++) { + World world = worlds.get(i); + statement.bind(0, world.randomnumber) + .bind(1, world.id); + if (i < worlds.size() - 1) { + statement.add(); + } + } + return Flux.from(statement.execute()); + }).flatMap(Result::getRowsUpdated).then(); } @Override public Flux fortunes() { - return databaseClient.execute() + return databaseClient .sql("SELECT id, message FROM fortune") - .as(Fortune.class) - .fetch() + .mapProperties(Fortune.class) .all(); } + } \ No newline at end of file diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/repository/RxJdbcDbRepository.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/repository/RxJdbcDbRepository.java deleted file mode 100644 index 1d07720f391..00000000000 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/repository/RxJdbcDbRepository.java +++ /dev/null @@ -1,60 +0,0 @@ -package benchmark.repository; - -import benchmark.model.Fortune; -import benchmark.model.World; -import io.reactivex.Flowable; -import org.davidmoten.rx.jdbc.Database; -import org.springframework.context.annotation.Profile; -import org.springframework.stereotype.Component; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -@Component -@Profile("rxjdbc") -public class RxJdbcDbRepository implements DbRepository { - private final Database db; - - public RxJdbcDbRepository(Database db) { - this.db = db; - } - - @Override - public Mono getWorld(int id) { - String sql = "SELECT * FROM world WHERE id = ?"; - - Flowable worldFlowable = db.select(sql) - .parameters(id) - .get(rs -> { - World world = new World(rs.getInt("id"), rs.getInt("randomnumber")); - return world; - }); - - return Mono.from(worldFlowable); - } - - public Mono updateWorld(World world) { - String sql = "UPDATE world SET randomnumber = ? WHERE id = ?"; - - Flowable worldFlowable = db.update(sql) - .parameters(world.randomnumber, world.id) - .counts().map(cnt -> world); - return Mono.from(worldFlowable); - } - - public Mono findAndUpdateWorld(int id, int randomNumber) { - return getWorld(id).flatMap(world -> { - world.randomnumber = randomNumber; - return updateWorld(world); - }); - } - - @Override - public Flux fortunes() { - String sql = "SELECT * FROM fortune"; - - Flowable fortuneFlowable = db.select(sql) - .get(rs -> new Fortune(rs.getInt("id"), rs.getString("message"))); - - return Flux.from(fortuneFlowable); - } -} \ No newline at end of file diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/web/DbHandler.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/web/DbHandler.java new file mode 100644 index 00000000000..03f90652f69 --- /dev/null +++ b/frameworks/Java/spring-webflux/src/main/java/benchmark/web/DbHandler.java @@ -0,0 +1,99 @@ +package benchmark.web; + +import java.util.Comparator; +import java.util.List; + +import benchmark.Utils; +import benchmark.model.Fortune; +import benchmark.model.World; +import benchmark.repository.DbRepository; +import io.jstach.jstachio.JStachio; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; +import org.springframework.web.reactive.function.server.ServerRequest; +import org.springframework.web.reactive.function.server.ServerResponse; + +@Component +public class DbHandler { + + private static final String CONTENT_TYPE_VALUE = "text/html; charset=utf-8"; + + private final DbRepository dbRepository; + + public DbHandler(DbRepository dbRepository) { + this.dbRepository = dbRepository; + } + + public Mono db(ServerRequest request) { + int id = Utils.randomWorldNumber(); + Mono world = dbRepository.getWorld(id) + .switchIfEmpty(Mono.error(new Exception("No World found with Id: " + id))); + + return ServerResponse.ok() + .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) + .body(world, World.class); + } + + public Mono queries(ServerRequest request) { + int queries = parseQueryCount(request.queryParams().getFirst("queries")); + + Mono> worlds = Flux.fromStream(Utils.randomWorldNumbers().limit(queries).boxed()) + .flatMap(dbRepository::getWorld) + .collectList(); + + return ServerResponse.ok() + .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) + .body(worlds, new ParameterizedTypeReference>() { + }); + } + + private static int parseQueryCount(String maybeTextValue) { + if (maybeTextValue == null) { + return 1; + } + int parsedValue; + try { + parsedValue = Integer.parseInt(maybeTextValue); + } catch (NumberFormatException e) { + return 1; + } + return Math.min(500, Math.max(1, parsedValue)); + } + + public Mono updates(ServerRequest request) { + int queries = parseQueryCount(request.queryParams().getFirst("queries")); + + Mono> worlds = Flux.fromStream(Utils.randomWorldNumbers().limit(queries).boxed()) + .flatMap(id -> dbRepository.getWorld(id).map(world -> { + int randomNumber; + do { + randomNumber = Utils.randomWorldNumber(); + } while (randomNumber == world.randomnumber); + world.randomnumber = randomNumber; + return world; + })) + .collectSortedList(Comparator.comparingInt(w -> w.id)) + .flatMap(list -> dbRepository.updateWorlds(list).thenReturn(list)); + + return ServerResponse.ok() + .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) + .body(worlds, new ParameterizedTypeReference>() { + }); + } + + public Mono fortunes(ServerRequest request) { + return dbRepository.fortunes() + .concatWith(Mono.just(new Fortune(0, "Additional fortune added at request time."))) + .collectSortedList() + .flatMap(fortunes -> + ServerResponse.ok() + .header(HttpHeaders.CONTENT_TYPE, CONTENT_TYPE_VALUE) + .bodyValue(JStachio.render(new Fortunes(fortunes)))); + } + +} \ No newline at end of file diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/web/Fortunes.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/web/Fortunes.java new file mode 100644 index 00000000000..d8fc3dd7e2d --- /dev/null +++ b/frameworks/Java/spring-webflux/src/main/java/benchmark/web/Fortunes.java @@ -0,0 +1,10 @@ +package benchmark.web; + +import java.util.List; + +import benchmark.model.Fortune; +import io.jstach.jstache.JStache; + +@JStache(path = "fortunes.mustache") +public record Fortunes(List fortunes) { +} diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/web/JsonHandler.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/web/JsonHandler.java new file mode 100644 index 00000000000..6f4bc19249f --- /dev/null +++ b/frameworks/Java/spring-webflux/src/main/java/benchmark/web/JsonHandler.java @@ -0,0 +1,54 @@ +package benchmark.web; + +import java.util.Map; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectWriter; +import reactor.core.publisher.Mono; + +import org.springframework.core.io.buffer.DataBuffer; +import org.springframework.core.io.buffer.DataBufferFactory; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; +import org.springframework.web.reactive.function.server.HandlerFunction; +import org.springframework.web.reactive.function.server.ServerRequest; +import org.springframework.web.reactive.function.server.ServerResponse; + +@Component +public class JsonHandler implements HandlerFunction { + + private final ObjectWriter writer; + + public JsonHandler(ObjectMapper objectMapper) { + this.writer = objectMapper.writerFor(Map.class); + } + + @Override + public Mono handle(ServerRequest request) { + return ServerResponse.ok() + .body((message, context) -> { + DataBuffer buffer = serialize(request, Map.of("message", "Hello, world!")); + HttpHeaders headers = message.getHeaders(); + headers.setContentLength(buffer.readableByteCount()); + headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); + return message.writeWith(Mono.just(buffer)); + }); + } + + private DataBuffer serialize(ServerRequest request, Object object) { + try { + byte[] bytes = this.writer.writeValueAsBytes(object); + return bufferFactory(request).wrap(bytes); + } + catch (JsonProcessingException ex) { + throw new RuntimeException(ex); + } + } + + private static DataBufferFactory bufferFactory(ServerRequest request) { + return request.exchange().getResponse().bufferFactory(); + } + +} \ No newline at end of file diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/web/ServerFilter.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/web/ServerFilter.java new file mode 100644 index 00000000000..38357eefdb2 --- /dev/null +++ b/frameworks/Java/spring-webflux/src/main/java/benchmark/web/ServerFilter.java @@ -0,0 +1,34 @@ +package benchmark.web; + +import org.springframework.http.HttpHeaders; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; +import org.springframework.web.server.ServerWebExchange; +import org.springframework.web.server.WebFilter; +import org.springframework.web.server.WebFilterChain; +import reactor.core.publisher.Mono; + +@Component +public class ServerFilter implements WebFilter { + + private static final String SERVER_NAME = "spring-webflux"; + + private String date; + + public ServerFilter() { + updateDate(); + } + + @Scheduled(fixedRate = 1000) + public void updateDate() { + this.date = java.time.format.DateTimeFormatter.RFC_1123_DATE_TIME.format(java.time.ZonedDateTime.now()); + } + + @Override + public Mono filter(ServerWebExchange exchange, WebFilterChain chain) { + HttpHeaders headers = exchange.getResponse().getHeaders(); + headers.add(HttpHeaders.SERVER, SERVER_NAME); + headers.add(HttpHeaders.DATE, this.date); + return chain.filter(exchange); + } +} \ No newline at end of file diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/web/TextHandler.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/web/TextHandler.java new file mode 100644 index 00000000000..8abac92606d --- /dev/null +++ b/frameworks/Java/spring-webflux/src/main/java/benchmark/web/TextHandler.java @@ -0,0 +1,37 @@ +package benchmark.web; + +import java.nio.charset.StandardCharsets; + +import reactor.core.publisher.Mono; + +import org.springframework.core.io.buffer.DataBufferFactory; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; +import org.springframework.web.reactive.function.server.HandlerFunction; +import org.springframework.web.reactive.function.server.ServerRequest; +import org.springframework.web.reactive.function.server.ServerResponse; + +@Component +public class TextHandler implements HandlerFunction { + + private static final byte[] TEXT_BODY = "Hello, World!".getBytes(StandardCharsets.UTF_8); + + private static final String TEXT_BODY_LENGTH = String.valueOf(TEXT_BODY.length); + + @Override + public Mono handle(ServerRequest request) { + return ServerResponse.ok() + .body((message, context) -> { + HttpHeaders headers = message.getHeaders(); + headers.add(HttpHeaders.CONTENT_LENGTH, TEXT_BODY_LENGTH); + headers.add(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN_VALUE); + return message.writeWith(Mono.just(bufferFactory(request).wrap(TEXT_BODY))); + }); + } + + private static DataBufferFactory bufferFactory(ServerRequest request) { + return request.exchange().getResponse().bufferFactory(); + } + +} \ No newline at end of file diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/web/WebfluxHandler.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/web/WebfluxHandler.java deleted file mode 100644 index e7fdeafa404..00000000000 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/web/WebfluxHandler.java +++ /dev/null @@ -1,108 +0,0 @@ -package benchmark.web; - -import benchmark.model.Fortune; -import benchmark.model.World; -import benchmark.repository.DbRepository; - -import org.springframework.core.ParameterizedTypeReference; -import org.springframework.http.MediaType; -import org.springframework.stereotype.Component; -import org.springframework.web.reactive.function.server.ServerRequest; -import org.springframework.web.reactive.function.server.ServerResponse; - -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -import java.util.*; -import java.util.concurrent.ThreadLocalRandom; - -import static java.util.Comparator.comparing; - -@Component -public class WebfluxHandler { - private final DbRepository dbRepository; - - public WebfluxHandler(DbRepository dbRepository) { - this.dbRepository = dbRepository; - } - - public Mono plaintext(ServerRequest request) { - return ServerResponse.ok() - .contentType(MediaType.TEXT_PLAIN) - .body(Mono.just("Hello, World!"), String.class); - } - - public Mono json(ServerRequest request) { - return ServerResponse.ok() - .contentType(MediaType.APPLICATION_JSON) - .body(Mono.just(Map.of("message", "Hello, World!")), Map.class); - } - - public Mono db(ServerRequest request) { - int id = randomWorldNumber(); - Mono world = dbRepository.getWorld(id) - .switchIfEmpty(Mono.error(new Exception("No World found with Id: " + id))); - - return ServerResponse.ok() - .contentType(MediaType.APPLICATION_JSON) - .body(world, World.class); - } - - public Mono queries(ServerRequest request) { - int queries = getQueries(request); - - Mono> worlds = Flux.range(0, queries) - .flatMap(i -> dbRepository.getWorld(randomWorldNumber())) - .collectList(); - - return ServerResponse.ok() - .contentType(MediaType.APPLICATION_JSON) - .body(worlds, new ParameterizedTypeReference>() { - }); - } - - private static int parseQueryCount(Optional maybeTextValue) { - if (!maybeTextValue.isPresent()) { - return 1; - } - int parsedValue; - try { - parsedValue = Integer.parseInt(maybeTextValue.get()); - } catch (NumberFormatException e) { - return 1; - } - return Math.min(500, Math.max(1, parsedValue)); - } - - public Mono updates(ServerRequest request) { - int queries = getQueries(request); - - Mono> worlds = Flux.range(0, queries) - .flatMap(i -> dbRepository.findAndUpdateWorld(randomWorldNumber(), randomWorldNumber())) - .collectList(); - - return ServerResponse.ok() - .contentType(MediaType.APPLICATION_JSON) - .body(worlds, new ParameterizedTypeReference>() { - }); - } - - public Mono fortunes(ServerRequest request) { - Mono> result = dbRepository.fortunes().collectList().flatMap(fortunes -> { - fortunes.add(new Fortune(0, "Additional fortune added at request time.")); - fortunes.sort(comparing(fortune -> fortune.message)); - return Mono.just(fortunes); - }); - - return ServerResponse.ok() - .render("fortunes", Collections.singletonMap("fortunes", result)); - } - - private static int getQueries(ServerRequest request) { - return parseQueryCount(request.queryParam("queries")); - } - - private static int randomWorldNumber() { - return 1 + ThreadLocalRandom.current().nextInt(10000); - } -} diff --git a/frameworks/Java/spring-webflux/src/main/java/benchmark/web/WebfluxRouter.java b/frameworks/Java/spring-webflux/src/main/java/benchmark/web/WebfluxRouter.java index b4dfb9be319..1499dc4f839 100644 --- a/frameworks/Java/spring-webflux/src/main/java/benchmark/web/WebfluxRouter.java +++ b/frameworks/Java/spring-webflux/src/main/java/benchmark/web/WebfluxRouter.java @@ -1,37 +1,32 @@ package benchmark.web; +import reactor.core.publisher.Mono; + import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.web.reactive.function.server.HandlerFunction; import org.springframework.web.reactive.function.server.RouterFunction; -import org.springframework.web.reactive.function.server.RouterFunctions; import org.springframework.web.reactive.function.server.ServerResponse; -import static org.springframework.web.reactive.function.server.RequestPredicates.GET; - @Configuration public class WebfluxRouter { @Bean - public RouterFunction route(WebfluxHandler handler) { - return RouterFunctions - .route( - GET("/plaintext"), - handler::plaintext) - .andRoute( - GET("/json"), - handler::json) - .andRoute( - GET("/db"), - handler::db) - .andRoute( - GET("/queries"), - handler::queries) - .andRoute( - GET("/updates"), - handler::updates) - .andRoute( - GET("/fortunes"), - handler::fortunes) - ; + public RouterFunction route( + TextHandler textHandler, JsonHandler jsonHandler, DbHandler dbHandler) { + + return request -> { + HandlerFunction fn = switch (request.uri().getRawPath()) { + case "/plaintext" -> textHandler; + case "/json" -> jsonHandler; + case "/db" -> dbHandler::db; + case "/queries" -> dbHandler::queries; + case "/updates" -> dbHandler::updates; + case "/fortunes" -> dbHandler::fortunes; + default -> r -> ServerResponse.notFound().build(); + }; + return Mono.just(fn); + }; } + } \ No newline at end of file diff --git a/frameworks/Java/spring-webflux/src/main/resources/application.yml b/frameworks/Java/spring-webflux/src/main/resources/application.yml index d45387cecde..45ca20c7d80 100755 --- a/frameworks/Java/spring-webflux/src/main/resources/application.yml +++ b/frameworks/Java/spring-webflux/src/main/resources/application.yml @@ -1,11 +1,3 @@ ---- -spring: - profiles: postgres - datasource: - url: jdbc:postgresql://${database.host}:${database.port}/${database.name} - username: ${database.username} - password: ${database.password} - database: name: hello_world host: tfb-database @@ -15,24 +7,27 @@ database: --- spring: - profiles: jdbc - ---- -spring: - profiles: pgclient - ---- -spring: - profiles: rxjdbc - ---- -spring: - profiles: r2dbc + config: + activate: + on-profile: r2dbc + autoconfigure: + exclude: org.springframework.boot.autoconfigure.mongo.MongoReactiveAutoConfiguration,org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration + r2dbc: + username: ${database.username} + password: ${database.password} + url: r2dbc:postgresql://${database.host}:${database.port}/${database.name}?loggerLevel=OFF&disableColumnSanitiser=true&assumeMinServerVersion=16&sslmode=disable + pool: + max-size: 256 --- spring: - profiles: mongo + config: + activate: + on-profile: mongo + autoconfigure: + exclude: org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration -database: - url: mongodb://tfb-database:27017/?waitQueueMultiple=200 - name: hello_world \ No newline at end of file + data: + mongodb: + uri: mongodb://tfb-database:27017/?waitQueueMultiple=200 + database: hello_world diff --git a/frameworks/Java/spring/src/main/resources/templates/fortunes.mustache b/frameworks/Java/spring-webflux/src/main/resources/fortunes.mustache similarity index 100% rename from frameworks/Java/spring/src/main/resources/templates/fortunes.mustache rename to frameworks/Java/spring-webflux/src/main/resources/fortunes.mustache diff --git a/frameworks/Java/spring/README.md b/frameworks/Java/spring/README.md index 8e25a585d44..742649fff7e 100644 --- a/frameworks/Java/spring/README.md +++ b/frameworks/Java/spring/README.md @@ -2,9 +2,7 @@ This is the Spring MVC portion of a [benchmarking test suite](../) comparing a variety of web development platforms. -An embedded undertow is used for the web server, with nearly everything configured with default settings. -The only thing changed is Hikari can use up to (2 * cores count) connections (the default is 10). -See [About-Pool-Sizing](https://github.com/brettwooldridge/HikariCP/wiki/About-Pool-Sizing) +An embedded undertow is used for the web server. There are two implementations : * For postgresql access, JdbcTemplate is used. See [JdbcDbRepository](src/main/java/hello/JdbcDbRepository.java). diff --git a/frameworks/Java/spring/benchmark_config.json b/frameworks/Java/spring/benchmark_config.json index 615c4a478ca..72362984811 100644 --- a/frameworks/Java/spring/benchmark_config.json +++ b/frameworks/Java/spring/benchmark_config.json @@ -24,27 +24,6 @@ "notes": "", "versus": "" }, - "jpa": { - "db_url": "/db", - "query_url": "/queries?queries=", - "fortune_url": "/fortunes", - "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-jpa", - "notes": "", - "versus": "spring" - }, "mongo": { "db_url": "/db", "query_url": "/queries?queries=", diff --git a/frameworks/Java/spring/pom.xml b/frameworks/Java/spring/pom.xml index b646277a3b0..3271ab04f03 100644 --- a/frameworks/Java/spring/pom.xml +++ b/frameworks/Java/spring/pom.xml @@ -11,12 +11,12 @@ org.springframework.boot spring-boot-starter-parent - 3.0.0 + 3.3.5 - 17 - 42.5.1 + 21 + 1.3.6 @@ -36,15 +36,23 @@ org.springframework.boot - spring-boot-starter-data-jpa + spring-boot-starter-jdbc org.springframework.boot spring-boot-starter-data-mongodb - org.springframework.boot - spring-boot-starter-mustache + io.jstach + jstachio + ${jstachio.version} + + + io.jstach + jstachio-apt + ${jstachio.version} + provided + true @@ -63,7 +71,13 @@ org.apache.maven.plugins maven-compiler-plugin - false + + + io.jstach + jstachio-apt + ${jstachio.version} + + diff --git a/frameworks/Java/spring/spring-jpa.dockerfile b/frameworks/Java/spring/spring-jpa.dockerfile deleted file mode 100644 index 4c197667a24..00000000000 --- a/frameworks/Java/spring/spring-jpa.dockerfile +++ /dev/null @@ -1,34 +0,0 @@ -FROM eclipse-temurin:17 as jre-build - -# Create a custom Java runtime -RUN $JAVA_HOME/bin/jlink \ - --add-modules ALL-MODULE-PATH \ - --strip-debug \ - --no-man-pages \ - --no-header-files \ - --compress=2 \ - --output /javaruntime - -FROM maven:3.8.5-openjdk-17-slim as maven -ENV JAVA_HOME=/opt/java/openjdk -ENV PATH "${JAVA_HOME}/bin:${PATH}" -COPY --from=jre-build /javaruntime $JAVA_HOME - -RUN mvn -version -WORKDIR /spring -COPY src src -COPY pom.xml pom.xml -RUN mvn package -q - -FROM debian:bullseye-slim -ENV JAVA_HOME=/opt/java/openjdk -ENV PATH "${JAVA_HOME}/bin:${PATH}" -COPY --from=jre-build /javaruntime $JAVA_HOME - -RUN java -version -WORKDIR /spring -COPY --from=maven /spring/target/hello-spring-1.0-SNAPSHOT.jar app.jar - -EXPOSE 8080 - -CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseG1GC", "-XX:+DisableExplicitGC", "-XX:+UseStringDeduplication", "-Dlogging.level.root=OFF", "-jar", "app.jar", "--spring.profiles.active=jpa"] diff --git a/frameworks/Java/spring/spring-mongo.dockerfile b/frameworks/Java/spring/spring-mongo.dockerfile index 3672481ca61..cc51f6c844c 100644 --- a/frameworks/Java/spring/spring-mongo.dockerfile +++ b/frameworks/Java/spring/spring-mongo.dockerfile @@ -1,34 +1,15 @@ -FROM eclipse-temurin:17 as jre-build - -# Create a custom Java runtime -RUN $JAVA_HOME/bin/jlink \ - --add-modules ALL-MODULE-PATH \ - --strip-debug \ - --no-man-pages \ - --no-header-files \ - --compress=2 \ - --output /javaruntime - -FROM maven:3.8.5-openjdk-17-slim as maven -ENV JAVA_HOME=/opt/java/openjdk -ENV PATH "${JAVA_HOME}/bin:${PATH}" -COPY --from=jre-build /javaruntime $JAVA_HOME - -RUN mvn -version +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 debian:bullseye-slim -ENV JAVA_HOME=/opt/java/openjdk -ENV PATH "${JAVA_HOME}/bin:${PATH}" -COPY --from=jre-build /javaruntime $JAVA_HOME - -RUN java -version +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", "-server", "-XX:+UseNUMA", "-XX:+UseG1GC", "-XX:+DisableExplicitGC", "-XX:+UseStringDeduplication", "-Dlogging.level.root=OFF", "-jar", "app.jar", "--spring.profiles.active=mongo"] +CMD ["java", "-XX:+DisableExplicitGC", "-XX:+UseStringDeduplication", "-Dlogging.level.root=OFF", "-jar", "app/app.jar", "--spring.profiles.active=mongo"] \ No newline at end of file diff --git a/frameworks/Java/spring/spring.dockerfile b/frameworks/Java/spring/spring.dockerfile index a06133e8c45..1f102057b99 100644 --- a/frameworks/Java/spring/spring.dockerfile +++ b/frameworks/Java/spring/spring.dockerfile @@ -1,34 +1,15 @@ -FROM eclipse-temurin:17 as jre-build - -# Create a custom Java runtime -RUN $JAVA_HOME/bin/jlink \ - --add-modules ALL-MODULE-PATH \ - --strip-debug \ - --no-man-pages \ - --no-header-files \ - --compress=2 \ - --output /javaruntime - -FROM maven:3.8.5-openjdk-17-slim as maven -ENV JAVA_HOME=/opt/java/openjdk -ENV PATH "${JAVA_HOME}/bin:${PATH}" -COPY --from=jre-build /javaruntime $JAVA_HOME - -RUN mvn -version +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 debian:bullseye-slim -ENV JAVA_HOME=/opt/java/openjdk -ENV PATH "${JAVA_HOME}/bin:${PATH}" -COPY --from=jre-build /javaruntime $JAVA_HOME - -RUN java -version +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", "-server", "-XX:+UseNUMA", "-XX:+UseG1GC", "-XX:+DisableExplicitGC", "-XX:+UseStringDeduplication", "-Dlogging.level.root=OFF", "-jar", "app.jar", "--spring.profiles.active=jdbc"] +CMD ["java", "-XX:+DisableExplicitGC", "-XX:+UseStringDeduplication", "-Dlogging.level.root=OFF", "-jar", "app/app.jar", "--spring.profiles.active=jdbc"] \ No newline at end of file diff --git a/frameworks/Java/spring/src/main/java/hello/App.java b/frameworks/Java/spring/src/main/java/hello/App.java index 435bbcf0dd4..da87b679f87 100644 --- a/frameworks/Java/spring/src/main/java/hello/App.java +++ b/frameworks/Java/spring/src/main/java/hello/App.java @@ -1,31 +1,20 @@ package hello; -import javax.sql.DataSource; - import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Profile; - -import com.zaxxer.hikari.HikariDataSource; +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.event.EventListener; -@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, MongoRepositoriesAutoConfiguration.class}) +@SpringBootApplication public class App { public static void main(String[] args) { SpringApplication.run(App.class, args); } - @Bean - @Profile({ "jdbc", "jpa" }) - public DataSource datasource(DataSourceProperties dataSourceProperties) { - HikariDataSource dataSource = dataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource.class) - .build(); - dataSource.setMaximumPoolSize(Runtime.getRuntime().availableProcessors() * 2); - - return dataSource; + @EventListener(ApplicationReadyEvent.class) + public void runAfterStartup() { + System.out.println("Application is ready"); } + } diff --git a/frameworks/Java/spring/src/main/java/hello/JpaConfig.java b/frameworks/Java/spring/src/main/java/hello/JpaConfig.java deleted file mode 100644 index c5b8576acab..00000000000 --- a/frameworks/Java/spring/src/main/java/hello/JpaConfig.java +++ /dev/null @@ -1,12 +0,0 @@ -package hello; - -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Profile; -import org.springframework.data.jpa.repository.config.EnableJpaRepositories; - -@Profile("jpa") -@Configuration -@EnableJpaRepositories(basePackages = "hello.jpa") -public class JpaConfig { - -} diff --git a/frameworks/Java/spring/src/main/java/hello/Utils.java b/frameworks/Java/spring/src/main/java/hello/Utils.java new file mode 100644 index 00000000000..fbb1216624f --- /dev/null +++ b/frameworks/Java/spring/src/main/java/hello/Utils.java @@ -0,0 +1,19 @@ +package hello; + +import java.util.concurrent.ThreadLocalRandom; +import java.util.stream.IntStream; + +abstract public 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/spring/src/main/java/hello/controller/HelloController.java b/frameworks/Java/spring/src/main/java/hello/controller/HelloController.java deleted file mode 100644 index 6046a2e7426..00000000000 --- a/frameworks/Java/spring/src/main/java/hello/controller/HelloController.java +++ /dev/null @@ -1,128 +0,0 @@ -package hello.controller; - -import static java.util.Comparator.comparing; - -import java.util.List; -import java.util.concurrent.ThreadLocalRandom; -import java.util.stream.IntStream; - -import jakarta.servlet.http.HttpServletResponse; -import org.springframework.http.MediaType; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.ModelAttribute; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -import hello.model.Fortune; -import hello.model.World; -import hello.repository.DbRepository; - -@RestController -public final class HelloController { - - private DbRepository dbRepository; - - public HelloController(DbRepository dbRepository) { - this.dbRepository = dbRepository; - } - - @GetMapping(value = "/plaintext") - String plaintext(HttpServletResponse response) { - response.setContentType(MediaType.TEXT_PLAIN_VALUE); - return "Hello, World!"; - } - - @GetMapping("/json") - Message json(HttpServletResponse response) { - response.setContentType(MediaType.APPLICATION_JSON_VALUE); - return new Message("Hello, World!"); - } - - @GetMapping("/db") - World db(HttpServletResponse response) { - response.setContentType(MediaType.APPLICATION_JSON_VALUE); - return dbRepository.getWorld(randomWorldNumber()); - } - - @GetMapping("/queries") - World[] queries(HttpServletResponse response, @RequestParam(required = false) String queries) { - response.setContentType(MediaType.APPLICATION_JSON_VALUE); - return randomWorldNumbers().mapToObj(dbRepository::getWorld).limit(parseQueryCount(queries)) - .toArray(World[]::new); - } - - @GetMapping("/updates") - World[] updates(HttpServletResponse response, @RequestParam(required = false) String queries) { - response.setContentType(MediaType.APPLICATION_JSON_VALUE); - return randomWorldNumbers().mapToObj(dbRepository::getWorld).map(world -> { - // Ensure that the new random number is not equal to the old one. - // That would cause the JPA-based implementation to avoid sending the - // UPDATE query to the database, which would violate the test - // requirements. - - // Locally the records doesn't exist, maybe in the yours is ok but we need to - // make this check - if (world == null) { - return null; - } - - int newRandomNumber; - do { - newRandomNumber = randomWorldNumber(); - } while (newRandomNumber == world.randomnumber); - - return dbRepository.updateWorld(world, newRandomNumber); - }).limit(parseQueryCount(queries)).toArray(World[]::new); - } - - @GetMapping("/fortunes") - @ModelAttribute("fortunes") - List fortunes(HttpServletResponse response) { - response.setContentType(MediaType.TEXT_HTML_VALUE); - var fortunes = dbRepository.fortunes(); - - fortunes.add(new Fortune(0, "Additional fortune added at request time.")); - fortunes.sort(comparing(fortune -> fortune.message)); - return fortunes; - } - - private static final int MIN_WORLD_NUMBER = 1; - private static final int MAX_WORLD_NUMBER_PLUS_ONE = 10_001; - - private static int randomWorldNumber() { - return ThreadLocalRandom.current().nextInt(MIN_WORLD_NUMBER, MAX_WORLD_NUMBER_PLUS_ONE); - } - - private static IntStream randomWorldNumbers() { - return ThreadLocalRandom.current().ints(MIN_WORLD_NUMBER, MAX_WORLD_NUMBER_PLUS_ONE) - // distinct() allows us to avoid using Hibernate's first-level cache in - // the JPA-based implementation. Using a cache like that would bypass - // querying the database, which would violate the test requirements. - .distinct(); - } - - 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)); - } - - static class Message { - private final String message; - - public Message(String message) { - this.message = message; - } - - public String getMessage() { - return message; - } - } -} diff --git a/frameworks/Java/spring/src/main/java/hello/jpa/FortuneRepository.java b/frameworks/Java/spring/src/main/java/hello/jpa/FortuneRepository.java deleted file mode 100644 index 30dea98cc27..00000000000 --- a/frameworks/Java/spring/src/main/java/hello/jpa/FortuneRepository.java +++ /dev/null @@ -1,12 +0,0 @@ -package hello.jpa; - -import org.springframework.context.annotation.Profile; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -import hello.model.Fortune; - -@Repository -@Profile("jpa") -public interface FortuneRepository extends JpaRepository { -} diff --git a/frameworks/Java/spring/src/main/java/hello/jpa/JpaDbRepository.java b/frameworks/Java/spring/src/main/java/hello/jpa/JpaDbRepository.java deleted file mode 100644 index 2b58841a035..00000000000 --- a/frameworks/Java/spring/src/main/java/hello/jpa/JpaDbRepository.java +++ /dev/null @@ -1,38 +0,0 @@ -package hello.jpa; - -import java.util.List; - -import org.springframework.context.annotation.Profile; -import org.springframework.stereotype.Service; - -import hello.model.Fortune; -import hello.model.World; -import hello.repository.DbRepository; - -@Service -@Profile("jpa") -public class JpaDbRepository implements DbRepository { - private final WorldRepository worldRepository; - private final FortuneRepository fortuneRepository; - - public JpaDbRepository(WorldRepository worldRepository, FortuneRepository fortuneRepository) { - this.worldRepository = worldRepository; - this.fortuneRepository = fortuneRepository; - } - - @Override - public World getWorld(int id) { - return worldRepository.findById(id).orElse(null); - } - - @Override - public World updateWorld(World world, int randomNumber) { - world.randomnumber = randomNumber; - return worldRepository.save(world); - } - - @Override - public List fortunes() { - return fortuneRepository.findAll(); - } -} diff --git a/frameworks/Java/spring/src/main/java/hello/jpa/WorldRepository.java b/frameworks/Java/spring/src/main/java/hello/jpa/WorldRepository.java deleted file mode 100644 index 70361aa40d6..00000000000 --- a/frameworks/Java/spring/src/main/java/hello/jpa/WorldRepository.java +++ /dev/null @@ -1,12 +0,0 @@ -package hello.jpa; - -import org.springframework.context.annotation.Profile; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -import hello.model.World; - -@Repository -@Profile("jpa") -public interface WorldRepository extends JpaRepository { -} 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 e4ff559610a..a628d3c755f 100644 --- a/frameworks/Java/spring/src/main/java/hello/model/Fortune.java +++ b/frameworks/Java/spring/src/main/java/hello/model/Fortune.java @@ -1,33 +1,25 @@ package hello.model; -import jakarta.persistence.Entity; - import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.mapping.Document; import org.springframework.data.mongodb.core.mapping.Field; @Document -@Entity -public final class Fortune { +public final class Fortune implements Comparable{ + @Id - @jakarta.persistence.Id - public int id; - @Field("message") - public String message; + public final int id; - protected Fortune() { - } + @Field("message") + public final String message; public Fortune(int id, String message) { this.id = id; this.message = message; } - public int getId() { - return id; - } - - public String getMessage() { - return message; + @Override + public int compareTo(final Fortune other) { + return message.compareTo(other.message); } -} \ No newline at end of file +} 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 2855df8a5d8..762e9e622ce 100644 --- a/frameworks/Java/spring/src/main/java/hello/model/World.java +++ b/frameworks/Java/spring/src/main/java/hello/model/World.java @@ -1,26 +1,22 @@ package hello.model; -import jakarta.persistence.Entity; - import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.mapping.Document; import org.springframework.data.mongodb.core.mapping.Field; @Document -@Entity public final class World { @Id - @jakarta.persistence.Id public int id; + @Field("randomNumber") - public int randomnumber; + public int randomNumber; - protected World() { - } - public World(int id, int randomnumber) { + public World(int id, int randomNumber) { this.id = id; - this.randomnumber = randomnumber; + this.randomNumber = randomNumber; } + } \ No newline at end of file diff --git a/frameworks/Java/spring/src/main/java/hello/repository/DbRepository.java b/frameworks/Java/spring/src/main/java/hello/repository/DbRepository.java index 5cfa8c7d5c3..d7733754c2c 100644 --- a/frameworks/Java/spring/src/main/java/hello/repository/DbRepository.java +++ b/frameworks/Java/spring/src/main/java/hello/repository/DbRepository.java @@ -6,9 +6,10 @@ import hello.model.World; public interface DbRepository { + World getWorld(int id); - World updateWorld(World world, int randomNumber); + void updateWorlds(List worlds); List fortunes(); } diff --git a/frameworks/Java/spring/src/main/java/hello/repository/JdbcDbRepository.java b/frameworks/Java/spring/src/main/java/hello/repository/JdbcDbRepository.java index f1dcdae0352..bc706e232c8 100644 --- a/frameworks/Java/spring/src/main/java/hello/repository/JdbcDbRepository.java +++ b/frameworks/Java/spring/src/main/java/hello/repository/JdbcDbRepository.java @@ -1,10 +1,15 @@ package hello.repository; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; import java.util.List; import org.springframework.context.annotation.Profile; import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.ParameterizedPreparedStatementSetter; import org.springframework.stereotype.Repository; import hello.model.Fortune; @@ -22,27 +27,34 @@ public JdbcDbRepository(JdbcTemplate jdbcTemplate) { @Override public World getWorld(int id) { try { - return jdbcTemplate.queryForObject("SELECT * FROM world WHERE id = ?", - (rs, rn) -> new World(rs.getInt("id"), rs.getInt("randomnumber")), id); + return jdbcTemplate.queryForObject("SELECT id, randomnumber FROM world WHERE id = ?", + (rs, rn) -> new World(rs.getInt(1), rs.getInt(2)), id); } catch (EmptyResultDataAccessException e) { return null; } } - private World updateWorld(World world) { - jdbcTemplate.update("UPDATE world SET randomnumber = ? WHERE id = ?", world.randomnumber, world.id); - return world; - } - @Override - public World updateWorld(World world, int randomNumber) { - world.randomnumber = randomNumber; - return updateWorld(world); + public void updateWorlds(List worlds) { + jdbcTemplate.batchUpdate("UPDATE world SET randomnumber = ? WHERE id = ?", worlds, worlds.size(), new ParameterizedPreparedStatementSetter() { + @Override + public void setValues(PreparedStatement ps, World world) throws SQLException { + ps.setInt(1, world.randomNumber); + ps.setInt(2, world.id); + } + }); } @Override public List fortunes() { - return jdbcTemplate.query("SELECT * FROM fortune", - (rs, rn) -> new Fortune(rs.getInt("id"), rs.getString("message"))); + return jdbcTemplate.query(con -> con.prepareStatement("SELECT id, message FROM fortune", + ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY), rs -> { + List results = new ArrayList<>(); + while (rs.next()) { + results.add(new Fortune(rs.getInt(1), rs.getString(2))); + } + return results; + }); } + } 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 66c81e64f1d..9b6b67c4c95 100644 --- a/frameworks/Java/spring/src/main/java/hello/repository/MongoDbRepository.java +++ b/frameworks/Java/spring/src/main/java/hello/repository/MongoDbRepository.java @@ -1,11 +1,18 @@ package hello.repository; +import java.util.ArrayList; import java.util.List; import org.springframework.context.annotation.Profile; +import org.springframework.data.mongodb.core.BulkOperations; import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.data.mongodb.core.query.Query; +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; @@ -24,9 +31,14 @@ public World getWorld(int id) { } @Override - public World updateWorld(World world, int randomNumber) { - world.randomnumber = randomNumber; - return mongoTemplate.save(world); + public void updateWorlds(List worlds) { + BulkOperations bulkOps = mongoTemplate.bulkOps(BulkOperations.BulkMode.UNORDERED, World.class); + for (World world : worlds) { + Query query = new Query().addCriteria(new Criteria("_id").is(world.id)); + Update update = new Update().set("randomNumber", world.randomNumber); + bulkOps.updateOne(query, update); + } + bulkOps.execute(); } @Override diff --git a/frameworks/Java/spring/src/main/java/hello/web/DbHandler.java b/frameworks/Java/spring/src/main/java/hello/web/DbHandler.java new file mode 100644 index 00000000000..983eb79f6b9 --- /dev/null +++ b/frameworks/Java/spring/src/main/java/hello/web/DbHandler.java @@ -0,0 +1,85 @@ +package hello.web; + +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import hello.Utils; +import hello.model.Fortune; +import hello.model.World; +import hello.repository.DbRepository; +import io.jstach.jstachio.JStachio; + +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; +import org.springframework.web.servlet.function.ServerRequest; +import org.springframework.web.servlet.function.ServerResponse; + +@Component +public class DbHandler { + + private final DbRepository dbRepository; + + public DbHandler(DbRepository dbRepository) { + this.dbRepository = dbRepository; + } + + ServerResponse db(ServerRequest request) { + return ServerResponse.ok() + .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) + .body(dbRepository.getWorld(Utils.randomWorldNumber())); + } + + ServerResponse queries(ServerRequest request) { + int queries = parseQueryCount(request.params().getFirst("queries")); + World[] worlds = Utils.randomWorldNumbers() + .mapToObj(dbRepository::getWorld).limit(queries) + .toArray(World[]::new); + return ServerResponse.ok() + .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) + .body(worlds); + } + + ServerResponse updates(ServerRequest request) { + int queries = parseQueryCount(request.params().getFirst("queries")); + List worlds = Utils.randomWorldNumbers() + .mapToObj(id -> { + World world = dbRepository.getWorld(id); + int randomNumber; + do { + randomNumber = Utils.randomWorldNumber(); + } while (randomNumber == world.randomNumber); + world.randomNumber = randomNumber; + return world; + }).limit(queries) + .sorted(Comparator.comparingInt(w -> w.id)) + .toList(); + dbRepository.updateWorlds(worlds); + return ServerResponse.ok() + .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) + .body(worlds); + } + + ServerResponse fortunes(ServerRequest request) { + List fortunes = dbRepository.fortunes(); + fortunes.add(new Fortune(0, "Additional fortune added at request time.")); + Collections.sort(fortunes); + return ServerResponse.ok() + .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_HTML_VALUE) + .body(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/spring/src/main/java/hello/web/Fortunes.java b/frameworks/Java/spring/src/main/java/hello/web/Fortunes.java new file mode 100644 index 00000000000..cbd6daf2396 --- /dev/null +++ b/frameworks/Java/spring/src/main/java/hello/web/Fortunes.java @@ -0,0 +1,10 @@ +package hello.web; + +import java.util.List; + +import hello.model.Fortune; +import io.jstach.jstache.JStache; + +@JStache(path = "fortunes.mustache") +public record Fortunes(List fortunes) { +} diff --git a/frameworks/Java/spring/src/main/java/hello/web/JsonHandler.java b/frameworks/Java/spring/src/main/java/hello/web/JsonHandler.java new file mode 100644 index 00000000000..c6690811eca --- /dev/null +++ b/frameworks/Java/spring/src/main/java/hello/web/JsonHandler.java @@ -0,0 +1,39 @@ +package hello.web; + +import java.util.Map; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectWriter; + +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; +import org.springframework.web.servlet.function.HandlerFunction; +import org.springframework.web.servlet.function.ServerRequest; +import org.springframework.web.servlet.function.ServerResponse; + +@Component +public class JsonHandler implements HandlerFunction { + + private final ObjectWriter writer; + + public JsonHandler(ObjectMapper objectMapper) { + this.writer = objectMapper.writerFor(Map.class); + } + + @Override + public ServerResponse handle(ServerRequest request) { + try { + byte[] body = this.writer.writeValueAsBytes(Map.of("message", "Hello, world!")); + return ServerResponse.ok() + .contentLength(body.length) + .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) + .body(body); + } + catch (JsonProcessingException ex) { + throw new RuntimeException(ex); + } + } + +} diff --git a/frameworks/Java/spring/src/main/java/hello/web/TextHandler.java b/frameworks/Java/spring/src/main/java/hello/web/TextHandler.java new file mode 100644 index 00000000000..b70b3010268 --- /dev/null +++ b/frameworks/Java/spring/src/main/java/hello/web/TextHandler.java @@ -0,0 +1,27 @@ +package hello.web; + +import java.nio.charset.StandardCharsets; + +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; +import org.springframework.web.servlet.function.HandlerFunction; +import org.springframework.web.servlet.function.ServerRequest; +import org.springframework.web.servlet.function.ServerResponse; + +@Component +public class TextHandler implements HandlerFunction { + + private static final byte[] TEXT_BODY = "Hello, World!".getBytes(StandardCharsets.UTF_8); + + private static final String TEXT_BODY_LENGTH = String.valueOf(TEXT_BODY.length); + + @Override + public ServerResponse handle(ServerRequest request) { + return ServerResponse.ok() + .header(HttpHeaders.CONTENT_LENGTH, TEXT_BODY_LENGTH) + .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN_VALUE) + .body(TEXT_BODY); + } + +} diff --git a/frameworks/Java/spring/src/main/java/hello/web/WebmvcRouter.java b/frameworks/Java/spring/src/main/java/hello/web/WebmvcRouter.java new file mode 100644 index 00000000000..0a5810affd2 --- /dev/null +++ b/frameworks/Java/spring/src/main/java/hello/web/WebmvcRouter.java @@ -0,0 +1,32 @@ +package hello.web; + +import java.util.Optional; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.function.HandlerFunction; +import org.springframework.web.servlet.function.RouterFunction; +import org.springframework.web.servlet.function.ServerResponse; + +@Configuration +public class WebmvcRouter { + + @Bean + public RouterFunction route( + TextHandler textHandler, + JsonHandler jsonHandler, + DbHandler dbHandler) { + + return request -> Optional.of((HandlerFunction) r -> + switch (r.uri().getRawPath()) { + case "/plaintext" -> textHandler.handle(r); + case "/json" -> jsonHandler.handle(r); + case "/db" -> dbHandler.db(r); + case "/queries" -> dbHandler.queries(r); + case "/updates" -> dbHandler.updates(r); + case "/fortunes" -> dbHandler.fortunes(r); + default -> ServerResponse.notFound().build(); + }); + } +} + diff --git a/frameworks/Java/spring/src/main/resources/application.yml b/frameworks/Java/spring/src/main/resources/application.yml index 0f411d6d8e9..efde83cda61 100644 --- a/frameworks/Java/spring/src/main/resources/application.yml +++ b/frameworks/Java/spring/src/main/resources/application.yml @@ -1,13 +1,21 @@ +server: + server-header: Spring + servlet: + encoding: + force: true --- spring: config: activate: - on-profile: jdbc,jpa + on-profile: jdbc + 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: - url: jdbc:postgresql://${database.host}:${database.port}/${database.name} + url: jdbc:postgresql://${database.host}:${database.port}/${database.name}?loggerLevel=OFF&disableColumnSanitiser=true&assumeMinServerVersion=16&sslmode=disable username: ${database.username} password: ${database.password} - + hikari: + maximum-pool-size: 256 database: name: hello_world host: tfb-database @@ -15,20 +23,13 @@ database: username: benchmarkdbuser password: benchmarkdbpass ---- -spring: - config: - activate: - on-profile: jpa - jpa: - database-platform: org.hibernate.dialect.PostgreSQLDialect - open-in-view: false - --- spring: config: activate: on-profile: mongo + autoconfigure: + exclude: org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration spring.data.mongodb: host: tfb-database @@ -39,6 +40,3 @@ spring.data.mongodb: spring: profiles: active: jdbc - -server.server-header: Spring -server.servlet.encoding.force: true \ No newline at end of file diff --git a/frameworks/Java/spring/src/main/resources/fortunes.mustache b/frameworks/Java/spring/src/main/resources/fortunes.mustache new file mode 100644 index 00000000000..3043546205b --- /dev/null +++ b/frameworks/Java/spring/src/main/resources/fortunes.mustache @@ -0,0 +1,20 @@ + + + + Fortunes + + + + + + + + {{#fortunes}} + + + + + {{/fortunes}} +
idmessage
{{id}}{{message}}
+ + diff --git a/frameworks/Java/tapestry/pom.xml b/frameworks/Java/tapestry/pom.xml index f76174d8b7e..e764bc2860d 100644 --- a/frameworks/Java/tapestry/pom.xml +++ b/frameworks/Java/tapestry/pom.xml @@ -95,7 +95,7 @@ of testing facilities designed for use with TestNG (http://testng.org/), so it's com.fasterxml.jackson.core jackson-databind - 2.13.4.2 + 2.16.0 org.glassfish.jaxb diff --git a/frameworks/Java/tio-boot/.dockerignore b/frameworks/Java/tio-boot/.dockerignore new file mode 100644 index 00000000000..cba5dfe3c3b --- /dev/null +++ b/frameworks/Java/tio-boot/.dockerignore @@ -0,0 +1,19 @@ +.github +.git +.DS_Store +docs +kubernetes +node_modules +/.svelte-kit +/package +.env +.env.* +vite.config.js.timestamp-* +vite.config.ts.timestamp-* +__pycache__ +.env +_old +uploads +.ipynb_checkpoints +**/*.db +_test \ No newline at end of file diff --git a/frameworks/Java/tio-boot/.gitignore b/frameworks/Java/tio-boot/.gitignore new file mode 100644 index 00000000000..2f089945614 --- /dev/null +++ b/frameworks/Java/tio-boot/.gitignore @@ -0,0 +1,3 @@ +/target/ +logs +.settings \ No newline at end of file diff --git a/frameworks/Java/tio-boot/README.md b/frameworks/Java/tio-boot/README.md new file mode 100644 index 00000000000..bb1539e7db1 --- /dev/null +++ b/frameworks/Java/tio-boot/README.md @@ -0,0 +1,114 @@ +# t-io Benchmarking Test + +This is the tio-server portion of a [benchmarking test suite](../) comparing a variety of web development platforms. + +## Controller + +These implementations use the tio-server's controller. + +### Plaintext Test + +* [Plaintext test source](src/main/java/com/litongjava/tio/http/server/controller/IndexController.java) + +### JSON Serialization Test + +* [JSON test source](src/main/java/com/litongjava/tio/http/server/controller/IndexController.java) + +### Database Query Test + +* [Database Query test source](src/main/java/com/litongjava/tio/http/server/controller/DbController.java)) + +### Database Queries Test + +* [Database Queries test source](src/main/java/com/litongjava/tio/http/server/controller/DbController.java)) + +### Database Update Test + +* [Database Update test source](src/main/java/com/litongjava/tio/http/server/controller/DbController.java)) + +### Template rendering Test + +* [Template rendering test source](src/main/java/com/litongjava/tio/http/server/controller/DbController.java)) + +### Cache Query Test +* [Cache query test source](src/main/java/com/litongjava/tio/http/server/controller/CacheController.java)) + + +## Versions +3.7.3.v20231218-RELEASE (https://gitee.com/litongjava/t-io) + +## Test URLs + +All implementations use the same 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 + +### Cache Query Test + + http://localhost:8080/cacheQuery?queries=10000 + +### Template rendering Test + + http://localhost:8080/fortunes + +### Database Update Test + + http://localhost:8080/updates?queries=5 + + ## Hot to run + ### install mysql 8 + - 1.please instal mysql 8.0.32,example cmd + ``` + docker run --restart=always -d --name mysql_8 --hostname mysql \ +-p 3306:3306 \ +-e 'MYSQL_ROOT_PASSWORD=robot_123456#' -e 'MYSQL_ROOT_HOST=%' -e 'MYSQL_DATABASE=hello_world' \ +mysql/mysql-server:8.0.32 \ +--character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --lower_case_table_names=1 + ``` + - 2.create database schema hello_world + - 3.create tablle,[example](sql/hello_world.sql) + - 4.import data + + ### docker + ``` + docker build -t tio-server-benchmark -f tio-server.dockerfile . +``` +The run is to specify the mysql database +``` +docker run --rm -p 8080:8080 \ +-e JDBC_URL="jdbc:mysql://192.168.3.9/hello_world" \ +-e JDBC_USER="root" \ +-e JDBC_PSWD="robot_123456#" \ +tio-server-benchmark +``` + +### windows + +-windows +``` +D:\java\jdk1.8.0_121\bin\java -jar target\tio-server-benchmark-1.0.jar --JDBC_URL=jdbc:mysql://192.168.3.9/hello_world?useSSL=false --JDBC_USER=root --JDBC_PSWD=robot_123456# +``` +or +``` +set JDBC_URL=jdbc:mysql://192.168.3.9/hello_world +set jdbc.user=root +set JDBC_PSWD=robot_123456# +D:\java\jdk1.8.0_121\bin\java -jar target\tio-server-benchmark-1.0.jar +``` + + + diff --git a/frameworks/Java/tio-boot/api/tio-server-benchmark.md b/frameworks/Java/tio-boot/api/tio-server-benchmark.md new file mode 100644 index 00000000000..1d302df2d5d --- /dev/null +++ b/frameworks/Java/tio-boot/api/tio-server-benchmark.md @@ -0,0 +1,227 @@ +--- +title: tio-server-benchmark v1.0.0 +language_tabs: + - shell: Shell + - http: HTTP + - javascript: JavaScript + - ruby: Ruby + - python: Python + - php: PHP + - java: Java + - go: Go +toc_footers: [] +includes: [] +search: true +code_clipboard: true +highlight_theme: darkula +headingLevel: 2 +generator: "@tarslib/widdershins v4.0.17" + +--- + +# tio-server-benchmark + +> v1.0.0 + +Base URLs: + +# Authentication + +# Default + +## GET plaintext + +GET /plaintext + +> 返回示例 + +> 200 Response + +```json +{} +``` + +### 返回结果 + +|状态码|状态码含义|说明|数据模型| +|---|---|---|---| +|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|成功|Inline| + +### 返回数据结构 + +## GET json + +GET /json + +> 返回示例 + +> 200 Response + +```json +{} +``` + +### 返回结果 + +|状态码|状态码含义|说明|数据模型| +|---|---|---|---| +|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|成功|Inline| + +### 返回数据结构 + +## GET db + +GET /db + +### 请求参数 + +|名称|位置|类型|必选|说明| +|---|---|---|---|---| +|id|query|string| 否 |none| + +> 返回示例 + +> 200 Response + +```json +{ + "id": 0, + "randomNumber": 0 +} +``` + +### 返回结果 + +|状态码|状态码含义|说明|数据模型| +|---|---|---|---| +|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|成功|Inline| + +### 返回数据结构 + +状态码 **200** + +|名称|类型|必选|约束|中文名|说明| +|---|---|---|---|---|---| +|» id|integer|true|none||none| +|» randomNumber|integer|true|none||none| + +## GET updates + +GET /updates + +### 请求参数 + +|名称|位置|类型|必选|说明| +|---|---|---|---|---| +|queries|query|string| 否 |none| + +> 返回示例 + +> 成功 + +```json +[ + { + "id": 28, + "randomNumber": 5399, + "randomnumber": 1498 + } +] +``` + +### 返回结果 + +|状态码|状态码含义|说明|数据模型| +|---|---|---|---| +|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|成功|Inline| + +### 返回数据结构 + +状态码 **200** + +|名称|类型|必选|约束|中文名|说明| +|---|---|---|---|---|---| +|» id|integer|false|none||none| +|» randomNumber|integer|false|none||none| +|» randomnumber|integer|false|none||none| + +## GET fortunes + +GET /fortunes + +> 返回示例 + +> 200 Response + +```json +{} +``` + +### 返回结果 + +|状态码|状态码含义|说明|数据模型| +|---|---|---|---| +|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|成功|Inline| + +### 返回数据结构 + +## GET cacheQuery + +GET /cacheQuery + +### 请求参数 + +|名称|位置|类型|必选|说明| +|---|---|---|---|---| +|queries|query|string| 否 |none| + +> 返回示例 + +> 200 Response + +```json +[ + { + "id": 0, + "randomNumber": 0 + } +] +``` + +### 返回结果 + +|状态码|状态码含义|说明|数据模型| +|---|---|---|---| +|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|成功|Inline| + +### 返回数据结构 + +状态码 **200** + +|名称|类型|必选|约束|中文名|说明| +|---|---|---|---|---|---| +|» id|integer|false|none||none| +|» randomNumber|integer|false|none||none| + +## GET cacheList + +GET /cacheList + +> 返回示例 + +> 200 Response + +```json +{} +``` + +### 返回结果 + +|状态码|状态码含义|说明|数据模型| +|---|---|---|---| +|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|成功|Inline| + +### 返回数据结构 + +# 数据模型 + diff --git a/frameworks/Java/tio-boot/benchmark_config.json b/frameworks/Java/tio-boot/benchmark_config.json new file mode 100644 index 00000000000..c1121359569 --- /dev/null +++ b/frameworks/Java/tio-boot/benchmark_config.json @@ -0,0 +1,29 @@ +{ + "framework": "tio-boot", + "tests": [{ + "default": { + "plaintext_url": "/plaintext", + "json_url": "/json", + "db_url": "/db", + "query_url": "/queries?queries=", + "fortune_url": "/fortunes", + "update_url": "/updates?queries=", + "cached_query_url" : "/cachedQuery?queries=", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "MySQL", + "framework": "tio-boot", + "language": "Java", + "flavor": "None", + "orm": "Raw", + "platform": "t-io", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "tio-boot", + "notes": "tio-boot", + "versus": "t-io" + } + }] +} diff --git a/frameworks/Java/tio-boot/config.toml b/frameworks/Java/tio-boot/config.toml new file mode 100644 index 00000000000..93dddb241c9 --- /dev/null +++ b/frameworks/Java/tio-boot/config.toml @@ -0,0 +1,19 @@ +[framework] +name = "t-io" + +[main] +urls.plaintext = "/plaintext" +urls.json = "/json" +urls.query = "/queries?queries=" +urls.update = "/updates?queries=" +urls.fortune = "/fortunes" +urls.cached_query = "/cachedQuery?queries=" +approach = "Realistic" +classification = "Micro" +database = "None" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "t-io" +webserver = "None" +versus = "t-io" diff --git a/frameworks/Java/tio-boot/pom.xml b/frameworks/Java/tio-boot/pom.xml new file mode 100644 index 00000000000..021e8366683 --- /dev/null +++ b/frameworks/Java/tio-boot/pom.xml @@ -0,0 +1,133 @@ + + 4.0.0 + com.litongjava + tio-boot-benchmark + 1.0 + ${project.artifactId} + + UTF-8 + 1.8 + ${java.version} + ${java.version} + 2.0.1 + + + com.litongjava.tio.http.server.MainApp + + + + + com.litongjava + tio-boot + ${tio-boot.version} + + + com.litongjava + java-db + 1.5.3 + + + + ch.qos.logback + logback-classic + 1.2.13 + + + + junit + junit + 4.12 + test + + + + com.alibaba.fastjson2 + fastjson2 + 2.0.52 + + + + net.sf.ehcache + ehcache-core + 2.6.11 + + + + mysql + mysql-connector-java + 5.1.46 + + + + com.zaxxer + HikariCP + 4.0.3 + + + + + + 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 + + + + + + + \ No newline at end of file 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 new file mode 100644 index 00000000000..5fb25eb411f --- /dev/null +++ b/frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/MainApp.java @@ -0,0 +1,13 @@ +package com.litongjava.tio.http.server; + +import com.litongjava.tio.boot.TioApplication; + +public class MainApp { + + public static void main(String[] args) { + long start = System.currentTimeMillis(); + TioApplication.run(MainApp.class, new MainAppConfig(), args); + long end = System.currentTimeMillis(); + System.out.println((end - start) + "ms"); + } +} \ No newline at end of file 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 new file mode 100644 index 00000000000..eda7de88674 --- /dev/null +++ b/frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/MainAppConfig.java @@ -0,0 +1,54 @@ +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/EhCachePluginConfig.java b/frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/config/EhCachePluginConfig.java new file mode 100644 index 00000000000..f949432cd5b --- /dev/null +++ b/frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/config/EhCachePluginConfig.java @@ -0,0 +1,12 @@ + package com.litongjava.tio.http.server.config; + +import com.litongjava.ehcache.EhCachePlugin; + +public class EhCachePluginConfig { + + public EhCachePlugin ehCachePlugin() { + EhCachePlugin ehCachePlugin = new EhCachePlugin(); + ehCachePlugin.start(); + return ehCachePlugin; + } +} diff --git a/frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/config/EnjoyEngineConfig.java b/frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/config/EnjoyEngineConfig.java new file mode 100644 index 00000000000..b40c74c448d --- /dev/null +++ b/frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/config/EnjoyEngineConfig.java @@ -0,0 +1,22 @@ +package com.litongjava.tio.http.server.config; + +import com.jfinal.template.Engine; + +public class EnjoyEngineConfig { + + private final String RESOURCE_BASE_PATH = "/templates/"; + + public Engine engine() { + Engine engine = Engine.use(); + engine.setBaseTemplatePath(RESOURCE_BASE_PATH); + engine.setToClassPathSourceFactory(); + // 支持模板热加载,绝大多数生产环境下也建议配置成 true,除非是极端高性能的场景 + // engine.setDevMode(true); + // 配置极速模式,性能提升 13% + Engine.setFastMode(true); + // jfinal 4.9.02 新增配置:支持中文表达式、中文变量名、中文方法名、中文模板函数名 + Engine.setChineseExpression(true); + return engine; + } + +} diff --git a/frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/config/MysqlDbConfig.java b/frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/config/MysqlDbConfig.java new file mode 100644 index 00000000000..8a547854783 --- /dev/null +++ b/frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/config/MysqlDbConfig.java @@ -0,0 +1,31 @@ +package com.litongjava.tio.http.server.config; + +import com.litongjava.db.activerecord.ActiveRecordPlugin; +import com.litongjava.db.activerecord.OrderedFieldContainerFactory; +import com.litongjava.db.hikaricp.HikariCpPlugin; +import com.litongjava.tio.utils.environment.EnvUtils; + +public class MysqlDbConfig { + + public void init() { + // start active recored + String jdbcUrl = EnvUtils.get("JDBC_URL"); + // String jdbcUrl = "jdbc:mysql://192.168.3.9/hello_world"; + + String jdbcUser = EnvUtils.get("JDBC_USER"); + // String jdbcUser = "root"; + + String jdbcPswd = EnvUtils.get("JDBC_PSWD"); + // String jdbcPswd = "robot_123456#"; + HikariCpPlugin hikariCpPlugin = new HikariCpPlugin(jdbcUrl, jdbcUser, jdbcPswd); + + ActiveRecordPlugin arp = new ActiveRecordPlugin(hikariCpPlugin); + arp.setContainerFactory(new OrderedFieldContainerFactory()); + + // arp.setShowSql(true); + + hikariCpPlugin.start(); + boolean start = arp.start(); + System.out.println("db started:" + start); + } +} 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 new file mode 100644 index 00000000000..ad11cc294ea --- /dev/null +++ b/frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/handler/CacheHandler.java @@ -0,0 +1,41 @@ +package com.litongjava.tio.http.server.handler; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import com.alibaba.fastjson2.JSON; +import com.litongjava.db.activerecord.Db; +import com.litongjava.db.activerecord.Row; +import com.litongjava.tio.boot.http.TioRequestContext; +import com.litongjava.tio.http.common.HeaderName; +import com.litongjava.tio.http.common.HeaderValue; +import com.litongjava.tio.http.common.HttpRequest; +import com.litongjava.tio.http.common.HttpResponse; +import com.litongjava.tio.http.server.utils.RandomUtils; + +public class CacheHandler { + // private Logger log = LoggerFactory.getLogger(this.getClass()); + String sql = "SELECT id, randomNumber FROM world WHERE id = ?"; + + public HttpResponse cachedQuery(HttpRequest request) { + String queries = request.getParam("queries"); + + int queryCount = RandomUtils.parseQueryCount(queries); + + List> recordMaps = new ArrayList<>(); + + int[] randomNumbers = RandomUtils.randomWorldNumbers().limit(queryCount).toArray(); + for (int id : randomNumbers) { + Row row = Db.findFirstByCache("world", id, sql, id); + if (row != null) { + recordMaps.add(row.toMap()); + } + } + + HttpResponse response = TioRequestContext.getResponse(); + response.addHeader(HeaderName.Content_Type, HeaderValue.Content_Type.TEXT_PLAIN_JSON); + response.setBody(JSON.toJSONBytes(recordMaps)); + return response; + } +} diff --git a/frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/handler/DbHandler.java b/frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/handler/DbHandler.java new file mode 100644 index 00000000000..603f4f2b96b --- /dev/null +++ b/frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/handler/DbHandler.java @@ -0,0 +1,127 @@ +package com.litongjava.tio.http.server.handler; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.alibaba.fastjson2.JSON; +import com.jfinal.template.Engine; +import com.jfinal.template.Template; +import com.litongjava.db.activerecord.Db; +import com.litongjava.db.activerecord.Row; +import com.litongjava.ehcache.EhCacheKit; +import com.litongjava.tio.boot.http.TioRequestContext; +import com.litongjava.tio.http.common.HeaderName; +import com.litongjava.tio.http.common.HeaderValue; +import com.litongjava.tio.http.common.HttpRequest; +import com.litongjava.tio.http.common.HttpResponse; +import com.litongjava.tio.http.server.model.Fortune; +import com.litongjava.tio.http.server.util.Resps; +import com.litongjava.tio.http.server.utils.RandomUtils; + +public class DbHandler { + private Engine engine = Engine.use(); + private String filename = "fortunes.html"; + private Template template = engine.getTemplate(filename); + private static final byte[] bytes = "{}".getBytes(); + + public HttpResponse db(HttpRequest request) { + Integer id = request.getInt("id"); + if (id == null) { + id = RandomUtils.randomWorldNumber(); + } + + //System.out.println("id:" + id); + HttpResponse httpResponse = TioRequestContext.getResponse(); + + // int id = 11; + // String sql="SELECT id, randomNumber FROM world WHERE id = ?"; + + Row recored = Db.findById("world", id); + if (recored != null) { + httpResponse.setBody(JSON.toJSONBytes(recored.toMap())); + } else { + httpResponse.setBody(bytes); + } + + httpResponse.addHeader(HeaderName.Content_Type, HeaderValue.Content_Type.TEXT_PLAIN_JSON); + + return httpResponse; + } + + // @GetMapping("/queries") + public HttpResponse queries(HttpRequest request) { + String queries = request.getParam("queries"); + int queryCount = RandomUtils.parseQueryCount(queries); + int[] randomNumbers = RandomUtils.randomWorldNumbers().limit(queryCount).toArray(); + + List> recordMaps = new ArrayList<>(); + + for (int id : randomNumbers) { + Row row = Db.findById("world", id); + if (row != null) { + recordMaps.add(row.toMap()); + } + } + + HttpResponse httpResponse = TioRequestContext.getResponse(); + httpResponse.addHeader(HeaderName.Content_Type, HeaderValue.Content_Type.TEXT_PLAIN_JSON); + httpResponse.setBody(JSON.toJSONBytes(recordMaps)); + return httpResponse; + } + + //@GetMapping("/updates") + public HttpResponse updates(HttpRequest request) { + String queries = request.getParam("queries"); + + EhCacheKit.removeAll("world"); + + int queryCount = RandomUtils.parseQueryCount(queries); + int[] randomNumbers = RandomUtils.randomWorldNumbers().limit(queryCount).toArray(); + List> updatedRecords = new ArrayList<>(); + + for (int id : randomNumbers) { + Row row = Db.findById("world", id); + if (row != null) { + int currentRandomNumber = row.getInt("randomNumber"); // "randomnumber" + int newRandomNumber; + do { + newRandomNumber = RandomUtils.randomWorldNumber(); + } while (newRandomNumber == currentRandomNumber); + + row.set("randomnumber", newRandomNumber); + Db.update("world", "id", row); // update + updatedRecords.add(row.toMap()); + } + } + + HttpResponse httpResponse = new HttpResponse(request); + httpResponse.addHeader(HeaderName.Content_Type, HeaderValue.Content_Type.TEXT_PLAIN_JSON); + httpResponse.setBody(JSON.toJSONBytes(updatedRecords)); + return httpResponse; + } + + public HttpResponse fortunes(HttpRequest request) throws IllegalAccessException, InstantiationException { + List records = Db.find("SELECT * FROM fortune"); + + List fortunes = new ArrayList<>(records.size()); + for (Row record : records) { + fortunes.add(record.toBean(Fortune.class)); + } + // 添加额外的 Fortune + fortunes.add(new Fortune(0L, "Additional fortune added at request time.")); + + // 按照消息排序 + fortunes.sort(Comparator.comparing(Fortune::getMessage)); + + Map viewData = new HashMap<>(); + viewData.put("fortunes", fortunes); + + // 转换为 HTML + String html = template.renderToString(viewData); + HttpResponse httpResponse = TioRequestContext.getResponse(); + return Resps.html(httpResponse, html); + } +} 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 new file mode 100644 index 00000000000..2122b1608e9 --- /dev/null +++ b/frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/handler/IndexHandler.java @@ -0,0 +1,38 @@ +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/model/Fortune.java b/frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/model/Fortune.java new file mode 100644 index 00000000000..728db88b837 --- /dev/null +++ b/frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/model/Fortune.java @@ -0,0 +1,23 @@ +package com.litongjava.tio.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/tio-boot/src/main/java/com/litongjava/tio/http/server/model/Message.java b/frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/model/Message.java new file mode 100644 index 00000000000..2ad66214e0f --- /dev/null +++ b/frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/model/Message.java @@ -0,0 +1,12 @@ +package com.litongjava.tio.http.server.model; +public final class Message { + private final String message; + + public Message(String message) { + this.message = message; + } + + public String getMessage() { + return message; + } +} diff --git a/frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/model/World.java b/frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/model/World.java new file mode 100644 index 00000000000..06c4ed9a22b --- /dev/null +++ b/frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/model/World.java @@ -0,0 +1,32 @@ +package com.litongjava.tio.http.server.model; + +public final class World { + + public int id; + public int randomnumber; + + protected World() { + } + + public World(int id, int randomnumber) { + this.id = id; + this.randomnumber = randomnumber; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public int getRandomnumber() { + return randomnumber; + } + + public void setRandomnumber(int randomnumber) { + this.randomnumber = randomnumber; + } + +} \ No newline at end of file diff --git a/frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/services/CacheName.java b/frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/services/CacheName.java new file mode 100644 index 00000000000..5707d4f05d4 --- /dev/null +++ b/frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/services/CacheName.java @@ -0,0 +1,50 @@ +package com.litongjava.tio.http.server.services; + +public class CacheName { + // `cacheName`(缓存名称) + private String name; + // `timeToLiveSeconds`(生存时间)和`timeToIdleSeconds`(闲置时间)。 + private Long timeToLiveSeconds; + private Long timeToIdleSeconds; + + public CacheName() { + } + + public CacheName(String name, Long timeToLiveSeconds, Long timeToIdleSeconds) { + super(); + this.name = name; + this.timeToLiveSeconds = timeToLiveSeconds; + this.timeToIdleSeconds = timeToIdleSeconds; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Long getTimeToLiveSeconds() { + return timeToLiveSeconds; + } + + public void setTimeToLiveSeconds(Long timeToLiveSeconds) { + this.timeToLiveSeconds = timeToLiveSeconds; + } + + public Long getTimeToIdleSeconds() { + return timeToIdleSeconds; + } + + public void setTimeToIdleSeconds(Long timeToIdleSeconds) { + this.timeToIdleSeconds = timeToIdleSeconds; + } + + @Override + public String toString() { + return "CacheName [name=" + name + ", timeToLiveSeconds=" + timeToLiveSeconds + ", timeToIdleSeconds=" + + timeToIdleSeconds + "]"; + } + +} \ No newline at end of file diff --git a/frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/services/CacheNameService.java b/frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/services/CacheNameService.java new file mode 100644 index 00000000000..5ab5d7e58e6 --- /dev/null +++ b/frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/services/CacheNameService.java @@ -0,0 +1,17 @@ +package com.litongjava.tio.http.server.services; + +import java.util.ArrayList; +import java.util.List; + +import com.litongjava.model.time.Time; + +public class CacheNameService { + private CacheName demo = new CacheName("world", null, Time.MINUTE_1 * 10); + + public List cacheNames() { + List list = new ArrayList<>(); + list.add(demo); + return list; + } + +} diff --git a/frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/utils/RandomUtils.java b/frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/utils/RandomUtils.java new file mode 100644 index 00000000000..e18e98ef880 --- /dev/null +++ b/frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/utils/RandomUtils.java @@ -0,0 +1,36 @@ +package com.litongjava.tio.http.server.utils; + +import java.util.concurrent.ThreadLocalRandom; +import java.util.stream.IntStream; + +public class RandomUtils { + + private static final int MIN_WORLD_NUMBER = 1; + private static final int MAX_WORLD_NUMBER_PLUS_ONE = 10_001; +// private static final int MAX_WORLD_NUMBER_PLUS_ONE = 30; + + 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() allows us to avoid using Hibernate's first-level cache in + // the JPA-based implementation. Using a cache like that would bypass + // querying the database, which would violate the test requirements. + .distinct(); + } + + public 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/tio-boot/src/main/resources/app.properties b/frameworks/Java/tio-boot/src/main/resources/app.properties new file mode 100644 index 00000000000..1c202a1c753 --- /dev/null +++ b/frameworks/Java/tio-boot/src/main/resources/app.properties @@ -0,0 +1,11 @@ +http.response.header.showServer=true +server.port=8080 +#JDBC_URL=jdbc:mysql://192.168.3.9/hello_world?useSSL=false&allowPublicKeyRetrieval=true +#JDBC_USER=root +#JDBC_PSWD=robot_123456# + +JDBC_URL=jdbc:mysql://tfb-database/hello_world +JDBC_USER=benchmarkdbuser +JDBC_PSWD=benchmarkdbpass + +#--tio.core.diagnostic=true --server.http.request.printPacket=true \ No newline at end of file diff --git a/frameworks/Java/tio-boot/src/main/resources/ehcache.xml b/frameworks/Java/tio-boot/src/main/resources/ehcache.xml new file mode 100644 index 00000000000..79b79e49479 --- /dev/null +++ b/frameworks/Java/tio-boot/src/main/resources/ehcache.xml @@ -0,0 +1,9 @@ + + + + + + + diff --git a/frameworks/Java/tio-boot/src/main/resources/logback.xml b/frameworks/Java/tio-boot/src/main/resources/logback.xml new file mode 100644 index 00000000000..6065c075e78 --- /dev/null +++ b/frameworks/Java/tio-boot/src/main/resources/logback.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + ${CONSOLE_LOG_PATTERN} + + + + + + + ${CONSOLE_LOG_PATTERN} + + + + ${LOG_HOME}/log.%d{yyyyMMddHH}.%i.log + + 180 + + 100MB + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frameworks/Java/tio-boot/src/main/resources/templates/fortunes.html b/frameworks/Java/tio-boot/src/main/resources/templates/fortunes.html new file mode 100644 index 00000000000..1f6817df007 --- /dev/null +++ b/frameworks/Java/tio-boot/src/main/resources/templates/fortunes.html @@ -0,0 +1,20 @@ + + + + Fortunes + + + + + + + + #for(fortune : fortunes) + + + + + #end +
idmessage
#(fortune.id)#escape(fortune.message)
+ + diff --git a/frameworks/Java/tio-boot/src/test/java/com/litongjava/tio/http/server/MainAppTest.java b/frameworks/Java/tio-boot/src/test/java/com/litongjava/tio/http/server/MainAppTest.java new file mode 100644 index 00000000000..41b724b15c4 --- /dev/null +++ b/frameworks/Java/tio-boot/src/test/java/com/litongjava/tio/http/server/MainAppTest.java @@ -0,0 +1,14 @@ +package com.litongjava.tio.http.server; + +import org.junit.Test; + +import com.litongjava.tio.utils.environment.EnvUtils; + +public class MainAppTest { + + // @Test + public void test() { + boolean boolean1 = EnvUtils.getBoolean("native", false); + System.out.println(boolean1); + } +} diff --git a/frameworks/Java/tio-boot/tio-boot.dockerfile b/frameworks/Java/tio-boot/tio-boot.dockerfile new file mode 100644 index 00000000000..3b779333565 --- /dev/null +++ b/frameworks/Java/tio-boot/tio-boot.dockerfile @@ -0,0 +1,20 @@ +FROM litongjava/maven:3.8.8-jdk8u391 AS builder +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 + +WORKDIR /app + +COPY --from=builder /app/target/tio-boot-benchmark-1.0-jar-with-dependencies.jar /app/tio-boot-benchmark-1.0.jar + +EXPOSE 8080 + +# java --server -XX:+UseNUMA XX:+UseParallelGC -cp target/tio-boot-benchmark-1.0-jar-with-dependencies.jar com.litongjava.tio.http.server.MainApp +CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC","-cp", "/app/tio-boot-benchmark-1.0.jar","com.litongjava.tio.http.server.MainApp"] \ No newline at end of file diff --git a/frameworks/Java/tio-http-server/.dockerignore b/frameworks/Java/tio-http-server/.dockerignore new file mode 100644 index 00000000000..cba5dfe3c3b --- /dev/null +++ b/frameworks/Java/tio-http-server/.dockerignore @@ -0,0 +1,19 @@ +.github +.git +.DS_Store +docs +kubernetes +node_modules +/.svelte-kit +/package +.env +.env.* +vite.config.js.timestamp-* +vite.config.ts.timestamp-* +__pycache__ +.env +_old +uploads +.ipynb_checkpoints +**/*.db +_test \ No newline at end of file diff --git a/frameworks/Java/tio-http-server/.gitignore b/frameworks/Java/tio-http-server/.gitignore new file mode 100644 index 00000000000..2f089945614 --- /dev/null +++ b/frameworks/Java/tio-http-server/.gitignore @@ -0,0 +1,3 @@ +/target/ +logs +.settings \ No newline at end of file diff --git a/frameworks/Java/tio-http-server/README.md b/frameworks/Java/tio-http-server/README.md new file mode 100644 index 00000000000..bb1539e7db1 --- /dev/null +++ b/frameworks/Java/tio-http-server/README.md @@ -0,0 +1,114 @@ +# t-io Benchmarking Test + +This is the tio-server portion of a [benchmarking test suite](../) comparing a variety of web development platforms. + +## Controller + +These implementations use the tio-server's controller. + +### Plaintext Test + +* [Plaintext test source](src/main/java/com/litongjava/tio/http/server/controller/IndexController.java) + +### JSON Serialization Test + +* [JSON test source](src/main/java/com/litongjava/tio/http/server/controller/IndexController.java) + +### Database Query Test + +* [Database Query test source](src/main/java/com/litongjava/tio/http/server/controller/DbController.java)) + +### Database Queries Test + +* [Database Queries test source](src/main/java/com/litongjava/tio/http/server/controller/DbController.java)) + +### Database Update Test + +* [Database Update test source](src/main/java/com/litongjava/tio/http/server/controller/DbController.java)) + +### Template rendering Test + +* [Template rendering test source](src/main/java/com/litongjava/tio/http/server/controller/DbController.java)) + +### Cache Query Test +* [Cache query test source](src/main/java/com/litongjava/tio/http/server/controller/CacheController.java)) + + +## Versions +3.7.3.v20231218-RELEASE (https://gitee.com/litongjava/t-io) + +## Test URLs + +All implementations use the same 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 + +### Cache Query Test + + http://localhost:8080/cacheQuery?queries=10000 + +### Template rendering Test + + http://localhost:8080/fortunes + +### Database Update Test + + http://localhost:8080/updates?queries=5 + + ## Hot to run + ### install mysql 8 + - 1.please instal mysql 8.0.32,example cmd + ``` + docker run --restart=always -d --name mysql_8 --hostname mysql \ +-p 3306:3306 \ +-e 'MYSQL_ROOT_PASSWORD=robot_123456#' -e 'MYSQL_ROOT_HOST=%' -e 'MYSQL_DATABASE=hello_world' \ +mysql/mysql-server:8.0.32 \ +--character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --lower_case_table_names=1 + ``` + - 2.create database schema hello_world + - 3.create tablle,[example](sql/hello_world.sql) + - 4.import data + + ### docker + ``` + docker build -t tio-server-benchmark -f tio-server.dockerfile . +``` +The run is to specify the mysql database +``` +docker run --rm -p 8080:8080 \ +-e JDBC_URL="jdbc:mysql://192.168.3.9/hello_world" \ +-e JDBC_USER="root" \ +-e JDBC_PSWD="robot_123456#" \ +tio-server-benchmark +``` + +### windows + +-windows +``` +D:\java\jdk1.8.0_121\bin\java -jar target\tio-server-benchmark-1.0.jar --JDBC_URL=jdbc:mysql://192.168.3.9/hello_world?useSSL=false --JDBC_USER=root --JDBC_PSWD=robot_123456# +``` +or +``` +set JDBC_URL=jdbc:mysql://192.168.3.9/hello_world +set jdbc.user=root +set JDBC_PSWD=robot_123456# +D:\java\jdk1.8.0_121\bin\java -jar target\tio-server-benchmark-1.0.jar +``` + + + diff --git a/frameworks/Java/tio-http-server/api/tio-server-benchmark.md b/frameworks/Java/tio-http-server/api/tio-server-benchmark.md new file mode 100644 index 00000000000..1d302df2d5d --- /dev/null +++ b/frameworks/Java/tio-http-server/api/tio-server-benchmark.md @@ -0,0 +1,227 @@ +--- +title: tio-server-benchmark v1.0.0 +language_tabs: + - shell: Shell + - http: HTTP + - javascript: JavaScript + - ruby: Ruby + - python: Python + - php: PHP + - java: Java + - go: Go +toc_footers: [] +includes: [] +search: true +code_clipboard: true +highlight_theme: darkula +headingLevel: 2 +generator: "@tarslib/widdershins v4.0.17" + +--- + +# tio-server-benchmark + +> v1.0.0 + +Base URLs: + +# Authentication + +# Default + +## GET plaintext + +GET /plaintext + +> 返回示例 + +> 200 Response + +```json +{} +``` + +### 返回结果 + +|状态码|状态码含义|说明|数据模型| +|---|---|---|---| +|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|成功|Inline| + +### 返回数据结构 + +## GET json + +GET /json + +> 返回示例 + +> 200 Response + +```json +{} +``` + +### 返回结果 + +|状态码|状态码含义|说明|数据模型| +|---|---|---|---| +|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|成功|Inline| + +### 返回数据结构 + +## GET db + +GET /db + +### 请求参数 + +|名称|位置|类型|必选|说明| +|---|---|---|---|---| +|id|query|string| 否 |none| + +> 返回示例 + +> 200 Response + +```json +{ + "id": 0, + "randomNumber": 0 +} +``` + +### 返回结果 + +|状态码|状态码含义|说明|数据模型| +|---|---|---|---| +|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|成功|Inline| + +### 返回数据结构 + +状态码 **200** + +|名称|类型|必选|约束|中文名|说明| +|---|---|---|---|---|---| +|» id|integer|true|none||none| +|» randomNumber|integer|true|none||none| + +## GET updates + +GET /updates + +### 请求参数 + +|名称|位置|类型|必选|说明| +|---|---|---|---|---| +|queries|query|string| 否 |none| + +> 返回示例 + +> 成功 + +```json +[ + { + "id": 28, + "randomNumber": 5399, + "randomnumber": 1498 + } +] +``` + +### 返回结果 + +|状态码|状态码含义|说明|数据模型| +|---|---|---|---| +|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|成功|Inline| + +### 返回数据结构 + +状态码 **200** + +|名称|类型|必选|约束|中文名|说明| +|---|---|---|---|---|---| +|» id|integer|false|none||none| +|» randomNumber|integer|false|none||none| +|» randomnumber|integer|false|none||none| + +## GET fortunes + +GET /fortunes + +> 返回示例 + +> 200 Response + +```json +{} +``` + +### 返回结果 + +|状态码|状态码含义|说明|数据模型| +|---|---|---|---| +|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|成功|Inline| + +### 返回数据结构 + +## GET cacheQuery + +GET /cacheQuery + +### 请求参数 + +|名称|位置|类型|必选|说明| +|---|---|---|---|---| +|queries|query|string| 否 |none| + +> 返回示例 + +> 200 Response + +```json +[ + { + "id": 0, + "randomNumber": 0 + } +] +``` + +### 返回结果 + +|状态码|状态码含义|说明|数据模型| +|---|---|---|---| +|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|成功|Inline| + +### 返回数据结构 + +状态码 **200** + +|名称|类型|必选|约束|中文名|说明| +|---|---|---|---|---|---| +|» id|integer|false|none||none| +|» randomNumber|integer|false|none||none| + +## GET cacheList + +GET /cacheList + +> 返回示例 + +> 200 Response + +```json +{} +``` + +### 返回结果 + +|状态码|状态码含义|说明|数据模型| +|---|---|---|---| +|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|成功|Inline| + +### 返回数据结构 + +# 数据模型 + diff --git a/frameworks/Java/tio-http-server/benchmark_config.json b/frameworks/Java/tio-http-server/benchmark_config.json new file mode 100644 index 00000000000..5cd4c92b275 --- /dev/null +++ b/frameworks/Java/tio-http-server/benchmark_config.json @@ -0,0 +1,29 @@ +{ + "framework": "tio-server", + "tests": [{ + "default": { + "plaintext_url": "/plaintext", + "json_url": "/json", + "db_url": "/db", + "query_url": "/queries?queries=", + "fortune_url": "/fortunes", + "update_url": "/updates?queries=", + "cached_query_url" : "/cachedQuery?queries=", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "MySQL", + "framework": "tio-server", + "language": "Java", + "flavor": "None", + "orm": "Raw", + "platform": "t-io", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "tio-server", + "notes": "tio-server", + "versus": "t-io" + } + }] +} diff --git a/frameworks/Java/tio-http-server/config.toml b/frameworks/Java/tio-http-server/config.toml new file mode 100644 index 00000000000..93dddb241c9 --- /dev/null +++ b/frameworks/Java/tio-http-server/config.toml @@ -0,0 +1,19 @@ +[framework] +name = "t-io" + +[main] +urls.plaintext = "/plaintext" +urls.json = "/json" +urls.query = "/queries?queries=" +urls.update = "/updates?queries=" +urls.fortune = "/fortunes" +urls.cached_query = "/cachedQuery?queries=" +approach = "Realistic" +classification = "Micro" +database = "None" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "t-io" +webserver = "None" +versus = "t-io" diff --git a/frameworks/Java/tio-http-server/pom.xml b/frameworks/Java/tio-http-server/pom.xml new file mode 100644 index 00000000000..a4416f26e29 --- /dev/null +++ b/frameworks/Java/tio-http-server/pom.xml @@ -0,0 +1,134 @@ + + 4.0.0 + com.litongjava + tio-http-server-benchmark + 1.0 + ${project.artifactId} + + UTF-8 + 1.8 + ${java.version} + ${java.version} + 23.1.1 + com.litongjava.tio.http.server.MainApp + + + + com.litongjava + tio-http-server + 3.7.3.v20250501-RELEASE + + + + com.litongjava + tio-utils + 3.7.3.v20250501-RELEASE + + + com.litongjava + java-db + 1.5.1 + + + junit + junit + 4.12 + test + + + + + com.alibaba.fastjson2 + fastjson2 + 2.0.52 + + + + net.sf.ehcache + ehcache-core + 2.6.11 + + + + mysql + mysql-connector-java + 5.1.46 + + + + com.zaxxer + HikariCP + 4.0.3 + + + + ch.qos.logback + logback-classic + 1.2.13 + + + + + + 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 + + + + + + + \ No newline at end of file diff --git a/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/MainApp.java b/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/MainApp.java new file mode 100644 index 00000000000..470dab91c46 --- /dev/null +++ b/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/MainApp.java @@ -0,0 +1,74 @@ +package com.litongjava.tio.http.server; + +import com.litongjava.tio.http.common.HttpConfig; +import com.litongjava.tio.http.common.handler.ITioHttpRequestHandler; +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.DefaultHttpRequestDispatcher; +import com.litongjava.tio.http.server.handler.IndexHandler; +import com.litongjava.tio.http.server.router.DefaultHttpRequestRouter; +import com.litongjava.tio.http.server.router.HttpRequestRouter; +import com.litongjava.tio.server.ServerTioConfig; +import com.litongjava.tio.utils.environment.EnvUtils; + +public class MainApp { + + public static void main(String[] args) { + long start = System.currentTimeMillis(); + EnvUtils.buildCmdArgsMap(args); + EnvUtils.load(); + // add route + IndexHandler controller = new IndexHandler(); + + HttpRequestRouter simpleHttpRoutes = new DefaultHttpRequestRouter(); + simpleHttpRoutes.add("/", controller::index); + simpleHttpRoutes.add("/plaintext", controller::plaintext); + simpleHttpRoutes.add("/json", controller::json); + + DbHandler dbQueryController = new DbHandler(); + simpleHttpRoutes.add("/db", dbQueryController::db); + simpleHttpRoutes.add("/queries", dbQueryController::queries); + simpleHttpRoutes.add("/updates", dbQueryController::updates); + simpleHttpRoutes.add("/fortunes", dbQueryController::fortunes); + + CacheHandler cacheController = new CacheHandler(); + simpleHttpRoutes.add("/cachedQuery", cacheController::cachedQuery); + + // config server + HttpConfig httpConfig = new HttpConfig(8080, null, null, null); + httpConfig.setUseSession(false); + httpConfig.setWelcomeFile(null); + httpConfig.setCheckHost(false); + httpConfig.setCompatible1_0(false); + + ITioHttpRequestHandler requestHandler = new DefaultHttpRequestDispatcher(httpConfig, simpleHttpRoutes); + HttpServerStarter httpServerStarter = new HttpServerStarter(httpConfig, requestHandler); + ServerTioConfig serverTioConfig = httpServerStarter.getServerTioConfig(); + // close Heartbeat + serverTioConfig.setHeartbeatTimeout(0); + serverTioConfig.statOn = false; + boolean db = EnvUtils.getBoolean("db", true); + if (db) { + try { + new MysqlDbConfig().init(); + } catch (Exception e) { + e.printStackTrace(); + } + } + // start server + try { + new EnjoyEngineConfig().engine(); + new EhCachePluginConfig().ehCachePlugin(); + httpServerStarter.start(); + long end = System.currentTimeMillis(); + System.out.println((end - start) + "ms"); + } catch (Exception e) { + e.printStackTrace(); + System.exit(1); + } + + } +} \ No newline at end of file diff --git a/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/config/EhCachePluginConfig.java b/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/config/EhCachePluginConfig.java new file mode 100644 index 00000000000..f949432cd5b --- /dev/null +++ b/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/config/EhCachePluginConfig.java @@ -0,0 +1,12 @@ + package com.litongjava.tio.http.server.config; + +import com.litongjava.ehcache.EhCachePlugin; + +public class EhCachePluginConfig { + + public EhCachePlugin ehCachePlugin() { + EhCachePlugin ehCachePlugin = new EhCachePlugin(); + ehCachePlugin.start(); + return ehCachePlugin; + } +} diff --git a/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/config/EnjoyEngineConfig.java b/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/config/EnjoyEngineConfig.java new file mode 100644 index 00000000000..b40c74c448d --- /dev/null +++ b/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/config/EnjoyEngineConfig.java @@ -0,0 +1,22 @@ +package com.litongjava.tio.http.server.config; + +import com.jfinal.template.Engine; + +public class EnjoyEngineConfig { + + private final String RESOURCE_BASE_PATH = "/templates/"; + + public Engine engine() { + Engine engine = Engine.use(); + engine.setBaseTemplatePath(RESOURCE_BASE_PATH); + engine.setToClassPathSourceFactory(); + // 支持模板热加载,绝大多数生产环境下也建议配置成 true,除非是极端高性能的场景 + // engine.setDevMode(true); + // 配置极速模式,性能提升 13% + Engine.setFastMode(true); + // jfinal 4.9.02 新增配置:支持中文表达式、中文变量名、中文方法名、中文模板函数名 + Engine.setChineseExpression(true); + return engine; + } + +} diff --git a/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/config/MysqlDbConfig.java b/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/config/MysqlDbConfig.java new file mode 100644 index 00000000000..8a547854783 --- /dev/null +++ b/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/config/MysqlDbConfig.java @@ -0,0 +1,31 @@ +package com.litongjava.tio.http.server.config; + +import com.litongjava.db.activerecord.ActiveRecordPlugin; +import com.litongjava.db.activerecord.OrderedFieldContainerFactory; +import com.litongjava.db.hikaricp.HikariCpPlugin; +import com.litongjava.tio.utils.environment.EnvUtils; + +public class MysqlDbConfig { + + public void init() { + // start active recored + String jdbcUrl = EnvUtils.get("JDBC_URL"); + // String jdbcUrl = "jdbc:mysql://192.168.3.9/hello_world"; + + String jdbcUser = EnvUtils.get("JDBC_USER"); + // String jdbcUser = "root"; + + String jdbcPswd = EnvUtils.get("JDBC_PSWD"); + // String jdbcPswd = "robot_123456#"; + HikariCpPlugin hikariCpPlugin = new HikariCpPlugin(jdbcUrl, jdbcUser, jdbcPswd); + + ActiveRecordPlugin arp = new ActiveRecordPlugin(hikariCpPlugin); + arp.setContainerFactory(new OrderedFieldContainerFactory()); + + // arp.setShowSql(true); + + hikariCpPlugin.start(); + boolean start = arp.start(); + System.out.println("db started:" + start); + } +} diff --git a/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/handler/CacheHandler.java b/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/handler/CacheHandler.java new file mode 100644 index 00000000000..8f951d73f2d --- /dev/null +++ b/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/handler/CacheHandler.java @@ -0,0 +1,41 @@ +package com.litongjava.tio.http.server.handler; + +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +import com.alibaba.fastjson2.JSON; +import com.litongjava.db.activerecord.Db; +import com.litongjava.db.activerecord.Row; +import com.litongjava.tio.http.common.HeaderName; +import com.litongjava.tio.http.common.HeaderValue; +import com.litongjava.tio.http.common.HttpRequest; +import com.litongjava.tio.http.common.HttpResponse; +import com.litongjava.tio.http.server.utils.RandomUtils; + +public class CacheHandler { + // private Logger log = LoggerFactory.getLogger(this.getClass()); + + public HttpResponse cachedQuery(HttpRequest request) { + String queries = request.getParam("queries"); + List> recordMaps = RandomUtils.randomWorldNumbers() + // limit + .limit(RandomUtils.parseQueryCount(queries)) // 限制查询数量 + .mapToObj(id -> findByIdWithCache("world", id)) // 使用 mapToObj 将 int 映射为对象 + .filter(Objects::nonNull) // 过滤掉 null 值 + .map(Row::toMap) // 将每个 Record 对象转换为 Map + .collect(Collectors.toList()); // 收集到 List + + HttpResponse httpResponse = new HttpResponse(request); + httpResponse.addHeader(HeaderName.Content_Type, HeaderValue.Content_Type.TEXT_PLAIN_JSON); + httpResponse.setBody(JSON.toJSONBytes(recordMaps)); + return httpResponse; + + } + + private Row findByIdWithCache(String tableName, int id) { + String sql = "SELECT id, randomNumber FROM world WHERE id = ?"; + return Db.findFirstByCache(tableName, id, sql, id); + } +} diff --git a/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/handler/DbHandler.java b/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/handler/DbHandler.java new file mode 100644 index 00000000000..ff6426874b8 --- /dev/null +++ b/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/handler/DbHandler.java @@ -0,0 +1,126 @@ +package com.litongjava.tio.http.server.handler; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +import com.alibaba.fastjson2.JSON; +import com.jfinal.template.Engine; +import com.jfinal.template.Template; +import com.litongjava.db.activerecord.Db; +import com.litongjava.db.activerecord.Row; +import com.litongjava.ehcache.EhCacheKit; +import com.litongjava.tio.http.common.HeaderName; +import com.litongjava.tio.http.common.HeaderValue; +import com.litongjava.tio.http.common.HttpRequest; +import com.litongjava.tio.http.common.HttpResponse; +import com.litongjava.tio.http.server.model.Fortune; +import com.litongjava.tio.http.server.util.Resps; +import com.litongjava.tio.http.server.utils.RandomUtils; + +public class DbHandler { + + public HttpResponse db(HttpRequest request) { + Integer id = request.getInt("id"); + if (id == null) { + id = RandomUtils.randomWorldNumber(); + } + + //System.out.println("id:" + id); + HttpResponse httpResponse = new HttpResponse(request); + + // int id = 11; + // String sql="SELECT id, randomNumber FROM world WHERE id = ?"; + + Row recored = Db.findById("world", id); + if (recored != null) { + httpResponse.setBody(JSON.toJSONBytes(recored.toMap())); + } else { + httpResponse.setBody("{}".getBytes()); + } + + httpResponse.addHeader(HeaderName.Content_Type, HeaderValue.Content_Type.TEXT_PLAIN_JSON); + + return httpResponse; + } + + // @GetMapping("/queries") + public HttpResponse queries(HttpRequest request) { + String queries = request.getParam("queries"); + List> recordMaps = RandomUtils.randomWorldNumbers() + // limit + .limit(RandomUtils.parseQueryCount(queries)) // 限制查询数量 + .mapToObj(id -> Db.findById("world", id)) // 使用 mapToObj 将 int 映射为对象 + .filter(Objects::nonNull) // 过滤掉 null 值 + .map(Row::toMap) // 将每个 Record 对象转换为 Map + .collect(Collectors.toList()); // 收集到 List + + HttpResponse httpResponse = new HttpResponse(request); + httpResponse.addHeader(HeaderName.Content_Type, HeaderValue.Content_Type.TEXT_PLAIN_JSON); + httpResponse.setBody(JSON.toJSONBytes(recordMaps)); + return httpResponse; + } + + //@GetMapping("/updates") + public HttpResponse updates(HttpRequest request) { + String queries = request.getParam("queries"); + + EhCacheKit.removeAll("world"); + + List> updatedRecords = RandomUtils.randomWorldNumbers()// random numbers + // limit + .limit(RandomUtils.parseQueryCount(queries)) + // map + .mapToObj(id -> Db.findById("world", id)) + // not null + .filter(Objects::nonNull).map(record -> { + int currentRandomNumber = record.getInt("randomNumber"); // "randomnumber" + int newRandomNumber; + do { + newRandomNumber = RandomUtils.randomWorldNumber(); + } while (newRandomNumber == currentRandomNumber); + + record.set("randomnumber", newRandomNumber); + Db.update("world", "id", record); // update + return record; + }) + // tomap + .map(Row::toMap) + // to List + .collect(Collectors.toList()); + + HttpResponse httpResponse = new HttpResponse(request); + httpResponse.addHeader(HeaderName.Content_Type, HeaderValue.Content_Type.TEXT_PLAIN_JSON); + httpResponse.setBody(JSON.toJSONBytes(updatedRecords)); + return httpResponse; + } + + public HttpResponse fortunes(HttpRequest request) throws IllegalAccessException, InstantiationException { + List records = Db.find("SELECT * FROM fortune"); + + List fortunes = new ArrayList<>(records.size()); + for (Row record : records) { + fortunes.add(record.toBean(Fortune.class)); + } + // 添加额外的 Fortune + fortunes.add(new Fortune(0L, "Additional fortune added at request time.")); + + // 按照消息排序 + fortunes.sort(Comparator.comparing(Fortune::getMessage)); + + Map viewData = new HashMap<>(); + viewData.put("fortunes", fortunes); + + // 转换为 HTML + Engine engine = Engine.use(); + String filename = "fortunes.html"; + Template template = engine.getTemplate(filename); + String html = template.renderToString(viewData); + + return Resps.html(request, html); + } +} diff --git a/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/handler/IndexHandler.java b/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/handler/IndexHandler.java new file mode 100644 index 00000000000..ccc3e9600b1 --- /dev/null +++ b/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/handler/IndexHandler.java @@ -0,0 +1,40 @@ +package com.litongjava.tio.http.server.handler; + +import com.alibaba.fastjson2.JSON; +import com.litongjava.tio.http.common.HeaderName; +import com.litongjava.tio.http.common.HeaderValue; +import com.litongjava.tio.http.common.HttpRequest; +import com.litongjava.tio.http.common.HttpResponse; +import com.litongjava.tio.http.server.model.Message; +import com.litongjava.tio.http.server.util.Resps; + +/** + * 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(); + + public HttpResponse index(HttpRequest request) { + return Resps.txt(request, "tio-server"); + } + + public HttpResponse plaintext(HttpRequest request) { + // 更高性能的写法 + HttpResponse ret = new HttpResponse(request); + ret.setBody(HELLO_WORLD_BYTES); + ret.addHeader(HeaderName.Content_Type, HeaderValue.Content_Type.TEXT_PLAIN_TXT); + return ret; + } + + // 在IndexController中添加 + public HttpResponse json(HttpRequest request) { + // 更高性能的写法 + HttpResponse ret = new HttpResponse(request); + ret.setBody(JSON.toJSONString(new Message(HELLO_WORLD)).getBytes()); + ret.addHeader(HeaderName.Content_Type, HeaderValue.Content_Type.TEXT_PLAIN_JSON); + return ret; + } +} diff --git a/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/model/Fortune.java b/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/model/Fortune.java new file mode 100644 index 00000000000..728db88b837 --- /dev/null +++ b/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/model/Fortune.java @@ -0,0 +1,23 @@ +package com.litongjava.tio.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/tio-http-server/src/main/java/com/litongjava/tio/http/server/model/Message.java b/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/model/Message.java new file mode 100644 index 00000000000..2ad66214e0f --- /dev/null +++ b/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/model/Message.java @@ -0,0 +1,12 @@ +package com.litongjava.tio.http.server.model; +public final class Message { + private final String message; + + public Message(String message) { + this.message = message; + } + + public String getMessage() { + return message; + } +} diff --git a/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/model/World.java b/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/model/World.java new file mode 100644 index 00000000000..06c4ed9a22b --- /dev/null +++ b/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/model/World.java @@ -0,0 +1,32 @@ +package com.litongjava.tio.http.server.model; + +public final class World { + + public int id; + public int randomnumber; + + protected World() { + } + + public World(int id, int randomnumber) { + this.id = id; + this.randomnumber = randomnumber; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public int getRandomnumber() { + return randomnumber; + } + + public void setRandomnumber(int randomnumber) { + this.randomnumber = randomnumber; + } + +} \ No newline at end of file diff --git a/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/services/CacheName.java b/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/services/CacheName.java new file mode 100644 index 00000000000..5707d4f05d4 --- /dev/null +++ b/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/services/CacheName.java @@ -0,0 +1,50 @@ +package com.litongjava.tio.http.server.services; + +public class CacheName { + // `cacheName`(缓存名称) + private String name; + // `timeToLiveSeconds`(生存时间)和`timeToIdleSeconds`(闲置时间)。 + private Long timeToLiveSeconds; + private Long timeToIdleSeconds; + + public CacheName() { + } + + public CacheName(String name, Long timeToLiveSeconds, Long timeToIdleSeconds) { + super(); + this.name = name; + this.timeToLiveSeconds = timeToLiveSeconds; + this.timeToIdleSeconds = timeToIdleSeconds; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Long getTimeToLiveSeconds() { + return timeToLiveSeconds; + } + + public void setTimeToLiveSeconds(Long timeToLiveSeconds) { + this.timeToLiveSeconds = timeToLiveSeconds; + } + + public Long getTimeToIdleSeconds() { + return timeToIdleSeconds; + } + + public void setTimeToIdleSeconds(Long timeToIdleSeconds) { + this.timeToIdleSeconds = timeToIdleSeconds; + } + + @Override + public String toString() { + return "CacheName [name=" + name + ", timeToLiveSeconds=" + timeToLiveSeconds + ", timeToIdleSeconds=" + + timeToIdleSeconds + "]"; + } + +} \ No newline at end of file diff --git a/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/services/CacheNameService.java b/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/services/CacheNameService.java new file mode 100644 index 00000000000..5ab5d7e58e6 --- /dev/null +++ b/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/services/CacheNameService.java @@ -0,0 +1,17 @@ +package com.litongjava.tio.http.server.services; + +import java.util.ArrayList; +import java.util.List; + +import com.litongjava.model.time.Time; + +public class CacheNameService { + private CacheName demo = new CacheName("world", null, Time.MINUTE_1 * 10); + + public List cacheNames() { + List list = new ArrayList<>(); + list.add(demo); + return list; + } + +} diff --git a/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/utils/RandomUtils.java b/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/utils/RandomUtils.java new file mode 100644 index 00000000000..e18e98ef880 --- /dev/null +++ b/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/utils/RandomUtils.java @@ -0,0 +1,36 @@ +package com.litongjava.tio.http.server.utils; + +import java.util.concurrent.ThreadLocalRandom; +import java.util.stream.IntStream; + +public class RandomUtils { + + private static final int MIN_WORLD_NUMBER = 1; + private static final int MAX_WORLD_NUMBER_PLUS_ONE = 10_001; +// private static final int MAX_WORLD_NUMBER_PLUS_ONE = 30; + + 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() allows us to avoid using Hibernate's first-level cache in + // the JPA-based implementation. Using a cache like that would bypass + // querying the database, which would violate the test requirements. + .distinct(); + } + + public 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/tio-http-server/src/main/resources/app.properties b/frameworks/Java/tio-http-server/src/main/resources/app.properties new file mode 100644 index 00000000000..b73b6ff144d --- /dev/null +++ b/frameworks/Java/tio-http-server/src/main/resources/app.properties @@ -0,0 +1,9 @@ +http.response.header.showServer=true + +#JDBC_URL=jdbc:mysql://192.168.3.9/hello_world?useSSL=false&allowPublicKeyRetrieval=true +#JDBC_USER=root +#JDBC_PSWD=robot_123456# + +JDBC_URL=jdbc:mysql://tfb-database/hello_world +JDBC_USER=benchmarkdbuser +JDBC_PSWD=benchmarkdbpass \ No newline at end of file diff --git a/frameworks/Java/tio-http-server/src/main/resources/ehcache.xml b/frameworks/Java/tio-http-server/src/main/resources/ehcache.xml new file mode 100644 index 00000000000..79b79e49479 --- /dev/null +++ b/frameworks/Java/tio-http-server/src/main/resources/ehcache.xml @@ -0,0 +1,9 @@ + + + + + + + diff --git a/frameworks/Java/tio-http-server/src/main/resources/logback.xml b/frameworks/Java/tio-http-server/src/main/resources/logback.xml new file mode 100644 index 00000000000..aff0c711191 --- /dev/null +++ b/frameworks/Java/tio-http-server/src/main/resources/logback.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + ${CONSOLE_LOG_PATTERN} + + + + + + + ${CONSOLE_LOG_PATTERN} + + + + ${LOG_HOME}/project-name-%d{yyyy-MM-dd}.log + + 180 + + + + 10MB + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/frameworks/Java/tio-http-server/src/main/resources/templates/fortunes.html b/frameworks/Java/tio-http-server/src/main/resources/templates/fortunes.html new file mode 100644 index 00000000000..1f6817df007 --- /dev/null +++ b/frameworks/Java/tio-http-server/src/main/resources/templates/fortunes.html @@ -0,0 +1,20 @@ + + + + Fortunes + + + + + + + + #for(fortune : fortunes) + + + + + #end +
idmessage
#(fortune.id)#escape(fortune.message)
+ + diff --git a/frameworks/Java/tio-http-server/src/test/java/com/litongjava/tio/http/server/MainAppTest.java b/frameworks/Java/tio-http-server/src/test/java/com/litongjava/tio/http/server/MainAppTest.java new file mode 100644 index 00000000000..e469fa256ef --- /dev/null +++ b/frameworks/Java/tio-http-server/src/test/java/com/litongjava/tio/http/server/MainAppTest.java @@ -0,0 +1,15 @@ +package com.litongjava.tio.http.server; + +import org.junit.Test; + +import com.litongjava.tio.utils.environment.EnvUtils; + +public class MainAppTest { + + @Test + public void test() { + boolean boolean1 = EnvUtils.getBoolean("native", false); + System.out.println(boolean1); + } + +} diff --git a/frameworks/Java/tio-http-server/tio-server-native.dockerfile b/frameworks/Java/tio-http-server/tio-server-native.dockerfile new file mode 100644 index 00000000000..8dd0f012ea0 --- /dev/null +++ b/frameworks/Java/tio-http-server/tio-server-native.dockerfile @@ -0,0 +1,9 @@ +FROM litongjava/maven:3.8.8-graalvm-jdk-21-slim +WORKDIR /t-io +COPY pom.xml pom.xml +COPY src src +RUN mvn package -Pnative -q + +EXPOSE 8080 + +CMD ["/t-io/target/tio-http-server-benchmark", " --native=true"] diff --git a/frameworks/Java/tio-http-server/tio-server.dockerfile b/frameworks/Java/tio-http-server/tio-server.dockerfile new file mode 100644 index 00000000000..4dbaf2afaa8 --- /dev/null +++ b/frameworks/Java/tio-http-server/tio-server.dockerfile @@ -0,0 +1,20 @@ +FROM litongjava/maven:3.8.8-jdk8u391 AS builder +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 + +WORKDIR /app + +COPY --from=builder /app/target/tio-http-server-benchmark-1.0-jar-with-dependencies.jar /app/tio-http-server-benchmark-1.0.jar + +EXPOSE 8080 + +# java --server -XX:+UseNUMA XX:+UseParallelGC -cp target/tio-http-server-benchmark-1.0-jar-with-dependencies.jar com.litongjava.tio.http.server.MainApp +CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC","-cp", "/app/tio-http-server-benchmark-1.0.jar","com.litongjava.tio.http.server.MainApp"] \ No newline at end of file diff --git a/frameworks/Java/today/.gitignore b/frameworks/Java/today/.gitignore new file mode 100644 index 00000000000..ed040c778b1 --- /dev/null +++ b/frameworks/Java/today/.gitignore @@ -0,0 +1,10 @@ +# Ignore Gradle project-specific cache directory +.gradle + +# Ignore Gradle build output directory +build + +.idea +today.properties +gradle +gradlew \ No newline at end of file diff --git a/frameworks/Java/today/README.md b/frameworks/Java/today/README.md new file mode 100644 index 00000000000..96aa3bbbdbb --- /dev/null +++ b/frameworks/Java/today/README.md @@ -0,0 +1,30 @@ +# [TODAY Infrastructure](https://github.com/TAKETODAY/today-infrastructure) Benchmarking Test + +## Test URLs +### JSON + +http://localhost:8080/json + +### PLAINTEXT + +http://localhost:8080/plaintext + +### DB + +http://localhost:8080/db + +### QUERY + +http://localhost:8080/queries?queries= + +### Caching QUERY + +http://localhost:8080/cached-queries?count=10 + +### UPDATE + +http://localhost:8080/update?queries= + +### FORTUNES + +http://localhost:8080/fortunes diff --git a/frameworks/Java/today/benchmark_config.json b/frameworks/Java/today/benchmark_config.json new file mode 100755 index 00000000000..c44a0306ce5 --- /dev/null +++ b/frameworks/Java/today/benchmark_config.json @@ -0,0 +1,31 @@ +{ + "framework": "today", + "tests": [ + { + "default": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "db_url": "/db", + "query_url": "/queries?queries=", + "fortune_url": "/fortunes", + "update_url": "/updates?queries=", + "cached_query_url": "/cached-queries?count=", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "database": "mysql", + "framework": "Today", + "language": "Java", + "flavor": "None", + "orm": "micro", + "platform": "Netty", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "TODAY", + "notes": "", + "versus": "None" + } + } + ] +} diff --git a/frameworks/Java/today/build.gradle b/frameworks/Java/today/build.gradle new file mode 100644 index 00000000000..0925eff2b4a --- /dev/null +++ b/frameworks/Java/today/build.gradle @@ -0,0 +1,71 @@ +description = "benchmark" + +apply plugin: 'java' +apply plugin: 'application' +apply plugin: 'infra.application' + +configure(allprojects) { + group = "cn.taketoday.benchmark" + + repositories { + mavenLocal() + mavenCentral() + maven { url = "https://oss.sonatype.org/content/repositories/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 'mysql:mysql-connector-java' + + implementation 'ch.qos.logback:logback-classic' + implementation 'com.github.ben-manes.caffeine:caffeine' + + implementation('io.netty:netty-transport-native-epoll') { + artifact { + classifier = 'linux-x86_64' + } + } + + implementation('io.netty.incubator:netty-incubator-transport-native-io_uring:0.0.21.Final') { + artifact { + classifier = 'linux-x86_64' + } + } + +// implementation('io.netty:netty-transport-native-kqueue') { +// artifact { +// classifier = 'osx-aarch_64' +// } +// } + +} + +java { + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 +} + +application { + mainClass = 'cn.taketoday.benchmark.BenchmarkApplication' + applicationDefaultJvmArgs = [ + "-server", + "-Xms2G", + "-Xmx2G", + "-XX:+UseNUMA", + "-XX:+UseStringDeduplication", + "-Dinfra.profiles.active=test", + "-Dio.netty.buffer.checkBounds=false", + "-Dio.netty.buffer.checkAccessible=false", + "-Dio.netty.leakDetection.level=disabled", + "-Dio.netty.iouring.iosqeAsyncThreshold=32000", + "-Djava.lang.Integer.IntegerCache.high=10000", + "--add-opens=java.base/java.nio=ALL-UNNAMED", + "--add-opens=java.base/sun.nio.ch=ALL-UNNAMED" + ] +} diff --git a/frameworks/Java/today/config.toml b/frameworks/Java/today/config.toml new file mode 100644 index 00000000000..36cf38bc9f5 --- /dev/null +++ b/frameworks/Java/today/config.toml @@ -0,0 +1,21 @@ +[framework] +name = "today" + +[main] +urls.plaintext = "/plaintext" +urls.json = "/json" +urls.db = "/db" +urls.query = "/queries?queries=" +urls.update = "/updates?queries=" +urls.fortune = "/fortunes" +urls.cached_query = "/cached-queries?count=" +approach = "Realistic" +classification = "Fullstack" +database = "mysql" +database_os = "Linux" +display_name = "today" +os = "Linux" +orm = "raw" +platform = "Netty" +webserver = "None" +versus = "None" diff --git a/frameworks/Java/today/gradle.properties b/frameworks/Java/today/gradle.properties new file mode 100644 index 00000000000..088db4d0de3 --- /dev/null +++ b/frameworks/Java/today/gradle.properties @@ -0,0 +1,7 @@ +version=1.1.0 +#infraVersion=5.0-Draft.2 +infraVersion=5.0-Draft.2-SNAPSHOT + +org.gradle.caching=true +org.gradle.jvmargs=-Xmx2048m +org.gradle.parallel=true diff --git a/frameworks/Java/today/settings.gradle b/frameworks/Java/today/settings.gradle new file mode 100644 index 00000000000..8cb2bee3734 --- /dev/null +++ b/frameworks/Java/today/settings.gradle @@ -0,0 +1,15 @@ +buildscript { + repositories { + mavenLocal() + maven { + url "https://oss.sonatype.org/content/repositories/snapshots/" + } + mavenCentral() + } + + dependencies { + classpath "cn.taketoday:infra-gradle-plugin:$infraVersion" + } +} + +rootProject.name = 'today' 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 new file mode 100644 index 00000000000..b5496ce042d --- /dev/null +++ b/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/AppConfig.java @@ -0,0 +1,93 @@ +package cn.taketoday.benchmark; + +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 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 static infra.http.HttpHeaders.DATE_FORMATTER; + +/** + * @author Harry Yang + * @since 1.0 2024/3/19 12:59 + */ +@DisableAllDependencyInjection +@Role(BeanDefinition.ROLE_INFRASTRUCTURE) +@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); + } + }; + } + + @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; + } + + @Override + public HttpHeaders newEmptyHeaders() { + return new ResponseHeaders(); + } + }) + .build(); + } + + static class ResponseHeaders extends DefaultHttpHeaders { + + public ResponseHeaders() { + super(name -> { }, v -> { }); + } + + } + +} diff --git a/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/BenchmarkApplication.java b/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/BenchmarkApplication.java new file mode 100644 index 00000000000..9dfe80b4d08 --- /dev/null +++ b/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/BenchmarkApplication.java @@ -0,0 +1,13 @@ +package cn.taketoday.benchmark; + +import infra.app.Application; +import infra.app.InfraApplication; + +@InfraApplication +public class BenchmarkApplication { + + public static void main(String[] args) { + Application.run(BenchmarkApplication.class, args); + } + +} 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 new file mode 100644 index 00000000000..3000a073aab --- /dev/null +++ b/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/http/BenchmarkHttpHandler.java @@ -0,0 +1,127 @@ +package cn.taketoday.benchmark.http; + +import java.util.Comparator; +import java.util.List; +import java.util.concurrent.ThreadLocalRandom; +import java.util.stream.IntStream; + +import cn.taketoday.benchmark.model.Fortune; +import cn.taketoday.benchmark.model.Message; +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; +import infra.web.annotation.GET; +import infra.web.annotation.RestController; +import infra.web.view.ViewRef; + +/** + * @author Harry Yang + * @since 1.0 2024/3/19 12:56 + */ +@RestController +final class BenchmarkHttpHandler { + + private static final int MIN_WORLD_NUMBER = 1; + + private static final int MAX_WORLD_NUMBER = 10_000; + + private final EntityManager entityManager; + + private final WorldCache worldCache; + + BenchmarkHttpHandler(EntityManager entityManager) { + this.entityManager = entityManager; + this.worldCache = new WorldCache(entityManager.find(World.class)); + } + + @GET("/json") + public ResponseEntity json() { + return ResponseEntity.ok() + .contentType(MediaType.APPLICATION_JSON) + .body(new Message("Hello, World!")); + } + + @GET("/plaintext") + public String plaintext() { + return "Hello, World!"; + } + + @Nullable + @GET("/db") + public World db() { + return entityManager.findById(World.class, nextInt()); + } + + @GET("/queries") + public Future> queries(@Nullable String queries) { + return Future.combine(randomNumbers().limit(parseQueryCount(queries)).mapToObj(this::findWorldByIdFuture)) + .asList(); + } + + @GET("/cached-queries") + public List cachedQueries(@Nullable String count) { + return worldCache.getCachedWorld(parseQueryCount(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(); + } + + @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)); + + model.addAttribute("fortunes", fortunes); + return ViewRef.forViewName("fortunes"); + } + + private Future findWorldByIdFuture(int id) { + return Future.run(() -> findWorldById(id)); + } + + @Nullable + private World findWorldById(int id) { + return entityManager.findById(World.class, id); + } + + // + + private static IntStream randomNumbers() { + return ThreadLocalRandom.current() + .ints(MIN_WORLD_NUMBER, MAX_WORLD_NUMBER) + .distinct(); + } + + private static int nextInt() { + return ThreadLocalRandom.current().nextInt(MIN_WORLD_NUMBER, MAX_WORLD_NUMBER); + } + + private static int parseQueryCount(@Nullable 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/today/src/main/java/cn/taketoday/benchmark/http/WorldCache.java b/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/http/WorldCache.java new file mode 100644 index 00000000000..899dafa7470 --- /dev/null +++ b/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/http/WorldCache.java @@ -0,0 +1,28 @@ +package cn.taketoday.benchmark.http; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ThreadLocalRandom; + +import cn.taketoday.benchmark.model.World; + +public class WorldCache { + + private final World[] cache; + + public WorldCache(List worlds) { + this.cache = worlds.toArray(new World[0]); + } + + public List getCachedWorld(int count) { + World[] worlds = this.cache; + int length = worlds.length; + ArrayList ret = new ArrayList<>(count); + ThreadLocalRandom current = ThreadLocalRandom.current(); + for (int i = 0; i < count; i++) { + ret.add(worlds[current.nextInt(length - 1)]); + } + return ret; + } + +} \ No newline at end of file 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 new file mode 100644 index 00000000000..4ef5fb0311b --- /dev/null +++ b/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/http/package-info.java @@ -0,0 +1,6 @@ +@NonNullApi +@NonNullFields +package cn.taketoday.benchmark.http; + +import infra.lang.NonNullApi; +import infra.lang.NonNullFields; \ 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 new file mode 100644 index 00000000000..1df119d4a3d --- /dev/null +++ b/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/model/Fortune.java @@ -0,0 +1,55 @@ +package cn.taketoday.benchmark.model; + +import java.util.Objects; + +import infra.persistence.Id; +import infra.persistence.Table; + +@Table("fortune") +public class Fortune { + + @Id + private Integer id; + + private String message; + + public Fortune() { + } + + public Fortune(Integer id, String message) { + this.id = id; + this.message = message; + } + + public void setId(Integer id) { + this.id = id; + } + + public void setMessage(String message) { + this.message = message; + } + + public Integer getId() { + return id; + } + + public String getMessage() { + return message; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (!(o instanceof Fortune fortune)) + return false; + return Objects.equals(id, fortune.id) + && Objects.equals(message, fortune.message); + } + + @Override + public int hashCode() { + return Objects.hash(id, message); + } + +} diff --git a/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/model/Message.java b/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/model/Message.java new file mode 100644 index 00000000000..fde5de5b8a8 --- /dev/null +++ b/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/model/Message.java @@ -0,0 +1,14 @@ +package cn.taketoday.benchmark.model; + +public class Message { + + private final String message; + + public Message(String message) { + this.message = message; + } + + public String getMessage() { + return message; + } +} \ No newline at end of file diff --git a/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/model/World.java b/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/model/World.java new file mode 100644 index 00000000000..4ff2a25c1d1 --- /dev/null +++ b/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/model/World.java @@ -0,0 +1,62 @@ +package cn.taketoday.benchmark.model; + +import java.util.Objects; + +import infra.persistence.Column; +import infra.persistence.Id; +import infra.persistence.Table; + +@Table("world") +public class World implements Comparable { + + @Id + private Integer id; + + @Column("randomNumber") + private Integer randomNumber; + + public World() { + } + + public World(Integer id, Integer randomNumber) { + this.id = id; + this.randomNumber = randomNumber; + } + + public Integer getId() { + return id; + } + + public Integer getRandomNumber() { + return randomNumber; + } + + public void setId(Integer id) { + this.id = id; + } + + public void setRandomNumber(Integer randomNumber) { + this.randomNumber = randomNumber; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (!(o instanceof World world)) + return false; + return Objects.equals(id, world.id) + && Objects.equals(randomNumber, world.randomNumber); + } + + @Override + public int hashCode() { + return Objects.hash(id, randomNumber); + } + + @Override + public int compareTo(World o) { + return Integer.compare(id, o.id); + } + +} 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 new file mode 100644 index 00000000000..115f7640198 --- /dev/null +++ b/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/model/package-info.java @@ -0,0 +1,6 @@ +@NonNullApi +@NonNullFields +package cn.taketoday.benchmark.model; + +import infra.lang.NonNullApi; +import infra.lang.NonNullFields; \ 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 new file mode 100644 index 00000000000..518576b46e9 --- /dev/null +++ b/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/package-info.java @@ -0,0 +1,6 @@ +@NonNullApi +@NonNullFields +package cn.taketoday.benchmark; + +import infra.lang.NonNullApi; +import infra.lang.NonNullFields; \ No newline at end of file diff --git a/frameworks/Java/today/src/main/resources/application-dev.yaml b/frameworks/Java/today/src/main/resources/application-dev.yaml new file mode 100644 index 00000000000..07dbdf12fbc --- /dev/null +++ b/frameworks/Java/today/src/main/resources/application-dev.yaml @@ -0,0 +1,9 @@ +datasource: + url: jdbc:mysql://localhost:3306/hello_world?useUnicode=true&characterEncoding=utf8&useSSL=false&autoReconnect=true&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai + username: root + password: 88888888 + +logging: + level: + root: info + sql: debug \ 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 new file mode 100644 index 00000000000..7d554af1c14 --- /dev/null +++ b/frameworks/Java/today/src/main/resources/application-test.yaml @@ -0,0 +1,15 @@ +datasource: + url: jdbc:mysql://tfb-database:3306/hello_world?useUnicode=true&characterEncoding=utf8&useSSL=false&autoReconnect=true&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai + username: benchmarkdbuser + password: benchmarkdbpass + +logging: + level: + root: OFF + +server: + netty: + acceptor-threads: 8 + worker-threads: 16 + max-connection: 8192 + validate-headers: false \ No newline at end of file diff --git a/frameworks/Java/today/src/main/resources/application.yaml b/frameworks/Java/today/src/main/resources/application.yaml new file mode 100644 index 00000000000..aba9b42e36a --- /dev/null +++ b/frameworks/Java/today/src/main/resources/application.yaml @@ -0,0 +1,38 @@ +app: + name: benchmark-app + +server: + port: 8080 + +infra: + output: + ansi: + enabled: always + +freemarker: + cache: true + settings: + classic_compatible: true + date_format: yyyy-MM-dd + datetime_format: yyyy-MM-dd HH:mm:ss + default_encoding: UTF-8 + locale: UTF-8 + log_template_exceptions: false + number_format: 0.#### + tag_syntax: auto_detect + template_exception_handler: ignore + template_update_delay: 0 + time_format: HH:mm:ss + url_escaping_charset: UTF-8 + +datasource: + name: 'app-datasource' + type: com.zaxxer.hikari.HikariDataSource + driver-class-name: com.mysql.cj.jdbc.Driver + hikari: + maximum-pool-size: 256 + connection-test-query: 'select 1' + +logging: + level: + root: OFF \ No newline at end of file diff --git a/frameworks/Java/today/src/main/resources/templates/fortunes.ftl b/frameworks/Java/today/src/main/resources/templates/fortunes.ftl new file mode 100644 index 00000000000..0ad737e5dcc --- /dev/null +++ b/frameworks/Java/today/src/main/resources/templates/fortunes.ftl @@ -0,0 +1,21 @@ +<#-- @ftlvariable name="fortunes" type="cn.taketoday.benchmark.model.Fortune[]" --> + + + + Fortunes + + + + + + + + <#list fortunes as fortune> + + + + + +
idmessage
#{fortune.id}${fortune.message?html}
+ + \ No newline at end of file diff --git a/frameworks/Java/today/today.dockerfile b/frameworks/Java/today/today.dockerfile new file mode 100644 index 00000000000..643bbe4c00a --- /dev/null +++ b/frameworks/Java/today/today.dockerfile @@ -0,0 +1,13 @@ +FROM gradle:8.13.0-jdk21 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 +RUN apt install findutils +WORKDIR /today +COPY --from=build /infra-src/build/install/today/ ./ + +EXPOSE 8080 +ENTRYPOINT "./bin/today" diff --git a/frameworks/Java/undertow-jersey/pom.xml b/frameworks/Java/undertow-jersey/pom.xml index 2a11ad2b658..84bdc08753d 100644 --- a/frameworks/Java/undertow-jersey/pom.xml +++ b/frameworks/Java/undertow-jersey/pom.xml @@ -145,7 +145,7 @@ com.fasterxml.jackson.core jackson-databind - 2.13.4.2 + 2.16.0 com.fasterxml.jackson.module @@ -174,7 +174,7 @@ io.undertow undertow-core - 2.3.5.Final + 2.3.20.Final diff --git a/frameworks/Java/undertow/pom.xml b/frameworks/Java/undertow/pom.xml index 524d4273c74..b75308fdd5c 100644 --- a/frameworks/Java/undertow/pom.xml +++ b/frameworks/Java/undertow/pom.xml @@ -14,13 +14,13 @@ 18 UTF-8 5.0.1 - 2.13.4.2 + 2.16.0 3.10.1 3.3.0 3.2.2 0.9.10 - 42.4.1 - 2.3.5.Final + 42.7.2 + 2.3.20.Final diff --git a/frameworks/Java/vertx/README.md b/frameworks/Java/vertx/README.md index 47a3f1d2673..1e8ef72450e 100644 --- a/frameworks/Java/vertx/README.md +++ b/frameworks/Java/vertx/README.md @@ -33,7 +33,7 @@ This is the Vert.x portion of a [benchmarking test suite](../) comparing a varie ## Versions * [Java 17](https://jdk.java.net) -* [vertx 4.3.8](http://vertx.io/) +* [vertx 5.0.0.CR6](http://vertx.io/) ## Test URLs diff --git a/frameworks/Java/vertx/pom.xml b/frameworks/Java/vertx/pom.xml index 80b21f4422e..06fd8183ed5 100644 --- a/frameworks/Java/vertx/pom.xml +++ b/frameworks/Java/vertx/pom.xml @@ -1,161 +1,252 @@ - 4.0.0 - com.techempower - vertx.benchmark - 0.0.1-SNAPSHOT + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 + com.techempower + vertx.benchmark + 0.0.1-SNAPSHOT - - 17 - 17 - - vertx.App - 4.4.2 - 2.15.0 - 4.1.92.Final - 0.0.21.Final - + + 17 + 17 + + vertx.App + 5.0.4 + 4.2.5.Final + 2.16.1 + - - - io.vertx - vertx-core - ${stack.version} - - - io.vertx - vertx-pg-client - ${stack.version} - - - com.fasterxml.jackson.core - jackson-core - ${jackson.version} - - - com.fasterxml.jackson.core - jackson-databind - ${jackson.version} - - - io.netty - netty-transport-native-kqueue - ${netty.version} - osx-x86_64 - - - io.netty - netty-transport-native-epoll - ${netty.version} - linux-x86_64 - - - com.github.ben-manes.caffeine - caffeine - 3.1.3 - - - com.fizzed - rocker-compiler - 1.3.0 - - - javax.xml.bind - jaxb-api - 2.3.1 - - + + + io.vertx + vertx-core + ${vertx.version} + + + io.vertx + vertx-core-logging + ${vertx.version} + + + io.vertx + vertx-pg-client + ${vertx.version} + + + com.dslplatform + dsl-json + 2.0.2 + + + com.julienviet + jsonsergen + 0.0.5 + + + com.github.ben-manes.caffeine + caffeine + 3.1.3 + + + com.fizzed + rocker-compiler + 1.3.0 + + + javax.xml.bind + jaxb-api + 2.3.1 + + - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.10.1 - - false - - - - com.fizzed - rocker-maven-plugin - 1.3.0 - - - generate-rocker-templates - generate-sources - - generate - - - 17 - ${basedir}/src/main/templates - ${basedir}/target/generated-sources/rocker - false - true - true - true - - - - - - org.apache.maven.plugins - maven-shade-plugin - 2.4.1 - - - package - - shade - - - - - - ${main.class} - - - - META-INF/services/io.vertx.core.spi.VerticleFactory - - - - - ${project.build.directory}/${project.artifactId}-${project.version}-fat.jar - - - - - + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.10.1 + + false + + + + default-compile + + + io.vertx.codegen.CodeGenProcessor + + + + + + + com.fizzed + rocker-maven-plugin + 1.3.0 + + + generate-rocker-templates + generate-sources + + generate + + + 17 + ${basedir}/src/main/templates + ${basedir}/target/generated-sources/rocker + true + true + true + true + + + + + + org.apache.maven.plugins + maven-shade-plugin + 2.4.1 + + + package + + shade + + + + + + ${main.class} + + + + META-INF/services/io.vertx.core.spi.VerticleFactory + + + + + + + *:* + + META-INF/versions/**/module-info.class + module-info.class + + + + ${project.build.directory}/${project.artifactId}-${project.version}-fat.jar + + + + + - + - - - Linux - - false - - unix - - - - - io.vertx - vertx-io_uring-incubator - ${stack.version} - - - io.netty.incubator - netty-incubator-transport-native-io_uring - ${netty.io_uring.version} - linux-x86_64 - - - - + + + linux-x86_64 + + + linux + x86_64 + + + + + io.netty + netty-transport-native-io_uring + ${netty.version} + linux-x86_64 + + + + + + linux-amd64 + + + linux + amd64 + + + + + io.netty + netty-transport-native-io_uring + ${netty.version} + linux-x86_64 + + + + + + linux-aarch64 + + + linux + aarch64 + + + + + io.netty + netty-transport-native-io_uring + ${netty.version} + linux-aarch_64 + + + + + + osx-x86_64 + + + mac + x86_64 + + + + + io.netty + netty-resolver-dns-native-macos + ${netty.version} + osx-x86_64 + + + io.netty + netty-transport-native-kqueue + ${netty.version} + osx-x86_64 + + + + + + osx-aarch64 + + + mac + aarch64 + + + + + io.netty + netty-resolver-dns-native-macos + ${netty.version} + osx-aarch_64 + + + io.netty + netty-transport-native-kqueue + ${netty.version} + osx-aarch_64 + + + + + diff --git a/frameworks/Java/vertx/src/main/java/vertx/App.java b/frameworks/Java/vertx/src/main/java/vertx/App.java index 6d225d77d6c..f2d54510503 100755 --- a/frameworks/Java/vertx/src/main/java/vertx/App.java +++ b/frameworks/Java/vertx/src/main/java/vertx/App.java @@ -3,7 +3,10 @@ import com.fizzed.rocker.ContentType; import com.fizzed.rocker.RockerOutputFactory; import io.netty.util.concurrent.MultithreadEventExecutorGroup; -import io.vertx.core.impl.VertxInternal; +import io.vertx.core.impl.SysProps; +import io.vertx.core.internal.VertxInternal; +import io.vertx.core.internal.logging.Logger; +import io.vertx.core.internal.logging.LoggerFactory; import io.vertx.pgclient.*; import io.vertx.core.*; import io.vertx.core.buffer.Buffer; @@ -12,23 +15,10 @@ import io.vertx.core.http.HttpServerOptions; import io.vertx.core.http.HttpServerRequest; import io.vertx.core.http.HttpServerResponse; -import io.vertx.core.json.Json; -import io.vertx.core.json.JsonArray; import io.vertx.core.json.JsonObject; -import io.vertx.core.logging.Logger; -import io.vertx.core.logging.LoggerFactory; -import io.vertx.sqlclient.PreparedQuery; -import io.vertx.sqlclient.PreparedStatement; -import io.vertx.sqlclient.Row; -import io.vertx.sqlclient.RowIterator; -import io.vertx.sqlclient.RowSet; -import io.vertx.sqlclient.Tuple; +import io.vertx.sqlclient.*; import io.vertx.sqlclient.impl.SqlClientInternal; -import vertx.model.CachedWorld; -import vertx.model.Fortune; -import vertx.model.Message; -import vertx.model.World; -import vertx.model.WorldCache; +import vertx.model.*; import vertx.rocker.BufferRockerOutput; import java.io.ByteArrayOutputStream; @@ -41,12 +31,15 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; -import java.util.LinkedHashMap; import java.util.List; import java.util.concurrent.ThreadLocalRandom; import java.util.stream.Collectors; +import java.util.stream.IntStream; -public class App extends AbstractVerticle implements Handler { +public class App extends VerticleBase implements Handler { + + private static final int NUM_PROCESSORS = Runtime.getRuntime().availableProcessors(); + private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(App.class); /** * Returns the value of the "queries" getRequest parameter, which is an integer @@ -69,7 +62,9 @@ static int getQueries(HttpServerRequest request) { } } - static Logger logger = LoggerFactory.getLogger(App.class.getName()); + private static Logger logger = LoggerFactory.getLogger(App.class.getName()); + + private static final Integer[] BOXED_RND = IntStream.range(1, 10001).boxed().toArray(Integer[]::new); private static final String PATH_PLAINTEXT = "/plaintext"; private static final String PATH_JSON = "/json"; @@ -79,8 +74,6 @@ static int getQueries(HttpServerRequest request) { private static final String PATH_FORTUNES = "/fortunes"; private static final String PATH_CACHING = "/cached-queries"; - private static final Handler> NULL_HANDLER = null; - 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"); @@ -88,49 +81,88 @@ static int getQueries(HttpServerRequest request) { 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.createOptimized("server"); - private static final CharSequence HEADER_DATE = HttpHeaders.createOptimized("date"); - private static final CharSequence HEADER_CONTENT_TYPE = HttpHeaders.createOptimized("content-type"); - private static final CharSequence HEADER_CONTENT_LENGTH = HttpHeaders.createOptimized("content-length"); + 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("" + new Message("Hello, World!").toJson().length()); private static final CharSequence SERVER = HttpHeaders.createOptimized("vert.x"); - 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 SELECT_WORLDS = "SELECT id, randomnumber from WORLD"; + public static CharSequence createDateHeader() { + return HttpHeaders.createOptimized(DateTimeFormatter.RFC_1123_DATE_TIME.format(ZonedDateTime.now())); + } + + /** + * Returns a random integer that is a suitable value for both the {@code id} + * and {@code randomNumber} properties of a world object. + * + * @return a random world number + */ + static Integer boxedRandomWorldNumber() { + final int rndValue = ThreadLocalRandom.current().nextInt(1, 10001); + final var boxedRnd = BOXED_RND[rndValue - 1]; + assert boxedRnd.intValue() == rndValue; + return boxedRnd; + } + private HttpServer server; private SqlClientInternal client; private CharSequence dateString; - private CharSequence[] plaintextHeaders; + private MultiMap plaintextHeaders; + private MultiMap jsonHeaders; private final RockerOutputFactory factory = BufferRockerOutput.factory(ContentType.RAW); private Throwable databaseErr; private PreparedQuery> SELECT_WORLD_QUERY; - private PreparedQuery> SELECT_FORTUNE_QUERY; - private PreparedQuery> UPDATE_WORLD_QUERY; + private PreparedQuery>> SELECT_FORTUNE_QUERY; + @SuppressWarnings("unchecked") + private PreparedQuery>[] AGGREGATED_UPDATE_WORLD_QUERY = new PreparedQuery[500]; private WorldCache WORLD_CACHE; - 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); } @Override - public void start(Promise startPromise) throws Exception { + public Future start() throws Exception { int port = 8080; - server = vertx.createHttpServer(new HttpServerOptions()) + server = vertx + .createHttpServer(new HttpServerOptions() + .setHttp2ClearTextEnabled(false) + .setStrictThreadMode(true)) .requestHandler(App.this); dateString = createDateHeader(); - plaintextHeaders = new CharSequence[] { - HEADER_CONTENT_TYPE, RESPONSE_TYPE_PLAIN, - HEADER_SERVER, SERVER, - HEADER_DATE, dateString, - HEADER_CONTENT_LENGTH, HELLO_WORLD_LENGTH }; + plaintextHeaders = plaintextHeaders(); + jsonHeaders = jsonHeaders(); JsonObject config = config(); - vertx.setPeriodic(1000, id -> plaintextHeaders[5] = dateString = createDateHeader()); + vertx.setPeriodic(1000, id -> { + dateString = createDateHeader(); + plaintextHeaders = plaintextHeaders(); + jsonHeaders = jsonHeaders(); + }); PgConnectOptions options = new PgConnectOptions(); options.setDatabase(config.getString("database", "hello_world")); options.setHost(config.getString("host", "tfb-database")); @@ -138,32 +170,65 @@ public void start(Promise startPromise) throws Exception { options.setUser(config.getString("username", "benchmarkdbuser")); options.setPassword(config.getString("password", "benchmarkdbpass")); options.setCachePreparedStatements(true); - options.setPipeliningLimit(100_000); // Large pipelining means less flushing and we use a single connection anyway - PgConnection.connect(vertx, options) + options.setPreparedStatementCacheMaxSize(1024); + options.setPipeliningLimit(256); // Large pipelining means less flushing and we use a single connection anyway + Future clientsInit = initClients(options); + return clientsInit + .transform(ar -> { + databaseErr = ar.cause(); + return server.listen(port); + }); + } + + private Future initClients(PgConnectOptions options) { + return PgConnection.connect(vertx, options) .flatMap(conn -> { client = (SqlClientInternal) conn; + List> list = new ArrayList<>(); Future f1 = conn.prepare(SELECT_WORLD) .andThen(onSuccess(ps -> SELECT_WORLD_QUERY = ps.query())); + list.add(f1); Future f2 = conn.prepare(SELECT_FORTUNE) - .andThen(onSuccess(ps -> SELECT_FORTUNE_QUERY = ps.query())); - Future f3 = conn.prepare(UPDATE_WORLD) - .andThen(onSuccess(ps -> UPDATE_WORLD_QUERY = ps.query())); - Future f4 = conn.preparedQuery(SELECT_WORLDS) + .andThen(onSuccess(ps -> { + SELECT_FORTUNE_QUERY = ps.query(). + collecting(Collectors.mapping(row -> new Fortune(row.getInteger(0), row.getString(1)), Collectors.toList())); + })); + list.add(f2); + Future f3 = conn.preparedQuery(SELECT_WORLDS) .collecting(Collectors.mapping(row -> new CachedWorld(row.getInteger(0), row.getInteger(1)), Collectors.toList())) .execute() .map(worlds -> new WorldCache(worlds.value())) .andThen(onSuccess(wc -> WORLD_CACHE = wc)); - return CompositeFuture.join(f1, f2, f3, f4); - }) - .transform(ar -> { - databaseErr = ar.cause(); - return server.listen(port); - }) - .mapEmpty() - .onComplete(startPromise); + list.add(f3); + for (int i = 0; i < AGGREGATED_UPDATE_WORLD_QUERY.length; i++) { + int idx = i; + Future fut = conn + .prepare(buildAggregatedUpdateQuery(1 + idx)) + .andThen(onSuccess(ps -> AGGREGATED_UPDATE_WORLD_QUERY[idx] = ps.query())); + list.add(fut); + } + return Future.join(list); + }); + } + + private static String buildAggregatedUpdateQuery(int len) { + StringBuilder sql = new StringBuilder(); + 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(" END WHERE ID IN ($1"); + for (int i = 1; i < len; i++) { + int offset = (i * 2) + 1; + sql.append(",$").append(offset); + } + sql.append(")"); + return sql.toString(); } - private static Handler> onSuccess(Handler handler) { + public static Handler> onSuccess(Handler handler) { return ar -> { if (ar.succeeded()) { handler.handle(ar.result()); @@ -197,8 +262,9 @@ public void handle(HttpServerRequest request) { handleCaching(request); break; default: - request.response().setStatusCode(404); - request.response().end(); + request.response() + .setStatusCode(404) + .end(); break; } } catch (Exception e) { @@ -207,8 +273,8 @@ public void handle(HttpServerRequest request) { } @Override - public void stop() { - if (server != null) server.close(); + public Future stop() throws Exception { + return server != null ? server.close() : super.stop(); } private void sendError(HttpServerRequest req, Throwable cause) { @@ -218,36 +284,19 @@ private void sendError(HttpServerRequest req, Throwable cause) { private void handlePlainText(HttpServerRequest request) { HttpServerResponse response = request.response(); - MultiMap headers = response.headers(); - for (int i = 0;i < plaintextHeaders.length; i+= 2) { - headers.add(plaintextHeaders[i], plaintextHeaders[i + 1]); - } - response.end(HELLO_WORLD_BUFFER, NULL_HANDLER); + response.headers().setAll(plaintextHeaders); + response.end(HELLO_WORLD_BUFFER); } private void handleJson(HttpServerRequest request) { HttpServerResponse response = request.response(); - MultiMap headers = response.headers(); - headers - .add(HEADER_CONTENT_TYPE, RESPONSE_TYPE_JSON) - .add(HEADER_SERVER, SERVER) - .add(HEADER_DATE, dateString); - response.end(new Message("Hello, World!").toBuffer(), NULL_HANDLER); - } - - /** - * Returns a random integer that is a suitable value for both the {@code id} - * and {@code randomNumber} properties of a world object. - * - * @return a random world number - */ - private static int randomWorld() { - return 1 + ThreadLocalRandom.current().nextInt(10000); + response.headers().setAll(jsonHeaders); + response.end(new Message("Hello, World!").toJson()); } private void handleDb(HttpServerRequest req) { HttpServerResponse resp = req.response(); - SELECT_WORLD_QUERY.execute(Tuple.of(randomWorld()), res -> { + SELECT_WORLD_QUERY.execute(Tuple.of(boxedRandomWorldNumber())).onComplete(res -> { if (res.succeeded()) { RowIterator resultSet = res.result().iterator(); if (!resultSet.hasNext()) { @@ -255,11 +304,12 @@ private void handleDb(HttpServerRequest req) { return; } Row row = resultSet.next(); - resp - .putHeader(HttpHeaders.SERVER, SERVER) - .putHeader(HttpHeaders.DATE, dateString) - .putHeader(HttpHeaders.CONTENT_TYPE, RESPONSE_TYPE_JSON) - .end(Json.encode(new World(row.getInteger(0), row.getInteger(1))), NULL_HANDLER); + World word = 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()); } else { sendError(req, res.cause()); } @@ -269,21 +319,28 @@ private void handleDb(HttpServerRequest req) { class Queries implements Handler>> { boolean failed; - JsonArray worlds = new JsonArray(); + final World[] worlds; final HttpServerRequest req; final HttpServerResponse resp; final int queries; + int worldsIndex; public Queries(HttpServerRequest req) { + int queries = getQueries(req); + this.req = req; this.resp = req.response(); - this.queries = getQueries(req); + this.queries = queries; + this.worlds = new World[queries]; + this.worldsIndex = 0; } private void handle() { - client.group(c -> { + client.group(/*queries, */c -> { for (int i = 0; i < queries; i++) { - c.preparedQuery(SELECT_WORLD).execute(Tuple.of(randomWorld()), this); + c.preparedQuery(SELECT_WORLD) + .execute(Tuple.of(boxedRandomWorldNumber())) + .onComplete(this); } }); } @@ -299,50 +356,48 @@ public void handle(AsyncResult> ar) { // we need a final reference final Tuple row = ar.result().iterator().next(); - worlds.add(new JsonObject().put("id", "" + row.getInteger(0)).put("randomNumber", "" + row.getInteger(1))); + worlds[worldsIndex++] = new World(row.getInteger(0), row.getInteger(1)); // stop condition - if (worlds.size() == queries) { - resp - .putHeader(HttpHeaders.SERVER, SERVER) - .putHeader(HttpHeaders.DATE, dateString) - .putHeader(HttpHeaders.CONTENT_TYPE, RESPONSE_TYPE_JSON) - .end(worlds.encode(), NULL_HANDLER); + if (worldsIndex == queries) { + MultiMap headers = resp.headers(); + headers.add(HttpHeaders.SERVER, SERVER); + headers.add(HttpHeaders.DATE, dateString); + headers.add(HttpHeaders.CONTENT_TYPE, RESPONSE_TYPE_JSON); + resp.end(World.toJson(worlds)); } } } } - class Update { + private class Update { - final HttpServerRequest req; - boolean failed; - int queryCount; - final World[] worlds; + private final HttpServerRequest request; + private final World[] worldsToUpdate; + private boolean failed; + private int selectWorldCompletedCount; - public Update(HttpServerRequest req) { - final int queries = getQueries(req); - this.req = req; - this.worlds = new World[queries]; + public Update(HttpServerRequest request) { + this.request = request; + this.worldsToUpdate = new World[getQueries(request)]; } - private void handle() { - - client.group(c -> { - PreparedQuery> preparedQuery = c.preparedQuery(SELECT_WORLD); - for (int i = 0; i < worlds.length; i++) { - int id = randomWorld(); - int index = i; - preparedQuery.execute(Tuple.of(id), ar2 -> { + public void handle() { + client.group(/*worldsToUpdate.length, */c -> { + final PreparedQuery> preparedQuery = c.preparedQuery(App.SELECT_WORLD); + for (int i = 0; i < worldsToUpdate.length; i++) { + final Integer id = boxedRandomWorldNumber(); + final int index = i; + preparedQuery.execute(Tuple.of(id)).onComplete(res -> { if (!failed) { - if (ar2.failed()) { + if (res.failed()) { failed = true; - sendError(req, ar2.cause()); + sendError(request, res.cause()); return; } - worlds[index] = new World(ar2.result().iterator().next().getInteger(0), randomWorld()); - if (++queryCount == worlds.length) { - handleUpdates(); + worldsToUpdate[index] = new World(res.result().iterator().next().getInteger(0), boxedRandomWorldNumber()); + if (++selectWorldCompletedCount == worldsToUpdate.length) { + randomWorldsQueryCompleted(); } } }); @@ -350,51 +405,56 @@ private void handle() { }); } - void handleUpdates() { - Arrays.sort(worlds); - List batch = new ArrayList<>(); - for (World world : worlds) { - batch.add(Tuple.of(world.getRandomNumber(), world.getId())); + private void randomWorldsQueryCompleted() { + Arrays.sort(worldsToUpdate); + final List params = new ArrayList<>(worldsToUpdate.length * 2); + for (int i = 0, count = worldsToUpdate.length;i < count;i++) { + var world = worldsToUpdate[i]; + params.add(world.getId()); + params.add(world.getRandomNumber()); } - UPDATE_WORLD_QUERY.executeBatch(batch, ar2 -> { - if (ar2.failed()) { - sendError(req, ar2.cause()); + AGGREGATED_UPDATE_WORLD_QUERY[worldsToUpdate.length - 1] + .execute(Tuple.wrap(params)) + .onComplete(updateResult -> { + if (updateResult.failed()) { + sendError(request, updateResult.cause()); return; } - JsonArray json = new JsonArray(); - for (World world : worlds) { - json.add(new JsonObject().put("id", "" + world.getId()).put("randomNumber", "" + world.getRandomNumber())); - } - req.response() - .putHeader(HttpHeaders.SERVER, SERVER) - .putHeader(HttpHeaders.DATE, dateString) - .putHeader(HttpHeaders.CONTENT_TYPE, RESPONSE_TYPE_JSON) - .end(json.toBuffer(), NULL_HANDLER); + sendResponse(); }); } + + private void sendResponse() { + var res = request.response(); + MultiMap headers = res.headers(); + headers.add(HttpHeaders.SERVER, App.SERVER); + headers.add(HttpHeaders.DATE, dateString); + headers.add(HttpHeaders.CONTENT_TYPE, RESPONSE_TYPE_JSON); + Buffer buff = WorldJsonSerializer.toJsonBuffer(worldsToUpdate); + res.end(buff); + } } private void handleFortunes(HttpServerRequest req) { - SELECT_FORTUNE_QUERY.execute(ar -> { + SELECT_FORTUNE_QUERY + .execute() + .onComplete(ar -> { HttpServerResponse response = req.response(); if (ar.succeeded()) { - List fortunes = new ArrayList<>(); - RowIterator resultSet = ar.result().iterator(); - if (!resultSet.hasNext()) { + SqlResult> result = ar.result(); + if (result.size() == 0) { response.setStatusCode(404).end("No results"); return; } - while (resultSet.hasNext()) { - Row row = resultSet.next(); - fortunes.add(new Fortune(row.getInteger(0), row.getString(1))); - } + List fortunes = result.value(); fortunes.add(new Fortune(0, "Additional fortune added at request time.")); Collections.sort(fortunes); - response - .putHeader(HttpHeaders.SERVER, SERVER) - .putHeader(HttpHeaders.DATE, dateString) - .putHeader(HttpHeaders.CONTENT_TYPE, RESPONSE_TYPE_HTML) - .end(FortunesTemplate.template(fortunes).render(factory).buffer(), NULL_HANDLER); + MultiMap headers = response.headers(); + headers.add(HttpHeaders.SERVER, SERVER); + headers.add(HttpHeaders.DATE, dateString); + headers.add(HttpHeaders.CONTENT_TYPE, RESPONSE_TYPE_HTML); + FortunesTemplate template = FortunesTemplate.template(fortunes); + response.end(template.render(factory).buffer()); } else { sendError(req, ar.cause()); } @@ -412,24 +472,18 @@ private void handleCaching(HttpServerRequest req) { } count = Math.max(1, count); count = Math.min(500, count); - CachedWorld[] worlds = WORLD_CACHE.getCachedWorld(count); - JsonArray json = new JsonArray(new ArrayList<>(count)); - for (int i = 0;i < count;i++) { - CachedWorld world = worlds[i]; - json.add(JsonObject.of("id", world.getId(), "randomNumber", world.getRandomNumber())); - } + List worlds = WORLD_CACHE.getCachedWorld(count); HttpServerResponse response = req.response(); MultiMap headers = response.headers(); headers .add(HEADER_CONTENT_TYPE, RESPONSE_TYPE_JSON) .add(HEADER_SERVER, SERVER) .add(HEADER_DATE, dateString); - response.end(json.toBuffer(), NULL_HANDLER); + response.end(CachedWorld.toJson(worlds)); } public static void main(String[] args) throws Exception { - - int eventLoopPoolSize = VertxOptions.DEFAULT_EVENT_LOOP_POOL_SIZE; + int eventLoopPoolSize = NUM_PROCESSORS; String sizeProp = System.getProperty("vertx.eventLoopPoolSize"); if (sizeProp != null) { try { @@ -439,24 +493,30 @@ public static void main(String[] args) throws Exception { } } JsonObject config = new JsonObject(new String(Files.readAllBytes(new File(args[0]).toPath()))); - Vertx vertx = Vertx.vertx(new VertxOptions().setEventLoopPoolSize(eventLoopPoolSize).setPreferNativeTransport(true)); + Vertx vertx = Vertx.vertx(new VertxOptions() + .setEventLoopPoolSize(eventLoopPoolSize) + .setPreferNativeTransport(true) + .setDisableTCCL(true) + ); vertx.exceptionHandler(err -> { err.printStackTrace(); }); - printConfig(vertx); - vertx.deployVerticle(App.class.getName(), - new DeploymentOptions().setInstances(eventLoopPoolSize).setConfig(config), event -> { - if (event.succeeded()) { - logger.info("Server listening on port " + 8080); - } else { - logger.error("Unable to start your application", event.cause()); - } - }); + printConfig((VertxInternal) vertx); + vertx.deployVerticle( + App.class.getName(), + new DeploymentOptions().setInstances(eventLoopPoolSize).setConfig(config)) + .onComplete(event -> { + if (event.succeeded()) { + logger.info("Server listening on port " + 8080); + } else { + logger.error("Unable to start your application", event.cause()); + } + }); } - private static void printConfig(Vertx vertx) { + private static void printConfig(VertxInternal vertx) { boolean nativeTransport = vertx.isNativeTransportEnabled(); - String transport = ((VertxInternal) vertx).transport().getClass().getSimpleName(); + String transport = vertx.transport().getClass().getSimpleName(); String version = "unknown"; try { InputStream in = Vertx.class.getClassLoader().getResourceAsStream("META-INF/vertx/vertx-version.txt"); @@ -477,8 +537,14 @@ private static void printConfig(Vertx vertx) { logger.error("Could not read Vertx version", e);; } logger.info("Vertx: " + version); + logger.info("Processors: " + NUM_PROCESSORS); logger.info("Event Loop Size: " + ((MultithreadEventExecutorGroup)vertx.nettyEventLoopGroup()).executorCount()); logger.info("Native transport : " + nativeTransport); logger.info("Transport : " + transport); + logger.info("Netty buffer bound check : " + System.getProperty("io.netty.buffer.checkBounds")); + logger.info("Netty buffer accessibility check : " + System.getProperty("io.netty.buffer.checkAccessible")); + for (SysProps sysProp : SysProps.values()) { + logger.info(sysProp.name + " : " + sysProp.get()); + } } } diff --git a/frameworks/Java/vertx/src/main/java/vertx/model/CachedWorld.java b/frameworks/Java/vertx/src/main/java/vertx/model/CachedWorld.java index b369cc824da..3a55bfc2e89 100644 --- a/frameworks/Java/vertx/src/main/java/vertx/model/CachedWorld.java +++ b/frameworks/Java/vertx/src/main/java/vertx/model/CachedWorld.java @@ -1,8 +1,17 @@ package vertx.model; +import com.julienviet.jsonsergen.Backend; +import com.julienviet.jsonsergen.JsonSerGen; +import io.vertx.codegen.annotations.DataObject; +import io.vertx.core.buffer.Buffer; + +import java.util.List; + /** * The model for the "world" database table. */ +@DataObject +@JsonSerGen(backends = Backend.DSL_JSON) public final class CachedWorld implements Comparable { private final int id; @@ -31,4 +40,8 @@ public int getRandomNumber() { public int compareTo(CachedWorld o) { return Integer.compare(id, o.id); } + + public static Buffer toJson(List worlds) { + return CachedWorldJsonSerializer.toJsonBuffer(worlds); + } } \ No newline at end of file diff --git a/frameworks/Java/vertx/src/main/java/vertx/model/Fortune.java b/frameworks/Java/vertx/src/main/java/vertx/model/Fortune.java index d1df6fcfa1a..eb21f93feee 100644 --- a/frameworks/Java/vertx/src/main/java/vertx/model/Fortune.java +++ b/frameworks/Java/vertx/src/main/java/vertx/model/Fortune.java @@ -7,11 +7,14 @@ /** * The model for the "fortune" database table. */ -public final class Fortune extends JsonObject implements Comparable { +public final class Fortune implements Comparable { private static final String ID = "id"; private static final String MESSAGE = "message"; + private final int id; + private final String message; + /** * Constructs a new fortune object with the given parameters. * @@ -19,20 +22,16 @@ public final class Fortune extends JsonObject implements Comparable { * @param message the message of the fortune */ public Fortune(int id, String message) { - put(ID, id); - put(MESSAGE, message); - } - - public Fortune(JsonObject doc) { - super(doc == null ? Collections.emptyMap() : doc.getMap()); + this.id = id; + this.message = message; } public int getId() { - return getInteger(ID); + return id; } public String getMessage() { - return getString(MESSAGE); + return message; } @Override diff --git a/frameworks/Java/vertx/src/main/java/vertx/model/Message.java b/frameworks/Java/vertx/src/main/java/vertx/model/Message.java index 0fe3274afe0..ab9cd2a3d48 100644 --- a/frameworks/Java/vertx/src/main/java/vertx/model/Message.java +++ b/frameworks/Java/vertx/src/main/java/vertx/model/Message.java @@ -1,16 +1,30 @@ package vertx.model; -import io.vertx.core.json.JsonObject; +import com.julienviet.jsonsergen.Backend; +import com.julienviet.jsonsergen.JsonSerGen; +import io.vertx.codegen.annotations.DataObject; +import io.vertx.core.buffer.Buffer; -public class Message extends JsonObject { +@DataObject +@JsonSerGen(backends = Backend.DSL_JSON) +public class Message { - private static final String MESSAGE = "message"; + private String message; public Message(String message) { - put(MESSAGE, message); + this.message = message; } public String getMessage() { - return getString(MESSAGE); + return message; + } + + public Message setMessage(String message) { + this.message = message; + return this; + } + + public Buffer toJson() { + return MessageJsonSerializer.toJsonBuffer(this); } } diff --git a/frameworks/Java/vertx/src/main/java/vertx/model/World.java b/frameworks/Java/vertx/src/main/java/vertx/model/World.java index e733b265d65..610f4371cab 100644 --- a/frameworks/Java/vertx/src/main/java/vertx/model/World.java +++ b/frameworks/Java/vertx/src/main/java/vertx/model/World.java @@ -1,8 +1,15 @@ package vertx.model; +import com.julienviet.jsonsergen.Backend; +import com.julienviet.jsonsergen.JsonSerGen; +import io.vertx.codegen.annotations.DataObject; +import io.vertx.core.buffer.Buffer; + /** * The model for the "world" database table. */ +@DataObject +@JsonSerGen(backends = Backend.DSL_JSON) public final class World implements Comparable { private final int id; @@ -31,4 +38,12 @@ public int getRandomNumber() { public int compareTo(World o) { return Integer.compare(id, o.id); } + + public Buffer toJson() { + return WorldJsonSerializer.toJsonBuffer(this); + } + + public static Buffer toJson(World[] worlds) { + return WorldJsonSerializer.toJsonBuffer(worlds); + } } \ No newline at end of file diff --git a/frameworks/Java/vertx/src/main/java/vertx/model/WorldCache.java b/frameworks/Java/vertx/src/main/java/vertx/model/WorldCache.java index c4d4b150283..2b0d4ae869c 100644 --- a/frameworks/Java/vertx/src/main/java/vertx/model/WorldCache.java +++ b/frameworks/Java/vertx/src/main/java/vertx/model/WorldCache.java @@ -3,6 +3,7 @@ import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; +import java.util.ArrayList; import java.util.List; import java.util.concurrent.ThreadLocalRandom; @@ -19,12 +20,12 @@ public WorldCache(List worlds) { this.cache = cache; } - public CachedWorld[] getCachedWorld(int count) { - CachedWorld[] ret = new CachedWorld[count]; + public List getCachedWorld(int count) { + List ret = new ArrayList<>(count); ThreadLocalRandom current = ThreadLocalRandom.current(); for (int i = 0;i < count;i++) { Integer key = Integer.valueOf(current.nextInt(1000)); - ret[i] = cache.getIfPresent(key); + ret.add(cache.getIfPresent(key)); } return ret; } diff --git a/frameworks/Java/vertx/src/main/java/vertx/model/package-info.java b/frameworks/Java/vertx/src/main/java/vertx/model/package-info.java new file mode 100644 index 00000000000..d0dfa9d492c --- /dev/null +++ b/frameworks/Java/vertx/src/main/java/vertx/model/package-info.java @@ -0,0 +1,4 @@ +@ModuleGen(name = "benchmark", groupPackage = "vertx.model") +package vertx.model; + +import io.vertx.codegen.annotations.ModuleGen; \ No newline at end of file diff --git a/frameworks/Java/vertx/src/main/java/vertx/rocker/BufferRockerOutput.java b/frameworks/Java/vertx/src/main/java/vertx/rocker/BufferRockerOutput.java index 326d45e3e96..36d1144f5d6 100644 --- a/frameworks/Java/vertx/src/main/java/vertx/rocker/BufferRockerOutput.java +++ b/frameworks/Java/vertx/src/main/java/vertx/rocker/BufferRockerOutput.java @@ -5,7 +5,8 @@ import com.fizzed.rocker.RockerOutputFactory; import io.netty.buffer.ByteBuf; import io.vertx.core.buffer.Buffer; -import io.vertx.core.buffer.impl.PartialPooledByteBufAllocator; +import io.vertx.core.impl.buffer.VertxByteBufAllocator; +import io.vertx.core.internal.buffer.BufferInternal; import java.io.IOException; import java.nio.charset.Charset; @@ -21,8 +22,8 @@ public static RockerOutputFactory factory(ContentType conten }; } - private final ByteBuf buff = PartialPooledByteBufAllocator.INSTANCE.directBuffer(); - private final Buffer buffer = Buffer.buffer(buff); + private final ByteBuf buff = VertxByteBufAllocator.DEFAULT.directBuffer(); + private final Buffer buffer = BufferInternal.buffer(buff); private final ContentType contentType; BufferRockerOutput(ContentType contentType) { diff --git a/frameworks/Java/vertx/src/main/templates/vertx/FortunesTemplate.rocker.html b/frameworks/Java/vertx/src/main/templates/vertx/FortunesTemplate.rocker.html index 4a76266c344..8ceb4d68c7e 100644 --- a/frameworks/Java/vertx/src/main/templates/vertx/FortunesTemplate.rocker.html +++ b/frameworks/Java/vertx/src/main/templates/vertx/FortunesTemplate.rocker.html @@ -1,18 +1,8 @@ @import vertx.model.Fortune @import java.util.List @args(List fortunes) - - -Fortunes - - - - - - @for ((ForIterator i, Fortune fortune) : fortunes) { - - - - }
idmessage
@fortune.getId()@fortune.getMessage()
- - +Fortunes +@for ((ForIterator i, Fortune fortune) : fortunes) { + +} +
idmessage
@fortune.getId()@fortune.getMessage()
\ No newline at end of file diff --git a/frameworks/Java/vertx/vertx-postgres.dockerfile b/frameworks/Java/vertx/vertx-postgres.dockerfile index 3072a3ad381..fe4477726c8 100644 --- a/frameworks/Java/vertx/vertx-postgres.dockerfile +++ b/frameworks/Java/vertx/vertx-postgres.dockerfile @@ -1,4 +1,4 @@ -FROM maven:3.9.0-eclipse-temurin-17 as maven +FROM maven:3.9.9-eclipse-temurin-24-noble as maven WORKDIR /vertx COPY src src COPY pom.xml pom.xml @@ -9,21 +9,26 @@ EXPOSE 8080 CMD export DBIP=`getent hosts tfb-database | awk '{ print $1 }'` && \ sed -i "s|tfb-database|$DBIP|g" /vertx/src/main/conf/config.json && \ java \ + --enable-native-access=ALL-UNNAMED \ + --sun-misc-unsafe-memory-access=allow \ + --add-opens=java.base/java.lang=ALL-UNNAMED \ -Xms2G \ -Xmx2G \ -server \ -XX:+UseNUMA \ -XX:+UseParallelGC \ + -XX:+UnlockDiagnosticVMOptions \ + -XX:+DebugNonSafepoints \ + -Djava.lang.Integer.IntegerCache.high=10000 \ -Dvertx.disableMetrics=true \ - -Dvertx.disableH2c=true \ -Dvertx.disableWebsockets=true \ - -Dvertx.flashPolicyHandler=false \ - -Dvertx.threadChecks=false \ -Dvertx.disableContextTimings=true \ - -Dvertx.disableTCCL=true \ -Dvertx.disableHttpHeadersValidation=true \ + -Dvertx.cacheImmutableHttpResponseHeaders=true \ + -Dvertx.internCommonHttpRequestHeadersToLowerCase=true \ -Dvertx.eventLoopPoolSize=$((`grep --count ^processor /proc/cpuinfo`)) \ - -Dio.netty.buffer.checkBounds=false \ + -Dio.netty.noUnsafe=false \ + -Dio.netty.buffer.checkBounds=false \ -Dio.netty.buffer.checkAccessible=false \ -jar \ target/vertx.benchmark-0.0.1-SNAPSHOT-fat.jar \ diff --git a/frameworks/Java/vertx/vertx.dockerfile b/frameworks/Java/vertx/vertx.dockerfile index cfd269e37ae..ae194f4c7f8 100644 --- a/frameworks/Java/vertx/vertx.dockerfile +++ b/frameworks/Java/vertx/vertx.dockerfile @@ -1,4 +1,4 @@ -FROM maven:3.9.0-eclipse-temurin-17 as maven +FROM maven:3.9.9-eclipse-temurin-24-noble as maven WORKDIR /vertx COPY src src COPY pom.xml pom.xml @@ -6,4 +6,4 @@ RUN mvn package -q EXPOSE 8080 -CMD ["java", "-Xms2G", "-Xmx2G", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-Dvertx.disableMetrics=true", "-Dvertx.disableH2c=true", "-Dvertx.disableWebsockets=true", "-Dvertx.flashPolicyHandler=false", "-Dvertx.threadChecks=false", "-Dvertx.disableContextTimings=true", "-Dvertx.disableTCCL=true", "-Dvertx.disableHttpHeadersValidation=true", "-Dio.netty.buffer.checkBounds=false", "-Dio.netty.buffer.checkAccessible=false", "-jar", "target/vertx.benchmark-0.0.1-SNAPSHOT-fat.jar", "src/main/conf/config.json"] +CMD ["java", "--enable-native-access=ALL-UNNAMED", "--sun-misc-unsafe-memory-access=allow", "--add-opens=java.base/java.lang=ALL-UNNAMED", "-Xms2G", "-Xmx2G", "-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", "-jar", "target/vertx.benchmark-0.0.1-SNAPSHOT-fat.jar", "src/main/conf/config.json"] diff --git a/frameworks/Java/voovan/pom.xml b/frameworks/Java/voovan/pom.xml index fec86f88048..853624578a2 100644 --- a/frameworks/Java/voovan/pom.xml +++ b/frameworks/Java/voovan/pom.xml @@ -6,8 +6,8 @@ 0.1 UTF-8 - 11 - 11 + 17 + 17 org.voovan.VoovanTFB diff --git a/frameworks/Java/voovan/voovan.dockerfile b/frameworks/Java/voovan/voovan.dockerfile index 61160d45d63..26ed65a1bdf 100644 --- a/frameworks/Java/voovan/voovan.dockerfile +++ b/frameworks/Java/voovan/voovan.dockerfile @@ -1,11 +1,11 @@ -FROM maven:3.6.1-jdk-11-slim as maven +FROM maven:3-eclipse-temurin-24-alpine as maven WORKDIR /voovan COPY pom.xml pom.xml COPY src src COPY config/framework.properties config/framework.properties RUN mvn package -q -FROM openjdk:11.0.3-jdk-slim +FROM amazoncorretto:25 WORKDIR /voovan COPY --from=maven /voovan/target/voovan-bench-0.1-jar-with-dependencies.jar app.jar COPY --from=maven /voovan/config/framework.properties config/framework.properties @@ -24,5 +24,12 @@ CMD java -DCheckTimeout=false \ -XX:+AlwaysPreTouch \ -XX:-RestrictContended \ -XX:+UseParallelGC -XX:+UseNUMA \ - -XX:+AggressiveOpts -XX:+UseBiasedLocking \ + --add-opens java.base/java.lang=ALL-UNNAMED \ + --add-opens java.base/java.util=ALL-UNNAMED \ + --add-opens java.base/java.io=ALL-UNNAMED \ + --add-opens java.base/java.nio=ALL-UNNAMED \ + --add-opens java.base/sun.nio.ch=ALL-UNNAMED \ + --add-opens java.base/java.security=ALL-UNNAMED \ + --add-opens java.base/java.util.concurrent=ALL-UNNAMED \ + --add-opens java.base/java.net=ALL-UNNAMED \ -cp ./config:voovan.jar:app.jar org.voovan.VoovanTFB diff --git a/frameworks/Java/wicket/pom.xml b/frameworks/Java/wicket/pom.xml index ec30df52f27..a27fab91670 100644 --- a/frameworks/Java/wicket/pom.xml +++ b/frameworks/Java/wicket/pom.xml @@ -1,128 +1,128 @@ - 4.0.0 - hellowicket - hellowicket - war - 1.0 - Hello Wicket - Wicket project for the TechEmpower Benchmark - - TechEmpower - https://github.com/TechEmpower/FrameworkBenchmarks - - - - The Apache Software License, Version 2.0 - http://www.apache.org/licenses/LICENSE-2.0.txt - repo - - - - UTF-8 - 11 - 11 - 2.13.0 - 1.7.25 - 9.6.0 - - - - - org.apache.wicket - wicket-core - ${wicket.version} - + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + 4.0.0 + hellowicket + hellowicket + war + 1.0 + Hello Wicket + Wicket project for the TechEmpower Benchmark + + TechEmpower + https://github.com/TechEmpower/FrameworkBenchmarks + + + + The Apache Software License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + + 17 + 17 + UTF-8 + 2.13.0 + 1.7.25 + 9.19.0 + + + + + org.apache.wicket + wicket-core + ${wicket.version} + - - - com.zaxxer - HikariCP - 5.0.0 - compile - + + + com.zaxxer + HikariCP + 5.0.0 + compile + - - - org.slf4j - slf4j-simple - ${slf4j.version} - + + + org.slf4j + slf4j-simple + ${slf4j.version} + - - com.fasterxml.jackson.module - jackson-module-afterburner - ${jackson.version} - + + com.fasterxml.jackson.module + jackson-module-afterburner + ${jackson.version} + - - com.fasterxml.jackson.core - jackson-annotations - ${jackson.version} - + + com.fasterxml.jackson.core + jackson-annotations + ${jackson.version} + - - mysql - mysql-connector-java - 8.0.28 - - - - - - false - src/main/resources - - - false - src/main/java - - ** - - - **/*.java - - - - - - false - src/test/resources - - - false - src/test/java - - ** - - - **/*.java - - - - - - true - org.apache.maven.plugins - maven-compiler-plugin - 3.8.1 - - false - - - - + + mysql + mysql-connector-java + 8.0.28 + + + + + + false + src/main/resources + + + false + src/main/java + + ** + + + **/*.java + + + + + + false + src/test/resources + + + false + src/test/java + + ** + + + **/*.java + + + + + + true + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + false + + + + - - - Apache Nexus - https://repository.apache.org/content/repositories/snapshots/ - - false - - - true - - - + + + Apache Nexus + https://repository.apache.org/content/repositories/snapshots/ + + false + + + true + + + diff --git a/frameworks/Java/wicket/resin.xml b/frameworks/Java/wicket/resin.xml index 5041ba51e4f..090bd3d200d 100755 --- a/frameworks/Java/wicket/resin.xml +++ b/frameworks/Java/wicket/resin.xml @@ -2,12 +2,12 @@ xmlns:resin="http://caucho.com/ns/resin/core"> - - - + + + - + diff --git a/frameworks/Java/wicket/wicket.dockerfile b/frameworks/Java/wicket/wicket.dockerfile index 0ab0578b1ea..3106bd3c480 100644 --- a/frameworks/Java/wicket/wicket.dockerfile +++ b/frameworks/Java/wicket/wicket.dockerfile @@ -1,16 +1,21 @@ -FROM maven:3.6.1-jdk-11-slim as maven +FROM maven:3-eclipse-temurin-24-alpine as maven WORKDIR /wicket COPY src src COPY pom.xml pom.xml RUN mvn compile war:war -q -FROM openjdk:11.0.3-jdk-stretch +FROM alpine/curl:8.1.2 as curl +WORKDIR /wicket +RUN curl -sL http://caucho.com/download/resin-4.0.61.tar.gz >resin.tar.gz + +FROM openjdk:25-ea-slim-bullseye WORKDIR /resin -RUN curl -sL http://caucho.com/download/resin-4.0.61.tar.gz | tar xz --strip-components=1 +COPY --from=curl /wicket/resin.tar.gz . +RUN tar xzf ./resin.tar.gz --strip-components=1 RUN rm -rf webapps/* COPY --from=maven /wicket/target/hellowicket-1.0.war webapps/ROOT.war COPY resin.xml conf/resin.xml EXPOSE 8080 -CMD ["java", "-Xms2G", "-Xmx2G", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AggressiveOpts", "-jar", "lib/resin.jar", "console"] +CMD ["java", "-Xms2G", "-Xmx2G", "-server", "-XX:+UseParallelGC", "-jar", "lib/resin.jar", "console"] diff --git a/frameworks/Java/wildfly-ee/benchmark_config.json b/frameworks/Java/wildfly-ee/benchmark_config.json index 1628dc35eef..7fc9770b023 100644 --- a/frameworks/Java/wildfly-ee/benchmark_config.json +++ b/frameworks/Java/wildfly-ee/benchmark_config.json @@ -22,7 +22,8 @@ "database_os": "Linux", "display_name": "wildfly-ee", "notes": "", + "tags": ["broken"], "versus": "" - } + } }] } diff --git a/frameworks/Java/wildfly-ee/pom.xml b/frameworks/Java/wildfly-ee/pom.xml index c2e6472f6e3..bd77be766bb 100644 --- a/frameworks/Java/wildfly-ee/pom.xml +++ b/frameworks/Java/wildfly-ee/pom.xml @@ -13,27 +13,69 @@ 17 3.9.0 3.3.2 - 8.0 - 26.0.1.Final - 7.0.0.Final - 2.0.6.Final + 10.0.0 + 5.0.1.Final + 8.0.1.Final - + + + + jakarta.platform + jakarta.jakartaee-bom + ${version.jakarta.ee} + import + pom + + + + - javax - javaee-api - ${version.javaee.api} + jakarta.annotation + jakarta.annotation-api + provided + + + jakarta.enterprise + jakarta.enterprise.cdi-api provided - - org.glassfish.jaxb - jaxb-runtime - 2.4.0-b180830.0438 + jakarta.enterprise.concurrent + jakarta.enterprise.concurrent-api + provided + + + jakarta.inject + jakarta.inject-api + provided + + + jakarta.json + jakarta.json-api + provided + + + jakarta.persistence + jakarta.persistence-api + provided + + + jakarta.transaction + jakarta.transaction-api + provided + + + jakarta.validation + jakarta.validation-api + provided + + + jakarta.ws.rs + jakarta.ws.rs-api + provided - @@ -50,63 +92,50 @@ maven-compiler-plugin ${version.compiler.plugin} - ${java.version} - ${java.version} ${java.version} + + org.wildfly.plugins + wildfly-maven-plugin + ${version.wildfly-maven-plugin} + + ROOT.war + + + + org.wildfly + wildfly-ee-galleon-pack + + + org.wildfly + wildfly-datasources-galleon-pack + ${version.wildfly.galleon.datasources.feature.pack} + + + + + + org.wildfly.channels + wildfly-ee + + + + + jaxrs-server + jpa + jsf + mysql-driver + + + + + + + + + + - - - - bootable-jar - - false - - - - - org.wildfly.plugins - wildfly-jar-maven-plugin - ${version.wildfly.maven.jar.plugin} - - - - wildfly@maven(org.jboss.universe:community-universe)#${version.wildfly.bootable} - - - org.wildfly - wildfly-datasources-galleon-pack - ${version.wildfly.galleon.datasources.feature.pack} - - - - jaxrs-server - jsf - mysql-driver - - - deployment-scanner - - - - - - - - - - - - - package - - - - - - - - diff --git a/frameworks/Java/wildfly-ee/scripts/bootable-jar.cli b/frameworks/Java/wildfly-ee/scripts/wildfly-setup.cli similarity index 100% rename from frameworks/Java/wildfly-ee/scripts/bootable-jar.cli rename to frameworks/Java/wildfly-ee/scripts/wildfly-setup.cli diff --git a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/jpa/PersistenceResources.java b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/jpa/PersistenceResources.java new file mode 100644 index 00000000000..aa580b31f68 --- /dev/null +++ b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/jpa/PersistenceResources.java @@ -0,0 +1,18 @@ +package com.techempower.ee7.jpa; + +import jakarta.enterprise.context.Dependent; +import jakarta.enterprise.inject.Produces; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; + +public class PersistenceResources { + + @PersistenceContext + private EntityManager em; + + @Produces + @Dependent + public EntityManager entityManager() { + return em; + } +} diff --git a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/model/Fortune.java b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/model/Fortune.java new file mode 100644 index 00000000000..7648c05b539 --- /dev/null +++ b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/model/Fortune.java @@ -0,0 +1,55 @@ +package com.techempower.ee7.model; + +import java.io.Serializable; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.NamedQuery; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; + +@NamedQuery(name = "allFortunes", query = "SELECT f FROM Fortune f") +@Entity +public class Fortune implements Comparable, Serializable { + + private static final long serialVersionUID = 1L; + + private int id; + private String message; + + public Fortune() { + + } + + public Fortune(int id, String message) { + this.id = id; + this.message = message; + } + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + @NotNull + @Size(max = 2048) + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + @Override + public int compareTo(Fortune o) { + return message.compareTo(o.getMessage()); + } +} diff --git a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/model/World.java b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/model/World.java new file mode 100644 index 00000000000..1ee3ae0e97a --- /dev/null +++ b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/model/World.java @@ -0,0 +1,37 @@ +package com.techempower.ee7.model; + +import java.io.Serializable; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.validation.constraints.NotNull; + +@Entity +public class World implements Serializable { + + private static final long serialVersionUID = 1L; + + private int id; + private int randomNumber; + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + @NotNull + public int getRandomNumber() { + return randomNumber; + } + + public void setRandomNumber(int randomNumber) { + this.randomNumber = randomNumber; + } +} diff --git a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/rest/CatchAllExceptionMapper.java b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/rest/CatchAllExceptionMapper.java new file mode 100644 index 00000000000..bc287fda07a --- /dev/null +++ b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/rest/CatchAllExceptionMapper.java @@ -0,0 +1,15 @@ +package com.techempower.ee7.rest; + +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.Response.Status; +import jakarta.ws.rs.ext.ExceptionMapper; +import jakarta.ws.rs.ext.Provider; + +@Provider +public class CatchAllExceptionMapper implements ExceptionMapper { + + @Override + public Response toResponse(Exception exception) { + return Response.status(Status.BAD_REQUEST).build(); + } +} diff --git a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/rest/MyApplication.java b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/rest/MyApplication.java new file mode 100644 index 00000000000..c1f912ec17d --- /dev/null +++ b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/rest/MyApplication.java @@ -0,0 +1,8 @@ +package com.techempower.ee7.rest; + +import jakarta.ws.rs.ApplicationPath; +import jakarta.ws.rs.core.Application; + +@ApplicationPath("rest") +public class MyApplication extends Application { +} diff --git a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/tests/Fortunes.java b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/tests/Fortunes.java new file mode 100644 index 00000000000..8bd06ae545c --- /dev/null +++ b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/tests/Fortunes.java @@ -0,0 +1,36 @@ +package com.techempower.ee7.tests; + +import java.util.Collections; +import java.util.List; + +import jakarta.annotation.PostConstruct; +import jakarta.enterprise.context.RequestScoped; +import jakarta.inject.Inject; +import jakarta.inject.Named; +import jakarta.persistence.EntityManager; + +import com.techempower.ee7.model.Fortune; + +@RequestScoped +@Named +public class Fortunes { + + private static final int ADDITIONAL_FORTUNE_ID = 0; + private static final String ADDITIONAL_FORTUNE_CONTENT = "Additional fortune added at request time."; + + @Inject + private EntityManager em; + + private List data; + + @PostConstruct + private void postConstruct() { + data = em.createNamedQuery("allFortunes", Fortune.class).getResultList(); + data.add(new Fortune(ADDITIONAL_FORTUNE_ID, ADDITIONAL_FORTUNE_CONTENT)); + Collections.sort(data); + } + + public List getData() { + return data; + } +} diff --git a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/tests/JsonSerialization.java b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/tests/JsonSerialization.java similarity index 81% rename from frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/tests/JsonSerialization.java rename to frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/tests/JsonSerialization.java index ad5d947b042..019afc50fc7 100644 --- a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/tests/JsonSerialization.java +++ b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/tests/JsonSerialization.java @@ -1,9 +1,9 @@ package com.techempower.ee7.tests; -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; @Path("/json") public class JsonSerialization { diff --git a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/tests/MultipleQueries.java b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/tests/MultipleQueries.java similarity index 78% rename from frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/tests/MultipleQueries.java rename to frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/tests/MultipleQueries.java index 936ddfb4b04..fbd764af7ee 100644 --- a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/tests/MultipleQueries.java +++ b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/tests/MultipleQueries.java @@ -3,13 +3,13 @@ import java.util.ArrayList; import java.util.List; -import javax.inject.Inject; -import javax.persistence.EntityManager; -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.MediaType; +import jakarta.inject.Inject; +import jakarta.persistence.EntityManager; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.core.MediaType; import com.techempower.ee7.model.World; import com.techempower.ee7.util.Helpers; diff --git a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/tests/PlainText.java b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/tests/PlainText.java similarity index 78% rename from frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/tests/PlainText.java rename to frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/tests/PlainText.java index f40da2ab7da..7ce9f37f3b9 100644 --- a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/tests/PlainText.java +++ b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/tests/PlainText.java @@ -1,9 +1,9 @@ package com.techempower.ee7.tests; -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; @Path("/plaintext") public class PlainText { diff --git a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/tests/SingleQuery.java b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/tests/SingleQuery.java new file mode 100644 index 00000000000..517ad710f45 --- /dev/null +++ b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/tests/SingleQuery.java @@ -0,0 +1,24 @@ +package com.techempower.ee7.tests; + +import jakarta.inject.Inject; +import jakarta.persistence.EntityManager; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; + +import com.techempower.ee7.model.World; +import com.techempower.ee7.util.Helpers; + +@Path("/db") +public class SingleQuery { + + @Inject + private EntityManager em; + + @GET + @Produces(MediaType.APPLICATION_JSON) + public World get() { + return em.find(World.class, Helpers.randomWorldId()); + } +} diff --git a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/tests/TestActions.java b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/tests/TestActions.java new file mode 100644 index 00000000000..d3847c9b661 --- /dev/null +++ b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/tests/TestActions.java @@ -0,0 +1,24 @@ +package com.techempower.ee7.tests; + +import jakarta.enterprise.context.RequestScoped; +import jakarta.inject.Inject; +import jakarta.persistence.EntityManager; +import jakarta.transaction.Transactional; + +import com.techempower.ee7.model.World; +import com.techempower.ee7.util.Helpers; + +@RequestScoped +public class TestActions { + + @Inject + private EntityManager em; + + @Transactional + public World updateWorld(int id) { + World w = em.find(World.class, id); + w.getRandomNumber(); // Mandatory to read for the test + w.setRandomNumber(Helpers.randomWorldId()); + return w; + } +} diff --git a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/tests/Updates.java b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/tests/Updates.java similarity index 81% rename from frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/tests/Updates.java rename to frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/tests/Updates.java index b041f24c939..5c3879bc363 100644 --- a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/tests/Updates.java +++ b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/tests/Updates.java @@ -3,12 +3,12 @@ import java.util.ArrayList; import java.util.List; -import javax.inject.Inject; -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.MediaType; +import jakarta.inject.Inject; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.core.MediaType; import com.techempower.ee7.model.World; import com.techempower.ee7.util.Helpers; diff --git a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/util/Helpers.java b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/util/Helpers.java similarity index 100% rename from frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/util/Helpers.java rename to frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee/util/Helpers.java diff --git a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/jpa/PersistenceResources.java b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/jpa/PersistenceResources.java deleted file mode 100644 index fcdc4aafa0d..00000000000 --- a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/jpa/PersistenceResources.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.techempower.ee7.jpa; - -import javax.enterprise.context.Dependent; -import javax.enterprise.inject.Produces; -import javax.persistence.EntityManager; -import javax.persistence.PersistenceContext; - -public class PersistenceResources { - - @PersistenceContext - private EntityManager em; - - @Produces - @Dependent - public EntityManager entityManager() { - return em; - } -} diff --git a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/model/Fortune.java b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/model/Fortune.java deleted file mode 100644 index dce49416f75..00000000000 --- a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/model/Fortune.java +++ /dev/null @@ -1,55 +0,0 @@ -package com.techempower.ee7.model; - -import java.io.Serializable; - -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.NamedQuery; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; - -@NamedQuery(name = "allFortunes", query = "SELECT f FROM Fortune f") -@Entity -public class Fortune implements Comparable, Serializable { - - private static final long serialVersionUID = 1L; - - private int id; - private String message; - - public Fortune() { - - } - - public Fortune(int id, String message) { - this.id = id; - this.message = message; - } - - @Id - @GeneratedValue(strategy = GenerationType.AUTO) - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - @NotNull - @Size(max = 2048) - public String getMessage() { - return message; - } - - public void setMessage(String message) { - this.message = message; - } - - @Override - public int compareTo(Fortune o) { - return message.compareTo(o.getMessage()); - } -} diff --git a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/model/World.java b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/model/World.java deleted file mode 100644 index 44fd914aee7..00000000000 --- a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/model/World.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.techempower.ee7.model; - -import java.io.Serializable; - -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.validation.constraints.NotNull; - -@Entity -public class World implements Serializable { - - private static final long serialVersionUID = 1L; - - private int id; - private int randomNumber; - - @Id - @GeneratedValue(strategy = GenerationType.AUTO) - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - @NotNull - public int getRandomNumber() { - return randomNumber; - } - - public void setRandomNumber(int randomNumber) { - this.randomNumber = randomNumber; - } -} diff --git a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/rest/CatchAllExceptionMapper.java b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/rest/CatchAllExceptionMapper.java deleted file mode 100644 index 0beb6e85c3d..00000000000 --- a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/rest/CatchAllExceptionMapper.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.techempower.ee7.rest; - -import javax.ws.rs.core.Response; -import javax.ws.rs.core.Response.Status; -import javax.ws.rs.ext.ExceptionMapper; -import javax.ws.rs.ext.Provider; - -@Provider -public class CatchAllExceptionMapper implements ExceptionMapper { - - @Override - public Response toResponse(Exception exception) { - return Response.status(Status.BAD_REQUEST).build(); - } -} diff --git a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/rest/MyApplication.java b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/rest/MyApplication.java deleted file mode 100644 index 5c82e49f3b9..00000000000 --- a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/rest/MyApplication.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.techempower.ee7.rest; - -import javax.ws.rs.ApplicationPath; -import javax.ws.rs.core.Application; - -@ApplicationPath("rest") -public class MyApplication extends Application { -} diff --git a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/tests/Fortunes.java b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/tests/Fortunes.java deleted file mode 100644 index 6bbff0fead8..00000000000 --- a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/tests/Fortunes.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.techempower.ee7.tests; - -import java.util.Collections; -import java.util.List; - -import javax.annotation.PostConstruct; -import javax.enterprise.context.RequestScoped; -import javax.inject.Inject; -import javax.inject.Named; -import javax.persistence.EntityManager; - -import com.techempower.ee7.model.Fortune; - -@RequestScoped -@Named -public class Fortunes { - - private static final int ADDITIONAL_FORTUNE_ID = 0; - private static final String ADDITIONAL_FORTUNE_CONTENT = "Additional fortune added at request time."; - - @Inject - private EntityManager em; - - private List data; - - @PostConstruct - private void postConstruct() { - data = em.createNamedQuery("allFortunes", Fortune.class).getResultList(); - data.add(new Fortune(ADDITIONAL_FORTUNE_ID, ADDITIONAL_FORTUNE_CONTENT)); - Collections.sort(data); - } - - public List getData() { - return data; - } -} diff --git a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/tests/SingleQuery.java b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/tests/SingleQuery.java deleted file mode 100644 index 30279ae4295..00000000000 --- a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/tests/SingleQuery.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.techempower.ee7.tests; - -import javax.inject.Inject; -import javax.persistence.EntityManager; -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; - -import com.techempower.ee7.model.World; -import com.techempower.ee7.util.Helpers; - -@Path("/db") -public class SingleQuery { - - @Inject - private EntityManager em; - - @GET - @Produces(MediaType.APPLICATION_JSON) - public World get() { - return em.find(World.class, Helpers.randomWorldId()); - } -} diff --git a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/tests/TestActions.java b/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/tests/TestActions.java deleted file mode 100644 index 9302373516c..00000000000 --- a/frameworks/Java/wildfly-ee/src/main/java/com/techempower/ee7/tests/TestActions.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.techempower.ee7.tests; - -import javax.enterprise.context.RequestScoped; -import javax.inject.Inject; -import javax.persistence.EntityManager; -import javax.transaction.Transactional; - -import com.techempower.ee7.model.World; -import com.techempower.ee7.util.Helpers; - -@RequestScoped -public class TestActions { - - @Inject - private EntityManager em; - - @Transactional - public World updateWorld(int id) { - World w = em.find(World.class, id); - w.getRandomNumber(); // Mandatory to read for the test - w.setRandomNumber(Helpers.randomWorldId()); - return w; - } -} diff --git a/frameworks/Java/wildfly-ee/src/main/resources/META-INF/persistence.xml b/frameworks/Java/wildfly-ee/src/main/resources/META-INF/persistence.xml index 2ac545e5dde..ff728916fe5 100644 --- a/frameworks/Java/wildfly-ee/src/main/resources/META-INF/persistence.xml +++ b/frameworks/Java/wildfly-ee/src/main/resources/META-INF/persistence.xml @@ -6,7 +6,6 @@ NONE - diff --git a/frameworks/Java/wildfly-ee/src/main/webapp/WEB-INF/web.xml b/frameworks/Java/wildfly-ee/src/main/webapp/WEB-INF/web.xml index 96378e310c9..126c5588694 100644 --- a/frameworks/Java/wildfly-ee/src/main/webapp/WEB-INF/web.xml +++ b/frameworks/Java/wildfly-ee/src/main/webapp/WEB-INF/web.xml @@ -8,7 +8,7 @@ Faces Servlet - javax.faces.webapp.FacesServlet + jakarta.faces.webapp.FacesServlet 1 @@ -18,12 +18,12 @@ - javax.faces.STATE_SAVING_METHOD + jakarta.faces.STATE_SAVING_METHOD client - javax.faces.PROJECT_STAGE + jakarta.faces.PROJECT_STAGE Production diff --git a/frameworks/Java/wildfly-ee/wildfly-ee.dockerfile b/frameworks/Java/wildfly-ee/wildfly-ee.dockerfile index ec4a1c6e063..b04e261e64d 100644 --- a/frameworks/Java/wildfly-ee/wildfly-ee.dockerfile +++ b/frameworks/Java/wildfly-ee/wildfly-ee.dockerfile @@ -1,9 +1,8 @@ FROM maven:3-openjdk-17 WORKDIR /wildfly EXPOSE 8080 -ENV MAVEN_OPTS="--add-exports=java.xml/com.sun.org.apache.xerces.internal.parsers=ALL-UNNAMED --add-exports=java.xml/com.sun.org.apache.xerces.internal.util=ALL-UNNAMED" COPY src src COPY scripts scripts COPY pom.xml pom.xml -RUN mvn clean package -P bootable-jar -CMD java -Djava.net.preferIPv4Stack=true -XX:SoftMaxHeapSize=18g -Xmx24g -XX:+UseZGC -jar target/wildfly-ee-bootable.jar +RUN mvn clean package wildfly:package +CMD JAVA_OPTS="-Djava.net.preferIPv4Stack=true -XX:SoftMaxHeapSize=18g -Xmx24g -XX:+UseZGC" ./target/server/bin/standalone.sh diff --git a/frameworks/JavaScript/0http/0http.dockerfile b/frameworks/JavaScript/0http/0http.dockerfile index 06be53b55c1..88dce479f8a 100644 --- a/frameworks/JavaScript/0http/0http.dockerfile +++ b/frameworks/JavaScript/0http/0http.dockerfile @@ -1,4 +1,4 @@ -FROM node:10 +FROM node:20.16-slim WORKDIR /usr/src/app diff --git a/frameworks/JavaScript/0http/app.js b/frameworks/JavaScript/0http/app.js index 8e6c81eb4b3..a0e19cde5a4 100644 --- a/frameworks/JavaScript/0http/app.js +++ b/frameworks/JavaScript/0http/app.js @@ -1,9 +1,5 @@ const cero = require('0http') -const low = require('0http/lib/server/low') - -const { router, server } = cero({ - server: low() -}) +const { router, server } = cero() router.on('GET', '/json', (req, res) => { res.setHeader('server', '0http') @@ -19,4 +15,4 @@ router.on('GET', '/plaintext', (req, res) => { res.end('Hello, World!') }) -server.start(8080, socket => {}) \ No newline at end of file +server.listen(8080) \ No newline at end of file diff --git a/frameworks/JavaScript/0http/package.json b/frameworks/JavaScript/0http/package.json index e25595b7ccf..041ccd1588c 100644 --- a/frameworks/JavaScript/0http/package.json +++ b/frameworks/JavaScript/0http/package.json @@ -1,8 +1,7 @@ { "name": "0http", "dependencies": { - "0http": "1.2.1", - "uWebSockets.js": "github:uNetworking/uWebSockets.js#v15.11.0" + "0http": "4.3.0" }, "main": "app.js" } diff --git a/frameworks/JavaScript/aroma.js/README.md b/frameworks/JavaScript/aroma.js/README.md new file mode 100644 index 00000000000..927f8006851 --- /dev/null +++ b/frameworks/JavaScript/aroma.js/README.md @@ -0,0 +1,27 @@ +# Aroma.js Benchmarking Test + +From [aroma.js.org](https://aroma.js.org): + +> Aroma.js is a lightweight, feature-rich, and developer-friendly web framework designed to build modern web applications with ease. It provides essential features like routing, middleware, session management, cookie handling, template rendering, static file serving, and more. With its simple API, it enables rapid development of web applications with flexibility. + +### Test Type Implementation Source Code + +- [JSON](app.js) +- [PLAINTEXT](app.js) + +## Important Libraries + +The tests were run with: + +- [Aroma.js](https://aroma.js.org/) +- [NodeJS](https://nodejs.org/en/) + +## Test URLs + +### JSON + +http://localhost:8080/json + +### PLAINTEXT + +http://localhost:8080/plaintext diff --git a/frameworks/JavaScript/aroma.js/app.js b/frameworks/JavaScript/aroma.js/app.js new file mode 100644 index 00000000000..414af881bfa --- /dev/null +++ b/frameworks/JavaScript/aroma.js/app.js @@ -0,0 +1,36 @@ + +const cluster = require('cluster'), + numCPUs = require('os').cpus().length, + Aroma = require('aroma.js'); + + +if (cluster.isPrimary) { + console.log(`Primary ${process.pid} is running`); + + for (let i = 0; i < numCPUs; i++) { + cluster.fork(); + } + + cluster.on('exit', (worker, code, signal) => { + console.log(`worker ${worker.process.pid} died`); + }); +} else { + const app = module.exports = new Aroma(); + + app.parseUrlEncoded(); + + app.use((req, res, next) => { + res.setHeader("Server", "Aroma.js"); + return next(); + }); + + app.get('/json', (req, res) => res.send({ message: 'Hello, World!' })); + + app.get('/plaintext', (req, res) => { + res.setHeader('Content-Type', 'text/plain'); + res.send('Hello, World!'); + }); + + + app.listen(8080); +} diff --git a/frameworks/JavaScript/aroma.js/aroma.js.dockerfile b/frameworks/JavaScript/aroma.js/aroma.js.dockerfile new file mode 100644 index 00000000000..ec726dd2800 --- /dev/null +++ b/frameworks/JavaScript/aroma.js/aroma.js.dockerfile @@ -0,0 +1,11 @@ +FROM node:20.16-slim + +COPY ./ ./ + +RUN npm install + +ENV NODE_ENV production + +EXPOSE 8080 + +CMD ["node", "app.js"] diff --git a/frameworks/JavaScript/aroma.js/benchmark_config.json b/frameworks/JavaScript/aroma.js/benchmark_config.json new file mode 100644 index 00000000000..5d5a3fdaa62 --- /dev/null +++ b/frameworks/JavaScript/aroma.js/benchmark_config.json @@ -0,0 +1,21 @@ +{ + "framework": "aroma.js", + "tests": [{ + "default": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "framework": "aroma.js", + "language": "JavaScript", + "flavor": "NodeJS", + "platform": "nodejs", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "aroma.js", + "versus": "nodejs" + } + }] + } \ No newline at end of file diff --git a/frameworks/JavaScript/aroma.js/config.toml b/frameworks/JavaScript/aroma.js/config.toml new file mode 100644 index 00000000000..b7c4320a60c --- /dev/null +++ b/frameworks/JavaScript/aroma.js/config.toml @@ -0,0 +1,13 @@ +[framework] +name = "aroma.js" + +[main] +urls.plaintext = "/plaintext" +urls.json = "/json" +approach = "Realistic" +classification = "Micro" +database_os = "Linux" +os = "Linux" +platform = "nodejs" +webserver = "None" +versus = "nodejs" diff --git a/frameworks/JavaScript/aroma.js/package.json b/frameworks/JavaScript/aroma.js/package.json new file mode 100644 index 00000000000..4f9d2856a44 --- /dev/null +++ b/frameworks/JavaScript/aroma.js/package.json @@ -0,0 +1,8 @@ +{ + "name": "aroma.js", + "dependencies": { + "aroma.js": "1.0.8" + }, + "main": "app.js" + } + \ No newline at end of file diff --git a/frameworks/JavaScript/elide/README.md b/frameworks/JavaScript/elide/README.md new file mode 100644 index 00000000000..7efbabcb033 --- /dev/null +++ b/frameworks/JavaScript/elide/README.md @@ -0,0 +1,49 @@ +# [Elide](https://github.com/elide-dev/elide) - A fast polyglot runtime + +## Description + +Elide is a runtime which can execute **JavaScript**, **Ruby**, **Python**, and others, all in one package. + +Elide is powered by [GraalVM](https://graalvm.org), which enables polyglot software design. Code units can interoperate from any supported language. + +The test script embedded for this benchmark uses Elide's built-in HTTP intrinsic from JavaScript: + +```javascript +// access the built-in HTTP server engine +const app = Elide.http; + +// register basic handler +app.router.handle("GET", "/plaintext", (request, response) => { + // respond using the captured path variables + response.send(200, "Hello, world!"); +}); + +// register a route handler +app.router.handle("GET", "/json", (request, response, context) => { + // respond using the captured path variables + response.send(200, JSON.stringify({ message: "Hello, world!" })); +}); + +// configure the server binding options +app.config.port = 3000; + +// receive a callback when the server starts +app.config.onBind(() => { + console.log(`Server listening at "http://localhost:${app.config.port}"! 🚀`); +}); + +// start the server +app.start(); +``` + +- [Elide Docs](https://docs.elide.dev) + +## Test URLs + +### Test 1: JSON Encoding + + http://localhost:3000/json + +### Test 2: Plaintext + + http://localhost:3000/plaintext diff --git a/frameworks/JavaScript/elide/benchmark_config.json b/frameworks/JavaScript/elide/benchmark_config.json new file mode 100644 index 00000000000..8b8e8599c57 --- /dev/null +++ b/frameworks/JavaScript/elide/benchmark_config.json @@ -0,0 +1,21 @@ +{ + "framework": "elide", + "tests": [{ + "default": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 3000, + "approach": "Realistic", + "classification": "Platform", + "language": "JavaScript", + "flavor": "elide", + "platform": "elide", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "elide", + "tags": ["broken"], + "versus": "nodejs" + } + }] +} diff --git a/frameworks/JavaScript/elide/config.toml b/frameworks/JavaScript/elide/config.toml new file mode 100644 index 00000000000..542f38180fd --- /dev/null +++ b/frameworks/JavaScript/elide/config.toml @@ -0,0 +1,15 @@ +[framework] +name = "elide" + +[main] +urls.plaintext = "/plaintext" +urls.json = "/json" +approach = "Realistic" +classification = "Platform" +database_os = "Linux" +database = "None" +os = "Linux" +orm = "Raw" +platform = "elide" +webserver = "None" +versus = "nodejs" diff --git a/frameworks/JavaScript/elide/elide.dockerfile b/frameworks/JavaScript/elide/elide.dockerfile new file mode 100644 index 00000000000..f780fec96eb --- /dev/null +++ b/frameworks/JavaScript/elide/elide.dockerfile @@ -0,0 +1,11 @@ +FROM --platform=linux/amd64 ghcr.io/elide-dev/bench:1.0-alpha10-bench1-compat@sha256:1e679d95e18f9826c24a74d1709856849f53d3ca20c9bb25b548a8ec62424ad9 AS runtime + +EXPOSE 3000 + +WORKDIR /app + +COPY ./src . + +ENV NODE_ENV=production + +CMD ["elide", "serve", "server.js"] diff --git a/frameworks/JavaScript/elide/src/server.js b/frameworks/JavaScript/elide/src/server.js new file mode 100644 index 00000000000..1d564fe50d7 --- /dev/null +++ b/frameworks/JavaScript/elide/src/server.js @@ -0,0 +1,26 @@ +// access the built-in HTTP server engine +const app = Elide.http; + +// register basic handler +app.router.handle("GET", "/plaintext", (request, response) => { + // respond using the captured path variables + response.send(200, "Hello, world!"); +}); + +// register a route handler +app.router.handle("GET", "/json", (request, response, context) => { + // respond using the captured path variables + response.header("Content-Type", "application/json"); + response.send(200, JSON.stringify({ message: "Hello, world!" })); +}); + +// configure the server binding options +app.config.port = 3000; + +// receive a callback when the server starts +app.config.onBind(() => { + console.log(`Server listening at "http://localhost:${app.config.port}"! 🚀`); +}); + +// start the server +app.start(); diff --git a/frameworks/JavaScript/express/app.js b/frameworks/JavaScript/express/app.js index c8614691135..9f1039e2179 100755 --- a/frameworks/JavaScript/express/app.js +++ b/frameworks/JavaScript/express/app.js @@ -41,5 +41,6 @@ if (cluster.isPrimary) { app.get('/plaintext', (req, res) => res.header('Content-Type', 'text/plain').send('Hello, World!')); - app.listen(8080); + const server = app.listen(8080); + server.keepAliveTimeout = 0; } diff --git a/frameworks/JavaScript/express/benchmark_config.json b/frameworks/JavaScript/express/benchmark_config.json index 658e5b378e6..9f04d0dd56e 100644 --- a/frameworks/JavaScript/express/benchmark_config.json +++ b/frameworks/JavaScript/express/benchmark_config.json @@ -17,22 +17,6 @@ "display_name": "express", "versus": "nodejs" }, - "chakra": { - "json_url": "/json", - "plaintext_url": "/plaintext", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "framework": "express", - "language": "JavaScript", - "flavor": "node-chakracore", - "platform": "nodejs", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "express", - "versus": "nodejs" - }, "mongodb": { "db_url": "/mongoose", "query_url": "/mongooseq?queries=", @@ -71,7 +55,7 @@ "orm": "Full", "os": "Linux", "database_os": "Linux", - "display_name": "express", + "display_name": "express[mysql-sequelize]", "notes": "", "versus": "nodejs" }, @@ -92,7 +76,30 @@ "orm": "Full", "os": "Linux", "database_os": "Linux", - "display_name": "express", + "display_name": "express[postgres-sequelize]", + "notes": "", + "versus": "nodejs" + }, + "postgresjs": { + "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": "express", + "language": "JavaScript", + "flavor": "NodeJS", + "platform": "nodejs", + "webserver": "None", + "orm": "Full", + "os": "Linux", + "database_os": "Linux", + "display_name": "express[postgres.js]", "notes": "", "versus": "nodejs" } diff --git a/frameworks/JavaScript/express/config.toml b/frameworks/JavaScript/express/config.toml index d5c8a111c67..a18c6244628 100644 --- a/frameworks/JavaScript/express/config.toml +++ b/frameworks/JavaScript/express/config.toml @@ -56,14 +56,3 @@ orm = "Full" platform = "nodejs" webserver = "None" versus = "nodejs" - -[chakra] -urls.plaintext = "/plaintext" -urls.json = "/json" -approach = "Realistic" -classification = "Micro" -database_os = "Linux" -os = "Linux" -platform = "nodejs" -webserver = "None" -versus = "nodejs" diff --git a/frameworks/JavaScript/express/express-chakra.dockerfile b/frameworks/JavaScript/express/express-chakra.dockerfile deleted file mode 100644 index 7d179c4fc6a..00000000000 --- a/frameworks/JavaScript/express/express-chakra.dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM node:chakracore - -COPY ./ ./ - -RUN npm install - -ENV NODE_ENV production - -EXPOSE 8080 - -CMD ["node", "app.js"] diff --git a/frameworks/JavaScript/express/express-mongodb.dockerfile b/frameworks/JavaScript/express/express-mongodb.dockerfile index 6eea6502e96..fdd130d3195 100644 --- a/frameworks/JavaScript/express/express-mongodb.dockerfile +++ b/frameworks/JavaScript/express/express-mongodb.dockerfile @@ -1,4 +1,4 @@ -FROM node:18.12.1-slim +FROM node:20.16-slim COPY ./ ./ diff --git a/frameworks/JavaScript/express/express-mysql.dockerfile b/frameworks/JavaScript/express/express-mysql.dockerfile index c0c727e57f2..f446c93d2f4 100644 --- a/frameworks/JavaScript/express/express-mysql.dockerfile +++ b/frameworks/JavaScript/express/express-mysql.dockerfile @@ -1,4 +1,4 @@ -FROM node:18.12.1-slim +FROM node:20.16-slim COPY ./ ./ diff --git a/frameworks/JavaScript/express/express-postgres.dockerfile b/frameworks/JavaScript/express/express-postgres.dockerfile index 3450df4395e..46cf427d0a2 100644 --- a/frameworks/JavaScript/express/express-postgres.dockerfile +++ b/frameworks/JavaScript/express/express-postgres.dockerfile @@ -1,4 +1,4 @@ -FROM node:18.12.1-slim +FROM node:20.16-slim COPY ./ ./ diff --git a/frameworks/JavaScript/express/express-postgresjs.dockerfile b/frameworks/JavaScript/express/express-postgresjs.dockerfile new file mode 100644 index 00000000000..bc570d57faf --- /dev/null +++ b/frameworks/JavaScript/express/express-postgresjs.dockerfile @@ -0,0 +1,12 @@ +FROM node:20.16-slim + +COPY ./ ./ + +RUN npm install + +ENV NODE_ENV production +ENV DATABASE postgres + +EXPOSE 8080 + +CMD ["node", "src/clustered.mjs"] diff --git a/frameworks/JavaScript/express/express.dockerfile b/frameworks/JavaScript/express/express.dockerfile index 6e463a2efd6..ec726dd2800 100644 --- a/frameworks/JavaScript/express/express.dockerfile +++ b/frameworks/JavaScript/express/express.dockerfile @@ -1,4 +1,4 @@ -FROM node:18.12.1-slim +FROM node:20.16-slim COPY ./ ./ diff --git a/frameworks/JavaScript/express/mongodb-app.js b/frameworks/JavaScript/express/mongodb-app.js index ad8bb0bfac4..534fddc63f5 100644 --- a/frameworks/JavaScript/express/mongodb-app.js +++ b/frameworks/JavaScript/express/mongodb-app.js @@ -6,11 +6,7 @@ const cluster = require('cluster'); const numCPUs = require('os').cpus().length; const express = require('express'); const mongoose = require('mongoose'); -const connection = mongoose.createConnection('mongodb://tfb-database/hello_world',{ - useNewUrlParser: true, - useUnifiedTopology: true, - useFindAndModify: false, -}); +const connection = mongoose.createConnection('mongodb://tfb-database/hello_world'); // Middleware const bodyParser = require('body-parser'); diff --git a/frameworks/JavaScript/express/package.json b/frameworks/JavaScript/express/package.json index 0b955c658a9..143da144588 100644 --- a/frameworks/JavaScript/express/package.json +++ b/frameworks/JavaScript/express/package.json @@ -3,15 +3,17 @@ "version": "0.0.1", "private": true, "dependencies": { - "body-parser": "1.19.0", + "body-parser": "1.20.3", "dateformat": "3.0.3", "escape-html": "1.0.3", - "express": "4.17.3", - "mongoose": "5.13.20", - "mysql2": "2.2.5", + "express": "4.18.2", + "mongoose": "8.9.5", + "mysql2": "3.9.8", "pg": "8.5.0", - "pg-promise": "10.7.3", - "pug": "2.0.1", + "pg-promise": "11.5.5", + "pug": "3.0.3", + "postgres": "^3.4.3", + "slow-json-stringify": "^2.0.1", "sequelize": "6.29.0" } } diff --git a/frameworks/JavaScript/express/src/clustered.mjs b/frameworks/JavaScript/express/src/clustered.mjs new file mode 100644 index 00000000000..07ebbfbc330 --- /dev/null +++ b/frameworks/JavaScript/express/src/clustered.mjs @@ -0,0 +1,25 @@ +import cluster from "node:cluster"; +import os from "node:os"; +import process from "node:process"; + +process.env.DATABASE = "postgres"; + +if (cluster.isPrimary) { + // Master Node + console.log(`Primary ${process.pid} is running`); + + // Fork workers + const numCPUs = os.availableParallelism(); + for (let i = 0; i < numCPUs; i++) { + cluster.fork(); + } + + cluster.on("exit", (worker) => { + console.log(`worker ${worker.process.pid} died`); + process.exit(1); + }); +} else { + // Cluster Node + await import("./server.mjs"); + console.log(`Worker ${process.pid} started`); +} diff --git a/frameworks/JavaScript/express/src/database/postgres.mjs b/frameworks/JavaScript/express/src/database/postgres.mjs new file mode 100644 index 00000000000..5f22801d234 --- /dev/null +++ b/frameworks/JavaScript/express/src/database/postgres.mjs @@ -0,0 +1,27 @@ +import postgres from "postgres"; + +const sql = postgres({ + host: "tfb-database", + user: "benchmarkdbuser", + password: "benchmarkdbpass", + database: "hello_world", + max: 1, +}); + +export const fortunes = async () => await 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 bulkUpdate = async (worlds) => { + const sorted = sql( + worlds + .map((world) => [world.id, world.randomNumber]) + .sort((a, b) => (a[0] < b[0] ? -1 : 1)) + ); + await sql`UPDATE world SET randomNumber = (update_data.randomNumber)::int + FROM (VALUES ${sorted}) AS update_data (id, randomNumber) + WHERE world.id = (update_data.id)::int`; +}; diff --git a/frameworks/JavaScript/express/src/server.mjs b/frameworks/JavaScript/express/src/server.mjs new file mode 100644 index 00000000000..0de81c196cb --- /dev/null +++ b/frameworks/JavaScript/express/src/server.mjs @@ -0,0 +1,105 @@ +import express from "express"; +import { + generateRandomNumber, + getQueriesCount, + handleError, + escape, + jsonSerializer, + worldObjectSerializer, + sortByMessage, + writeResponse, + headerTypes, + GREETING, +} 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 app = express(); + +app.get("/plaintext", (req, res) => { + writeResponse(res, GREETING, headerTypes["plain"]); +}); + +app.get("/json", (req, res) => { + writeResponse(res, 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); + } + }); + + 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); + } + }); + + 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); + } + }); + + 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); + + for (let i = 0; i < queriesCount; i++) { + worldObjects[i].randomNumber = generateRandomNumber(); + } + await db.bulkUpdate(worldObjects); + writeResponse(res, JSON.stringify(worldObjects)); + } catch (error) { + handleError(error, res); + } + }); +} + +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, () => { + console.log(`Server running at http://${host}:${port}/`); +}); diff --git a/frameworks/JavaScript/express/src/utils.mjs b/frameworks/JavaScript/express/src/utils.mjs new file mode 100644 index 00000000000..1acf96b0d51 --- /dev/null +++ b/frameworks/JavaScript/express/src/utils.mjs @@ -0,0 +1,68 @@ +import { sjs, attr } from "slow-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 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 function generateRandomNumber() { + return Math.ceil(Math.random() * 10000); +} + +const escapeHTMLRules = { + "&": "&", + "<": "<", + ">": ">", + '"': """, + "'": "'", + "/": "/", +}; + +const unsafeHTMLMatcher = /[&<>"'\/]/g; + +export function escape(text) { + if (unsafeHTMLMatcher.test(text) === false) return text; + return text.replace(unsafeHTMLMatcher, function (m) { + return escapeHTMLRules[m] || m; + }); +} + +export const jsonSerializer = sjs({ message: attr("string") }); +export const worldObjectSerializer = sjs({ + id: attr("number"), + randomnumber: attr("number"), +}); + +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--; + } + arr[j + 1] = c; + } + return arr; +} diff --git a/frameworks/JavaScript/fastify/README.md b/frameworks/JavaScript/fastify/README.md index 705c282aee8..fe63567a9d5 100644 --- a/frameworks/JavaScript/fastify/README.md +++ b/frameworks/JavaScript/fastify/README.md @@ -19,33 +19,3 @@ Information about Fastify can be found at https://github.com/fastify/fastify ### JSON Encoding Test http://TFB-server:8080/json - -### Data-Store/Database Mapping Test - -MongoDB: -http://TFB-server:8080/mongoose/ - -MySQL: -http://TFB-server:8080/mysql-orm/ - -### Variable Query Test - -MongoDB: -http://TFB-server:8080/mongoose/2 - -MySQL: -http://TFB-server:8080/mysql-orm/2 - -### Fortune Test - -MySQL: -http://TFB-server:8080/fortune - -### Database Update Test - -MongoDB: -http://TFB-server:8080/mongoose-update/2 - -MySQL: -http://TFB-server:8080/mysql-orm-update/2 - diff --git a/frameworks/JavaScript/fastify/benchmark_config.json b/frameworks/JavaScript/fastify/benchmark_config.json index 944ae63a3ed..b4203ea43b9 100644 --- a/frameworks/JavaScript/fastify/benchmark_config.json +++ b/frameworks/JavaScript/fastify/benchmark_config.json @@ -5,14 +5,9 @@ "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": "Micro", - "database": "MongoDB", "framework": "fastify", "language": "JavaScript", "flavor": "NodeJS", @@ -42,7 +37,7 @@ "webserver": "None", "os": "Linux", "database_os": "Linux", - "display_name": "fastify", + "display_name": "fastify [mysql]", "notes": "", "versus": "nodejs" }, @@ -63,7 +58,7 @@ "webserver": "None", "os": "Linux", "database_os": "Linux", - "display_name": "fastify", + "display_name": "fastify [postgres]", "notes": "", "versus": "nodejs" } diff --git a/frameworks/JavaScript/fastify/config.toml b/frameworks/JavaScript/fastify/config.toml index c512a025989..d47b5822fa4 100644 --- a/frameworks/JavaScript/fastify/config.toml +++ b/frameworks/JavaScript/fastify/config.toml @@ -4,13 +4,8 @@ name = "fastify" [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 = "MongoDB" database_os = "Linux" os = "Linux" orm = "Raw" diff --git a/frameworks/JavaScript/fastify/create-server.js b/frameworks/JavaScript/fastify/create-server.js index 5680ef31f04..a20ba97e6e8 100644 --- a/frameworks/JavaScript/fastify/create-server.js +++ b/frameworks/JavaScript/fastify/create-server.js @@ -1,6 +1,11 @@ -const fastify = require("fastify")(); +const fastify = require("fastify")({ logger: false, keepAliveTimeout: 0 }); const handlers = require("./handlers"); +fastify.setErrorHandler((error, request, reply) => { + console.log(error) + reply.status(500).send({ ok: false }) +}) + fastify.register(require("@fastify/view"), { engine: { handlebars: require("handlebars") diff --git a/frameworks/JavaScript/fastify/db/mongo.js b/frameworks/JavaScript/fastify/db/mongo.js deleted file mode 100644 index ca4200ad550..00000000000 --- a/frameworks/JavaScript/fastify/db/mongo.js +++ /dev/null @@ -1,53 +0,0 @@ -const { MongoClient } = require("mongodb"); - -const mongoUrl = "mongodb://tfb-database:27017"; -const dbName = "hello_world"; - -let client; - -async function getCollection(name) { - if (!client) { - client = await new MongoClient( - mongoUrl, - { - useNewUrlParser: true, - useUnifiedTopology: true - } - ).connect(); - } - - const db = client.db(dbName); - - return db.collection(name); -} - -async function allFortunes() { - const collection = await getCollection("fortune"); - const fortunes = await collection.find({}, { projection: { _id: 0 } }); - - return fortunes.toArray(); -} - -async function getWorld(id) { - const collection = await getCollection("world"); - - return collection.findOne({ id }, { projection: { _id: 0 } }); -} - -async function saveWorlds(worlds) { - const collection = await getCollection("world"); - - const bulk = collection.initializeUnorderedBulkOp(); - - worlds.forEach(world => { - bulk.find({ id: world.id }).updateOne(world); - }); - - return bulk.execute(); -} - -module.exports = { - getWorld, - saveWorlds, - allFortunes -}; diff --git a/frameworks/JavaScript/fastify/db/mysql.js b/frameworks/JavaScript/fastify/db/mysql.js index 3887cc20dd1..ed2c26b44a4 100644 --- a/frameworks/JavaScript/fastify/db/mysql.js +++ b/frameworks/JavaScript/fastify/db/mysql.js @@ -1,41 +1,35 @@ -const knex = require("knex")({ - client: "mysql2", - connection: { - host: "tfb-database", - user: "benchmarkdbuser", - password: "benchmarkdbpass", - database: "hello_world" - } -}); +const { createPool } = require("mariadb"); + +const clientOpts = { + host: process.env.MYSQL_HOST, + user: process.env.MYSQL_USER, + password: process.env.MYSQL_PSWD, + database: process.env.MYSQL_DBNAME, +}; + +const pool = createPool({ ...clientOpts, connectionLimit: 1 }); +const execute = (text, values) => pool.execute(text, values || undefined); async function allFortunes() { - return knex("Fortune").select("*"); + return execute("select id, message from fortune", []); } async function getWorld(id) { - return knex("World") - .first() - .where({ id }); + return execute("select id, randomNumber from world where id = ?", [id]).then( + (arr) => arr[0] + ); } -async function saveWorlds(worlds) { - const updates = []; - - worlds.forEach(world => { - const { id, randomNumber } = world; - - updates.push( - knex("World") - .update({ randomNumber }) - .where({ id }) - ); - }); - - return Promise.all(updates); +async function bulkUpdate(worlds) { + const sql = "update world set randomNumber = ? where id = ?"; + const values = worlds + .map((world) => [world.randomnumber, world.id]) + .sort((a, b) => (a[0] < b[0] ? -1 : 1)); + return pool.batch(sql, values); } module.exports = { getWorld, - saveWorlds, - allFortunes + bulkUpdate, + allFortunes, }; diff --git a/frameworks/JavaScript/fastify/db/postgres.js b/frameworks/JavaScript/fastify/db/postgres.js index 1d5820eeeac..45f62c5eee4 100644 --- a/frameworks/JavaScript/fastify/db/postgres.js +++ b/frameworks/JavaScript/fastify/db/postgres.js @@ -1,41 +1,38 @@ -const knex = require("knex")({ - client: "pg", - connection: { - host: "tfb-database", - user: "benchmarkdbuser", - password: "benchmarkdbpass", - database: "hello_world" - } -}); +const postgres = require("postgres"); + +const clientOpts = { + host: process.env.PG_HOST, + user: process.env.PG_USER, + password: process.env.PG_PSWD, + database: process.env.PG_DBNAME, +}; + +const sql = postgres({ ...clientOpts, max: 1 }); async function allFortunes() { - return knex("Fortune").select("*"); + return sql`select id, message from fortune`; } async function getWorld(id) { - return knex("World") - .first() - .where({ id }); + return sql`select id, randomNumber from world where id = ${id}`.then( + (arr) => arr[0] + ); } -async function saveWorlds(worlds) { - const updates = []; - - worlds.forEach(world => { - const { id, randomNumber } = world; - - updates.push( - knex("World") - .update({ randomnumber: randomNumber }) - .where({ id }) - ); - }); +async function bulkUpdate(worlds) { + const values = sql( + worlds + .map((world) => [world.id, world.randomnumber]) + .sort((a, b) => (a[0] < b[0] ? -1 : 1)) + ); - return Promise.all(updates); + return sql`update world set randomNumber = (update_data.randomNumber)::int + from (values ${values}) as update_data (id, randomNumber) + where world.id = (update_data.id)::int`; } module.exports = { getWorld, - saveWorlds, - allFortunes + bulkUpdate, + allFortunes, }; diff --git a/frameworks/JavaScript/fastify/fastify-mysql.dockerfile b/frameworks/JavaScript/fastify/fastify-mysql.dockerfile index dce82ff1a90..8da0cc484d0 100644 --- a/frameworks/JavaScript/fastify/fastify-mysql.dockerfile +++ b/frameworks/JavaScript/fastify/fastify-mysql.dockerfile @@ -1,4 +1,4 @@ -FROM node:18.12.1-alpine +FROM node:20.16-slim COPY ./ ./ @@ -6,6 +6,10 @@ RUN npm install ENV NODE_ENV production ENV DATABASE mysql +ENV MYSQL_HOST tfb-database +ENV MYSQL_USER benchmarkdbuser +ENV MYSQL_PSWD benchmarkdbpass +ENV MYSQL_DBNAME hello_world EXPOSE 8080 diff --git a/frameworks/JavaScript/fastify/fastify-postgres.dockerfile b/frameworks/JavaScript/fastify/fastify-postgres.dockerfile index 65bf195566d..e5b63795e13 100644 --- a/frameworks/JavaScript/fastify/fastify-postgres.dockerfile +++ b/frameworks/JavaScript/fastify/fastify-postgres.dockerfile @@ -1,4 +1,4 @@ -FROM node:18.12.1-alpine +FROM node:20.16-slim COPY ./ ./ @@ -6,6 +6,10 @@ RUN npm install ENV NODE_ENV production ENV DATABASE postgres +ENV PG_HOST tfb-database +ENV PG_USER benchmarkdbuser +ENV PG_PSWD benchmarkdbpass +ENV PG_DBNAME hello_world EXPOSE 8080 diff --git a/frameworks/JavaScript/fastify/fastify.dockerfile b/frameworks/JavaScript/fastify/fastify.dockerfile index fdd8dcf4946..ec726dd2800 100644 --- a/frameworks/JavaScript/fastify/fastify.dockerfile +++ b/frameworks/JavaScript/fastify/fastify.dockerfile @@ -1,11 +1,10 @@ -FROM node:18.12.1-alpine +FROM node:20.16-slim COPY ./ ./ RUN npm install ENV NODE_ENV production -ENV DATABASE mongo EXPOSE 8080 diff --git a/frameworks/JavaScript/fastify/handlers.js b/frameworks/JavaScript/fastify/handlers.js index df2d37fc378..5032b4b829d 100644 --- a/frameworks/JavaScript/fastify/handlers.js +++ b/frameworks/JavaScript/fastify/handlers.js @@ -4,7 +4,7 @@ const h = require("./helper"); * @param databaseLayer * @returns {{singleQuery: function(*), multipleQueries: function(*), fortunes: function(*), updates: function(*)}} */ -module.exports = databaseLayer => ({ +module.exports = (databaseLayer) => ({ singleQuery: async (req, reply) => { const world = await databaseLayer.getWorld(h.randomTfbNumber()); @@ -34,29 +34,29 @@ module.exports = databaseLayer => ({ }, updates: async (req, reply) => { - const queries = h.getQueries(req.query.queries); + const num = h.getQueries(req.query.queries); const worldPromises = []; - for (let i = 0; i < queries; i++) { - worldPromises.push(databaseLayer.getWorld(h.randomTfbNumber())); + for (let i = 0; i < num; i++) { + const id = h.randomTfbNumber(); + worldPromises.push(databaseLayer.getWorld(id)); } const worlds = await Promise.all(worldPromises); - const worldsToUpdate = worlds.map(world => { - world.randomNumber = h.randomTfbNumber(); + const worldsToUpdate = worlds.map((world) => { + world.randomnumber = h.randomTfbNumber(); return world; }); - await databaseLayer.saveWorlds(worldsToUpdate); - + await databaseLayer.bulkUpdate(worldsToUpdate); reply.send(worldsToUpdate); - } + }, }); // faster than localeCompare function compare(a, b) { - if(a.message < b.message){ + if (a.message < b.message) { return -1; } else if (a.message > b.message) { return 1; diff --git a/frameworks/JavaScript/fastify/helper.js b/frameworks/JavaScript/fastify/helper.js index 8ed4447dbc4..6369564b902 100644 --- a/frameworks/JavaScript/fastify/helper.js +++ b/frameworks/JavaScript/fastify/helper.js @@ -1,12 +1,12 @@ module.exports = { randomTfbNumber: () => Math.floor(Math.random() * 10000) + 1, - getQueries: queries => { + getQueries: (queries) => { return Math.min(Math.max(parseInt(queries) || 1, 1), 500); }, additionalFortune: { id: 0, - message: "Additional fortune added at request time." - } + message: "Additional fortune added at request time.", + }, }; diff --git a/frameworks/JavaScript/fastify/package.json b/frameworks/JavaScript/fastify/package.json index e0740139501..4de1056bfe7 100644 --- a/frameworks/JavaScript/fastify/package.json +++ b/frameworks/JavaScript/fastify/package.json @@ -5,12 +5,10 @@ "main": "app.js", "private": true, "dependencies": { - "@fastify/view": "7.4.1", - "fastify": "4.13.0", - "handlebars": "4.7.6", - "knex": "2.4.2", - "mongodb": "3.5.9", - "mysql2": "2.2.5", - "pg": "8.5.1" + "@fastify/view": "^10.0.1", + "fastify": "^5.1.0", + "handlebars": "4.7.8", + "mariadb": "^3.4.0", + "postgres": "^3.4.5" } } diff --git a/frameworks/JavaScript/hapi/create-server.js b/frameworks/JavaScript/hapi/create-server.js index 6286264fd2e..db3c86b3f19 100644 --- a/frameworks/JavaScript/hapi/create-server.js +++ b/frameworks/JavaScript/hapi/create-server.js @@ -13,6 +13,7 @@ const options = { }; const server = new Hapi.server(options); +server.listener.keepAliveTimeout = 0; const provision = async () => { diff --git a/frameworks/JavaScript/hapi/hapi-mysql.dockerfile b/frameworks/JavaScript/hapi/hapi-mysql.dockerfile index 695bacf9e1e..f902c839a26 100644 --- a/frameworks/JavaScript/hapi/hapi-mysql.dockerfile +++ b/frameworks/JavaScript/hapi/hapi-mysql.dockerfile @@ -1,4 +1,4 @@ -FROM node:18.12.1-slim +FROM node:20.16-slim COPY ./ ./ diff --git a/frameworks/JavaScript/hapi/hapi-postgres.dockerfile b/frameworks/JavaScript/hapi/hapi-postgres.dockerfile index ee4e9251ee8..e9c8fb0e9a9 100644 --- a/frameworks/JavaScript/hapi/hapi-postgres.dockerfile +++ b/frameworks/JavaScript/hapi/hapi-postgres.dockerfile @@ -1,4 +1,4 @@ -FROM node:18.12.1-slim +FROM node:20.16-slim COPY ./ ./ diff --git a/frameworks/JavaScript/hapi/hapi.dockerfile b/frameworks/JavaScript/hapi/hapi.dockerfile index 23b09a88995..233cd3c53b0 100644 --- a/frameworks/JavaScript/hapi/hapi.dockerfile +++ b/frameworks/JavaScript/hapi/hapi.dockerfile @@ -1,4 +1,4 @@ -FROM node:18.12.1-slim +FROM node:20.16-slim COPY ./ ./ diff --git a/frameworks/JavaScript/hapi/package.json b/frameworks/JavaScript/hapi/package.json index 4aae630d9fa..1865dffe88e 100644 --- a/frameworks/JavaScript/hapi/package.json +++ b/frameworks/JavaScript/hapi/package.json @@ -8,9 +8,9 @@ "async": "2.1.5", "bluebird": "3.4.7", "handlebars": "4.3.0", - "mongoose": "5.13.20", + "mongoose": "8.9.5", "mysql": "2.16.0", - "mysql2": "1.6.5", + "mysql2": "3.9.8", "pg": "8.5.1", "pg-hstore": "2.3.2", "sequelize": "6.29.0" diff --git a/frameworks/JavaScript/hono/README.md b/frameworks/JavaScript/hono/README.md new file mode 100644 index 00000000000..34d9f271d37 --- /dev/null +++ b/frameworks/JavaScript/hono/README.md @@ -0,0 +1,50 @@ +# Hono Benchmarking Test + +Hono - [炎] means flame🔥 in Japanese - is a small, simple, and ultrafast web framework for the Edges. It works on any JavaScript runtime: Cloudflare Workers, Fastly Compute, Deno, Bun, Vercel, Lagon, AWS Lambda, Lambda@Edge, and Node.js. https://github.com/honojs/hono + +## Important Libraries + +The tests were run with: + +- [Hono](https://github.com/honojs/hono) +- [Postgres.js](https://github.com/porsager/postgres/) + +## Database + +There are individual handlers for each DB approach. The logic for each of them are found here: + +- [PostgreSQL](database/postgres.js) + +There are **no database endpoints** or drivers attached by default. + +To initialize the application with one of these, run any _one_ of the following commands: + +```sh +$ DATABASE=postgres npm start +``` + +## Test Endpoints + +> Visit the test requirements [here](https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview) + +```sh +$ curl localhost:8080/json +$ curl localhost:8080/plaintext + +# The following are only available with the DATABASE env var + +$ curl localhost:8080/db +$ curl localhost:8080/fortunes + +$ curl localhost:8080/updates?queries= +$ curl localhost:8080/updates?queries=2 +$ curl localhost:8080/updates?queries=1000 +$ curl localhost:8080/updates?queries=foo +$ curl localhost:8080/updates?queries=0 + +$ curl localhost:8080/queries?queries= +$ curl localhost:8080/queries?queries=2 +$ curl localhost:8080/queries?queries=1000 +$ curl localhost:8080/queries?queries=foo +$ curl localhost:8080/queries?queries=0 +``` diff --git a/frameworks/JavaScript/hono/benchmark_config.json b/frameworks/JavaScript/hono/benchmark_config.json new file mode 100644 index 00000000000..116064254e5 --- /dev/null +++ b/frameworks/JavaScript/hono/benchmark_config.json @@ -0,0 +1,47 @@ +{ + "framework": "hono", + "tests": [ + { + "default": { + "approach": "Realistic", + "classification": "Micro", + "database": "None", + "database_os": "Linux", + "display_name": "Hono", + "flavor": "NodeJS", + "framework": "Hono", + "json_url": "/json", + "language": "JavaScript", + "notes": "", + "orm": "Raw", + "os": "Linux", + "plaintext_url": "/plaintext", + "platform": "nodejs", + "port": 8080, + "versus": "nodejs", + "webserver": "None" + }, + "postgres": { + "approach": "Realistic", + "classification": "Platform", + "database": "Postgres", + "database_os": "Linux", + "db_url": "/db", + "display_name": "Hono", + "flavor": "NodeJS", + "fortune_url": "/fortunes", + "framework": "Hono", + "language": "JavaScript", + "notes": "", + "orm": "Raw", + "os": "Linux", + "platform": "None", + "port": 8080, + "query_url": "/queries?queries=", + "update_url": "/updates?queries=", + "versus": "nodejs", + "webserver": "None" + } + } + ] +} diff --git a/frameworks/JavaScript/hono/hono-postgres.dockerfile b/frameworks/JavaScript/hono/hono-postgres.dockerfile new file mode 100644 index 00000000000..ba7d0eee5f6 --- /dev/null +++ b/frameworks/JavaScript/hono/hono-postgres.dockerfile @@ -0,0 +1,12 @@ +FROM node:20-slim + +COPY ./ ./ + +RUN npm install + +ENV NODE_ENV production +ENV DATABASE postgres + +EXPOSE 8080 + +CMD ["npm", "start"] diff --git a/frameworks/JavaScript/hono/hono.dockerfile b/frameworks/JavaScript/hono/hono.dockerfile new file mode 100644 index 00000000000..4262ad19953 --- /dev/null +++ b/frameworks/JavaScript/hono/hono.dockerfile @@ -0,0 +1,11 @@ +FROM node:20-slim + +COPY ./ ./ + +RUN npm install + +ENV NODE_ENV production + +EXPOSE 8080 + +CMD ["npm", "start"] diff --git a/frameworks/JavaScript/hono/package-lock.json b/frameworks/JavaScript/hono/package-lock.json new file mode 100644 index 00000000000..ee69cbea0c1 --- /dev/null +++ b/frameworks/JavaScript/hono/package-lock.json @@ -0,0 +1,46 @@ +{ + "name": "hono", + "version": "0.0.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "hono", + "version": "0.0.1", + "license": "MIT", + "dependencies": { + "@hono/node-server": "^1.10.1", + "hono": "^3.10.4", + "postgres": "^3.4.3" + } + }, + "node_modules/@hono/node-server": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.10.1.tgz", + "integrity": "sha512-5BKW25JH5PQKPDkTcIgv3yNUPtOAbnnjFFgWvIxxAY/B/ZNeYjjWoAeDmqhIiCgOAJ3Tauuw+0G+VainhuZRYQ==", + "engines": { + "node": ">=18.14.1" + } + }, + "node_modules/hono": { + "version": "3.12.12", + "resolved": "https://registry.npmjs.org/hono/-/hono-3.12.12.tgz", + "integrity": "sha512-5IAMJOXfpA5nT+K0MNjClchzz0IhBHs2Szl7WFAhrFOsbtQsYmNynFyJRg/a3IPsmCfxcrf8txUGiNShXpK5Rg==", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/postgres": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/postgres/-/postgres-3.4.3.tgz", + "integrity": "sha512-iHJn4+M9vbTdHSdDzNkC0crHq+1CUdFhx+YqCE+SqWxPjm+Zu63jq7yZborOBF64c8pc58O5uMudyL1FQcHacA==", + "engines": { + "node": ">=12" + }, + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/porsager" + } + } + } +} diff --git a/frameworks/JavaScript/hono/package.json b/frameworks/JavaScript/hono/package.json new file mode 100644 index 00000000000..39a6184c2c5 --- /dev/null +++ b/frameworks/JavaScript/hono/package.json @@ -0,0 +1,17 @@ +{ + "dependencies": { + "@hono/node-server": "^1.10.1", + "hono": "^3.10.4", + "postgres": "^3.4.3" + }, + "license": "MIT", + "main": "src/server.js", + "name": "hono", + "private": true, + "scripts": { + "dev": "node src/server.js", + "start": "node src/clustered.js" + }, + "type": "module", + "version": "0.0.1" +} diff --git a/frameworks/JavaScript/hono/src/clustered.js b/frameworks/JavaScript/hono/src/clustered.js new file mode 100644 index 00000000000..95a57ec77f3 --- /dev/null +++ b/frameworks/JavaScript/hono/src/clustered.js @@ -0,0 +1,23 @@ +import cluster from "node:cluster"; +import os from "node:os"; +import process from "node:process"; + +if (cluster.isPrimary) { + // Master Node + console.log(`Primary ${process.pid} is running`); + + // Fork workers + const numCPUs = os.availableParallelism(); + for (let i = 0; i < numCPUs; i++) { + cluster.fork(); + } + + cluster.on("exit", (worker) => { + console.log(`worker ${worker.process.pid} died`); + process.exit(1); + }); +} else { + // Cluster Node + await import("./server.js"); + console.log(`Worker ${process.pid} started`); +} diff --git a/frameworks/JavaScript/hono/src/database/postgres.js b/frameworks/JavaScript/hono/src/database/postgres.js new file mode 100644 index 00000000000..54ef83e4da9 --- /dev/null +++ b/frameworks/JavaScript/hono/src/database/postgres.js @@ -0,0 +1,25 @@ +import postgres from "postgres"; + +const sql = postgres({ + host: "tfb-database", + user: "benchmarkdbuser", + password: "benchmarkdbpass", + database: "hello_world", + max: 1, +}); + +export const fortunes = async () => await 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 bulkUpdate = async (worlds) => + await sql`UPDATE world SET randomNumber = (update_data.randomNumber)::int + FROM (VALUES ${sql( + worlds + .map((world) => [world.id, world.randomNumber]) + .sort((a, b) => (a[0] < b[0] ? -1 : 1)) + )}) AS update_data (id, randomNumber) + WHERE world.id = (update_data.id)::int`; diff --git a/frameworks/JavaScript/hono/src/server.js b/frameworks/JavaScript/hono/src/server.js new file mode 100644 index 00000000000..43364616d55 --- /dev/null +++ b/frameworks/JavaScript/hono/src/server.js @@ -0,0 +1,108 @@ +import { serve } from "@hono/node-server"; +import { Hono } from "hono"; +import { + addBenchmarkHeaders, + escape, + generateRandomNumber, + getQueriesCount, + handleError, + sortByMessage, +} from "./utils.js"; + +let db; +const { DATABASE } = process.env; +if (DATABASE) db = await import(`./database/${DATABASE}.js`); + +const app = new Hono(); + +app + .get("/plaintext", (c) => { + addBenchmarkHeaders(c); + return c.text("Hello, World!"); + }) + .get("/json", (c) => { + addBenchmarkHeaders(c); + return c.json({ message: "Hello, World!" }); + }); + +if (db) { + const extra = { id: 0, message: "Additional fortune added at request time." }; + + app + .get("/db", async (c) => { + const randomNumber = await db.find(generateRandomNumber()); + addBenchmarkHeaders(c); + return c.json(randomNumber); + }) + .get("/queries", async (c) => { + const queriesCount = getQueriesCount(c); + + const databaseJobs = new Array(queriesCount); + + for (let i = 0; i < queriesCount; i++) { + databaseJobs[i] = db.find(generateRandomNumber()); + } + + const worldObjects = await Promise.all(databaseJobs); + + addBenchmarkHeaders(c); + return c.json(worldObjects); + }) + .get("/fortunes", async (c) => { + 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 + )}`; + } + + addBenchmarkHeaders(c); + return c.html( + `Fortunes${html}
idmessage
` + ); + }) + .get("/updates", async (c) => { + const queriesCount = getQueriesCount(c); + + 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(); + } + + await db.bulkUpdate(worldObjects); + + addBenchmarkHeaders(c); + return c.json(worldObjects); + }); +} + +app + .all("/*", (c) => { + addBenchmarkHeaders(c); + return c.text("Not Found", 404); + }) + .onError(handleError); + +const port = parseInt(process.env.PORT || "8080"); +const hostname = process.env.HOST || "0.0.0.0"; +serve({ fetch: app.fetch, hostname, port }, (info) => { + if (!info) { + console.error(`Couldn't bind to http://${hostname}:${port}!`); + process.exit(1); + } + console.log(`Successfully bound to http://${hostname}:${port}.`); +}); diff --git a/frameworks/JavaScript/hono/src/utils.js b/frameworks/JavaScript/hono/src/utils.js new file mode 100644 index 00000000000..7c17c12f1a6 --- /dev/null +++ b/frameworks/JavaScript/hono/src/utils.js @@ -0,0 +1,81 @@ +/** + * Add Benchmark HTTP response headers. + * + * Add HTTP response headers `Server` and `Date` which is required by the test suite. + * + * https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview + * + * @param {import('hono').Context} c + */ +export function addBenchmarkHeaders(c) { + c.header("Server", "Hono"); +} + +/** + * Handle error for response + * + * @param {Error} err + * @param {import('hono').Context} c + */ +export function handleError(err, c) { + console.error(err); + addBenchmarkHeaders(c); + c.text("Internal Server Error"); +} + +/** + * Get queries count + * + * @param {import('hono').Context} c + */ +export function getQueriesCount(c) { + return Math.min(parseInt(c.req.query("queries")) || 1, 500); +} + +/** + * Generate random number + * + */ +export function generateRandomNumber() { + return Math.ceil(Math.random() * 10000); +} + +/** + * Escape unsafe HTML Code + * + */ +const escapeHTMLRules = { + "&": "&", + "<": "<", + ">": ">", + '"': """, + "'": "'", + "/": "/", +}; + +const unsafeHTMLMatcher = /[&<>"'\/]/g; + +export function escape(text) { + if (unsafeHTMLMatcher.test(text) === false) return text; + return text.replace(unsafeHTMLMatcher, function (m) { + return escapeHTMLRules[m] || m; + }); +} + +/** + * Using Sort method which is performant for the test scenario + * @returns + */ +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--; + } + arr[j + 1] = c; + } + return arr; +} diff --git a/frameworks/JavaScript/hyperexpress/package-lock.json b/frameworks/JavaScript/hyperexpress/package-lock.json index cbaea996902..7e4af63b97f 100644 --- a/frameworks/JavaScript/hyperexpress/package-lock.json +++ b/frameworks/JavaScript/hyperexpress/package-lock.json @@ -9,120 +9,17 @@ "version": "0.0.1", "license": "MIT", "dependencies": { - "hyper-express": "^6.8.5", + "hyper-express": "^6.17.3", "lru-cache": "^10.0.1", "mariadb": "^3.2.0", "postgres": "^3.3.5" } }, - "node_modules/@types/body-parser": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", - "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", - "dependencies": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "node_modules/@types/busboy": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@types/busboy/-/busboy-0.3.2.tgz", - "integrity": "sha512-iEvdm9Z9KdSs/ozuh1Z7ZsXrOl8F4M/CLMXPZHr3QuJ4d6Bjn+HBMC5EMKpwpAo8oi8iK9GZfFoHaIMrrZgwVw==", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/connect": { - "version": "3.4.35", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", - "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/express": { - "version": "4.17.17", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz", - "integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==", - "dependencies": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.33", - "@types/qs": "*", - "@types/serve-static": "*" - } - }, - "node_modules/@types/express-serve-static-core": { - "version": "4.17.35", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.35.tgz", - "integrity": "sha512-wALWQwrgiB2AWTT91CB62b6Yt0sNHpznUXeZEcnPU3DRdlDIz74x8Qg1UUYKSVFi+va5vKOLYRBI1bRKiLLKIg==", - "dependencies": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*", - "@types/send": "*" - } - }, "node_modules/@types/geojson": { "version": "7946.0.10", "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.10.tgz", "integrity": "sha512-Nmh0K3iWQJzniTuPRcJn5hxXkfB1T1pgB89SBig5PlJQU5yocazeu4jATJlaA0GYFKWMqDdvYemoSnF2pXgLVA==" }, - "node_modules/@types/http-errors": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.1.tgz", - "integrity": "sha512-/K3ds8TRAfBvi5vfjuz8y6+GiAYBZ0x4tXv1Av6CWBWn0IlADc+ZX9pMq7oU0fNQPnBwIZl3rmeLp6SBApbxSQ==" - }, - "node_modules/@types/mime": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", - "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==" - }, - "node_modules/@types/node": { - "version": "16.18.38", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.38.tgz", - "integrity": "sha512-6sfo1qTulpVbkxECP+AVrHV9OoJqhzCsfTNp5NIG+enM4HyM3HvZCO798WShIXBN0+QtDIcutJCjsVYnQP5rIQ==" - }, - "node_modules/@types/qs": { - "version": "6.9.7", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==" - }, - "node_modules/@types/range-parser": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", - "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" - }, - "node_modules/@types/send": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.1.tgz", - "integrity": "sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q==", - "dependencies": { - "@types/mime": "^1", - "@types/node": "*" - } - }, - "node_modules/@types/serve-static": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.2.tgz", - "integrity": "sha512-J2LqtvFYCzaj8pVYKw8klQXrLLk7TBZmQ4ShlcdkELFKGwGMfevMLneMMRkMgZxotOD9wg497LpC7O8PcvAmfw==", - "dependencies": { - "@types/http-errors": "*", - "@types/mime": "*", - "@types/node": "*" - } - }, - "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/busboy": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", @@ -135,11 +32,11 @@ } }, "node_modules/cookie": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", - "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", + "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", "engines": { - "node": ">= 0.6" + "node": ">=18" } }, "node_modules/cookie-signature": { @@ -159,22 +56,19 @@ } }, "node_modules/hyper-express": { - "version": "6.8.5", - "resolved": "https://registry.npmjs.org/hyper-express/-/hyper-express-6.8.5.tgz", - "integrity": "sha512-tlHCGg0xKRHRheqY3Fgb8FvuvluCqIf6tJXiiyadsQh108g/givMqKt0XBYV+Rw0vstmmROuJ3cHXiUkQoddgg==", + "version": "6.17.3", + "resolved": "https://registry.npmjs.org/hyper-express/-/hyper-express-6.17.3.tgz", + "integrity": "sha512-fNFrRVEAIqjADtAq2F5wFRBlpo3G63QgK9PsNklsKLpM2S3fNlFaojafv926mlEW+C4zZ1VI8Tm5PCJOaIWJMQ==", "dependencies": { - "@types/busboy": "^0.3.1", - "@types/express": "^4.17.13", - "@types/node": "^16.11.6", - "accepts": "^1.3.7", - "busboy": "^1.0.0", - "cookie": "^0.4.1", - "cookie-signature": "^1.1.0", - "mime-types": "^2.1.33", + "busboy": "^1.6.0", + "cookie": "^1.0.1", + "cookie-signature": "^1.2.1", + "mime-types": "^2.1.35", + "negotiator": "^1.0.0", "range-parser": "^1.2.1", "type-is": "^1.6.18", "typed-emitter": "^2.1.0", - "uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.31.0" + "uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.51.0" } }, "node_modules/iconv-lite": { @@ -252,9 +146,9 @@ } }, "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", "engines": { "node": ">= 0.6" } @@ -330,111 +224,11 @@ } }, "dependencies": { - "@types/body-parser": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", - "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", - "requires": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "@types/busboy": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@types/busboy/-/busboy-0.3.2.tgz", - "integrity": "sha512-iEvdm9Z9KdSs/ozuh1Z7ZsXrOl8F4M/CLMXPZHr3QuJ4d6Bjn+HBMC5EMKpwpAo8oi8iK9GZfFoHaIMrrZgwVw==", - "requires": { - "@types/node": "*" - } - }, - "@types/connect": { - "version": "3.4.35", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", - "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", - "requires": { - "@types/node": "*" - } - }, - "@types/express": { - "version": "4.17.17", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz", - "integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==", - "requires": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.33", - "@types/qs": "*", - "@types/serve-static": "*" - } - }, - "@types/express-serve-static-core": { - "version": "4.17.35", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.35.tgz", - "integrity": "sha512-wALWQwrgiB2AWTT91CB62b6Yt0sNHpznUXeZEcnPU3DRdlDIz74x8Qg1UUYKSVFi+va5vKOLYRBI1bRKiLLKIg==", - "requires": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*", - "@types/send": "*" - } - }, "@types/geojson": { "version": "7946.0.10", "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.10.tgz", "integrity": "sha512-Nmh0K3iWQJzniTuPRcJn5hxXkfB1T1pgB89SBig5PlJQU5yocazeu4jATJlaA0GYFKWMqDdvYemoSnF2pXgLVA==" }, - "@types/http-errors": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.1.tgz", - "integrity": "sha512-/K3ds8TRAfBvi5vfjuz8y6+GiAYBZ0x4tXv1Av6CWBWn0IlADc+ZX9pMq7oU0fNQPnBwIZl3rmeLp6SBApbxSQ==" - }, - "@types/mime": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", - "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==" - }, - "@types/node": { - "version": "16.18.38", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.38.tgz", - "integrity": "sha512-6sfo1qTulpVbkxECP+AVrHV9OoJqhzCsfTNp5NIG+enM4HyM3HvZCO798WShIXBN0+QtDIcutJCjsVYnQP5rIQ==" - }, - "@types/qs": { - "version": "6.9.7", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==" - }, - "@types/range-parser": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", - "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" - }, - "@types/send": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.1.tgz", - "integrity": "sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q==", - "requires": { - "@types/mime": "^1", - "@types/node": "*" - } - }, - "@types/serve-static": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.2.tgz", - "integrity": "sha512-J2LqtvFYCzaj8pVYKw8klQXrLLk7TBZmQ4ShlcdkELFKGwGMfevMLneMMRkMgZxotOD9wg497LpC7O8PcvAmfw==", - "requires": { - "@types/http-errors": "*", - "@types/mime": "*", - "@types/node": "*" - } - }, - "accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "requires": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - } - }, "busboy": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", @@ -444,9 +238,9 @@ } }, "cookie": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", - "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==" + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", + "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==" }, "cookie-signature": { "version": "1.2.1", @@ -459,22 +253,19 @@ "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==" }, "hyper-express": { - "version": "6.8.5", - "resolved": "https://registry.npmjs.org/hyper-express/-/hyper-express-6.8.5.tgz", - "integrity": "sha512-tlHCGg0xKRHRheqY3Fgb8FvuvluCqIf6tJXiiyadsQh108g/givMqKt0XBYV+Rw0vstmmROuJ3cHXiUkQoddgg==", + "version": "6.17.3", + "resolved": "https://registry.npmjs.org/hyper-express/-/hyper-express-6.17.3.tgz", + "integrity": "sha512-fNFrRVEAIqjADtAq2F5wFRBlpo3G63QgK9PsNklsKLpM2S3fNlFaojafv926mlEW+C4zZ1VI8Tm5PCJOaIWJMQ==", "requires": { - "@types/busboy": "^0.3.1", - "@types/express": "^4.17.13", - "@types/node": "^16.11.6", - "accepts": "^1.3.7", - "busboy": "^1.0.0", - "cookie": "^0.4.1", - "cookie-signature": "^1.1.0", - "mime-types": "^2.1.33", + "busboy": "^1.6.0", + "cookie": "^1.0.1", + "cookie-signature": "^1.2.1", + "mime-types": "^2.1.35", + "negotiator": "^1.0.0", "range-parser": "^1.2.1", "type-is": "^1.6.18", "typed-emitter": "^2.1.0", - "uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.31.0" + "uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.51.0" } }, "iconv-lite": { @@ -533,9 +324,9 @@ } }, "negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==" }, "postgres": { "version": "3.3.5", @@ -591,7 +382,7 @@ }, "uWebSockets.js": { "version": "git+ssh://git@github.com/uNetworking/uWebSockets.js.git#e6ecc2102d68d99dc35969b0898fbd201e0f252b", - "from": "uWebSockets.js@github:uNetworking/uWebSockets.js#v20.31.0" + "from": "uWebSockets.js@github:uNetworking/uWebSockets.js#v20.51.0" } } } diff --git a/frameworks/JavaScript/hyperexpress/package.json b/frameworks/JavaScript/hyperexpress/package.json index ba3cacbd893..a2500fe07a5 100644 --- a/frameworks/JavaScript/hyperexpress/package.json +++ b/frameworks/JavaScript/hyperexpress/package.json @@ -8,7 +8,7 @@ "author": "", "license": "MIT", "dependencies": { - "hyper-express": "^6.8.5", + "hyper-express": "^6.17.3", "lru-cache": "^10.0.1", "mariadb": "^3.2.0", "postgres": "^3.3.5" diff --git a/frameworks/JavaScript/just/just.dockerfile b/frameworks/JavaScript/just/just.dockerfile index 9410a4d6c9b..74f5c90902e 100644 --- a/frameworks/JavaScript/just/just.dockerfile +++ b/frameworks/JavaScript/just/just.dockerfile @@ -1,11 +1,11 @@ -FROM debian:buster-slim AS pre-build +FROM debian:bookworm-slim as pre-build RUN apt update RUN apt upgrade -y RUN apt install -y g++ curl make tar gzip libfindbin-libs-perl FROM pre-build AS builder WORKDIR /build -RUN sh -c "$(curl -sSL https://raw.githubusercontent.com/just-js/just/0.1.8/install.sh)" +RUN sh -c "$(curl -sSL https://raw.githubusercontent.com/just-js/just/0.1.13/install.sh)" RUN make -C just install ENV JUST_HOME=/build/just ENV JUST_TARGET=/build/just diff --git a/frameworks/JavaScript/koa/package.json b/frameworks/JavaScript/koa/package.json index 2931b364147..353a1d3990b 100644 --- a/frameworks/JavaScript/koa/package.json +++ b/frameworks/JavaScript/koa/package.json @@ -7,12 +7,12 @@ "dependencies": { "bluebird": "3.5.1", "handlebars": "4.3.0", - "koa": "2.5.0", + "koa": "2.16.1", "koa-bodyparser": "4.2.0", "koa-hbs": "1.0.0", "koa-router": "7.4.0", "mongoose": "5.13.20", - "mysql2": "1.5.3", + "mysql2": "3.9.8", "pg": "8.5.1", "pg-hstore": "2.3.2", "sequelize": "6.29.0" diff --git a/frameworks/JavaScript/mesh/README.md b/frameworks/JavaScript/mesh/README.md new file mode 100644 index 00000000000..cf161c498e7 --- /dev/null +++ b/frameworks/JavaScript/mesh/README.md @@ -0,0 +1,48 @@ +# Mesh Benchmarking Test + +This is the [`Mesh`](https://github.com/ionited/mesh) portion of a [benchmarking test suite](../) comparing a variety of web development platforms. + +Information about Mesh can be found at https://github.com/ionited/mesh + +## Database Drivers + +There are individual handlers for each DB approach. The logic for each of them are found here: + +* [MySQL](drivers/mysql.js) +* [MongoDB](drivers/mongodb.js) +* [PostgreSQL](drivers/postgres.js) + +There are **no database endpoints** or drivers attached by default.
+To initialize the application with one of these, run any _one_ of the following commands: + +```sh +$ DATABASE=mysql node app.js +$ DATABASE=mongodb node app.js +$ DATABASE=postgres node app.js +``` + +## Test Endpoints + +> Visit the test requirements [here](https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview) + +```sh +$ curl localhost:8080/json +$ curl localhost:8080/plaintext + +# The following are only available w/ DATABASE + +$ curl localhost:8080/db +$ curl localhost:8080/fortunes + +$ curl localhost:8080/updates?queries= +$ curl localhost:8080/updates?queries=2 +$ curl localhost:8080/updates?queries=1000 +$ curl localhost:8080/updates?queries=foo +$ curl localhost:8080/updates?queries=0 + +$ curl localhost:8080/queries?queries= +$ curl localhost:8080/queries?queries=2 +$ curl localhost:8080/queries?queries=1000 +$ curl localhost:8080/queries?queries=foo +$ curl localhost:8080/queries?queries=0 +``` diff --git a/frameworks/JavaScript/mesh/app.js b/frameworks/JavaScript/mesh/app.js new file mode 100644 index 00000000000..20d9145ebab --- /dev/null +++ b/frameworks/JavaScript/mesh/app.js @@ -0,0 +1,18 @@ +const cluster = require("cluster"); +const numCPUs = require("os").cpus().length; + +if (cluster.isPrimary) { + console.log(`Primary ${process.pid} is running`); + + // Fork workers. + for (let i = 0; i < numCPUs; i++) { + cluster.fork(); + } + + cluster.on('exit', (worker, code, signal) => { + console.log(`worker ${worker.process.pid} died`); + }); +} else { + // worker task + require("./server"); +} diff --git a/frameworks/JavaScript/mesh/benchmark_config.json b/frameworks/JavaScript/mesh/benchmark_config.json new file mode 100644 index 00000000000..bf91e85e86f --- /dev/null +++ b/frameworks/JavaScript/mesh/benchmark_config.json @@ -0,0 +1,92 @@ +{ + "framework": "mesh", + "tests": [ + { + "default": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Platform", + "database": "None", + "framework": "mesh", + "language": "JavaScript", + "flavor": "NodeJS", + "orm": "Raw", + "platform": "nodejs", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "Mesh", + "notes": "", + "versus": "nodejs" + }, + "mysql": { + "dockerfile": "mesh-mysql.dockerfile", + "db_url": "/db", + "query_url": "/queries?queries=", + "fortune_url": "/fortunes", + "update_url": "/updates?queries=", + "port": 8080, + "approach": "Realistic", + "classification": "Platform", + "database": "MySQL", + "framework": "mesh", + "language": "JavaScript", + "flavor": "NodeJS", + "orm": "Raw", + "platform": "nodejs", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "Mesh", + "notes": "", + "versus": "nodejs" + }, + "postgres": { + "dockerfile": "mesh-postgres.dockerfile", + "db_url": "/db", + "query_url": "/queries?queries=", + "fortune_url": "/fortunes", + "update_url": "/updates?queries=", + "port": 8080, + "approach": "Realistic", + "classification": "Platform", + "database": "Postgres", + "framework": "mesh", + "language": "JavaScript", + "flavor": "NodeJS", + "orm": "Raw", + "platform": "None", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "Mesh", + "notes": "", + "versus": "nodejs" + }, + "mongodb": { + "dockerfile": "mesh-mongodb.dockerfile", + "db_url": "/db", + "query_url": "/queries?queries=", + "fortune_url": "/fortunes", + "update_url": "/updates?queries=", + "port": 8080, + "approach": "Realistic", + "classification": "Platform", + "database": "MongoDB", + "framework": "mesh", + "language": "JavaScript", + "flavor": "NodeJS", + "orm": "Raw", + "platform": "None", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "Mesh", + "notes": "", + "versus": "nodejs" + } + } + ] +} diff --git a/frameworks/JavaScript/polkadot/drivers/mongodb.js b/frameworks/JavaScript/mesh/drivers/mongodb.js similarity index 100% rename from frameworks/JavaScript/polkadot/drivers/mongodb.js rename to frameworks/JavaScript/mesh/drivers/mongodb.js diff --git a/frameworks/JavaScript/polkadot/drivers/mysql.js b/frameworks/JavaScript/mesh/drivers/mysql.js similarity index 100% rename from frameworks/JavaScript/polkadot/drivers/mysql.js rename to frameworks/JavaScript/mesh/drivers/mysql.js diff --git a/frameworks/JavaScript/polkadot/drivers/postgres.js b/frameworks/JavaScript/mesh/drivers/postgres.js similarity index 100% rename from frameworks/JavaScript/polkadot/drivers/postgres.js rename to frameworks/JavaScript/mesh/drivers/postgres.js diff --git a/frameworks/JavaScript/mesh/mesh-mongodb.dockerfile b/frameworks/JavaScript/mesh/mesh-mongodb.dockerfile new file mode 100644 index 00000000000..ed44c5dce07 --- /dev/null +++ b/frameworks/JavaScript/mesh/mesh-mongodb.dockerfile @@ -0,0 +1,12 @@ +FROM node:20-slim + +COPY ./ ./ + +RUN npm install + +ENV NODE_ENV production +ENV DATABASE mongodb + +EXPOSE 8080 + +CMD ["node", "app.js"] diff --git a/frameworks/JavaScript/mesh/mesh-mysql.dockerfile b/frameworks/JavaScript/mesh/mesh-mysql.dockerfile new file mode 100644 index 00000000000..4eb47cce4aa --- /dev/null +++ b/frameworks/JavaScript/mesh/mesh-mysql.dockerfile @@ -0,0 +1,12 @@ +FROM node:20-slim + +COPY ./ ./ + +RUN npm install + +ENV NODE_ENV production +ENV DATABASE mysql + +EXPOSE 8080 + +CMD ["node", "app.js"] diff --git a/frameworks/JavaScript/mesh/mesh-postgres.dockerfile b/frameworks/JavaScript/mesh/mesh-postgres.dockerfile new file mode 100644 index 00000000000..4b948d766d3 --- /dev/null +++ b/frameworks/JavaScript/mesh/mesh-postgres.dockerfile @@ -0,0 +1,12 @@ +FROM node:20-slim + +COPY ./ ./ + +RUN npm install + +ENV NODE_ENV production +ENV DATABASE postgres + +EXPOSE 8080 + +CMD ["node", "app.js"] diff --git a/frameworks/JavaScript/mesh/mesh.dockerfile b/frameworks/JavaScript/mesh/mesh.dockerfile new file mode 100644 index 00000000000..e479cd4a1e2 --- /dev/null +++ b/frameworks/JavaScript/mesh/mesh.dockerfile @@ -0,0 +1,11 @@ +FROM node:20-slim + +COPY ./ ./ + +RUN npm install + +ENV NODE_ENV production + +EXPOSE 8080 + +CMD ["node", "app.js"] diff --git a/frameworks/JavaScript/mesh/package-lock.json b/frameworks/JavaScript/mesh/package-lock.json new file mode 100644 index 00000000000..a4aa12eb197 --- /dev/null +++ b/frameworks/JavaScript/mesh/package-lock.json @@ -0,0 +1,369 @@ +{ + "name": "mesh", + "version": "0.0.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "mesh", + "version": "0.0.1", + "dependencies": { + "@ionited/mesh": "^0.6.0", + "mongodb": "^3.7.4", + "mysql": "^2.18.1", + "pg": "^8.11.3" + } + }, + "node_modules/@ionited/mesh": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@ionited/mesh/-/mesh-0.6.0.tgz", + "integrity": "sha512-SnRY0JML4Sa7WZ3J6hFibti/euRONuagTOE0QnEbwsMTzPFzVDl1fdQTO4NZKcDPVyBC74XdEUTw9+AEz+ZFlA==", + "dependencies": { + "uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.43.0" + } + }, + "node_modules/bignumber.js": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", + "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==", + "engines": { + "node": "*" + } + }, + "node_modules/bl": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz", + "integrity": "sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g==", + "dependencies": { + "readable-stream": "^2.3.5", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/bson": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.6.tgz", + "integrity": "sha512-EvVNVeGo4tHxwi8L6bPj3y3itEvStdwvvlojVxxbyYfoaxJ6keLgrTuKdyfEAszFK+H3olzBuafE0yoh0D1gdg==", + "engines": { + "node": ">=0.6.19" + } + }, + "node_modules/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==", + "engines": { + "node": ">=4" + } + }, + "node_modules/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/denque": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz", + "integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw==", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "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 + }, + "node_modules/mongodb": { + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.7.4.tgz", + "integrity": "sha512-K5q8aBqEXMwWdVNh94UQTwZ6BejVbFhh1uB6c5FKtPE9eUMZPUO3sRZdgIEcHSrAWmxzpG/FeODDKL388sqRmw==", + "dependencies": { + "bl": "^2.2.1", + "bson": "^1.1.4", + "denque": "^1.4.1", + "optional-require": "^1.1.8", + "safe-buffer": "^5.1.2" + }, + "engines": { + "node": ">=4" + }, + "optionalDependencies": { + "saslprep": "^1.0.0" + }, + "peerDependenciesMeta": { + "aws4": { + "optional": true + }, + "bson-ext": { + "optional": true + }, + "kerberos": { + "optional": true + }, + "mongodb-client-encryption": { + "optional": true + }, + "mongodb-extjson": { + "optional": true + }, + "snappy": { + "optional": true + } + } + }, + "node_modules/mysql": { + "version": "2.18.1", + "resolved": "https://registry.npmjs.org/mysql/-/mysql-2.18.1.tgz", + "integrity": "sha512-Bca+gk2YWmqp2Uf6k5NFEurwY/0td0cpebAucFpY/3jhrwrVGuxU2uQFCHjU19SJfje0yQvi+rVWdq78hR5lig==", + "dependencies": { + "bignumber.js": "9.0.0", + "readable-stream": "2.3.7", + "safe-buffer": "5.1.2", + "sqlstring": "2.3.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mysql/node_modules/sqlstring": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz", + "integrity": "sha512-ooAzh/7dxIG5+uDik1z/Rd1vli0+38izZhGzSa34FwR7IbelPWCCKSNIl8jlL/F7ERvy8CB2jNeM1E9i9mXMAQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/optional-require": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/optional-require/-/optional-require-1.1.8.tgz", + "integrity": "sha512-jq83qaUb0wNg9Krv1c5OQ+58EK+vHde6aBPzLvPPqJm89UQWsvSuFy9X/OSNJnFeSOKo7btE0n8Nl2+nE+z5nA==", + "dependencies": { + "require-at": "^1.0.6" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/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==" + }, + "node_modules/pg": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.11.3.tgz", + "integrity": "sha512-+9iuvG8QfaaUrrph+kpF24cXkH1YOOUeArRNYIxq1viYHZagBxrTno7cecY1Fa44tJeZvaoG+Djpkc3JwehN5g==", + "dependencies": { + "buffer-writer": "2.0.0", + "packet-reader": "1.0.0", + "pg-connection-string": "^2.6.2", + "pg-pool": "^3.6.1", + "pg-protocol": "^1.6.0", + "pg-types": "^2.1.0", + "pgpass": "1.x" + }, + "engines": { + "node": ">= 8.0.0" + }, + "optionalDependencies": { + "pg-cloudflare": "^1.1.1" + }, + "peerDependencies": { + "pg-native": ">=3.0.1" + }, + "peerDependenciesMeta": { + "pg-native": { + "optional": true + } + } + }, + "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==", + "optional": true + }, + "node_modules/pg-connection-string": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.2.tgz", + "integrity": "sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==" + }, + "node_modules/pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-pool": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.6.1.tgz", + "integrity": "sha512-jizsIzhkIitxCGfPRzJn1ZdcosIt3pz9Sh3V01fm1vZnbnCMgmGl5wvGGdNN2EL9Rmb0EcFoCkixH4Pu+sP9Og==", + "peerDependencies": { + "pg": ">=8.0" + } + }, + "node_modules/pg-protocol": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.6.0.tgz", + "integrity": "sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q==" + }, + "node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "dependencies": { + "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" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "dependencies": { + "split2": "^4.1.0" + } + }, + "node_modules/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==", + "engines": { + "node": ">=4" + } + }, + "node_modules/postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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==", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/require-at": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/require-at/-/require-at-1.0.6.tgz", + "integrity": "sha512-7i1auJbMUrXEAZCOQ0VNJgmcT2VOKPRl2YGJwgpHpC9CE91Mv4/4UYIUm4chGJaI381ZDq1JUicFii64Hapd8g==", + "engines": { + "node": ">=4" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/saslprep": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz", + "integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==", + "optional": true, + "dependencies": { + "sparse-bitfield": "^3.0.3" + }, + "engines": { + "node": ">=6" + } + }, + "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, + "dependencies": { + "memory-pager": "^1.0.2" + } + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/uWebSockets.js": { + "version": "20.43.0", + "resolved": "git+ssh://git@github.com/uNetworking/uWebSockets.js.git#1977b5039938ad863d42fc4958d48c17e5a1fa06", + "license": "Apache-2.0" + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } + } + } +} diff --git a/frameworks/JavaScript/mesh/package.json b/frameworks/JavaScript/mesh/package.json new file mode 100644 index 00000000000..2f65506f61e --- /dev/null +++ b/frameworks/JavaScript/mesh/package.json @@ -0,0 +1,13 @@ +{ + "name": "mesh", + "version": "0.0.1", + "description": "Mesh tests for TechEmpower Framework Benchmarks.", + "main": "app.js", + "private": true, + "dependencies": { + "@ionited/mesh": "^0.6.0", + "mongodb": "^3.7.4", + "mysql": "^2.18.1", + "pg": "^8.11.3" + } +} diff --git a/frameworks/JavaScript/mesh/server.js b/frameworks/JavaScript/mesh/server.js new file mode 100644 index 00000000000..a606c8abed3 --- /dev/null +++ b/frameworks/JavaScript/mesh/server.js @@ -0,0 +1,104 @@ +const db = process.env.DATABASE; + +const { App } = require('@ionited/mesh'); + +const addHeaders = (res, contentType) => res.header('Content-Type', contentType).header('Server', 'Mesh'); + +const escapeHTMLRules = { + "&": "&", + "<": "<", + ">": ">", + '"': """, + "'": "'", + "/": "/", +}; + +const unsafeHTMLMatcher = /[&<>"'\/]/g; + +const escape = text => { + if (unsafeHTMLMatcher.test(text) === false) return text; + return text.replace(unsafeHTMLMatcher, m => escapeHTMLRules[m] || m); +} + +const random = () => Math.floor(Math.random() * 1e4) + 1; + +const app = new App(); + +app + +.get('/json', (_, res) => { + addHeaders(res, 'application/json'); + + res.json({ message: 'Hello, World!' }); +}) + +.get('/plaintext', (_, res) => { + addHeaders(res, 'text/plain'); + + res.send('Hello, World!'); +}); + +if (db) { + const DRIVER = require(`./drivers/${db}`); + + app + + .get('/db', async (_, res) => { + addHeaders(res, 'application/json'); + + res.json(await DRIVER.find(random())); + }) + + .get('/queries', async (req, res) => { + const { queries } = req.query(); + + const count = Math.min(parseInt(queries) || 1, 500); + + const arr = []; + + for (let i = 0; i < count; i++) arr.push(await DRIVER.find(random())); + + addHeaders(res, 'application/json'); + + res.json(arr); + }) + + .get('/fortunes', async (_, res) => { + const items = [{ + id: 0, + message: 'Additional fortune added at request time.' + }, ...await DRIVER.fortunes()].sort((a, b) => a.message.localeCompare(b.message)); + + let html = 'Fortunes'; + + for (let i = 0; i < items.length; i++) html += ``; + + html += '
idmessage
${items[i].id}${escape(items[i].message)}
'; + + addHeaders(res, 'text/html; charset=utf-8'); + + res.send(html); + }) + + .get('/updates', async (req, res) => { + const { queries } = req.query(); + + const count = Math.min(parseInt(queries) || 1, 500); + + const arr = []; + + for (let i = 0; i < count; i++) arr.push(await DRIVER.find(random())); + + for (let i = 0; i < count; i++) { + arr[i].randomNumber = random(); + + await DRIVER.update(arr[i]); + } + + addHeaders(res, 'application/json'); + + res.json(arr); + }); +} + +app.listen(8080); diff --git a/frameworks/JavaScript/nodejs/handlers/mysql-raw.js b/frameworks/JavaScript/nodejs/handlers/mysql-raw.js index 5fa1ea3c625..6063b4020e4 100644 --- a/frameworks/JavaScript/nodejs/handlers/mysql-raw.js +++ b/frameworks/JavaScript/nodejs/handlers/mysql-raw.js @@ -1,6 +1,6 @@ const h = require('../helper'); const async = require('async'); -const mysql = require('mysql'); +const mysql = require('mysql2'); const connection = mysql.createConnection({ host: 'tfb-database', user: 'benchmarkdbuser', diff --git a/frameworks/JavaScript/nodejs/package.json b/frameworks/JavaScript/nodejs/package.json index 3c7a14550af..28dc35a011c 100644 --- a/frameworks/JavaScript/nodejs/package.json +++ b/frameworks/JavaScript/nodejs/package.json @@ -8,7 +8,7 @@ "mongodb": "3.7.3", "mongoose": "5.13.20", "mysql": "2.16.0", - "mysql2": "1.6.5", + "mysql2": "3.9.8", "parseurl": "1.3.2", "pg": "8.5.0", "pg-hstore": "2.3.2", diff --git a/frameworks/JavaScript/polkadot/.npmrc b/frameworks/JavaScript/polkadot/.npmrc deleted file mode 100644 index 43c97e719a5..00000000000 --- a/frameworks/JavaScript/polkadot/.npmrc +++ /dev/null @@ -1 +0,0 @@ -package-lock=false diff --git a/frameworks/JavaScript/polkadot/README.md b/frameworks/JavaScript/polkadot/README.md deleted file mode 100644 index 275cf83227d..00000000000 --- a/frameworks/JavaScript/polkadot/README.md +++ /dev/null @@ -1,49 +0,0 @@ -# Polkadot Benchmarking Test - -This is the [`polkadot`](https://github.com/lukeed/polkadot) portion of a [benchmarking test suite](../) comparing a variety of web development platforms. - -Information about Polkadot can be found at https://github.com/lukeed/polkadot - -## Database Drivers - -There are individual handlers for each DB approach. The logic for each of them are found here: - -* [MySQL](drivers/mysql.js) -* [MongoDB](drivers/mongodb.js) -* [PostgreSQL](drivers/postgres.js) - -There are **no database endpoints** or drivers attached by default.
-To initialize the application with one of these, run any _one_ of the following commands: - -```sh -$ DATABASE=mysql node app.js -$ DATABASE=mongodb node app.js -$ DATABASE=postgres node app.js -``` - -## Test Endpoints - -> Visit the test requirements [here](https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview) - -```sh -$ curl localhost:8080/json -$ curl localhost:8080/plaintext - -# The following are only available w/ DATABASE -# --- - -$ curl localhost:8080/db -$ curl localhost:8080/fortunes - -$ curl localhost:8080/updates?queries= -$ curl localhost:8080/updates?queries=2 -$ curl localhost:8080/updates?queries=1000 -$ curl localhost:8080/updates?queries=foo -$ curl localhost:8080/updates?queries=0 - -$ curl localhost:8080/queries?queries= -$ curl localhost:8080/queries?queries=2 -$ curl localhost:8080/queries?queries=1000 -$ curl localhost:8080/queries?queries=foo -$ curl localhost:8080/queries?queries=0 -``` diff --git a/frameworks/JavaScript/polkadot/app.js b/frameworks/JavaScript/polkadot/app.js deleted file mode 100755 index 0b34b676af4..00000000000 --- a/frameworks/JavaScript/polkadot/app.js +++ /dev/null @@ -1,18 +0,0 @@ -const cluster = require('cluster'); -const numCPUs = require('os').cpus().length; - -if (cluster.isMaster) { - // Fork workers. - for (let i = 0; i < numCPUs; i++) { - cluster.fork(); - } - - console.log('Master starting ' + new Date().toISOString()); - - cluster.on('exit', () => { - process.exit(1); - }); -} else { - // worker task - require('./init'); -} diff --git a/frameworks/JavaScript/polkadot/benchmark_config.json b/frameworks/JavaScript/polkadot/benchmark_config.json deleted file mode 100644 index 614c55d27ba..00000000000 --- a/frameworks/JavaScript/polkadot/benchmark_config.json +++ /dev/null @@ -1,90 +0,0 @@ -{ - "framework": "polkadot", - "tests": [ - { - "default": { - "json_url": "/json", - "plaintext_url": "/plaintext", - "port": 8080, - "approach": "Realistic", - "classification": "Platform", - "database": "None", - "framework": "polkadot", - "language": "JavaScript", - "flavor": "NodeJS", - "orm": "Raw", - "platform": "nodejs", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "polkadot", - "notes": "", - "versus": "nodejs" - }, - "mysql": { - "dockerfile": "polkadot-mysql.dockerfile", - "db_url": "/db", - "query_url": "/queries?queries=", - "fortune_url": "/fortunes", - "update_url": "/updates?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Platform", - "database": "MySQL", - "framework": "polkadot", - "language": "JavaScript", - "flavor": "NodeJS", - "orm": "Raw", - "platform": "nodejs", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "polkadot", - "notes": "", - "versus": "nodejs" - }, - "postgres": { - "db_url": "/db", - "query_url": "/queries?queries=", - "fortune_url": "/fortunes", - "update_url": "/updates?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Platform", - "database": "Postgres", - "framework": "polkadot", - "language": "JavaScript", - "flavor": "NodeJS", - "orm": "Raw", - "platform": "None", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "polkadot", - "notes": "", - "versus": "nodejs" - }, - "mongodb": { - "db_url": "/db", - "query_url": "/queries?queries=", - "fortune_url": "/fortunes", - "update_url": "/updates?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Platform", - "database": "MongoDB", - "framework": "polkadot", - "language": "JavaScript", - "flavor": "NodeJS", - "orm": "Raw", - "platform": "None", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "polkadot", - "notes": "", - "versus": "nodejs" - } - } - ] -} diff --git a/frameworks/JavaScript/polkadot/config.toml b/frameworks/JavaScript/polkadot/config.toml deleted file mode 100644 index 571a537149f..00000000000 --- a/frameworks/JavaScript/polkadot/config.toml +++ /dev/null @@ -1,61 +0,0 @@ -[framework] -name = "polkadot" - -[main] -urls.plaintext = "/plaintext" -urls.json = "/json" -approach = "Realistic" -classification = "Platform" -database = "None" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "nodejs" -webserver = "None" -versus = "nodejs" - -[mongodb] -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 = "None" -webserver = "None" -versus = "nodejs" - -[postgres] -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 = "None" -versus = "nodejs" - -[mysql] -urls.db = "/db" -urls.query = "/queries?queries=" -urls.update = "/updates?queries=" -urls.fortune = "/fortunes" -approach = "Realistic" -classification = "Platform" -database = "MySQL" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "nodejs" -webserver = "None" -versus = "nodejs" -dockerfile = "polkadot-mysql.dockerfile" diff --git a/frameworks/JavaScript/polkadot/helper.js b/frameworks/JavaScript/polkadot/helper.js deleted file mode 100644 index abdec861082..00000000000 --- a/frameworks/JavaScript/polkadot/helper.js +++ /dev/null @@ -1,8 +0,0 @@ -exports.random = () => Math.floor(Math.random() * 1e4) + 1; - -exports.parse = queries => Math.min(Math.max(parseInt(queries, 10) || 1, 1), 500); - -exports.fortune = { - id: 0, - message: 'Additional fortune added at request time.' -}; diff --git a/frameworks/JavaScript/polkadot/init.js b/frameworks/JavaScript/polkadot/init.js deleted file mode 100644 index 544a3ce92fc..00000000000 --- a/frameworks/JavaScript/polkadot/init.js +++ /dev/null @@ -1,66 +0,0 @@ -const polkadot = require('polkadot'); -const XSS = require('html-escaper'); -const helper = require('./helper'); - -const { DATABASE } = process.env; -const DRIVER = DATABASE && require(`./drivers/${DATABASE}`); - -polkadot(async (req, res) => { - res.setHeader('Server', 'Polkadot'); - - if (req.path === '/json') { - res.setHeader('Content-Type', 'application/json'); - return { message: 'Hello, World!' }; - } - - if (req.path === '/plaintext') { - return 'Hello, World!'; - } - - if (DRIVER) { - if (req.path === '/db') { - res.setHeader('Content-Type', 'application/json'); - return DRIVER.find(helper.random()); - } - - if (req.path === '/queries') { - let arr=[], num=helper.parse(req.query.queries); - while (num-- > 0) arr.push(DRIVER.find(helper.random())); - res.setHeader('Content-Type', 'application/json'); - return Promise.all(arr); - } - - if (req.path === '/fortunes') { - const items = await DRIVER.fortunes(); - items.push(helper.fortune); - - items.sort((a, b) => a.message.localeCompare(b.message)); - - let i=0, html='Fortunes'; - for (; i < items.length; i++) html += ``; - html += '
idmessage
${items[i].id}${XSS.escape(items[i].message)}
'; - - res.setHeader('Content-Type', 'text/html; charset=utf-8'); - return html; - } - - if (req.path === '/updates') { - let reads=[], num=helper.parse(req.query.queries); - while (num-- > 0) reads.push(DRIVER.find(helper.random())); - const rows = await Promise.all(reads); - - let i=0, writes=[]; - for (; i < rows.length; i++) { - rows[i].randomNumber = helper.random(); - writes.push(DRIVER.update(rows[i])); - } - - await Promise.all(writes); - res.setHeader('Content-Type', 'application/json'); - return rows; - } - } -}).listen(8080, '0.0.0.0', err => { - if (err) throw err; - console.log(`Worker started and listening on http://0.0.0.0:8080 ${new Date().toISOString()}`); -}); diff --git a/frameworks/JavaScript/polkadot/package.json b/frameworks/JavaScript/polkadot/package.json deleted file mode 100644 index 6f595e761db..00000000000 --- a/frameworks/JavaScript/polkadot/package.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "private": true, - "name": "polkadot-tfb", - "version": "0.0.0", - "main": "app.js", - "dependencies": { - "html-escaper": "1.0.1", - "mongodb": "3.2.2", - "mysql": "2.16.0", - "pg": "7.9.0", - "polkadot": "1.0.0" - } -} diff --git a/frameworks/JavaScript/polkadot/polkadot-mongodb.dockerfile b/frameworks/JavaScript/polkadot/polkadot-mongodb.dockerfile deleted file mode 100644 index be4249701f9..00000000000 --- a/frameworks/JavaScript/polkadot/polkadot-mongodb.dockerfile +++ /dev/null @@ -1,12 +0,0 @@ -FROM node:12.3.1-slim - -COPY ./ ./ - -RUN npm install - -ENV NODE_ENV production -ENV DATABASE mongodb - -EXPOSE 8080 - -CMD ["node", "app.js"] diff --git a/frameworks/JavaScript/polkadot/polkadot-mysql.dockerfile b/frameworks/JavaScript/polkadot/polkadot-mysql.dockerfile deleted file mode 100644 index 51208eb47db..00000000000 --- a/frameworks/JavaScript/polkadot/polkadot-mysql.dockerfile +++ /dev/null @@ -1,12 +0,0 @@ -FROM node:12.3.1-slim - -COPY ./ ./ - -RUN npm install - -ENV NODE_ENV production -ENV DATABASE mysql - -EXPOSE 8080 - -CMD ["node", "app.js"] diff --git a/frameworks/JavaScript/polkadot/polkadot-postgres.dockerfile b/frameworks/JavaScript/polkadot/polkadot-postgres.dockerfile deleted file mode 100644 index 1a078246bcc..00000000000 --- a/frameworks/JavaScript/polkadot/polkadot-postgres.dockerfile +++ /dev/null @@ -1,12 +0,0 @@ -FROM node:12.3.1-slim - -COPY ./ ./ - -RUN npm install - -ENV NODE_ENV production -ENV DATABASE postgres - -EXPOSE 8080 - -CMD ["node", "app.js"] diff --git a/frameworks/JavaScript/polkadot/polkadot.dockerfile b/frameworks/JavaScript/polkadot/polkadot.dockerfile deleted file mode 100644 index c3337439882..00000000000 --- a/frameworks/JavaScript/polkadot/polkadot.dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM node:12.3.1-slim - -COPY ./ ./ - -RUN npm install - -ENV NODE_ENV production - -EXPOSE 8080 - -CMD ["node", "app.js"] diff --git a/frameworks/JavaScript/sailsjs/package.json b/frameworks/JavaScript/sailsjs/package.json index 90e44e19f8e..b2886f07639 100644 --- a/frameworks/JavaScript/sailsjs/package.json +++ b/frameworks/JavaScript/sailsjs/package.json @@ -7,10 +7,10 @@ "dependencies": { "async": "1.5.2", "bluebird": "3.4.1", - "ejs": "2.5.7", + "ejs": "3.1.10", "handlebars": "4.7.6", "mysql": "2.16.0", - "mysql2": "1.6.5", + "mysql2": "3.9.8", "pg": "6.0.5", "pg-hstore": "2.3.2", "rc": "1.1.6", diff --git a/frameworks/JavaScript/spliffy/benchmark_config.json b/frameworks/JavaScript/spliffy/benchmark_config.json index 750dc5bd0cc..40dcb1614bd 100644 --- a/frameworks/JavaScript/spliffy/benchmark_config.json +++ b/frameworks/JavaScript/spliffy/benchmark_config.json @@ -19,6 +19,7 @@ "database_os": "Linux", "display_name": "spliffy", "notes": "directory based routing for node", + "tags": ["broken"], "versus": "nodejs" }, "mongodb": { @@ -41,6 +42,7 @@ "database_os": "Linux", "display_name": "spliffy", "notes": "directory based routing for node", + "tags": ["broken"], "versus": "nodejs" }, "mysql": { @@ -63,6 +65,7 @@ "database_os": "Linux", "display_name": "spliffy", "notes": "directory based routing for node", + "tags": ["broken"], "versus": "nodejs" }, "postgres": { @@ -85,6 +88,7 @@ "database_os": "Linux", "display_name": "spliffy", "notes": "directory based routing for node", + "tags": ["broken"], "versus": "nodejs" } } diff --git a/frameworks/JavaScript/spliffy/package-lock.json b/frameworks/JavaScript/spliffy/package-lock.json index 22f2726af09..114cddc45d1 100644 --- a/frameworks/JavaScript/spliffy/package-lock.json +++ b/frameworks/JavaScript/spliffy/package-lock.json @@ -4,986 +4,2619 @@ "lockfileVersion": 1, "requires": true, "dependencies": { - "@aws-crypto/crc32": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-3.0.0.tgz", - "integrity": "sha512-IzSgsrxUcsrejQbPVilIKy16kAT52EwB6zSaI+M3xxIhKh5+aldEyvI+z6erM7TCLB2BJsFrtHjp6/4/sr+3dA==", - "optional": true, - "requires": { - "@aws-crypto/util": "^3.0.0", - "@aws-sdk/types": "^3.222.0", - "tslib": "^1.11.1" + "@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": { + "@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": { - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "optional": true + "@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-crypto/ie11-detection": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/ie11-detection/-/ie11-detection-3.0.0.tgz", - "integrity": "sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q==", - "optional": true, - "requires": { - "tslib": "^1.11.1" + "@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": { - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "optional": true + "@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" + } } } }, - "@aws-crypto/sha256-browser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-3.0.0.tgz", - "integrity": "sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==", - "optional": true, - "requires": { - "@aws-crypto/ie11-detection": "^3.0.0", - "@aws-crypto/sha256-js": "^3.0.0", - "@aws-crypto/supports-web-crypto": "^3.0.0", - "@aws-crypto/util": "^3.0.0", - "@aws-sdk/types": "^3.222.0", - "@aws-sdk/util-locate-window": "^3.0.0", - "@aws-sdk/util-utf8-browser": "^3.0.0", - "tslib": "^1.11.1" + "@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": { - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "optional": true - } - } - }, - "@aws-crypto/sha256-js": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-3.0.0.tgz", - "integrity": "sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==", - "optional": true, - "requires": { - "@aws-crypto/util": "^3.0.0", - "@aws-sdk/types": "^3.222.0", - "tslib": "^1.11.1" - }, - "dependencies": { - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "optional": true - } - } - }, - "@aws-crypto/supports-web-crypto": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-3.0.0.tgz", - "integrity": "sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==", - "optional": true, - "requires": { - "tslib": "^1.11.1" - }, - "dependencies": { - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "optional": true - } - } - }, - "@aws-crypto/util": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-3.0.0.tgz", - "integrity": "sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==", - "optional": true, - "requires": { - "@aws-sdk/types": "^3.222.0", - "@aws-sdk/util-utf8-browser": "^3.0.0", - "tslib": "^1.11.1" - }, - "dependencies": { - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "optional": true + "@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" + } } } }, - "@aws-sdk/client-cognito-identity": { - "version": "3.398.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.398.0.tgz", - "integrity": "sha512-Pr/S1f8R2FsJ8DwBC6g0CSdtZNNV5dMHhlIi+t8YAmCJvP4KT+UhzFjbvQRINlBRLFuGUuP7p5vRcGVELD3+wA==", - "optional": true, - "requires": { - "@aws-crypto/sha256-browser": "3.0.0", - "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/client-sts": "3.398.0", - "@aws-sdk/credential-provider-node": "3.398.0", - "@aws-sdk/middleware-host-header": "3.398.0", - "@aws-sdk/middleware-logger": "3.398.0", - "@aws-sdk/middleware-recursion-detection": "3.398.0", - "@aws-sdk/middleware-signing": "3.398.0", - "@aws-sdk/middleware-user-agent": "3.398.0", - "@aws-sdk/types": "3.398.0", - "@aws-sdk/util-endpoints": "3.398.0", - "@aws-sdk/util-user-agent-browser": "3.398.0", - "@aws-sdk/util-user-agent-node": "3.398.0", - "@smithy/config-resolver": "^2.0.5", - "@smithy/fetch-http-handler": "^2.0.5", - "@smithy/hash-node": "^2.0.5", - "@smithy/invalid-dependency": "^2.0.5", - "@smithy/middleware-content-length": "^2.0.5", - "@smithy/middleware-endpoint": "^2.0.5", - "@smithy/middleware-retry": "^2.0.5", - "@smithy/middleware-serde": "^2.0.5", - "@smithy/middleware-stack": "^2.0.0", - "@smithy/node-config-provider": "^2.0.5", - "@smithy/node-http-handler": "^2.0.5", - "@smithy/protocol-http": "^2.0.5", - "@smithy/smithy-client": "^2.0.5", - "@smithy/types": "^2.2.2", - "@smithy/url-parser": "^2.0.5", - "@smithy/util-base64": "^2.0.0", - "@smithy/util-body-length-browser": "^2.0.0", - "@smithy/util-body-length-node": "^2.1.0", - "@smithy/util-defaults-mode-browser": "^2.0.5", - "@smithy/util-defaults-mode-node": "^2.0.5", - "@smithy/util-retry": "^2.0.0", - "@smithy/util-utf8": "^2.0.0", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/client-sso": { - "version": "3.398.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.398.0.tgz", - "integrity": "sha512-CygL0jhfibw4kmWXG/3sfZMFNjcXo66XUuPC4BqZBk8Rj5vFoxp1vZeMkDLzTIk97Nvo5J5Bh+QnXKhub6AckQ==", - "optional": true, - "requires": { - "@aws-crypto/sha256-browser": "3.0.0", - "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/middleware-host-header": "3.398.0", - "@aws-sdk/middleware-logger": "3.398.0", - "@aws-sdk/middleware-recursion-detection": "3.398.0", - "@aws-sdk/middleware-user-agent": "3.398.0", - "@aws-sdk/types": "3.398.0", - "@aws-sdk/util-endpoints": "3.398.0", - "@aws-sdk/util-user-agent-browser": "3.398.0", - "@aws-sdk/util-user-agent-node": "3.398.0", - "@smithy/config-resolver": "^2.0.5", - "@smithy/fetch-http-handler": "^2.0.5", - "@smithy/hash-node": "^2.0.5", - "@smithy/invalid-dependency": "^2.0.5", - "@smithy/middleware-content-length": "^2.0.5", - "@smithy/middleware-endpoint": "^2.0.5", - "@smithy/middleware-retry": "^2.0.5", - "@smithy/middleware-serde": "^2.0.5", - "@smithy/middleware-stack": "^2.0.0", - "@smithy/node-config-provider": "^2.0.5", - "@smithy/node-http-handler": "^2.0.5", - "@smithy/protocol-http": "^2.0.5", - "@smithy/smithy-client": "^2.0.5", - "@smithy/types": "^2.2.2", - "@smithy/url-parser": "^2.0.5", - "@smithy/util-base64": "^2.0.0", - "@smithy/util-body-length-browser": "^2.0.0", - "@smithy/util-body-length-node": "^2.1.0", - "@smithy/util-defaults-mode-browser": "^2.0.5", - "@smithy/util-defaults-mode-node": "^2.0.5", - "@smithy/util-retry": "^2.0.0", - "@smithy/util-utf8": "^2.0.0", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/client-sts": { - "version": "3.398.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.398.0.tgz", - "integrity": "sha512-/3Pa9wLMvBZipKraq3AtbmTfXW6q9kyvhwOno64f1Fz7kFb8ijQFMGoATS70B2pGEZTlxkUqJFWDiisT6Q6dFg==", - "optional": true, - "requires": { - "@aws-crypto/sha256-browser": "3.0.0", - "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/credential-provider-node": "3.398.0", - "@aws-sdk/middleware-host-header": "3.398.0", - "@aws-sdk/middleware-logger": "3.398.0", - "@aws-sdk/middleware-recursion-detection": "3.398.0", - "@aws-sdk/middleware-sdk-sts": "3.398.0", - "@aws-sdk/middleware-signing": "3.398.0", - "@aws-sdk/middleware-user-agent": "3.398.0", - "@aws-sdk/types": "3.398.0", - "@aws-sdk/util-endpoints": "3.398.0", - "@aws-sdk/util-user-agent-browser": "3.398.0", - "@aws-sdk/util-user-agent-node": "3.398.0", - "@smithy/config-resolver": "^2.0.5", - "@smithy/fetch-http-handler": "^2.0.5", - "@smithy/hash-node": "^2.0.5", - "@smithy/invalid-dependency": "^2.0.5", - "@smithy/middleware-content-length": "^2.0.5", - "@smithy/middleware-endpoint": "^2.0.5", - "@smithy/middleware-retry": "^2.0.5", - "@smithy/middleware-serde": "^2.0.5", - "@smithy/middleware-stack": "^2.0.0", - "@smithy/node-config-provider": "^2.0.5", - "@smithy/node-http-handler": "^2.0.5", - "@smithy/protocol-http": "^2.0.5", - "@smithy/smithy-client": "^2.0.5", - "@smithy/types": "^2.2.2", - "@smithy/url-parser": "^2.0.5", - "@smithy/util-base64": "^2.0.0", - "@smithy/util-body-length-browser": "^2.0.0", - "@smithy/util-body-length-node": "^2.1.0", - "@smithy/util-defaults-mode-browser": "^2.0.5", - "@smithy/util-defaults-mode-node": "^2.0.5", - "@smithy/util-retry": "^2.0.0", - "@smithy/util-utf8": "^2.0.0", - "fast-xml-parser": "4.2.5", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/credential-provider-cognito-identity": { - "version": "3.398.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.398.0.tgz", - "integrity": "sha512-MFUhy1YayHg5ypRTk4OTfDumQRP+OJBagaGv14kA8DzhKH1sNrU4HV7A7y2J4SvkN5hG/KnLJqxpakCtB2/O2g==", - "optional": true, - "requires": { - "@aws-sdk/client-cognito-identity": "3.398.0", - "@aws-sdk/types": "3.398.0", - "@smithy/property-provider": "^2.0.0", - "@smithy/types": "^2.2.2", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/credential-provider-env": { - "version": "3.398.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.398.0.tgz", - "integrity": "sha512-Z8Yj5z7FroAsR6UVML+XUdlpoqEe9Dnle8c2h8/xWwIC2feTfIBhjLhRVxfbpbM1pLgBSNEcZ7U8fwq5l7ESVQ==", - "optional": true, - "requires": { - "@aws-sdk/types": "3.398.0", - "@smithy/property-provider": "^2.0.0", - "@smithy/types": "^2.2.2", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/credential-provider-ini": { - "version": "3.398.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.398.0.tgz", - "integrity": "sha512-AsK1lStK3nB9Cn6S6ODb1ktGh7SRejsNVQVKX3t5d3tgOaX+aX1Iwy8FzM/ZEN8uCloeRifUGIY9uQFygg5mSw==", - "optional": true, - "requires": { - "@aws-sdk/credential-provider-env": "3.398.0", - "@aws-sdk/credential-provider-process": "3.398.0", - "@aws-sdk/credential-provider-sso": "3.398.0", - "@aws-sdk/credential-provider-web-identity": "3.398.0", - "@aws-sdk/types": "3.398.0", - "@smithy/credential-provider-imds": "^2.0.0", - "@smithy/property-provider": "^2.0.0", - "@smithy/shared-ini-file-loader": "^2.0.0", - "@smithy/types": "^2.2.2", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/credential-provider-node": { - "version": "3.398.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.398.0.tgz", - "integrity": "sha512-odmI/DSKfuWUYeDnGTCEHBbC8/MwnF6yEq874zl6+owoVv0ZsYP8qBHfiJkYqrwg7wQ7Pi40sSAPC1rhesGwzg==", - "optional": true, - "requires": { - "@aws-sdk/credential-provider-env": "3.398.0", - "@aws-sdk/credential-provider-ini": "3.398.0", - "@aws-sdk/credential-provider-process": "3.398.0", - "@aws-sdk/credential-provider-sso": "3.398.0", - "@aws-sdk/credential-provider-web-identity": "3.398.0", - "@aws-sdk/types": "3.398.0", - "@smithy/credential-provider-imds": "^2.0.0", - "@smithy/property-provider": "^2.0.0", - "@smithy/shared-ini-file-loader": "^2.0.0", - "@smithy/types": "^2.2.2", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/credential-provider-process": { - "version": "3.398.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.398.0.tgz", - "integrity": "sha512-WrkBL1W7TXN508PA9wRXPFtzmGpVSW98gDaHEaa8GolAPHMPa5t2QcC/z/cFpglzrcVv8SA277zu9Z8tELdZhg==", - "optional": true, - "requires": { - "@aws-sdk/types": "3.398.0", - "@smithy/property-provider": "^2.0.0", - "@smithy/shared-ini-file-loader": "^2.0.0", - "@smithy/types": "^2.2.2", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/credential-provider-sso": { - "version": "3.398.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.398.0.tgz", - "integrity": "sha512-2Dl35587xbnzR/GGZqA2MnFs8+kS4wbHQO9BioU0okA+8NRueohNMdrdQmQDdSNK4BfIpFspiZmFkXFNyEAfgw==", - "optional": true, - "requires": { - "@aws-sdk/client-sso": "3.398.0", - "@aws-sdk/token-providers": "3.398.0", - "@aws-sdk/types": "3.398.0", - "@smithy/property-provider": "^2.0.0", - "@smithy/shared-ini-file-loader": "^2.0.0", - "@smithy/types": "^2.2.2", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/credential-provider-web-identity": { - "version": "3.398.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.398.0.tgz", - "integrity": "sha512-iG3905Alv9pINbQ8/MIsshgqYMbWx+NDQWpxbIW3W0MkSH3iAqdVpSCteYidYX9G/jv2Um1nW3y360ib20bvNg==", - "optional": true, - "requires": { - "@aws-sdk/types": "3.398.0", - "@smithy/property-provider": "^2.0.0", - "@smithy/types": "^2.2.2", - "tslib": "^2.5.0" - } - }, "@aws-sdk/credential-providers": { - "version": "3.398.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.398.0.tgz", - "integrity": "sha512-355vXmImn2e85mIWSYDVb101AF2lIVHKNCaH6sV1U/8i0ZOXh2cJYNdkRYrxNt1ezDB0k97lSKvuDx7RDvJyRg==", - "optional": true, - "requires": { - "@aws-sdk/client-cognito-identity": "3.398.0", - "@aws-sdk/client-sso": "3.398.0", - "@aws-sdk/client-sts": "3.398.0", - "@aws-sdk/credential-provider-cognito-identity": "3.398.0", - "@aws-sdk/credential-provider-env": "3.398.0", - "@aws-sdk/credential-provider-ini": "3.398.0", - "@aws-sdk/credential-provider-node": "3.398.0", - "@aws-sdk/credential-provider-process": "3.398.0", - "@aws-sdk/credential-provider-sso": "3.398.0", - "@aws-sdk/credential-provider-web-identity": "3.398.0", - "@aws-sdk/types": "3.398.0", - "@smithy/credential-provider-imds": "^2.0.0", - "@smithy/property-provider": "^2.0.0", - "@smithy/types": "^2.2.2", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/middleware-host-header": { - "version": "3.398.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.398.0.tgz", - "integrity": "sha512-m+5laWdBaxIZK2ko0OwcCHJZJ5V1MgEIt8QVQ3k4/kOkN9ICjevOYmba751pHoTnbOYB7zQd6D2OT3EYEEsUcA==", - "optional": true, - "requires": { - "@aws-sdk/types": "3.398.0", - "@smithy/protocol-http": "^2.0.5", - "@smithy/types": "^2.2.2", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/middleware-logger": { - "version": "3.398.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.398.0.tgz", - "integrity": "sha512-CiJjW+FL12elS6Pn7/UVjVK8HWHhXMfvHZvOwx/Qkpy340sIhkuzOO6fZEruECDTZhl2Wqn81XdJ1ZQ4pRKpCg==", - "optional": true, - "requires": { - "@aws-sdk/types": "3.398.0", - "@smithy/types": "^2.2.2", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/middleware-recursion-detection": { - "version": "3.398.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.398.0.tgz", - "integrity": "sha512-7QpOqPQAZNXDXv6vsRex4R8dLniL0E/80OPK4PPFsrCh9btEyhN9Begh4i1T+5lL28hmYkztLOkTQ2N5J3hgRQ==", - "optional": true, - "requires": { - "@aws-sdk/types": "3.398.0", - "@smithy/protocol-http": "^2.0.5", - "@smithy/types": "^2.2.2", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/middleware-sdk-sts": { - "version": "3.398.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-sts/-/middleware-sdk-sts-3.398.0.tgz", - "integrity": "sha512-+JH76XHEgfVihkY+GurohOQ5Z83zVN1nYcQzwCFnCDTh4dG4KwhnZKG+WPw6XJECocY0R+H0ivofeALHvVWJtQ==", - "optional": true, - "requires": { - "@aws-sdk/middleware-signing": "3.398.0", - "@aws-sdk/types": "3.398.0", - "@smithy/types": "^2.2.2", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/middleware-signing": { - "version": "3.398.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.398.0.tgz", - "integrity": "sha512-O0KqXAix1TcvZBFt1qoFkHMUNJOSgjJTYS7lFTRKSwgsD27bdW2TM2r9R8DAccWFt5Amjkdt+eOwQMIXPGTm8w==", - "optional": true, - "requires": { - "@aws-sdk/types": "3.398.0", - "@smithy/property-provider": "^2.0.0", - "@smithy/protocol-http": "^2.0.5", - "@smithy/signature-v4": "^2.0.0", - "@smithy/types": "^2.2.2", - "@smithy/util-middleware": "^2.0.0", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/middleware-user-agent": { - "version": "3.398.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.398.0.tgz", - "integrity": "sha512-nF1jg0L+18b5HvTcYzwyFgfZQQMELJINFqI0mi4yRKaX7T5a3aGp5RVLGGju/6tAGTuFbfBoEhkhU3kkxexPYQ==", - "optional": true, - "requires": { - "@aws-sdk/types": "3.398.0", - "@aws-sdk/util-endpoints": "3.398.0", - "@smithy/protocol-http": "^2.0.5", - "@smithy/types": "^2.2.2", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/token-providers": { - "version": "3.398.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.398.0.tgz", - "integrity": "sha512-nrYgjzavGCKJL/48Vt0EL+OlIc5UZLfNGpgyUW9cv3XZwl+kXV0QB+HH0rHZZLfpbBgZ2RBIJR9uD5ieu/6hpQ==", - "optional": true, - "requires": { - "@aws-crypto/sha256-browser": "3.0.0", - "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/middleware-host-header": "3.398.0", - "@aws-sdk/middleware-logger": "3.398.0", - "@aws-sdk/middleware-recursion-detection": "3.398.0", - "@aws-sdk/middleware-user-agent": "3.398.0", - "@aws-sdk/types": "3.398.0", - "@aws-sdk/util-endpoints": "3.398.0", - "@aws-sdk/util-user-agent-browser": "3.398.0", - "@aws-sdk/util-user-agent-node": "3.398.0", - "@smithy/config-resolver": "^2.0.5", - "@smithy/fetch-http-handler": "^2.0.5", - "@smithy/hash-node": "^2.0.5", - "@smithy/invalid-dependency": "^2.0.5", - "@smithy/middleware-content-length": "^2.0.5", - "@smithy/middleware-endpoint": "^2.0.5", - "@smithy/middleware-retry": "^2.0.5", - "@smithy/middleware-serde": "^2.0.5", - "@smithy/middleware-stack": "^2.0.0", - "@smithy/node-config-provider": "^2.0.5", - "@smithy/node-http-handler": "^2.0.5", - "@smithy/property-provider": "^2.0.0", - "@smithy/protocol-http": "^2.0.5", - "@smithy/shared-ini-file-loader": "^2.0.0", - "@smithy/smithy-client": "^2.0.5", - "@smithy/types": "^2.2.2", - "@smithy/url-parser": "^2.0.5", - "@smithy/util-base64": "^2.0.0", - "@smithy/util-body-length-browser": "^2.0.0", - "@smithy/util-body-length-node": "^2.1.0", - "@smithy/util-defaults-mode-browser": "^2.0.5", - "@smithy/util-defaults-mode-node": "^2.0.5", - "@smithy/util-retry": "^2.0.0", - "@smithy/util-utf8": "^2.0.0", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/types": { - "version": "3.398.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.398.0.tgz", - "integrity": "sha512-r44fkS+vsEgKCuEuTV+TIk0t0m5ZlXHNjSDYEUvzLStbbfUFiNus/YG4UCa0wOk9R7VuQI67badsvvPeVPCGDQ==", - "optional": true, - "requires": { - "@smithy/types": "^2.2.2", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/util-endpoints": { - "version": "3.398.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.398.0.tgz", - "integrity": "sha512-Fy0gLYAei/Rd6BrXG4baspCnWTUSd0NdokU1pZh4KlfEAEN1i8SPPgfiO5hLk7+2inqtCmqxVJlfqbMVe9k4bw==", - "optional": true, - "requires": { - "@aws-sdk/types": "3.398.0", - "tslib": "^2.5.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==", - "optional": true, - "requires": { - "tslib": "^2.5.0" - } - }, - "@aws-sdk/util-user-agent-browser": { - "version": "3.398.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.398.0.tgz", - "integrity": "sha512-A3Tzx1tkDHlBT+IgxmsMCHbV8LM7SwwCozq2ZjJRx0nqw3MCrrcxQFXldHeX/gdUMO+0Oocb7HGSnVODTq+0EA==", - "optional": true, - "requires": { - "@aws-sdk/types": "3.398.0", - "@smithy/types": "^2.2.2", - "bowser": "^2.11.0", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/util-user-agent-node": { - "version": "3.398.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.398.0.tgz", - "integrity": "sha512-RTVQofdj961ej4//fEkppFf4KXqKGMTCqJYghx3G0C/MYXbg7MGl7LjfNGtJcboRE8pfHHQ/TUWBDA7RIAPPlQ==", - "optional": true, - "requires": { - "@aws-sdk/types": "3.398.0", - "@smithy/node-config-provider": "^2.0.5", - "@smithy/types": "^2.2.2", - "tslib": "^2.5.0" - } - }, - "@aws-sdk/util-utf8-browser": { - "version": "3.259.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.259.0.tgz", - "integrity": "sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==", - "optional": true, - "requires": { - "tslib": "^2.3.1" - } - }, - "@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, - "requires": { - "sparse-bitfield": "^3.0.3" - } - }, - "@smithy/abort-controller": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-2.0.5.tgz", - "integrity": "sha512-byVZ2KWLMPYAZGKjRpniAzLcygJO4ruClZKdJTuB0eCB76ONFTdptBHlviHpAZXknRz7skYWPfcgO9v30A1SyA==", - "optional": true, - "requires": { - "@smithy/types": "^2.2.2", - "tslib": "^2.5.0" - } - }, - "@smithy/config-resolver": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-2.0.5.tgz", - "integrity": "sha512-n0c2AXz+kjALY2FQr7Zy9zhYigXzboIh1AuUUVCqFBKFtdEvTwnwPXrTDoEehLiRTUHNL+4yzZ3s+D0kKYSLSg==", - "optional": true, - "requires": { - "@smithy/types": "^2.2.2", - "@smithy/util-config-provider": "^2.0.0", - "@smithy/util-middleware": "^2.0.0", - "tslib": "^2.5.0" - } - }, - "@smithy/credential-provider-imds": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-2.0.5.tgz", - "integrity": "sha512-KFcf/e0meFkQNyteJ65f1G19sgUEY1e5zL7hyAEUPz2SEfBmC9B37WyRq87G3MEEsvmAWwCRu7nFFYUKtR3svQ==", - "optional": true, - "requires": { - "@smithy/node-config-provider": "^2.0.5", - "@smithy/property-provider": "^2.0.5", - "@smithy/types": "^2.2.2", - "@smithy/url-parser": "^2.0.5", - "tslib": "^2.5.0" - } - }, - "@smithy/eventstream-codec": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-2.0.5.tgz", - "integrity": "sha512-iqR6OuOV3zbQK8uVs9o+9AxhVk8kW9NAxA71nugwUB+kTY9C35pUd0A5/m4PRT0Y0oIW7W4kgnSR3fdYXQjECw==", - "optional": true, - "requires": { - "@aws-crypto/crc32": "3.0.0", - "@smithy/types": "^2.2.2", - "@smithy/util-hex-encoding": "^2.0.0", - "tslib": "^2.5.0" - } - }, - "@smithy/fetch-http-handler": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-2.0.5.tgz", - "integrity": "sha512-EzFoMowdBNy1VqtvkiXgPFEdosIAt4/4bgZ8uiDiUyfhmNXq/3bV+CagPFFBsgFOR/X2XK4zFZHRsoa7PNHVVg==", - "optional": true, - "requires": { - "@smithy/protocol-http": "^2.0.5", - "@smithy/querystring-builder": "^2.0.5", - "@smithy/types": "^2.2.2", - "@smithy/util-base64": "^2.0.0", - "tslib": "^2.5.0" - } - }, - "@smithy/hash-node": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-2.0.5.tgz", - "integrity": "sha512-mk551hIywBITT+kXruRNXk7f8Fy7DTzBjZJSr/V6nolYKmUHIG3w5QU6nO9qPYEQGKc/yEPtkpdS28ndeG93lA==", - "optional": true, - "requires": { - "@smithy/types": "^2.2.2", - "@smithy/util-buffer-from": "^2.0.0", - "@smithy/util-utf8": "^2.0.0", - "tslib": "^2.5.0" - } - }, - "@smithy/invalid-dependency": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-2.0.5.tgz", - "integrity": "sha512-0wEi+JT0hM+UUwrJVYbqjuGFhy5agY/zXyiN7BNAJ1XoCDjU5uaNSj8ekPWsXd/d4yM6NSe8UbPd8cOc1+3oBQ==", - "optional": true, - "requires": { - "@smithy/types": "^2.2.2", - "tslib": "^2.5.0" - } - }, - "@smithy/is-array-buffer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.0.0.tgz", - "integrity": "sha512-z3PjFjMyZNI98JFRJi/U0nGoLWMSJlDjAW4QUX2WNZLas5C0CmVV6LJ01JI0k90l7FvpmixjWxPFmENSClQ7ug==", - "optional": true, - "requires": { - "tslib": "^2.5.0" - } - }, - "@smithy/middleware-content-length": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-2.0.5.tgz", - "integrity": "sha512-E7VwV5H02fgZIUGRli4GevBCAPvkyEI/fgl9SU47nPPi3DAAX3nEtUb8xfGbXjOcJ5BdSUoWWZn42tEd/blOqA==", - "optional": true, - "requires": { - "@smithy/protocol-http": "^2.0.5", - "@smithy/types": "^2.2.2", - "tslib": "^2.5.0" - } - }, - "@smithy/middleware-endpoint": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-2.0.5.tgz", - "integrity": "sha512-tyzDuoNTbsMQCq5Xkc4QOt6e2GACUllQIV8SQ5fc59FtOIV9/vbf58/GxVjZm2o8+MMbdDBANjTDZe/ijZKfyA==", - "optional": true, - "requires": { - "@smithy/middleware-serde": "^2.0.5", - "@smithy/types": "^2.2.2", - "@smithy/url-parser": "^2.0.5", - "@smithy/util-middleware": "^2.0.0", - "tslib": "^2.5.0" - } - }, - "@smithy/middleware-retry": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-2.0.5.tgz", - "integrity": "sha512-ulIfbFyzQTVnJbLjUl1CTSi0etg6tej/ekwaLp0Gn8ybUkDkKYa+uB6CF/m2J5B6meRwyJlsryR+DjaOVyiicg==", - "optional": true, - "requires": { - "@smithy/protocol-http": "^2.0.5", - "@smithy/service-error-classification": "^2.0.0", - "@smithy/types": "^2.2.2", - "@smithy/util-middleware": "^2.0.0", - "@smithy/util-retry": "^2.0.0", - "tslib": "^2.5.0", - "uuid": "^8.3.2" + "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": { - "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "optional": true - } - } - }, - "@smithy/middleware-serde": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-2.0.5.tgz", - "integrity": "sha512-in0AA5sous74dOfTGU9rMJBXJ0bDVNxwdXtEt5lh3FVd2sEyjhI+rqpLLRF1E4ixbw3RSEf80hfRpcPdjg4vvQ==", - "optional": true, - "requires": { - "@smithy/types": "^2.2.2", - "tslib": "^2.5.0" - } - }, - "@smithy/middleware-stack": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-2.0.0.tgz", - "integrity": "sha512-31XC1xNF65nlbc16yuh3wwTudmqs6qy4EseQUGF8A/p2m/5wdd/cnXJqpniy/XvXVwkHPz/GwV36HqzHtIKATQ==", - "optional": true, - "requires": { - "tslib": "^2.5.0" - } - }, - "@smithy/node-config-provider": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-2.0.5.tgz", - "integrity": "sha512-LRtjV9WkhONe2lVy+ipB/l1GX60ybzBmFyeRUoLUXWKdnZ3o81jsnbKzMK8hKq8eFSWPk+Lmyx6ZzCQabGeLxg==", - "optional": true, - "requires": { - "@smithy/property-provider": "^2.0.5", - "@smithy/shared-ini-file-loader": "^2.0.5", - "@smithy/types": "^2.2.2", - "tslib": "^2.5.0" - } - }, - "@smithy/node-http-handler": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-2.0.5.tgz", - "integrity": "sha512-lZm5DZf4b3V0saUw9WTC4/du887P6cy2fUyQgQQKRRV6OseButyD5yTzeMmXE53CaXJBMBsUvvIQ0hRVxIq56w==", - "optional": true, - "requires": { - "@smithy/abort-controller": "^2.0.5", - "@smithy/protocol-http": "^2.0.5", - "@smithy/querystring-builder": "^2.0.5", - "@smithy/types": "^2.2.2", - "tslib": "^2.5.0" - } - }, - "@smithy/property-provider": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-2.0.5.tgz", - "integrity": "sha512-cAFSUhX6aiHcmpWfrCLKvwBtgN1F6A0N8qY/8yeSi0LRLmhGqsY1/YTxFE185MCVzYbqBGXVr9TBv4RUcIV4rA==", - "optional": true, - "requires": { - "@smithy/types": "^2.2.2", - "tslib": "^2.5.0" - } - }, - "@smithy/protocol-http": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-2.0.5.tgz", - "integrity": "sha512-d2hhHj34mA2V86doiDfrsy2fNTnUOowGaf9hKb0hIPHqvcnShU4/OSc4Uf1FwHkAdYF3cFXTrj5VGUYbEuvMdw==", - "optional": true, - "requires": { - "@smithy/types": "^2.2.2", - "tslib": "^2.5.0" - } - }, - "@smithy/querystring-builder": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-2.0.5.tgz", - "integrity": "sha512-4DCX9krxLzATj+HdFPC3i8pb7XTAWzzKqSw8aTZMjXjtQY+vhe4azMAqIvbb6g7JKwIkmkRAjK6EXO3YWSnJVQ==", - "optional": true, - "requires": { - "@smithy/types": "^2.2.2", - "@smithy/util-uri-escape": "^2.0.0", - "tslib": "^2.5.0" - } - }, - "@smithy/querystring-parser": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-2.0.5.tgz", - "integrity": "sha512-C2stCULH0r54KBksv3AWcN8CLS3u9+WsEW8nBrvctrJ5rQTNa1waHkffpVaiKvcW2nP0aIMBPCobD/kYf/q9mA==", - "optional": true, - "requires": { - "@smithy/types": "^2.2.2", - "tslib": "^2.5.0" - } - }, - "@smithy/service-error-classification": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-2.0.0.tgz", - "integrity": "sha512-2z5Nafy1O0cTf69wKyNjGW/sNVMiqDnb4jgwfMG8ye8KnFJ5qmJpDccwIbJNhXIfbsxTg9SEec2oe1cexhMJvw==", - "optional": true - }, - "@smithy/shared-ini-file-loader": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-2.0.5.tgz", - "integrity": "sha512-Mvtk6FwMtfbKRC4YuSsIqRYp9WTxsSUJVVo2djgyhcacKGMqicHDWSAmgy3sDrKv+G/G6xTZCPwm6pJARtdxVg==", - "optional": true, - "requires": { - "@smithy/types": "^2.2.2", - "tslib": "^2.5.0" - } - }, - "@smithy/signature-v4": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-2.0.5.tgz", - "integrity": "sha512-ABIzXmUDXK4n2c9cXjQLELgH2RdtABpYKT+U131e2I6RbCypFZmxIHmIBufJzU2kdMCQ3+thBGDWorAITFW04A==", - "optional": true, - "requires": { - "@smithy/eventstream-codec": "^2.0.5", - "@smithy/is-array-buffer": "^2.0.0", - "@smithy/types": "^2.2.2", - "@smithy/util-hex-encoding": "^2.0.0", - "@smithy/util-middleware": "^2.0.0", - "@smithy/util-uri-escape": "^2.0.0", - "@smithy/util-utf8": "^2.0.0", - "tslib": "^2.5.0" - } - }, - "@smithy/smithy-client": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-2.0.5.tgz", - "integrity": "sha512-kCTFr8wfOAWKDzGvfBElc6shHigWtHNhMQ1IbosjC4jOlayFyZMSs2PysKB+Ox/dhQ41KqOzgVjgiQ+PyWqHMQ==", - "optional": true, - "requires": { - "@smithy/middleware-stack": "^2.0.0", - "@smithy/types": "^2.2.2", - "@smithy/util-stream": "^2.0.5", - "tslib": "^2.5.0" - } - }, - "@smithy/types": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-2.2.2.tgz", - "integrity": "sha512-4PS0y1VxDnELGHGgBWlDksB2LJK8TG8lcvlWxIsgR+8vROI7Ms8h1P4FQUx+ftAX2QZv5g1CJCdhdRmQKyonyw==", - "optional": true, - "requires": { - "tslib": "^2.5.0" - } - }, - "@smithy/url-parser": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-2.0.5.tgz", - "integrity": "sha512-OdMBvZhpckQSkugCXNJQCvqJ71wE7Ftxce92UOQLQ9pwF6hoS5PLL7wEfpnuEXtStzBqJYkzu1C1ZfjuFGOXAA==", - "optional": true, - "requires": { - "@smithy/querystring-parser": "^2.0.5", - "@smithy/types": "^2.2.2", - "tslib": "^2.5.0" - } - }, - "@smithy/util-base64": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-2.0.0.tgz", - "integrity": "sha512-Zb1E4xx+m5Lud8bbeYi5FkcMJMnn+1WUnJF3qD7rAdXpaL7UjkFQLdmW5fHadoKbdHpwH9vSR8EyTJFHJs++tA==", - "optional": true, - "requires": { - "@smithy/util-buffer-from": "^2.0.0", - "tslib": "^2.5.0" - } - }, - "@smithy/util-body-length-browser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-2.0.0.tgz", - "integrity": "sha512-JdDuS4ircJt+FDnaQj88TzZY3+njZ6O+D3uakS32f2VNnDo3vyEuNdBOh/oFd8Df1zSZOuH1HEChk2AOYDezZg==", - "optional": true, - "requires": { - "tslib": "^2.5.0" - } - }, - "@smithy/util-body-length-node": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-2.1.0.tgz", - "integrity": "sha512-/li0/kj/y3fQ3vyzn36NTLGmUwAICb7Jbe/CsWCktW363gh1MOcpEcSO3mJ344Gv2dqz8YJCLQpb6hju/0qOWw==", - "optional": true, - "requires": { - "tslib": "^2.5.0" - } - }, - "@smithy/util-buffer-from": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.0.0.tgz", - "integrity": "sha512-/YNnLoHsR+4W4Vf2wL5lGv0ksg8Bmk3GEGxn2vEQt52AQaPSCuaO5PM5VM7lP1K9qHRKHwrPGktqVoAHKWHxzw==", - "optional": true, - "requires": { - "@smithy/is-array-buffer": "^2.0.0", - "tslib": "^2.5.0" - } - }, - "@smithy/util-config-provider": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-2.0.0.tgz", - "integrity": "sha512-xCQ6UapcIWKxXHEU4Mcs2s7LcFQRiU3XEluM2WcCjjBtQkUN71Tb+ydGmJFPxMUrW/GWMgQEEGipLym4XG0jZg==", - "optional": true, - "requires": { - "tslib": "^2.5.0" - } - }, - "@smithy/util-defaults-mode-browser": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-2.0.5.tgz", - "integrity": "sha512-yciP6TPttLsj731aHTvekgyuCGXQrEAJibEwEWAh3kzaDsfGAVCuZSBlyvC2Dl3TZmHKCOQwHV8mIE7KQCTPuQ==", - "optional": true, - "requires": { - "@smithy/property-provider": "^2.0.5", - "@smithy/types": "^2.2.2", - "bowser": "^2.11.0", - "tslib": "^2.5.0" + "@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==" + } } }, - "@smithy/util-defaults-mode-node": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-2.0.5.tgz", - "integrity": "sha512-M07t99rWasXt+IaDZDyP3BkcoEm/mgIE1RIMASrE49LKSNxaVN7PVcgGc77+4uu2kzBAyqJKy79pgtezuknyjQ==", - "optional": true, + "@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": { - "@smithy/config-resolver": "^2.0.5", - "@smithy/credential-provider-imds": "^2.0.5", - "@smithy/node-config-provider": "^2.0.5", - "@smithy/property-provider": "^2.0.5", - "@smithy/types": "^2.2.2", - "tslib": "^2.5.0" + "@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", + "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/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" + } + } } }, - "@smithy/util-hex-encoding": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-2.0.0.tgz", - "integrity": "sha512-c5xY+NUnFqG6d7HFh1IFfrm3mGl29lC+vF+geHv4ToiuJCBmIfzx6IeHLg+OgRdPFKDXIw6pvi+p3CsscaMcMA==", - "optional": true, + "@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" } }, - "@smithy/util-middleware": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-2.0.0.tgz", - "integrity": "sha512-eCWX4ECuDHn1wuyyDdGdUWnT4OGyIzV0LN1xRttBFMPI9Ff/4heSHVxneyiMtOB//zpXWCha1/SWHJOZstG7kA==", + "@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, "requires": { - "tslib": "^2.5.0" + "sparse-bitfield": "^3.0.3" } }, - "@smithy/util-retry": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-2.0.0.tgz", - "integrity": "sha512-/dvJ8afrElasuiiIttRJeoS2sy8YXpksQwiM/TcepqdRVp7u4ejd9C4IQURHNjlfPUT7Y6lCDSa2zQJbdHhVTg==", - "optional": true, - "requires": { - "@smithy/service-error-classification": "^2.0.0", - "tslib": "^2.5.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==" + } } }, - "@smithy/util-stream": { + "@smithy/util-endpoints": { "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-2.0.5.tgz", - "integrity": "sha512-ylx27GwI05xLpYQ4hDIfS15vm+wYjNN0Sc2P0FxuzgRe8v0BOLHppGIQ+Bezcynk8C9nUzsUue3TmtRhjut43g==", - "optional": true, - "requires": { - "@smithy/fetch-http-handler": "^2.0.5", - "@smithy/node-http-handler": "^2.0.5", - "@smithy/types": "^2.2.2", - "@smithy/util-base64": "^2.0.0", - "@smithy/util-buffer-from": "^2.0.0", - "@smithy/util-hex-encoding": "^2.0.0", - "@smithy/util-utf8": "^2.0.0", - "tslib": "^2.5.0" - } - }, - "@smithy/util-uri-escape": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-2.0.0.tgz", - "integrity": "sha512-ebkxsqinSdEooQduuk9CbKcI+wheijxEb3utGXkCoYQkJnwTnLbH1JXGimJtUkQwNQbsbuYwG2+aFVyZf5TLaw==", - "optional": true, - "requires": { - "tslib": "^2.5.0" - } - }, - "@smithy/util-utf8": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.0.0.tgz", - "integrity": "sha512-rctU1VkziY84n5OXe3bPNpKR001ZCME2JCaBBFgtiM2hfKbHFudc/BkMuPab8hRbLd0j3vbnBTTZ1igBf0wgiQ==", - "optional": true, + "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-2.0.5.tgz", + "integrity": "sha512-ReQP0BWihIE68OAblC/WQmDD40Gx+QY1Ez8mTdFMXpmjfxSyz2fVQu3A4zXRfQU9sZXtewk3GmhfOHswvX+eNg==", "requires": { - "@smithy/util-buffer-from": "^2.0.0", - "tslib": "^2.5.0" + "@smithy/node-config-provider": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "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" + } + } } }, "@srfnstack/spliffy": { @@ -1032,8 +2665,7 @@ "bowser": { "version": "2.11.0", "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz", - "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==", - "optional": true + "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==" }, "bson": { "version": "4.7.2", @@ -1073,24 +2705,15 @@ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" }, "denque": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.0.tgz", - "integrity": "sha512-CYiCSgIF1p6EUByQPlGkKnP1M9g0ZV3qMIrqMqZqdwazygIA/YP2vrbcyl1h/WppKJTdl1F85cXIle+394iDAQ==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", + "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==" }, "etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" }, - "fast-xml-parser": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.2.5.tgz", - "integrity": "sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g==", - "optional": true, - "requires": { - "strnum": "^1.0.5" - } - }, "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", @@ -1128,14 +2751,14 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "ip": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", - "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.1.tgz", + "integrity": "sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==" }, "is-property": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", - "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=" + "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==" }, "isarray": { "version": "0.0.1", @@ -1152,17 +2775,14 @@ } }, "long": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", - "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", + "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==" }, "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "requires": { - "yallist": "^4.0.0" - } + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-8.0.5.tgz", + "integrity": "sha512-MhWWlVnuab1RG5/zMRRcVGXZLCXrZTgfwMikgzCegsPnG62yDQo5JnqKkrK4jO5iKqDAZGItAqN5CtKBCBWRUA==" }, "memory-pager": { "version": "1.5.0", @@ -1192,48 +2812,32 @@ } }, "mysql2": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-2.2.5.tgz", - "integrity": "sha512-XRqPNxcZTpmFdXbJqb+/CtYVLCx14x1RTeNMD4954L331APu75IC74GDqnZMEt1kwaXy6TySo55rF2F3YJS78g==", + "version": "3.9.8", + "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.9.8.tgz", + "integrity": "sha512-+5JKNjPuks1FNMoy9TYpl77f+5frbTklz7eb3XDwbpsERRLEeXiW2PDEkakYF50UuKU2qwfGnyXpKYvukv8mGA==", "requires": { - "denque": "^1.4.1", + "denque": "^2.1.0", "generate-function": "^2.3.1", - "iconv-lite": "^0.6.2", - "long": "^4.0.0", - "lru-cache": "^6.0.0", - "named-placeholders": "^1.1.2", + "iconv-lite": "^0.6.3", + "long": "^5.2.1", + "lru-cache": "^8.0.0", + "named-placeholders": "^1.1.3", "seq-queue": "^0.0.5", "sqlstring": "^2.3.2" - }, - "dependencies": { - "sqlstring": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.2.tgz", - "integrity": "sha512-vF4ZbYdKS8OnoJAWBmMxCQDkiEBkGQYU7UZPtL8flbDRSNkhaXvRJ279ZtI6M+zDaQovVU4tuRgzK5fVhvFAhg==" - } } }, "named-placeholders": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.2.tgz", - "integrity": "sha512-wiFWqxoLL3PGVReSZpjLVxyJ1bRqe+KKJVbr4hGs1KWfTZTQyezHFBbuKj9hsizHyGV2ne7EMjHdxEGAybD5SA==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.3.tgz", + "integrity": "sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==", "requires": { - "lru-cache": "^4.1.3" + "lru-cache": "^7.14.1" }, "dependencies": { "lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==" } } }, @@ -1377,11 +2981,6 @@ "xtend": "^4.0.0" } }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" - }, "punycode": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", @@ -1410,7 +3009,7 @@ "seq-queue": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", - "integrity": "sha1-1WgS4cAXpuTnw+Ojeh2m143TyT4=" + "integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==" }, "smart-buffer": { "version": "4.2.0", @@ -1443,6 +3042,11 @@ "readable-stream": "^3.0.0" } }, + "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", @@ -1454,8 +3058,7 @@ "strnum": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", - "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==", - "optional": true + "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==" }, "tr46": { "version": "3.0.0", @@ -1468,8 +3071,7 @@ "tslib": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "optional": true + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, "uWebSockets.js": { "version": "github:uNetworking/uWebSockets.js#7bf0faac5859fef2d113e83d22803f7833774c11", @@ -1503,11 +3105,6 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" } } } diff --git a/frameworks/JavaScript/spliffy/package.json b/frameworks/JavaScript/spliffy/package.json index 0d1a3d5dbf3..62b2240acf3 100644 --- a/frameworks/JavaScript/spliffy/package.json +++ b/frameworks/JavaScript/spliffy/package.json @@ -6,7 +6,7 @@ "@srfnstack/spliffy": "0.6.1", "html-escaper": "3.0.3", "mongodb": "^4.17.0", - "mysql2": "^2.2.5", + "mysql2": "^3.9.8", "node-cache": "5.1.2", "pg": "8.6.0", "pg-native": "3.0.1" diff --git a/frameworks/JavaScript/ultimate-express/README.md b/frameworks/JavaScript/ultimate-express/README.md new file mode 100644 index 00000000000..5580806833d --- /dev/null +++ b/frameworks/JavaScript/ultimate-express/README.md @@ -0,0 +1,60 @@ +# UltimateExpress Benchmarking Test + +The Ultimate Express. Fastest http server with full Express compatibility, based on [µWebSockets](https://github.com/uNetworking/uWebSockets.js). + +## Important Libraries + +The tests were run with: + +- [ultimate-express](https://github.com/dimdenGD/ultimate-express) +- [postgres](https://github.com/porsager/postgres) +- [mariadb](https://github.com/mariadb-corporation/mariadb-connector-nodejs) +- [lru-cache](https://github.com/isaacs/node-lru-cache) + +## Database + +There are individual handlers for each DB approach. The logic for each of them are found here: + +- [Postgres](database/postgres.js) +- [MySQL](database/mysql.js) + +There are **no database endpoints** or drivers attached by default. + +To initialize the application with one of these, run any _one_ of the following commands: + +```sh +$ DATABASE=postgres npm start +$ DATABASE=mysql npm start +``` + +## Test Endpoints + +> Visit the test requirements [here](https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview) + +```sh +$ curl localhost:8080/json +$ curl localhost:8080/plaintext + +# The following are only available with the DATABASE env var + +$ curl localhost:8080/db +$ curl localhost:8080/fortunes + +$ curl localhost:8080/queries?queries=2 +$ curl localhost:8080/queries?queries=0 +$ curl localhost:8080/queries?queries=foo +$ curl localhost:8080/queries?queries=501 +$ curl localhost:8080/queries?queries= + +$ curl localhost:8080/updates?queries=2 +$ curl localhost:8080/updates?queries=0 +$ curl localhost:8080/updates?queries=foo +$ curl localhost:8080/updates?queries=501 +$ curl localhost:8080/updates?queries= + +$ curl localhost:8080/cached-worlds?count=2 +$ curl localhost:8080/cached-worlds?count=0 +$ curl localhost:8080/cached-worlds?count=foo +$ curl localhost:8080/cached-worlds?count=501 +$ curl localhost:8080/cached-worlds?count= +``` diff --git a/frameworks/JavaScript/ultimate-express/app.js b/frameworks/JavaScript/ultimate-express/app.js new file mode 100755 index 00000000000..1914abf8d17 --- /dev/null +++ b/frameworks/JavaScript/ultimate-express/app.js @@ -0,0 +1,157 @@ +import express from 'ultimate-express'; +import { LRUCache } from 'lru-cache'; +import cluster, { isWorker } from 'node:cluster'; +import { maxQuery, maxRows } from './config.js'; +import fjs from 'fast-json-stringify'; + +const { DATABASE } = process.env; +const db = DATABASE ? await import(`./database/${DATABASE}.js`) : null; + +const jsonSerializer = fjs({ + type: 'object', + properties: { + message: { + type: 'string', + format: 'unsafe', + } + } +}); + +const generateRandomNumber = () => Math.floor(Math.random() * maxRows) + 1; + +const parseQueries = (i) => Math.min(parseInt(i) || 1, maxQuery); + +const escapeHTMLRules = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''', '/': '/' }; + +const unsafeHTMLMatcher = /[&<>"'\/]/g; + +const escapeHTMLCode = (text) => unsafeHTMLMatcher.test(text) ? text.replace(unsafeHTMLMatcher, function (m) { return escapeHTMLRules[m] || m; }) : text; + +const cache = new LRUCache({ + max: maxRows +}); + +const app = express(); +app.set("etag", false); +app.set("x-powered-by", false); + +app.get('/plaintext', (req, res) => { + res.setHeader('Server', 'UltimateExpress'); + res.setHeader('Content-Type', 'text/plain'); + res.end('Hello, World!'); +}); + +app.get('/json', (req, res) => { + res.setHeader('Server', 'UltimateExpress'); + res.setHeader('Content-Type', 'application/json'); + res.end(jsonSerializer({ message: "Hello, World!" })); +}); + +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; + } + }); + + app.get('/queries', async (req, res) => { + res.setHeader('Server', 'UltimateExpress'); + + try { + 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.json(worlds); + } catch (error) { + throw error; + } + }) + + app.get('/updates', async (req, res) => { + res.setHeader('Server', 'UltimateExpress'); + + try { + 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); + + for (let i = 0; i < queries; i++) { + worlds[i].randomNumber = generateRandomNumber(); + } + + await db.bulkUpdate(worlds); + + res.json(worlds); + } catch (error) { + throw error; + } + }) + + app.get('/fortunes', async (req, res) => { + res.setHeader('Server', 'UltimateExpress'); + + try { + const fortunes = await db.fortunes() + + fortunes.push({ id: 0, message: 'Additional fortune added at request time.' }); + + fortunes.sort((a, b) => (a.message < b.message) ? -1 : 1); + + const n = fortunes.length + + 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; + } + }) + + let isCachePopulated = false + app.get('/cached-worlds', async (req, res) => { + res.setHeader('Server', 'UltimateExpress'); + + 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()); + } + + res.json(worlds); + } catch (error) { + throw error; + } + }); +} + +app.listen(8080, () => { + console.log(`${isWorker ? `${cluster.worker.id}: ` : ''}Successfully bound to http://0.0.0.0:8080`); +}); \ No newline at end of file diff --git a/frameworks/JavaScript/ultimate-express/benchmark_config.json b/frameworks/JavaScript/ultimate-express/benchmark_config.json new file mode 100644 index 00000000000..c477aa24007 --- /dev/null +++ b/frameworks/JavaScript/ultimate-express/benchmark_config.json @@ -0,0 +1,70 @@ +{ + "framework": "ultimate-express", + "tests": [ + { + "default": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "None", + "framework": "ultimate-express", + "language": "JavaScript", + "flavor": "None", + "orm": "Raw", + "platform": "NodeJS", + "webserver": "µws", + "os": "Linux", + "database_os": "Linux", + "display_name": "ultimate-express", + "notes": "", + "versus": "nodejs" + }, + "postgres": { + "db_url": "/db", + "fortune_url": "/fortunes", + "query_url": "/queries?queries=", + "update_url": "/updates?queries=", + "cached_query_url": "/cached-worlds?count=", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "Postgres", + "framework": "ultimate-express", + "language": "JavaScript", + "flavor": "None", + "orm": "Raw", + "platform": "NodeJS", + "webserver": "µws", + "os": "Linux", + "database_os": "Linux", + "display_name": "ultimate-express-postgres", + "notes": "", + "versus": "nodejs" + }, + "mysql": { + "db_url": "/db", + "fortune_url": "/fortunes", + "query_url": "/queries?queries=", + "update_url": "/updates?queries=", + "cached_query_url": "/cached-worlds?count=", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "MySQL", + "framework": "ultimate-express", + "language": "JavaScript", + "flavor": "None", + "orm": "Raw", + "platform": "NodeJS", + "webserver": "µws", + "os": "Linux", + "database_os": "Linux", + "display_name": "ultimate-express-mysql", + "notes": "", + "versus": "nodejs" + } + } + ] +} diff --git a/frameworks/JavaScript/ultimate-express/clustered.js b/frameworks/JavaScript/ultimate-express/clustered.js new file mode 100644 index 00000000000..6bf96c8a57f --- /dev/null +++ b/frameworks/JavaScript/ultimate-express/clustered.js @@ -0,0 +1,15 @@ +import cluster, { isPrimary, setupPrimary, fork } from 'node:cluster' +import { cpus } from 'node:os' + +if (isPrimary) { + setupPrimary({ + exec: 'app.js', + }) + cluster.on('exit', (worker) => { + console.log(`worker ${worker.process.pid} died`) + process.exit(1) + }) + for (let i = 0; i < cpus().length; i++) { + fork() + } +} \ No newline at end of file diff --git a/frameworks/JavaScript/ultimate-express/config.js b/frameworks/JavaScript/ultimate-express/config.js new file mode 100644 index 00000000000..b85d510b405 --- /dev/null +++ b/frameworks/JavaScript/ultimate-express/config.js @@ -0,0 +1,8 @@ +export const maxQuery = 500 +export const maxRows = 10000 +export const clientOpts = { + host: 'tfb-database', + user: 'benchmarkdbuser', + password: 'benchmarkdbpass', + database: 'hello_world', +} \ No newline at end of file diff --git a/frameworks/JavaScript/ultimate-express/database/mysql.js b/frameworks/JavaScript/ultimate-express/database/mysql.js new file mode 100644 index 00000000000..5e7949997e7 --- /dev/null +++ b/frameworks/JavaScript/ultimate-express/database/mysql.js @@ -0,0 +1,15 @@ +import { createPool } from 'mariadb' +import { cpus } from 'node:os' +import { clientOpts } from '../config.js' + +const pool = createPool({ ...clientOpts, connectionLimit: cpus().length }) + +const execute = (text, values) => pool.execute(text, values || undefined) + +export const fortunes = () => execute('SELECT id, message FROM fortune') + +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 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 new file mode 100644 index 00000000000..5bfad8e13ad --- /dev/null +++ b/frameworks/JavaScript/ultimate-express/database/postgres.js @@ -0,0 +1,14 @@ +import postgres from 'postgres' +import { clientOpts } from '../config.js' + +const sql = postgres({ ...clientOpts, max: 1 }) + +export const fortunes = async () => 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 getAllWorlds = async () => sql`SELECT id, randomNumber FROM world` + +export const bulkUpdate = async (worlds) => await sql`UPDATE world SET randomNumber = (update_data.randomNumber)::int + FROM (VALUES ${sql(worlds.map(world => [world.id, world.randomNumber]).sort((a, b) => (a[0] < b[0]) ? -1 : 1))}) AS update_data (id, randomNumber) + 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 new file mode 100644 index 00000000000..682c187f205 --- /dev/null +++ b/frameworks/JavaScript/ultimate-express/package-lock.json @@ -0,0 +1,895 @@ +{ + "name": "ultimate-express", + "version": "0.0.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "ultimate-express", + "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" + } + }, + "node_modules/@fastify/merge-json-schemas": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@fastify/merge-json-schemas/-/merge-json-schemas-0.2.1.tgz", + "integrity": "sha512-OA3KGBCy6KtIvLf8DINC5880o5iBlDX4SxzLQS8HorJAbqluzLRn80UXU0bxZn7UOFhFgpRJDasfwn9nG4FG4A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT", + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.6", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", + "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", + "license": "MIT", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/express": { + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.23.tgz", + "integrity": "sha512-Crp6WY9aTYP3qPi2wGDo9iUe/rceX01UMhnF1jmwDcKCFM6cx7YhGP/Mpr3y9AASpfHixIG0E6azCcL5OcDHsQ==", + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.19.6", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz", + "integrity": "sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/geojson": { + "version": "7946.0.16", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", + "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", + "license": "MIT" + }, + "node_modules/@types/http-errors": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", + "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", + "license": "MIT" + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "24.3.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.0.tgz", + "integrity": "sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow==", + "license": "MIT", + "dependencies": { + "undici-types": "~7.10.0" + } + }, + "node_modules/@types/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==", + "license": "MIT" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "license": "MIT" + }, + "node_modules/@types/send": { + "version": "0.17.5", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.5.tgz", + "integrity": "sha512-z6F2D3cOStZvuk2SaP6YrwkNO65iTZcwA2ZkSABegdkAh/lf+Aa/YQndZVfmEXT5vgAp6zv06VQ3ejSVjAny4w==", + "license": "MIT", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.8", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.8.tgz", + "integrity": "sha512-roei0UY3LhpOJvjbIP6ZZFngyLKl5dskOtDhxY5THRSpO+ZI+nzJ+m5yUMzGrp89YRa7lvknKkMYjqQFGwA7Sg==", + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "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==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", + "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/denque": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", + "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fast-decode-uri-component": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz", + "integrity": "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==", + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "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==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT", + "dependencies": { + "@fastify/merge-json-schemas": "^0.2.0", + "ajv": "^8.12.0", + "ajv-formats": "^3.0.1", + "fast-uri": "^3.0.0", + "json-schema-ref-resolver": "^2.0.0", + "rfdc": "^1.2.0" + } + }, + "node_modules/fast-querystring": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fast-querystring/-/fast-querystring-1.1.2.tgz", + "integrity": "sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==", + "license": "MIT", + "dependencies": { + "fast-decode-uri-component": "^1.0.1" + } + }, + "node_modules/fast-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fast-zlib": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-zlib/-/fast-zlib-2.0.1.tgz", + "integrity": "sha512-DCoYgNagM2Bt1VIpXpdGnRx4LzqJeYG0oh6Nf/7cWo6elTXkFGMw9CrRCYYUIapYNrozYMoyDRflx9mgT3Awyw==", + "license": "MIT", + "funding": { + "type": "patreon", + "url": "https://patreon.com/timotejroiko" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "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==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "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==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT", + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "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" + }, + "node_modules/mariadb": { + "version": "3.4.5", + "resolved": "https://registry.npmjs.org/mariadb/-/mariadb-3.4.5.tgz", + "integrity": "sha512-gThTYkhIS5rRqkVr+Y0cIdzr+GRqJ9sA2Q34e0yzmyhMCwyApf3OKAC1jnF23aSlIOqJuyaUFUcj7O1qZslmmQ==", + "license": "LGPL-2.1-or-later", + "dependencies": { + "@types/geojson": "^7946.0.16", + "@types/node": "^24.0.13", + "denque": "^2.1.0", + "iconv-lite": "^0.6.3", + "lru-cache": "^10.4.3" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/postgres": { + "version": "3.4.7", + "resolved": "https://registry.npmjs.org/postgres/-/postgres-3.4.7.tgz", + "integrity": "sha512-Jtc2612XINuBjIl/QTWsV5UvE8UHuNblcO3vVADSrKsrc6RqGX6lOW1cEo3CM2v0XG4Nat8nI+YM7/f26VxXLw==", + "license": "Unlicense", + "engines": { + "node": ">=12" + }, + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/porsager" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/tseep": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/tseep/-/tseep-1.3.1.tgz", + "integrity": "sha512-ZPtfk1tQnZVyr7BPtbJ93qaAh2lZuIOpTMjhrYa4XctT8xe7t4SAW9LIxrySDuYMsfNNayE51E/WNGrNVgVicQ==", + "license": "MIT" + }, + "node_modules/type-is": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", + "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "license": "MIT", + "dependencies": { + "content-type": "^1.0.5", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/type-is/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/type-is/node_modules/mime-types": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "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==", + "license": "Apache-2.0", + "dependencies": { + "@types/express": "^4.17.21", + "accepts": "^1.3.8", + "acorn": "^8.14.1", + "bytes": "^3.1.2", + "cookie": "^1.0.2", + "cookie-signature": "^1.2.2", + "encodeurl": "^2.0.0", + "etag": "^1.8.1", + "fast-querystring": "^1.1.2", + "fast-zlib": "^2.0.1", + "fresh": "^0.5.2", + "mime-types": "^2.1.35", + "ms": "^2.1.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "statuses": "^2.0.1", + "tseep": "^1.3.1", + "type-is": "^2.0.1", + "uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.52.0", + "vary": "^1.1.2" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/undici-types": { + "version": "7.10.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz", + "integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==", + "license": "MIT" + }, + "node_modules/uWebSockets.js": { + "version": "20.52.0", + "resolved": "git+ssh://git@github.com/uNetworking/uWebSockets.js.git#cfc9a40d8132a34881813cec3d5f8e3a185b3ce3", + "license": "Apache-2.0" + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + } + } +} diff --git a/frameworks/JavaScript/ultimate-express/package.json b/frameworks/JavaScript/ultimate-express/package.json new file mode 100644 index 00000000000..968b92c246e --- /dev/null +++ b/frameworks/JavaScript/ultimate-express/package.json @@ -0,0 +1,18 @@ +{ + "name": "ultimate-express", + "version": "0.0.1", + "main": "app.js", + "scripts": { + "start": "node clustered.js" + }, + "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" + }, + "type": "module" +} diff --git a/frameworks/JavaScript/ultimate-express/ultimate-express-mysql.dockerfile b/frameworks/JavaScript/ultimate-express/ultimate-express-mysql.dockerfile new file mode 100644 index 00000000000..18de0be4891 --- /dev/null +++ b/frameworks/JavaScript/ultimate-express/ultimate-express-mysql.dockerfile @@ -0,0 +1,18 @@ +# syntax=docker/dockerfile:1 +FROM node:24-slim + +WORKDIR /app + +COPY --chown=node:node . . + +ENV NODE_ENV production + +RUN npm install ci + +ENV DATABASE mysql + +USER node + +EXPOSE 8080 + +CMD ["node", "clustered.js"] diff --git a/frameworks/JavaScript/ultimate-express/ultimate-express-postgres.dockerfile b/frameworks/JavaScript/ultimate-express/ultimate-express-postgres.dockerfile new file mode 100644 index 00000000000..2e055cd0857 --- /dev/null +++ b/frameworks/JavaScript/ultimate-express/ultimate-express-postgres.dockerfile @@ -0,0 +1,18 @@ +# syntax=docker/dockerfile:1 +FROM node:24-slim + +WORKDIR /app + +COPY --chown=node:node . . + +ENV NODE_ENV production + +RUN npm install ci + +ENV DATABASE postgres + +USER node + +EXPOSE 8080 + +CMD ["node", "clustered.js"] diff --git a/frameworks/JavaScript/ultimate-express/ultimate-express.dockerfile b/frameworks/JavaScript/ultimate-express/ultimate-express.dockerfile new file mode 100644 index 00000000000..cf49a184b60 --- /dev/null +++ b/frameworks/JavaScript/ultimate-express/ultimate-express.dockerfile @@ -0,0 +1,16 @@ +# syntax=docker/dockerfile:1 +FROM node:24-slim + +WORKDIR /app + +COPY --chown=node:node . . + +ENV NODE_ENV production + +RUN npm install ci + +USER node + +EXPOSE 8080 + +CMD ["node", "clustered.js"] diff --git a/frameworks/JavaScript/uwebsockets.js/README.md b/frameworks/JavaScript/uwebsockets.js/README.md index e8f8ad1162a..bc59e8c3026 100644 --- a/frameworks/JavaScript/uwebsockets.js/README.md +++ b/frameworks/JavaScript/uwebsockets.js/README.md @@ -15,7 +15,7 @@ The tests were run with: There are individual handlers for each DB approach. The logic for each of them are found here: -- [PostgreSQL](database/postgres.js) +- [PostgreSQL](src/database/postgres.js) There are **no database endpoints** or drivers attached by default. diff --git a/frameworks/JavaScript/uwebsockets.js/benchmark_config.json b/frameworks/JavaScript/uwebsockets.js/benchmark_config.json index 9c45b755447..a0ac515dcfe 100644 --- a/frameworks/JavaScript/uwebsockets.js/benchmark_config.json +++ b/frameworks/JavaScript/uwebsockets.js/benchmark_config.json @@ -4,7 +4,7 @@ { "default": { "approach": "Realistic", - "classification": "Micro", + "classification": "Platform", "database": "None", "database_os": "Linux", "display_name": "uWebSockets.js", diff --git a/frameworks/JavaScript/uwebsockets.js/package-lock.json b/frameworks/JavaScript/uwebsockets.js/package-lock.json index 6e9b94da9da..13fff11e161 100644 --- a/frameworks/JavaScript/uwebsockets.js/package-lock.json +++ b/frameworks/JavaScript/uwebsockets.js/package-lock.json @@ -9,15 +9,18 @@ "version": "0.0.1", "license": "MIT", "dependencies": { - "postgres": "^3.4.0", + "postgres": "3.4.4", "slow-json-stringify": "^2.0.1", - "uWebSockets.js": "uNetworking/uWebSockets.js#v20.32.0" + "uWebSockets.js": "uNetworking/uWebSockets.js#v20.44.0" } }, "node_modules/postgres": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/postgres/-/postgres-3.4.0.tgz", - "integrity": "sha512-d7UtSoCg4hUtzxM9aRi3J8BrM6t0h4bQmgAHG96cDCNpP9CnnWQRdRl7WWNvKs0oOaQU2InGoOi1jETmdZK02g==", + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/postgres/-/postgres-3.4.4.tgz", + "integrity": "sha512-IbyN+9KslkqcXa8AO9fxpk97PA4pzewvpi2B3Dwy9u4zpV32QicaEdgmF3eSQUzdRk7ttDHQejNgAEr4XoeH4A==", + "engines": { + "node": ">=12" + }, "funding": { "type": "individual", "url": "https://github.com/sponsors/porsager" @@ -29,8 +32,8 @@ "integrity": "sha512-jqyzIqTaSkRGcWdWqjmOLKHZgOGUT71ZCTsvQu1xGu9Mqaod7O26y5FJJEmaUQhaTWh0bkXv2qqN0i+EQsD1jQ==" }, "node_modules/uWebSockets.js": { - "version": "20.31.0", - "resolved": "git+ssh://git@github.com/uNetworking/uWebSockets.js.git#809b99d2d7d12e2cbf89b7135041e9b41ff84084" + "version": "20.44.0", + "resolved": "git+ssh://git@github.com/uNetworking/uWebSockets.js.git#8fa05571bf6ea95be8966ad313d9d39453e381ae" } } } diff --git a/frameworks/JavaScript/uwebsockets.js/package.json b/frameworks/JavaScript/uwebsockets.js/package.json index 05ac667ab57..635c0a2b12a 100644 --- a/frameworks/JavaScript/uwebsockets.js/package.json +++ b/frameworks/JavaScript/uwebsockets.js/package.json @@ -1,8 +1,8 @@ { "dependencies": { - "postgres": "^3.4.0", - "uWebSockets.js": "uNetworking/uWebSockets.js#v20.32.0", - "slow-json-stringify": "^2.0.1" + "postgres": "3.4.4", + "slow-json-stringify": "^2.0.1", + "uWebSockets.js": "uNetworking/uWebSockets.js#v20.44.0" }, "license": "MIT", "main": "src/server.js", diff --git a/frameworks/JavaScript/uwebsockets.js/src/database/postgres.js b/frameworks/JavaScript/uwebsockets.js/src/database/postgres.js index 105eeef99e5..db262a9757d 100644 --- a/frameworks/JavaScript/uwebsockets.js/src/database/postgres.js +++ b/frameworks/JavaScript/uwebsockets.js/src/database/postgres.js @@ -5,6 +5,7 @@ const sql = postgres({ user: "benchmarkdbuser", password: "benchmarkdbpass", database: "hello_world", + fetch_types: false, max: 1 }); diff --git a/frameworks/JavaScript/uwebsockets.js/src/server.js b/frameworks/JavaScript/uwebsockets.js/src/server.js index f67f33e874b..0305347a2cf 100644 --- a/frameworks/JavaScript/uwebsockets.js/src/server.js +++ b/frameworks/JavaScript/uwebsockets.js/src/server.js @@ -16,11 +16,13 @@ if (DATABASE) db = await import(`./database/${DATABASE}.js`); const webserver = uWebSockets.App(); -webserver.get("/plaintext", (response) => { - addBenchmarkHeaders(response); - response.writeHeader("Content-Type", "text/plain"); - response.end("Hello, World!"); -}); +uWebSockets._cfg('silent'); + +webserver.get("/plaintext", new uWebSockets.DeclarativeResponse() + .writeHeader("Server", "uWS") + .writeHeader("Content-Type", "text/plain") + .end("Hello, World!") +); webserver.get("/json", (response) => { addBenchmarkHeaders(response); @@ -90,7 +92,7 @@ if (db) { handleError(error, response); } }); - + const extra = { id: 0, message: "Additional fortune added at request time." }; webserver.get("/fortunes", async (response) => { diff --git a/frameworks/JavaScript/velocy/package.json b/frameworks/JavaScript/velocy/package.json index a51441b5c26..320f6058e7a 100644 --- a/frameworks/JavaScript/velocy/package.json +++ b/frameworks/JavaScript/velocy/package.json @@ -1,5 +1,5 @@ { "dependencies": { - "velocy": "0.0.13" + "velocy": "0.0.14" } } diff --git a/frameworks/Julia/oxygen/README.md b/frameworks/Julia/oxygen/README.md new file mode 100755 index 00000000000..5b7ac109195 --- /dev/null +++ b/frameworks/Julia/oxygen/README.md @@ -0,0 +1,21 @@ +# Oxygen.jl Benchmarking Test + +Oxygen is a micro-framework built on top of the HTTP.jl library and comes with helpful utilities to quickly setup and run web applications in Julia. + +### Test Type Implementation Source Code + +* [JSON](Relative/Path/To/Your/Source/File) +* [PLAINTEXT](Relative/Path/To/Your/Source/File) + +## Important Libraries +The tests were run with: +* [Oxygen.jl](https://github.com/OxygenFramework/Oxygen.jl) + +## Test URLs +### JSON + +http://localhost:8080/json + +### PLAINTEXT + +http://localhost:8080/plaintext diff --git a/frameworks/Julia/oxygen/benchmark_config.json b/frameworks/Julia/oxygen/benchmark_config.json new file mode 100755 index 00000000000..e998bb13773 --- /dev/null +++ b/frameworks/Julia/oxygen/benchmark_config.json @@ -0,0 +1,26 @@ +{ + "framework": "oxygen", + "tests": [ + { + "default": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "None", + "database": "None", + "framework": "Oxygen.jl", + "language": "Julia", + "orm": "None", + "platform": "None", + "webserver": "Oxygen.jl", + "os": "Linux", + "database_os": "Linux", + "display_name": "Oxygen.jl", + "notes": "", + "versus": "", + "tags": [] + } + } + ] +} \ No newline at end of file diff --git a/frameworks/Julia/oxygen/oxygen.dockerfile b/frameworks/Julia/oxygen/oxygen.dockerfile new file mode 100644 index 00000000000..df34f0a4b38 --- /dev/null +++ b/frameworks/Julia/oxygen/oxygen.dockerfile @@ -0,0 +1,8 @@ +FROM julia:latest + +WORKDIR /app +COPY ./src ./ +RUN julia --project -e 'using Pkg; Pkg.instantiate()' + +EXPOSE 8080 +CMD julia -t 2 --project server.jl \ No newline at end of file diff --git a/frameworks/Julia/oxygen/src/Project.toml b/frameworks/Julia/oxygen/src/Project.toml new file mode 100644 index 00000000000..dbe190679c2 --- /dev/null +++ b/frameworks/Julia/oxygen/src/Project.toml @@ -0,0 +1,4 @@ +[deps] +Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" +HTTP = "cd3eb016-35fb-5094-929b-558a96fad6f3" +Oxygen = "df9a0d86-3283-4920-82dc-4555fc0d1d8b" diff --git a/frameworks/Julia/oxygen/src/server.jl b/frameworks/Julia/oxygen/src/server.jl new file mode 100644 index 00000000000..e88c1669472 --- /dev/null +++ b/frameworks/Julia/oxygen/src/server.jl @@ -0,0 +1,23 @@ + +using Oxygen +using Dates +using HTTP + +@get "/json" function() + return json(("message" => "Hello, World!")) +end + +@get "/plaintext" function() + return text("Hello, World!") +end + +function HeaderMiddleware(handle::Function) + function(req::HTTP.Request) + response = handle(req) + HTTP.setheader(response, "Server" => "Julia-Oxygen") + HTTP.setheader(response, "Date" => Dates.format(Dates.now(), Dates.RFC1123Format) * " GMT") + return response + end +end + +serveparallel(host="0.0.0.0", port=8080, middleware=[HeaderMiddleware], access_log=nothing, metrics=false, docs=false) \ No newline at end of file diff --git a/frameworks/Kotlin/hexagon/benchmark_config.json b/frameworks/Kotlin/hexagon/benchmark_config.json index 8155e24b68c..3791218d0c8 100644 --- a/frameworks/Kotlin/hexagon/benchmark_config.json +++ b/frameworks/Kotlin/hexagon/benchmark_config.json @@ -25,7 +25,7 @@ "notes": "http://hexagonkt.com", "versus": "servlet" }, - "jetty-native": { + "jdk": { "json_url": "/json", "db_url": "/db", "query_url": "/query?queries=", @@ -44,11 +44,11 @@ "webserver": "None", "os": "Linux", "database_os": "Linux", - "display_name": "Hexagon Jetty Native PostgreSQL", + "display_name": "Hexagon JDK PostgreSQL", "notes": "http://hexagonkt.com", "versus": "servlet" }, - "jettyloom": { + "jdk-pgclient": { "json_url": "/json", "db_url": "/db", "query_url": "/query?queries=", @@ -67,30 +67,7 @@ "webserver": "None", "os": "Linux", "database_os": "Linux", - "display_name": "Hexagon Jetty Loom PostgreSQL", - "notes": "http://hexagonkt.com", - "versus": "servlet" - }, - "jettyloom-pgclient": { - "json_url": "/json", - "db_url": "/db", - "query_url": "/query?queries=", - "fortune_url": "/fortunes", - "update_url": "/update?queries=", - "cached_query_url": "/cached-queries?count=", - "plaintext_url": "/plaintext", - "port": 9090, - "approach": "Realistic", - "classification": "Micro", - "database": "postgres", - "framework": "Hexagon", - "language": "Kotlin", - "orm": "Raw", - "platform": "Servlet", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "Hexagon Jetty Loom PgClient", + "display_name": "Hexagon JDK PgClient", "notes": "http://hexagonkt.com", "versus": "servlet" }, @@ -163,29 +140,6 @@ "notes": "http://hexagonkt.com", "versus": "helidon-helidon" }, - "helidon-native": { - "json_url": "/json", - "db_url": "/db", - "query_url": "/query?queries=", - "fortune_url": "/fortunes", - "update_url": "/update?queries=", - "cached_query_url": "/cached-queries?count=", - "plaintext_url": "/plaintext", - "port": 9090, - "approach": "Realistic", - "classification": "Micro", - "database": "postgres", - "framework": "Hexagon", - "language": "Kotlin", - "orm": "Raw", - "platform": "Helidon", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "Hexagon Helidon Native PgClient", - "notes": "http://hexagonkt.com", - "versus": "helidon-helidon" - }, "helidon-pgclient": { "json_url": "/json", "db_url": "/db", diff --git a/frameworks/Kotlin/hexagon/build.gradle b/frameworks/Kotlin/hexagon/build.gradle index 06489534605..7938c3958ac 100644 --- a/frameworks/Kotlin/hexagon/build.gradle +++ b/frameworks/Kotlin/hexagon/build.gradle @@ -1,26 +1,26 @@ plugins { - id "org.jetbrains.kotlin.jvm" version "1.9.20" apply false - id "org.graalvm.buildtools.native" version "0.9.28" apply false + id "org.jetbrains.kotlin.jvm" version "2.2.20" apply false + id "org.graalvm.buildtools.native" version "0.11.1" apply false } version = "1.0.0" description = "TFB benchmark" -group = "com.hexagonkt" +group = "com.hexagontk" ext { - hexagonVersion = "3.4.3" - jettyVersion = "12.0.3" - nettyVersion = "4.1.100.Final" + hexagonVersion = "4.2.4" + jettyVersion = "12.1.1" + nettyVersion = "4.2.6.Final" - hikariVersion = "5.1.0" - postgresqlVersion = "42.6.0" - vertxVersion = "4.4.6" + hikariVersion = "7.0.2" + postgresqlVersion = "42.7.8" + vertxVersion = "5.0.4" cache2kVersion = "2.6.1.Final" - applicationClass = "com.hexagonkt.BenchmarkKt" + applicationClass = "com.hexagontk.BenchmarkKt" modules = "java.naming,java.sql,java.management" - gradleScripts = "https://raw.githubusercontent.com/hexagonkt/hexagon/$hexagonVersion/gradle" + gradleScripts = "https://raw.githubusercontent.com/hexagontk/hexagon/$hexagonVersion/gradle" } subprojects { @@ -30,5 +30,5 @@ subprojects { } tasks.wrapper { - gradleVersion = "8.4" + gradleVersion = "9.1.0" } diff --git a/frameworks/Kotlin/hexagon/config.toml b/frameworks/Kotlin/hexagon/config.toml index 6f25ab27753..c7d5be77ece 100644 --- a/frameworks/Kotlin/hexagon/config.toml +++ b/frameworks/Kotlin/hexagon/config.toml @@ -19,7 +19,7 @@ platform = "Servlet" webserver = "None" versus = "servlet" -[jettyloom] +[jdk] urls.plaintext = "/plaintext" urls.json = "/json" urls.db = "/db" @@ -37,7 +37,7 @@ platform = "Servlet" webserver = "None" versus = "servlet" -[jettyloom-pgclient] +[jdk-pgclient] urls.plaintext = "/plaintext" urls.json = "/json" urls.db = "/db" @@ -73,24 +73,6 @@ platform = "Netty" webserver = "None" versus = "netty" -[nettyepoll-native] -urls.plaintext = "/plaintext" -urls.json = "/json" -urls.db = "/db" -urls.query = "/query?queries=" -urls.update = "/update?queries=" -urls.fortune = "/fortunes" -urls.cached_query = "/cached-queries?count=" -approach = "Realistic" -classification = "Micro" -database = "postgres" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "Netty" -webserver = "None" -versus = "netty" - [nettyepoll-pgclient] urls.plaintext = "/plaintext" urls.json = "/json" @@ -127,24 +109,6 @@ platform = "Helidon" webserver = "None" versus = "helidon-helidon" -[helidon-native] -urls.plaintext = "/plaintext" -urls.json = "/json" -urls.db = "/db" -urls.query = "/query?queries=" -urls.update = "/update?queries=" -urls.fortune = "/fortunes" -urls.cached_query = "/cached-queries?count=" -approach = "Realistic" -classification = "Micro" -database = "postgres" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "Helidon" -webserver = "None" -versus = "helidon-helidon" - [helidon-pgclient] urls.plaintext = "/plaintext" urls.json = "/json" diff --git a/frameworks/Kotlin/hexagon/core/build.gradle b/frameworks/Kotlin/hexagon/core/build.gradle index 18212db6bee..8ca086d1905 100644 --- a/frameworks/Kotlin/hexagon/core/build.gradle +++ b/frameworks/Kotlin/hexagon/core/build.gradle @@ -1,16 +1,16 @@ plugins { - id("gg.jte.gradle") version("3.1.4") + id("gg.jte.gradle") version("3.2.1") } dependencies { api(project(":model")) - api("com.hexagonkt:http_server:$hexagonVersion") - api("com.hexagonkt:templates_jte:$hexagonVersion") - api("com.hexagonkt:serialization_jackson_json:$hexagonVersion") + api("com.hexagontk.http:http_server:$hexagonVersion") + api("com.hexagontk.templates:templates_jte:$hexagonVersion") + api("com.hexagontk.serialization:serialization_jackson_json:$hexagonVersion") api("org.cache2k:cache2k-core:$cache2kVersion") - jteGenerate("gg.jte:jte-native-resources:3.1.4") + jteGenerate("gg.jte:jte-native-resources:3.2.1") } tasks.register("minimizeTemplate") { diff --git a/frameworks/Kotlin/hexagon/core/src/main/kotlin/Benchmark.kt b/frameworks/Kotlin/hexagon/core/src/main/kotlin/Benchmark.kt index ef2da876dae..128b84ecbc4 100644 --- a/frameworks/Kotlin/hexagon/core/src/main/kotlin/Benchmark.kt +++ b/frameworks/Kotlin/hexagon/core/src/main/kotlin/Benchmark.kt @@ -1,10 +1,10 @@ -package com.hexagonkt +package com.hexagontk -import com.hexagonkt.http.server.HttpServer -import com.hexagonkt.http.server.HttpServerPort -import com.hexagonkt.http.server.HttpServerSettings -import com.hexagonkt.store.BenchmarkStore -import com.hexagonkt.templates.TemplatePort +import com.hexagontk.http.server.HttpServer +import com.hexagontk.http.server.HttpServerPort +import com.hexagontk.http.server.HttpServerSettings +import com.hexagontk.store.BenchmarkStore +import com.hexagontk.templates.TemplatePort import java.net.InetAddress import java.net.URL diff --git a/frameworks/Kotlin/hexagon/core/src/main/kotlin/Controller.kt b/frameworks/Kotlin/hexagon/core/src/main/kotlin/Controller.kt index 5bfd17dfcd5..78b36c61401 100644 --- a/frameworks/Kotlin/hexagon/core/src/main/kotlin/Controller.kt +++ b/frameworks/Kotlin/hexagon/core/src/main/kotlin/Controller.kt @@ -1,21 +1,21 @@ -package com.hexagonkt - -import com.hexagonkt.core.fieldsMapOf -import com.hexagonkt.core.media.APPLICATION_JSON -import com.hexagonkt.core.media.TEXT_HTML -import com.hexagonkt.core.media.TEXT_PLAIN -import com.hexagonkt.http.model.ContentType -import com.hexagonkt.http.model.Header -import com.hexagonkt.http.model.Headers -import com.hexagonkt.http.server.callbacks.DateCallback -import com.hexagonkt.http.handlers.HttpContext -import com.hexagonkt.http.handlers.PathHandler -import com.hexagonkt.http.handlers.path -import com.hexagonkt.model.* -import com.hexagonkt.serialization.jackson.json.Json -import com.hexagonkt.serialization.serialize -import com.hexagonkt.store.BenchmarkStore -import com.hexagonkt.templates.TemplatePort +package com.hexagontk + +import com.hexagontk.core.fieldsMapOf +import com.hexagontk.core.media.APPLICATION_JSON +import com.hexagontk.core.media.TEXT_HTML +import com.hexagontk.core.media.TEXT_PLAIN +import com.hexagontk.http.model.ContentType +import com.hexagontk.http.model.Field +import com.hexagontk.http.model.Headers +import com.hexagontk.http.server.callbacks.DateCallback +import com.hexagontk.http.handlers.HttpContext +import com.hexagontk.http.handlers.PathHandler +import com.hexagontk.http.handlers.path +import com.hexagontk.model.* +import com.hexagontk.serialization.jackson.json.Json +import com.hexagontk.serialization.serialize +import com.hexagontk.store.BenchmarkStore +import com.hexagontk.templates.TemplatePort import java.net.URL import java.util.concurrent.ThreadLocalRandom import kotlin.text.Charsets.UTF_8 @@ -35,7 +35,7 @@ class Controller( private val json: ContentType = ContentType(APPLICATION_JSON) private val html: ContentType = ContentType(TEXT_HTML, charset = UTF_8) - private val headers = Headers(Header("server", "Hexagon")) + private val headers = Headers(Field("server", "Hexagon")) val path: PathHandler by lazy { path { @@ -105,7 +105,7 @@ class Controller( ok(body.serialize(Json.raw), contentType = json) private fun HttpContext.getWorldsCount(parameter: String): Int = - request.queryParameters[parameter]?.string()?.toIntOrNull().let { + request.queryParameters[parameter]?.text?.toIntOrNull().let { when { it == null -> 1 it < 1 -> 1 diff --git a/frameworks/Kotlin/hexagon/core/src/main/kotlin/store/BenchmarkStore.kt b/frameworks/Kotlin/hexagon/core/src/main/kotlin/store/BenchmarkStore.kt index 5182fe4ccae..384c81580f9 100644 --- a/frameworks/Kotlin/hexagon/core/src/main/kotlin/store/BenchmarkStore.kt +++ b/frameworks/Kotlin/hexagon/core/src/main/kotlin/store/BenchmarkStore.kt @@ -1,9 +1,9 @@ -package com.hexagonkt.store +package com.hexagontk.store -import com.hexagonkt.model.CachedWorld -import com.hexagonkt.model.Fortune -import com.hexagonkt.Settings -import com.hexagonkt.model.World +import com.hexagontk.model.CachedWorld +import com.hexagontk.model.Fortune +import com.hexagontk.Settings +import com.hexagontk.model.World import org.cache2k.Cache import org.cache2k.Cache2kBuilder diff --git a/frameworks/Kotlin/hexagon/core/src/main/resources/META-INF/native-image/com.hexagonkt.benchmark/core/native-image.properties b/frameworks/Kotlin/hexagon/core/src/main/resources/META-INF/native-image/com.hexagonkt.benchmark/core/native-image.properties index 4dac65fae39..50844ff8098 100644 --- a/frameworks/Kotlin/hexagon/core/src/main/resources/META-INF/native-image/com.hexagonkt.benchmark/core/native-image.properties +++ b/frameworks/Kotlin/hexagon/core/src/main/resources/META-INF/native-image/com.hexagonkt.benchmark/core/native-image.properties @@ -2,4 +2,8 @@ Args= \ -march=native \ --static \ --libc=musl \ - --initialize-at-build-time=org.slf4j.LoggerFactory + --gc=G1 \ + --enable-sbom \ + --initialize-at-build-time=org.slf4j.LoggerFactory \ + --initialize-at-build-time=org.slf4j.helpers.Reporter \ + --initialize-at-build-time=org.slf4j.LoggerFactoinitialize-at-build-timery diff --git a/frameworks/Kotlin/hexagon/core/src/main/resources/fortunes.jte b/frameworks/Kotlin/hexagon/core/src/main/resources/fortunes.jte index 82b28ce94c3..9c9aabbdb01 100644 --- a/frameworks/Kotlin/hexagon/core/src/main/resources/fortunes.jte +++ b/frameworks/Kotlin/hexagon/core/src/main/resources/fortunes.jte @@ -1,5 +1,5 @@ @import java.util.* -@import com.hexagonkt.model.Fortune +@import com.hexagontk.model.Fortune @param List fortunes diff --git a/frameworks/Kotlin/hexagon/gradle/wrapper/gradle-wrapper.jar b/frameworks/Kotlin/hexagon/gradle/wrapper/gradle-wrapper.jar index 7f93135c49b..8bdaf60c75a 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 3fa8f862f75..2e1113280ef 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-8.4-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/frameworks/Kotlin/hexagon/gradlew b/frameworks/Kotlin/hexagon/gradlew index 1aa94a42690..adff685a034 100755 --- a/frameworks/Kotlin/hexagon/gradlew +++ b/frameworks/Kotlin/hexagon/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/. @@ -84,7 +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 "${APP_HOME:-./}" > /dev/null && pwd -P ) || 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 @@ -112,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. @@ -170,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" ) @@ -203,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/hexagon/gradlew.bat b/frameworks/Kotlin/hexagon/gradlew.bat index 93e3f59f135..c4bdd3ab8e3 100644 --- a/frameworks/Kotlin/hexagon/gradlew.bat +++ b/frameworks/Kotlin/hexagon/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/hexagon/hexagon-helidon-native.dockerfile b/frameworks/Kotlin/hexagon/hexagon-helidon-native.dockerfile index 54ddbfc48c4..2cabf6006e0 100644 --- a/frameworks/Kotlin/hexagon/hexagon-helidon-native.dockerfile +++ b/frameworks/Kotlin/hexagon/hexagon-helidon-native.dockerfile @@ -1,7 +1,7 @@ # # BUILD # -FROM ghcr.io/graalvm/native-image-community:21-muslib-ol9 as build +FROM container-registry.oracle.com/graalvm/native-image:25-muslib-ol10 as build USER root WORKDIR /hexagon @@ -16,6 +16,8 @@ RUN ./gradlew --quiet -x test hexagon_helidon_pgclient:nativeCompile FROM scratch ARG PROJECT=hexagon_helidon_pgclient +ENV maximumPoolSize 300 + COPY --from=build /hexagon/$PROJECT/build/native/nativeCompile/$PROJECT / ENTRYPOINT [ "/hexagon_helidon_pgclient" ] diff --git a/frameworks/Kotlin/hexagon/hexagon-helidon-pgclient.dockerfile b/frameworks/Kotlin/hexagon/hexagon-helidon-pgclient.dockerfile index 0ecb7488d43..a000e1e6cf1 100644 --- a/frameworks/Kotlin/hexagon/hexagon-helidon-pgclient.dockerfile +++ b/frameworks/Kotlin/hexagon/hexagon-helidon-pgclient.dockerfile @@ -1,22 +1,23 @@ # # BUILD # -FROM docker.io/gradle:8.4-jdk21-alpine AS build +FROM docker.io/bellsoft/liberica-runtime-container:jdk-all-25-cds-musl AS build USER root WORKDIR /hexagon ADD . . -RUN gradle --quiet classes -RUN gradle --quiet -x test installDist +RUN ./gradlew --quiet classes +RUN ./gradlew --quiet -x test installDist # # RUNTIME # -FROM docker.io/eclipse-temurin:21-jre-alpine +FROM docker.io/bellsoft/liberica-runtime-container:jre-25-cds-slim-musl ARG PROJECT=hexagon_helidon_pgclient ENV POSTGRESQL_DB_HOST tfb-database ENV JDK_JAVA_OPTIONS --enable-preview -XX:+AlwaysPreTouch -XX:+UseParallelGC -XX:+UseNUMA +ENV maximumPoolSize 300 COPY --from=build /hexagon/$PROJECT/build/install/$PROJECT /opt/$PROJECT diff --git a/frameworks/Kotlin/hexagon/hexagon-helidon.dockerfile b/frameworks/Kotlin/hexagon/hexagon-helidon.dockerfile index 5c790a00c72..335d6e20d9d 100644 --- a/frameworks/Kotlin/hexagon/hexagon-helidon.dockerfile +++ b/frameworks/Kotlin/hexagon/hexagon-helidon.dockerfile @@ -1,22 +1,23 @@ # # BUILD # -FROM docker.io/gradle:8.4-jdk21-alpine AS build +FROM docker.io/bellsoft/liberica-runtime-container:jdk-all-25-cds-musl AS build USER root WORKDIR /hexagon ADD . . -RUN gradle --quiet classes -RUN gradle --quiet -x test installDist +RUN ./gradlew --quiet classes +RUN ./gradlew --quiet -x test installDist # # RUNTIME # -FROM docker.io/eclipse-temurin:21-jre-alpine +FROM docker.io/bellsoft/liberica-runtime-container:jre-25-cds-slim-musl ARG PROJECT=hexagon_helidon_postgresql ENV POSTGRESQL_DB_HOST tfb-database ENV JDK_JAVA_OPTIONS --enable-preview -XX:+AlwaysPreTouch -XX:+UseParallelGC -XX:+UseNUMA +ENV maximumPoolSize 300 COPY --from=build /hexagon/$PROJECT/build/install/$PROJECT /opt/$PROJECT diff --git a/frameworks/Kotlin/hexagon/hexagon-jdk-pgclient.dockerfile b/frameworks/Kotlin/hexagon/hexagon-jdk-pgclient.dockerfile new file mode 100644 index 00000000000..d169dfcdfa2 --- /dev/null +++ b/frameworks/Kotlin/hexagon/hexagon-jdk-pgclient.dockerfile @@ -0,0 +1,24 @@ +# +# BUILD +# +FROM docker.io/bellsoft/liberica-runtime-container:jdk-all-25-cds-musl AS build +USER root +WORKDIR /hexagon + +ADD . . +RUN ./gradlew --quiet classes +RUN ./gradlew --quiet -x test installDist + +# +# RUNTIME +# +FROM docker.io/bellsoft/liberica-runtime-container:jre-25-cds-slim-musl +ARG PROJECT=hexagon_jdk_pgclient + +ENV POSTGRESQL_DB_HOST tfb-database +ENV JDK_JAVA_OPTIONS --enable-preview -XX:+AlwaysPreTouch -XX:+UseParallelGC -XX:+UseNUMA -DvirtualThreads=true +ENV maximumPoolSize 300 + +COPY --from=build /hexagon/$PROJECT/build/install/$PROJECT /opt/$PROJECT + +ENTRYPOINT [ "/opt/hexagon_jdk_pgclient/bin/hexagon_jdk_pgclient" ] diff --git a/frameworks/Kotlin/hexagon/hexagon-jdk.dockerfile b/frameworks/Kotlin/hexagon/hexagon-jdk.dockerfile new file mode 100644 index 00000000000..d80d61c88b2 --- /dev/null +++ b/frameworks/Kotlin/hexagon/hexagon-jdk.dockerfile @@ -0,0 +1,24 @@ +# +# BUILD +# +FROM docker.io/bellsoft/liberica-runtime-container:jdk-all-25-cds-musl AS build +USER root +WORKDIR /hexagon + +ADD . . +RUN ./gradlew --quiet classes +RUN ./gradlew --quiet -x test installDist + +# +# RUNTIME +# +FROM docker.io/bellsoft/liberica-runtime-container:jre-25-cds-slim-musl +ARG PROJECT=hexagon_jdk_postgresql + +ENV POSTGRESQL_DB_HOST tfb-database +ENV JDK_JAVA_OPTIONS --enable-preview -XX:+AlwaysPreTouch -XX:+UseParallelGC -XX:+UseNUMA -DvirtualThreads=true +ENV maximumPoolSize 300 + +COPY --from=build /hexagon/$PROJECT/build/install/$PROJECT /opt/$PROJECT + +ENTRYPOINT [ "/opt/hexagon_jdk_postgresql/bin/hexagon_jdk_postgresql" ] diff --git a/frameworks/Kotlin/hexagon/hexagon-jetty-native.dockerfile b/frameworks/Kotlin/hexagon/hexagon-jetty-native.dockerfile index 3e9f700ba25..1360bb8556c 100644 --- a/frameworks/Kotlin/hexagon/hexagon-jetty-native.dockerfile +++ b/frameworks/Kotlin/hexagon/hexagon-jetty-native.dockerfile @@ -1,7 +1,7 @@ # # BUILD # -FROM ghcr.io/graalvm/native-image-community:21-muslib-ol9 as build +FROM container-registry.oracle.com/graalvm/native-image:25-muslib-ol10 as build USER root WORKDIR /hexagon @@ -16,6 +16,8 @@ RUN ./gradlew --quiet -x test hexagon_jetty_postgresql:nativeCompile FROM scratch ARG PROJECT=hexagon_jetty_postgresql +ENV maximumPoolSize 300 + COPY --from=build /hexagon/$PROJECT/build/native/nativeCompile/$PROJECT / ENTRYPOINT [ "/hexagon_jetty_postgresql" ] diff --git a/frameworks/Kotlin/hexagon/hexagon-jettyloom-pgclient.dockerfile b/frameworks/Kotlin/hexagon/hexagon-jettyloom-pgclient.dockerfile deleted file mode 100644 index 10f40528c0a..00000000000 --- a/frameworks/Kotlin/hexagon/hexagon-jettyloom-pgclient.dockerfile +++ /dev/null @@ -1,23 +0,0 @@ -# -# BUILD -# -FROM docker.io/gradle:8.4-jdk21-alpine AS build -USER root -WORKDIR /hexagon - -ADD . . -RUN gradle --quiet classes -RUN gradle --quiet -x test installDist - -# -# RUNTIME -# -FROM docker.io/eclipse-temurin:21-jre-alpine -ARG PROJECT=hexagon_jetty_pgclient - -ENV POSTGRESQL_DB_HOST tfb-database -ENV JDK_JAVA_OPTIONS --enable-preview -XX:+AlwaysPreTouch -XX:+UseParallelGC -XX:+UseNUMA -DvirtualThreads=true - -COPY --from=build /hexagon/$PROJECT/build/install/$PROJECT /opt/$PROJECT - -ENTRYPOINT [ "/opt/hexagon_jetty_pgclient/bin/hexagon_jetty_pgclient" ] diff --git a/frameworks/Kotlin/hexagon/hexagon-jettyloom.dockerfile b/frameworks/Kotlin/hexagon/hexagon-jettyloom.dockerfile deleted file mode 100644 index ce807d1c2fe..00000000000 --- a/frameworks/Kotlin/hexagon/hexagon-jettyloom.dockerfile +++ /dev/null @@ -1,23 +0,0 @@ -# -# BUILD -# -FROM docker.io/gradle:8.4-jdk21-alpine AS build -USER root -WORKDIR /hexagon - -ADD . . -RUN gradle --quiet classes -RUN gradle --quiet -x test installDist - -# -# RUNTIME -# -FROM docker.io/eclipse-temurin:21-jre-alpine -ARG PROJECT=hexagon_jetty_postgresql - -ENV POSTGRESQL_DB_HOST tfb-database -ENV JDK_JAVA_OPTIONS --enable-preview -XX:+AlwaysPreTouch -XX:+UseParallelGC -XX:+UseNUMA -DvirtualThreads=true - -COPY --from=build /hexagon/$PROJECT/build/install/$PROJECT /opt/$PROJECT - -ENTRYPOINT [ "/opt/hexagon_jetty_postgresql/bin/hexagon_jetty_postgresql" ] diff --git a/frameworks/Kotlin/hexagon/hexagon-nettyepoll-pgclient.dockerfile b/frameworks/Kotlin/hexagon/hexagon-nettyepoll-pgclient.dockerfile index d07a610bcd8..957951bc713 100644 --- a/frameworks/Kotlin/hexagon/hexagon-nettyepoll-pgclient.dockerfile +++ b/frameworks/Kotlin/hexagon/hexagon-nettyepoll-pgclient.dockerfile @@ -1,22 +1,23 @@ # # BUILD # -FROM docker.io/gradle:8.4-jdk21-alpine AS build +FROM docker.io/bellsoft/liberica-runtime-container:jdk-all-25-cds-musl AS build USER root WORKDIR /hexagon ADD . . -RUN gradle --quiet classes -RUN gradle --quiet -x test installDist +RUN ./gradlew --quiet classes +RUN ./gradlew --quiet -x test installDist # # RUNTIME # -FROM docker.io/eclipse-temurin:21-jre-alpine +FROM docker.io/bellsoft/liberica-runtime-container:jre-25-cds-slim-musl ARG PROJECT=hexagon_nettyepoll_pgclient ENV POSTGRESQL_DB_HOST tfb-database ENV JDK_JAVA_OPTIONS -XX:+AlwaysPreTouch -XX:+UseParallelGC -XX:+UseNUMA +ENV maximumPoolSize 300 COPY --from=build /hexagon/$PROJECT/build/install/$PROJECT /opt/$PROJECT diff --git a/frameworks/Kotlin/hexagon/hexagon-nettyepoll.dockerfile b/frameworks/Kotlin/hexagon/hexagon-nettyepoll.dockerfile index c813f85bf27..64e5077b30e 100644 --- a/frameworks/Kotlin/hexagon/hexagon-nettyepoll.dockerfile +++ b/frameworks/Kotlin/hexagon/hexagon-nettyepoll.dockerfile @@ -1,22 +1,23 @@ # # BUILD # -FROM docker.io/gradle:8.4-jdk21-alpine AS build +FROM docker.io/bellsoft/liberica-runtime-container:jdk-all-25-cds-musl AS build USER root WORKDIR /hexagon ADD . . -RUN gradle --quiet classes -RUN gradle --quiet -x test installDist +RUN ./gradlew --quiet classes +RUN ./gradlew --quiet -x test installDist # # RUNTIME # -FROM docker.io/eclipse-temurin:21-jre-alpine +FROM docker.io/bellsoft/liberica-runtime-container:jre-25-cds-slim-musl ARG PROJECT=hexagon_nettyepoll_postgresql ENV POSTGRESQL_DB_HOST tfb-database ENV JDK_JAVA_OPTIONS -XX:+AlwaysPreTouch -XX:+UseParallelGC -XX:+UseNUMA +ENV maximumPoolSize 300 COPY --from=build /hexagon/$PROJECT/build/install/$PROJECT /opt/$PROJECT diff --git a/frameworks/Kotlin/hexagon/hexagon-tomcat.dockerfile b/frameworks/Kotlin/hexagon/hexagon-tomcat.dockerfile index c28cb74d5d4..50a13f35392 100644 --- a/frameworks/Kotlin/hexagon/hexagon-tomcat.dockerfile +++ b/frameworks/Kotlin/hexagon/hexagon-tomcat.dockerfile @@ -1,21 +1,22 @@ # # BUILD # -FROM docker.io/gradle:8.4-jdk21-alpine AS build +FROM docker.io/bellsoft/liberica-runtime-container:jdk-all-25-cds-musl AS build USER root WORKDIR /hexagon ADD . . -RUN gradle --quiet classes -RUN gradle --quiet -x test war +RUN ./gradlew --quiet classes +RUN ./gradlew --quiet -x test war # # RUNTIME # -FROM docker.io/tomcat:10-jre21-temurin-jammy +FROM docker.io/tomcat:11-jre25-temurin-noble ARG MODULE=/hexagon/hexagon_tomcat_postgresql ENV POSTGRESQL_DB_HOST tfb-database ENV JDK_JAVA_OPTIONS -XX:+AlwaysPreTouch -XX:+UseParallelGC -XX:+UseNUMA +ENV maximumPoolSize 300 COPY --from=build $MODULE/build/libs/ROOT.war /usr/local/tomcat/webapps/ROOT.war diff --git a/frameworks/Kotlin/hexagon/hexagon.dockerfile b/frameworks/Kotlin/hexagon/hexagon.dockerfile index 7723b0cae2d..7d7a48b0e6b 100644 --- a/frameworks/Kotlin/hexagon/hexagon.dockerfile +++ b/frameworks/Kotlin/hexagon/hexagon.dockerfile @@ -1,22 +1,23 @@ # # BUILD # -FROM docker.io/gradle:8.4-jdk21-alpine AS build +FROM docker.io/bellsoft/liberica-runtime-container:jdk-all-25-cds-musl AS build USER root WORKDIR /hexagon ADD . . -RUN gradle --quiet classes -RUN gradle --quiet -x test installDist +RUN ./gradlew --quiet classes +RUN ./gradlew --quiet -x test installDist # # RUNTIME # -FROM docker.io/eclipse-temurin:21-jre-alpine +FROM docker.io/bellsoft/liberica-runtime-container:jre-25-cds-slim-musl ARG PROJECT=hexagon_jetty_postgresql ENV POSTGRESQL_DB_HOST tfb-database ENV JDK_JAVA_OPTIONS -XX:+AlwaysPreTouch -XX:+UseParallelGC -XX:+UseNUMA +ENV maximumPoolSize 300 COPY --from=build /hexagon/$PROJECT/build/install/$PROJECT /opt/$PROJECT diff --git a/frameworks/Kotlin/hexagon/hexagon_helidon_pgclient/build.gradle b/frameworks/Kotlin/hexagon/hexagon_helidon_pgclient/build.gradle index 5e64c7bde3f..68a431b25a8 100644 --- a/frameworks/Kotlin/hexagon/hexagon_helidon_pgclient/build.gradle +++ b/frameworks/Kotlin/hexagon/hexagon_helidon_pgclient/build.gradle @@ -4,5 +4,5 @@ apply(from: "$gradleScripts/native.gradle") dependencies { api(project(":store_pgclient")) - api("com.hexagonkt:http_server_helidon:$hexagonVersion") + api("com.hexagontk.http:http_server_helidon:$hexagonVersion") } diff --git a/frameworks/Kotlin/hexagon/hexagon_helidon_pgclient/src/main/kotlin/Benchmark.kt b/frameworks/Kotlin/hexagon/hexagon_helidon_pgclient/src/main/kotlin/Benchmark.kt index d38d33281f8..61018ea73bf 100644 --- a/frameworks/Kotlin/hexagon/hexagon_helidon_pgclient/src/main/kotlin/Benchmark.kt +++ b/frameworks/Kotlin/hexagon/hexagon_helidon_pgclient/src/main/kotlin/Benchmark.kt @@ -1,18 +1,31 @@ -package com.hexagonkt +package com.hexagontk -import com.hexagonkt.core.media.TEXT_HTML -import com.hexagonkt.core.urlOf -import com.hexagonkt.http.server.helidon.HelidonServerAdapter -import com.hexagonkt.store.BenchmarkPgClientStore -import com.hexagonkt.templates.jte.JteAdapter +import com.hexagontk.core.Platform.systemSettingOrNull +import com.hexagontk.core.media.TEXT_HTML +import com.hexagontk.core.urlOf +import com.hexagontk.http.server.helidon.HelidonHttpServer +import com.hexagontk.store.BenchmarkPgClientStore +import com.hexagontk.templates.jte.Jte +import java.time.Duration fun main() { - val settings = Settings() val store = BenchmarkPgClientStore("postgresql") - val templateEngine = JteAdapter(TEXT_HTML, precompiled = true) + val templateEngine = Jte(TEXT_HTML, precompiled = true) val templateUrl = urlOf("classpath:fortunes.jte") - val engine = HelidonServerAdapter() + val engine = HelidonHttpServer( + backlog = systemSettingOrNull("backlog") ?: (8 * 1024), + writeQueueLength = systemSettingOrNull("writeQueueLength") ?: (8 * 1024), + readTimeout = Duration.parse(systemSettingOrNull("readTimeout") ?: "PT0S"), + connectTimeout = Duration.parse(systemSettingOrNull("connectTimeout") ?: "PT0S"), + tcpNoDelay = systemSettingOrNull("tcpNoDelay") ?: true, + receiveLog = systemSettingOrNull("receiveLog") ?: false, + sendLog = systemSettingOrNull("sendLog") ?: false, + validatePath = systemSettingOrNull("validatePath") ?: false, + validateRequestHeaders = systemSettingOrNull("validateRequestHeaders") ?: false, + validateResponseHeaders = systemSettingOrNull("validateResponseHeaders") ?: false, + smartAsyncWrites = true, + ) - val benchmark = Benchmark(engine, store, templateEngine, templateUrl, settings) + val benchmark = Benchmark(engine, store, templateEngine, templateUrl, Settings()) benchmark.server.start() } diff --git a/frameworks/Kotlin/hexagon/hexagon_helidon_pgclient/src/main/resources/META-INF/native-image/com.hexagonkt.benchmark/helidon_pgclient/native-image.properties b/frameworks/Kotlin/hexagon/hexagon_helidon_pgclient/src/main/resources/META-INF/native-image/com.hexagonkt.benchmark/helidon_pgclient/native-image.properties new file mode 100644 index 00000000000..85b899d04fb --- /dev/null +++ b/frameworks/Kotlin/hexagon/hexagon_helidon_pgclient/src/main/resources/META-INF/native-image/com.hexagonkt.benchmark/helidon_pgclient/native-image.properties @@ -0,0 +1,2 @@ +Args= \ + --initialize-at-build-time=io.vertx.core.impl.buffer.VertxByteBufAllocator diff --git a/frameworks/Kotlin/hexagon/hexagon_helidon_postgresql/build.gradle b/frameworks/Kotlin/hexagon/hexagon_helidon_postgresql/build.gradle index 1fb3fbffab6..2fa5b450d0c 100644 --- a/frameworks/Kotlin/hexagon/hexagon_helidon_postgresql/build.gradle +++ b/frameworks/Kotlin/hexagon/hexagon_helidon_postgresql/build.gradle @@ -3,5 +3,5 @@ apply(from: "$gradleScripts/application.gradle") dependencies { api(project(":store_sql")) - api("com.hexagonkt:http_server_helidon:$hexagonVersion") + api("com.hexagontk.http:http_server_helidon:$hexagonVersion") } diff --git a/frameworks/Kotlin/hexagon/hexagon_helidon_postgresql/src/main/kotlin/Benchmark.kt b/frameworks/Kotlin/hexagon/hexagon_helidon_postgresql/src/main/kotlin/Benchmark.kt index cbfb372cbd5..d5165e88359 100644 --- a/frameworks/Kotlin/hexagon/hexagon_helidon_postgresql/src/main/kotlin/Benchmark.kt +++ b/frameworks/Kotlin/hexagon/hexagon_helidon_postgresql/src/main/kotlin/Benchmark.kt @@ -1,17 +1,31 @@ -package com.hexagonkt +package com.hexagontk -import com.hexagonkt.core.media.TEXT_HTML -import com.hexagonkt.core.urlOf -import com.hexagonkt.http.server.helidon.HelidonServerAdapter -import com.hexagonkt.store.BenchmarkSqlStore -import com.hexagonkt.templates.jte.JteAdapter +import com.hexagontk.core.Platform.systemSettingOrNull +import com.hexagontk.core.media.TEXT_HTML +import com.hexagontk.core.urlOf +import com.hexagontk.http.server.helidon.HelidonHttpServer +import com.hexagontk.store.BenchmarkSqlStore +import com.hexagontk.templates.jte.Jte +import java.time.Duration fun main() { val settings = Settings() val store = BenchmarkSqlStore("postgresql") - val templateEngine = JteAdapter(TEXT_HTML, precompiled = true) + val templateEngine = Jte(TEXT_HTML, precompiled = true) val templateUrl = urlOf("classpath:fortunes.jte") - val engine = HelidonServerAdapter() + val engine = HelidonHttpServer( + backlog = systemSettingOrNull("backlog") ?: (8 * 1024), + writeQueueLength = systemSettingOrNull("writeQueueLength") ?: (8 * 1024), + readTimeout = Duration.parse(systemSettingOrNull("readTimeout") ?: "PT0S"), + connectTimeout = Duration.parse(systemSettingOrNull("connectTimeout") ?: "PT0S"), + tcpNoDelay = systemSettingOrNull("tcpNoDelay") ?: true, + receiveLog = systemSettingOrNull("receiveLog") ?: false, + sendLog = systemSettingOrNull("sendLog") ?: false, + validatePath = systemSettingOrNull("validatePath") ?: false, + validateRequestHeaders = systemSettingOrNull("validateRequestHeaders") ?: false, + validateResponseHeaders = systemSettingOrNull("validateResponseHeaders") ?: false, + smartAsyncWrites = true, + ) val benchmark = Benchmark(engine, store, templateEngine, templateUrl, settings) benchmark.server.start() diff --git a/frameworks/Kotlin/hexagon/hexagon_jdk_pgclient/build.gradle b/frameworks/Kotlin/hexagon/hexagon_jdk_pgclient/build.gradle new file mode 100644 index 00000000000..52bd337daf9 --- /dev/null +++ b/frameworks/Kotlin/hexagon/hexagon_jdk_pgclient/build.gradle @@ -0,0 +1,7 @@ + +apply(from: "$gradleScripts/application.gradle") + +dependencies { + api(project(":store_pgclient")) + api("com.hexagontk.http:http_server_jdk:$hexagonVersion") +} diff --git a/frameworks/Kotlin/hexagon/hexagon_jdk_pgclient/src/main/kotlin/Benchmark.kt b/frameworks/Kotlin/hexagon/hexagon_jdk_pgclient/src/main/kotlin/Benchmark.kt new file mode 100644 index 00000000000..58c811603f4 --- /dev/null +++ b/frameworks/Kotlin/hexagon/hexagon_jdk_pgclient/src/main/kotlin/Benchmark.kt @@ -0,0 +1,26 @@ +package com.hexagontk + +import com.hexagontk.core.Platform.systemSettingOrNull +import com.hexagontk.core.media.TEXT_HTML +import com.hexagontk.core.urlOf +import com.hexagontk.http.server.jdk.JdkHttpServer +import com.hexagontk.store.BenchmarkPgClientStore +import com.hexagontk.templates.jte.Jte +import java.util.concurrent.Executors.newVirtualThreadPerTaskExecutor + +fun main() { + System.setProperty("sun.net.httpserver.idleInterval", "5") + System.setProperty("sun.net.httpserver.maxIdleConnections", "400") + + val settings = Settings() + val store = BenchmarkPgClientStore("postgresql") + val templateEngine = Jte(TEXT_HTML, precompiled = true) + val templateUrl = urlOf("classpath:fortunes.jte") + val engine = JdkHttpServer( + executor = newVirtualThreadPerTaskExecutor(), + backlog = systemSettingOrNull("backlog") ?: (8 * 1024), + ) + + val benchmark = Benchmark(engine, store, templateEngine, templateUrl, settings) + benchmark.server.start() +} diff --git a/frameworks/Kotlin/hexagon/hexagon_jdk_postgresql/build.gradle b/frameworks/Kotlin/hexagon/hexagon_jdk_postgresql/build.gradle new file mode 100644 index 00000000000..b1ea253c073 --- /dev/null +++ b/frameworks/Kotlin/hexagon/hexagon_jdk_postgresql/build.gradle @@ -0,0 +1,8 @@ + +apply(from: "$gradleScripts/application.gradle") +apply(from: "$gradleScripts/native.gradle") + +dependencies { + api(project(":store_sql")) + api("com.hexagontk.http:http_server_jdk:$hexagonVersion") +} diff --git a/frameworks/Kotlin/hexagon/hexagon_jdk_postgresql/src/main/kotlin/Benchmark.kt b/frameworks/Kotlin/hexagon/hexagon_jdk_postgresql/src/main/kotlin/Benchmark.kt new file mode 100644 index 00000000000..2ca266d7829 --- /dev/null +++ b/frameworks/Kotlin/hexagon/hexagon_jdk_postgresql/src/main/kotlin/Benchmark.kt @@ -0,0 +1,26 @@ +package com.hexagontk + +import com.hexagontk.core.Platform.systemSettingOrNull +import com.hexagontk.core.media.TEXT_HTML +import com.hexagontk.core.urlOf +import com.hexagontk.http.server.jdk.JdkHttpServer +import com.hexagontk.store.BenchmarkSqlStore +import com.hexagontk.templates.jte.Jte +import java.util.concurrent.Executors.newVirtualThreadPerTaskExecutor + +fun main() { + System.setProperty("sun.net.httpserver.idleInterval", "5") + System.setProperty("sun.net.httpserver.maxIdleConnections", "400") + + val settings = Settings() + val store = BenchmarkSqlStore("postgresql") + val templateEngine = Jte(TEXT_HTML, precompiled = true) + val templateUrl = urlOf("classpath:fortunes.jte") + val engine = JdkHttpServer( + executor = newVirtualThreadPerTaskExecutor(), + backlog = systemSettingOrNull("backlog") ?: (8 * 1024), + ) + + val benchmark = Benchmark(engine, store, templateEngine, templateUrl, settings) + benchmark.server.start() +} diff --git a/frameworks/Kotlin/hexagon/hexagon_jetty_pgclient/build.gradle b/frameworks/Kotlin/hexagon/hexagon_jetty_pgclient/build.gradle index 3b3d4b51b92..a9c2a1b12d2 100644 --- a/frameworks/Kotlin/hexagon/hexagon_jetty_pgclient/build.gradle +++ b/frameworks/Kotlin/hexagon/hexagon_jetty_pgclient/build.gradle @@ -3,5 +3,5 @@ apply(from: "$gradleScripts/application.gradle") dependencies { api(project(":store_pgclient")) - api("com.hexagonkt:http_server_jetty:$hexagonVersion") + api("com.hexagontk.http:http_server_jetty:$hexagonVersion") } diff --git a/frameworks/Kotlin/hexagon/hexagon_jetty_pgclient/src/main/kotlin/Benchmark.kt b/frameworks/Kotlin/hexagon/hexagon_jetty_pgclient/src/main/kotlin/Benchmark.kt index c6e8dbcf855..6bb62708b6c 100644 --- a/frameworks/Kotlin/hexagon/hexagon_jetty_pgclient/src/main/kotlin/Benchmark.kt +++ b/frameworks/Kotlin/hexagon/hexagon_jetty_pgclient/src/main/kotlin/Benchmark.kt @@ -1,22 +1,20 @@ -package com.hexagonkt +package com.hexagontk -import com.hexagonkt.core.Jvm.systemFlag -import com.hexagonkt.core.media.TEXT_HTML -import com.hexagonkt.core.urlOf -import com.hexagonkt.http.server.jetty.JettyServletAdapter -import com.hexagonkt.store.BenchmarkPgClientStore -import com.hexagonkt.templates.jte.JteAdapter +import com.hexagontk.core.media.TEXT_HTML +import com.hexagontk.core.urlOf +import com.hexagontk.http.server.jetty.JettyServletHttpServer +import com.hexagontk.store.BenchmarkPgClientStore +import com.hexagontk.templates.jte.Jte fun main() { val settings = Settings() val store = BenchmarkPgClientStore("postgresql") - val templateEngine = JteAdapter(TEXT_HTML, precompiled = true) + val templateEngine = Jte(TEXT_HTML, precompiled = true) val templateUrl = urlOf("classpath:fortunes.jte") - val engine = JettyServletAdapter( + val engine = JettyServletHttpServer( sendDateHeader = settings.sendDateHeader, sendServerVersion = settings.sendServerVersion, sendXPoweredBy = settings.sendXPoweredBy, - useVirtualThreads = systemFlag("virtualThreads"), ) val benchmark = Benchmark(engine, store, templateEngine, templateUrl, settings) diff --git a/frameworks/Kotlin/hexagon/hexagon_jetty_postgresql/build.gradle b/frameworks/Kotlin/hexagon/hexagon_jetty_postgresql/build.gradle index 059804ac9ff..5576046c945 100644 --- a/frameworks/Kotlin/hexagon/hexagon_jetty_postgresql/build.gradle +++ b/frameworks/Kotlin/hexagon/hexagon_jetty_postgresql/build.gradle @@ -4,5 +4,5 @@ apply(from: "$gradleScripts/native.gradle") dependencies { api(project(":store_sql")) - api("com.hexagonkt:http_server_jetty:$hexagonVersion") + api("com.hexagontk.http:http_server_jetty:$hexagonVersion") } diff --git a/frameworks/Kotlin/hexagon/hexagon_jetty_postgresql/src/main/kotlin/Benchmark.kt b/frameworks/Kotlin/hexagon/hexagon_jetty_postgresql/src/main/kotlin/Benchmark.kt index 64585b785b6..b3632a893ed 100644 --- a/frameworks/Kotlin/hexagon/hexagon_jetty_postgresql/src/main/kotlin/Benchmark.kt +++ b/frameworks/Kotlin/hexagon/hexagon_jetty_postgresql/src/main/kotlin/Benchmark.kt @@ -1,22 +1,20 @@ -package com.hexagonkt +package com.hexagontk -import com.hexagonkt.core.Jvm.systemFlag -import com.hexagonkt.core.media.TEXT_HTML -import com.hexagonkt.core.urlOf -import com.hexagonkt.http.server.jetty.JettyServletAdapter -import com.hexagonkt.store.BenchmarkSqlStore -import com.hexagonkt.templates.jte.JteAdapter +import com.hexagontk.core.media.TEXT_HTML +import com.hexagontk.core.urlOf +import com.hexagontk.http.server.jetty.JettyServletHttpServer +import com.hexagontk.store.BenchmarkSqlStore +import com.hexagontk.templates.jte.Jte fun main() { val settings = Settings() val store = BenchmarkSqlStore("postgresql") - val templateEngine = JteAdapter(TEXT_HTML, precompiled = true) + val templateEngine = Jte(TEXT_HTML, precompiled = true) val templateUrl = urlOf("classpath:fortunes.jte") - val engine = JettyServletAdapter( + val engine = JettyServletHttpServer( sendDateHeader = settings.sendDateHeader, sendServerVersion = settings.sendServerVersion, sendXPoweredBy = settings.sendXPoweredBy, - useVirtualThreads = systemFlag("virtualThreads"), ) val benchmark = Benchmark(engine, store, templateEngine, templateUrl, settings) diff --git a/frameworks/Kotlin/hexagon/hexagon_nettyepoll_pgclient/build.gradle b/frameworks/Kotlin/hexagon/hexagon_nettyepoll_pgclient/build.gradle index 0017123ec54..c73ef55f5bc 100644 --- a/frameworks/Kotlin/hexagon/hexagon_nettyepoll_pgclient/build.gradle +++ b/frameworks/Kotlin/hexagon/hexagon_nettyepoll_pgclient/build.gradle @@ -3,6 +3,7 @@ apply(from: "$gradleScripts/application.gradle") dependencies { api(project(":store_pgclient")) - api("com.hexagonkt:http_server_netty_epoll:$hexagonVersion") + api("com.hexagontk.http:http_server_netty:$hexagonVersion") api("io.netty:netty-transport-native-epoll:$nettyVersion:linux-x86_64") + api("io.netty:netty-transport-native-io_uring:$nettyVersion:linux-x86_64") } diff --git a/frameworks/Kotlin/hexagon/hexagon_nettyepoll_pgclient/src/main/kotlin/Benchmark.kt b/frameworks/Kotlin/hexagon/hexagon_nettyepoll_pgclient/src/main/kotlin/Benchmark.kt index 0bbd8038edd..f094b7bc217 100644 --- a/frameworks/Kotlin/hexagon/hexagon_nettyepoll_pgclient/src/main/kotlin/Benchmark.kt +++ b/frameworks/Kotlin/hexagon/hexagon_nettyepoll_pgclient/src/main/kotlin/Benchmark.kt @@ -1,10 +1,10 @@ -package com.hexagonkt +package com.hexagontk -import com.hexagonkt.core.media.TEXT_HTML -import com.hexagonkt.core.urlOf -import com.hexagonkt.http.server.netty.epoll.NettyEpollServerAdapter -import com.hexagonkt.store.BenchmarkPgClientStore -import com.hexagonkt.templates.jte.JteAdapter +import com.hexagontk.core.media.TEXT_HTML +import com.hexagontk.core.urlOf +import com.hexagontk.http.server.netty.epoll.NettyEpollHttpServer +import com.hexagontk.store.BenchmarkPgClientStore +import com.hexagontk.templates.jte.Jte import io.netty.util.ResourceLeakDetector import io.netty.util.ResourceLeakDetector.Level.DISABLED @@ -16,9 +16,9 @@ fun main() { val settings = Settings() val store = BenchmarkPgClientStore("postgresql") - val templateEngine = JteAdapter(TEXT_HTML, precompiled = true) + val templateEngine = Jte(TEXT_HTML, precompiled = true) val templateUrl = urlOf("classpath:fortunes.jte") - val engine = NettyEpollServerAdapter( + val engine = NettyEpollHttpServer( keepAliveHandler = false, httpAggregatorHandler = false, chunkedHandler = false, diff --git a/frameworks/Kotlin/hexagon/hexagon_nettyepoll_postgresql/build.gradle b/frameworks/Kotlin/hexagon/hexagon_nettyepoll_postgresql/build.gradle index 243fa57c121..6577f8f90cd 100644 --- a/frameworks/Kotlin/hexagon/hexagon_nettyepoll_postgresql/build.gradle +++ b/frameworks/Kotlin/hexagon/hexagon_nettyepoll_postgresql/build.gradle @@ -3,6 +3,7 @@ apply(from: "$gradleScripts/application.gradle") dependencies { api(project(":store_sql")) - api("com.hexagonkt:http_server_netty_epoll:$hexagonVersion") + api("com.hexagontk.http:http_server_netty:$hexagonVersion") api("io.netty:netty-transport-native-epoll:$nettyVersion:linux-x86_64") + api("io.netty:netty-transport-native-io_uring:$nettyVersion:linux-x86_64") } diff --git a/frameworks/Kotlin/hexagon/hexagon_nettyepoll_postgresql/src/main/kotlin/Benchmark.kt b/frameworks/Kotlin/hexagon/hexagon_nettyepoll_postgresql/src/main/kotlin/Benchmark.kt index 77fa370b915..eaba3b48b40 100644 --- a/frameworks/Kotlin/hexagon/hexagon_nettyepoll_postgresql/src/main/kotlin/Benchmark.kt +++ b/frameworks/Kotlin/hexagon/hexagon_nettyepoll_postgresql/src/main/kotlin/Benchmark.kt @@ -1,10 +1,10 @@ -package com.hexagonkt +package com.hexagontk -import com.hexagonkt.core.media.TEXT_HTML -import com.hexagonkt.core.urlOf -import com.hexagonkt.http.server.netty.epoll.NettyEpollServerAdapter -import com.hexagonkt.store.BenchmarkSqlStore -import com.hexagonkt.templates.jte.JteAdapter +import com.hexagontk.core.media.TEXT_HTML +import com.hexagontk.core.urlOf +import com.hexagontk.http.server.netty.epoll.NettyEpollHttpServer +import com.hexagontk.store.BenchmarkSqlStore +import com.hexagontk.templates.jte.Jte import io.netty.util.ResourceLeakDetector import io.netty.util.ResourceLeakDetector.Level.DISABLED @@ -16,9 +16,9 @@ fun main() { val settings = Settings() val store = BenchmarkSqlStore("postgresql") - val templateEngine = JteAdapter(TEXT_HTML, precompiled = true) + val templateEngine = Jte(TEXT_HTML, precompiled = true) val templateUrl = urlOf("classpath:fortunes.jte") - val engine = NettyEpollServerAdapter( + val engine = NettyEpollHttpServer( keepAliveHandler = false, httpAggregatorHandler = false, chunkedHandler = false, diff --git a/frameworks/Kotlin/hexagon/hexagon_tomcat_postgresql/build.gradle b/frameworks/Kotlin/hexagon/hexagon_tomcat_postgresql/build.gradle index 3c72b9d4b0a..ca5fd01a071 100644 --- a/frameworks/Kotlin/hexagon/hexagon_tomcat_postgresql/build.gradle +++ b/frameworks/Kotlin/hexagon/hexagon_tomcat_postgresql/build.gradle @@ -9,7 +9,7 @@ build.dependsOn("war") dependencies { api(project(":store_sql")) - api("com.hexagonkt:http_server_servlet:$hexagonVersion") + api("com.hexagontk.http:http_server_servlet:$hexagonVersion") compileOnly("jakarta.servlet:jakarta.servlet-api:5.0.0") } diff --git a/frameworks/Kotlin/hexagon/hexagon_tomcat_postgresql/src/main/kotlin/WebListenerServer.kt b/frameworks/Kotlin/hexagon/hexagon_tomcat_postgresql/src/main/kotlin/WebListenerServer.kt index 69fe6d13ba6..d50232ab974 100644 --- a/frameworks/Kotlin/hexagon/hexagon_tomcat_postgresql/src/main/kotlin/WebListenerServer.kt +++ b/frameworks/Kotlin/hexagon/hexagon_tomcat_postgresql/src/main/kotlin/WebListenerServer.kt @@ -1,14 +1,15 @@ -package com.hexagonkt +package com.hexagontk -import com.hexagonkt.core.media.TEXT_HTML -import com.hexagonkt.core.urlOf -import com.hexagonkt.http.model.Header -import com.hexagonkt.http.model.Headers -import com.hexagonkt.http.handlers.HttpHandler -import com.hexagonkt.http.handlers.OnHandler -import com.hexagonkt.http.server.servlet.ServletServer -import com.hexagonkt.store.BenchmarkSqlStore -import com.hexagonkt.templates.jte.JteAdapter +import com.hexagontk.core.media.TEXT_HTML +import com.hexagontk.core.urlOf +import com.hexagontk.http.model.Field +import com.hexagontk.http.model.Headers +import com.hexagontk.http.handlers.HttpHandler +import com.hexagontk.http.handlers.OnHandler +import com.hexagontk.http.handlers.PathHandler +import com.hexagontk.http.server.servlet.ServletServer +import com.hexagontk.store.BenchmarkSqlStore +import com.hexagontk.templates.jte.Jte import jakarta.servlet.annotation.WebListener @WebListener class WebListenerServer( @@ -16,11 +17,11 @@ import jakarta.servlet.annotation.WebListener ) : ServletServer(createHandlers(settings)) { private companion object { - val headers = Headers(Header("server", "Tomcat")) + val headers = Headers(Field("server", "Tomcat")) - fun createHandlers(settings: Settings): List { + fun createHandlers(settings: Settings): HttpHandler { val store = BenchmarkSqlStore("postgresql") - val templateEngine = JteAdapter(TEXT_HTML, precompiled = true) + val templateEngine = Jte(TEXT_HTML, precompiled = true) val templateUrl = urlOf("classpath:fortunes.jte") val controller = Controller(settings, store, templateEngine, templateUrl) val controllerPath = controller.path @@ -28,7 +29,7 @@ import jakarta.servlet.annotation.WebListener send(headers = headers) } - return listOf(serverHeaderHandler, controllerPath) + return PathHandler(serverHeaderHandler, controllerPath) } } } diff --git a/frameworks/Kotlin/hexagon/model/build.gradle b/frameworks/Kotlin/hexagon/model/build.gradle index bb97bfd9a3d..a606fb03967 100644 --- a/frameworks/Kotlin/hexagon/model/build.gradle +++ b/frameworks/Kotlin/hexagon/model/build.gradle @@ -1,4 +1,4 @@ dependencies { - api("com.hexagonkt:core:$hexagonVersion") + api("com.hexagontk:core:$hexagonVersion") } diff --git a/frameworks/Kotlin/hexagon/model/src/main/kotlin/Settings.kt b/frameworks/Kotlin/hexagon/model/src/main/kotlin/Settings.kt index b11ed02c9e9..70fdd0f5b81 100644 --- a/frameworks/Kotlin/hexagon/model/src/main/kotlin/Settings.kt +++ b/frameworks/Kotlin/hexagon/model/src/main/kotlin/Settings.kt @@ -1,7 +1,7 @@ -package com.hexagonkt +package com.hexagontk -import com.hexagonkt.core.Jvm.systemFlag -import com.hexagonkt.core.Jvm.systemSettingOrNull +import com.hexagontk.core.Platform.systemFlag +import com.hexagontk.core.Platform.systemSettingOrNull data class Settings( val bindPort: Int = systemSettingOrNull("bindPort") ?: 9090, diff --git a/frameworks/Kotlin/hexagon/model/src/main/kotlin/model/CachedWorld.kt b/frameworks/Kotlin/hexagon/model/src/main/kotlin/model/CachedWorld.kt index 101176e3c39..edfa5ee0ec5 100644 --- a/frameworks/Kotlin/hexagon/model/src/main/kotlin/model/CachedWorld.kt +++ b/frameworks/Kotlin/hexagon/model/src/main/kotlin/model/CachedWorld.kt @@ -1,3 +1,3 @@ -package com.hexagonkt.model +package com.hexagontk.model data class CachedWorld(val id: Int, val randomNumber: Int) diff --git a/frameworks/Kotlin/hexagon/model/src/main/kotlin/model/Fortune.kt b/frameworks/Kotlin/hexagon/model/src/main/kotlin/model/Fortune.kt index b4781735ec1..a8061b81db3 100644 --- a/frameworks/Kotlin/hexagon/model/src/main/kotlin/model/Fortune.kt +++ b/frameworks/Kotlin/hexagon/model/src/main/kotlin/model/Fortune.kt @@ -1,3 +1,3 @@ -package com.hexagonkt.model +package com.hexagontk.model data class Fortune(val id: Int, val message: String) diff --git a/frameworks/Kotlin/hexagon/model/src/main/kotlin/model/Message.kt b/frameworks/Kotlin/hexagon/model/src/main/kotlin/model/Message.kt index 090dcbf0be6..3231b8bd961 100644 --- a/frameworks/Kotlin/hexagon/model/src/main/kotlin/model/Message.kt +++ b/frameworks/Kotlin/hexagon/model/src/main/kotlin/model/Message.kt @@ -1,3 +1,3 @@ -package com.hexagonkt.model +package com.hexagontk.model data class Message(val message: String) diff --git a/frameworks/Kotlin/hexagon/model/src/main/kotlin/model/World.kt b/frameworks/Kotlin/hexagon/model/src/main/kotlin/model/World.kt index 5f3316f9a5a..347e00e608f 100644 --- a/frameworks/Kotlin/hexagon/model/src/main/kotlin/model/World.kt +++ b/frameworks/Kotlin/hexagon/model/src/main/kotlin/model/World.kt @@ -1,3 +1,3 @@ -package com.hexagonkt.model +package com.hexagontk.model data class World(val id: Int, val randomNumber: Int) diff --git a/frameworks/Kotlin/hexagon/settings.gradle b/frameworks/Kotlin/hexagon/settings.gradle index f7b97fb2582..2636b07ef6a 100644 --- a/frameworks/Kotlin/hexagon/settings.gradle +++ b/frameworks/Kotlin/hexagon/settings.gradle @@ -9,6 +9,8 @@ include( "hexagon_jetty_postgresql", "hexagon_helidon_pgclient", "hexagon_helidon_postgresql", + "hexagon_jdk_pgclient", + "hexagon_jdk_postgresql", "hexagon_nettyepoll_pgclient", "hexagon_nettyepoll_postgresql", "hexagon_tomcat_postgresql", diff --git a/frameworks/Kotlin/hexagon/store_pgclient/src/main/kotlin/BenchmarkPgClientStore.kt b/frameworks/Kotlin/hexagon/store_pgclient/src/main/kotlin/BenchmarkPgClientStore.kt index 1fb9547353f..02359461502 100644 --- a/frameworks/Kotlin/hexagon/store_pgclient/src/main/kotlin/BenchmarkPgClientStore.kt +++ b/frameworks/Kotlin/hexagon/store_pgclient/src/main/kotlin/BenchmarkPgClientStore.kt @@ -1,13 +1,15 @@ -package com.hexagonkt.store +package com.hexagontk.store -import com.hexagonkt.Settings -import com.hexagonkt.core.Jvm -import com.hexagonkt.model.CachedWorld -import com.hexagonkt.model.Fortune -import com.hexagonkt.model.World +import com.hexagontk.Settings +import com.hexagontk.core.Platform +import com.hexagontk.model.CachedWorld +import com.hexagontk.model.Fortune +import com.hexagontk.model.World import io.vertx.core.Future +import io.vertx.core.Vertx +import io.vertx.core.VertxOptions +import io.vertx.pgclient.PgBuilder import io.vertx.pgclient.PgConnectOptions -import io.vertx.pgclient.PgPool import io.vertx.sqlclient.* import org.cache2k.Cache @@ -17,14 +19,15 @@ class BenchmarkPgClientStore( ) : BenchmarkStore(settings) { companion object { - private const val SELECT_WORLD: String = "select * from world where id = $1" + private const val LOAD_WORLDS: String = "select id, randomNumber from world" + private const val SELECT_WORLD: String = "select id, randomNumber from world where id = $1" private const val UPDATE_WORLD: String = "update world set randomNumber = $1 where id = $2" - private const val SELECT_ALL_FORTUNES: String = "select * from fortune" + private const val SELECT_ALL_FORTUNES: String = "select id, message from fortune" } private val connectOptions: PgConnectOptions by lazy { PgConnectOptions().apply { - host = Jvm.systemSettingOrNull("${engine.uppercase()}_DB_HOST") ?: "tfb-database" + host = Platform.systemSettingOrNull("${engine.uppercase()}_DB_HOST") ?: "tfb-database" database = settings.databaseName user = settings.databaseUsername password = settings.databasePassword @@ -34,12 +37,16 @@ class BenchmarkPgClientStore( private val poolOptions: PoolOptions by lazy { PoolOptions().apply { - val environment = Jvm.systemSettingOrNull("BENCHMARK_ENV")?.lowercase() - maxSize = 8 + if (environment == "citrine") Jvm.cpuCount else Jvm.cpuCount * 2 + val environment = Platform.systemSettingOrNull("BENCHMARK_ENV")?.lowercase() + val poolSize = 8 + if (environment == "citrine") Platform.cpuCount else Platform.cpuCount * 2 + maxSize = Platform.systemSettingOrNull(Int::class, "maximumPoolSize") ?: poolSize } } - private val dataSource: SqlClient by lazy { PgPool.client(connectOptions, poolOptions) } + private val dataSource: SqlClient by lazy { + val vertx = Vertx.vertx(VertxOptions().setPreferNativeTransport(true)) + PgBuilder.client().using(vertx).connectingTo(connectOptions).with(poolOptions).build() + } override fun findAllFortunes(): List = dataSource.preparedQuery(SELECT_ALL_FORTUNES) @@ -75,13 +82,12 @@ class BenchmarkPgClientStore( .toCompletionStage() .toCompletableFuture() .get() - } } override fun initWorldsCache(cache: Cache) { dataSource - .preparedQuery("select * from world") + .preparedQuery(LOAD_WORLDS) .execute() .map { rowSet -> rowSet.map { row -> diff --git a/frameworks/Kotlin/hexagon/store_sql/src/main/kotlin/BenchmarkSqlStore.kt b/frameworks/Kotlin/hexagon/store_sql/src/main/kotlin/BenchmarkSqlStore.kt index 501a4d9ce34..126a9fc946a 100644 --- a/frameworks/Kotlin/hexagon/store_sql/src/main/kotlin/BenchmarkSqlStore.kt +++ b/frameworks/Kotlin/hexagon/store_sql/src/main/kotlin/BenchmarkSqlStore.kt @@ -1,10 +1,10 @@ -package com.hexagonkt.store +package com.hexagontk.store -import com.hexagonkt.model.CachedWorld -import com.hexagonkt.model.Fortune -import com.hexagonkt.Settings -import com.hexagonkt.model.World -import com.hexagonkt.core.Jvm +import com.hexagontk.model.CachedWorld +import com.hexagontk.model.Fortune +import com.hexagontk.Settings +import com.hexagontk.model.World +import com.hexagontk.core.Platform import com.zaxxer.hikari.HikariConfig import com.zaxxer.hikari.HikariDataSource import org.cache2k.Cache @@ -16,15 +16,16 @@ class BenchmarkSqlStore( ) : BenchmarkStore(settings) { companion object { - private const val SELECT_WORLD: String = "select * from world where id = ?" + private const val LOAD_WORLDS: String = "select id, randomNumber from world" + private const val SELECT_WORLD: String = "select id, randomNumber from world where id = ?" private const val UPDATE_WORLD: String = "update world set randomNumber = ? where id = ?" - private const val SELECT_ALL_FORTUNES: String = "select * from fortune" + private const val SELECT_ALL_FORTUNES: String = "select id, message from fortune" } private val dataSource: HikariDataSource by lazy { - val dbHost = Jvm.systemSettingOrNull("${engine.uppercase()}_DB_HOST") ?: "tfb-database" - val environment = Jvm.systemSettingOrNull(String::class, "BENCHMARK_ENV")?.lowercase() - val poolSize = 8 + if (environment == "citrine") Jvm.cpuCount else Jvm.cpuCount * 2 + val dbHost = Platform.systemSettingOrNull("${engine.uppercase()}_DB_HOST") ?: "tfb-database" + val environment = Platform.systemSettingOrNull(String::class, "BENCHMARK_ENV")?.lowercase() + val poolSize = 8 + if (environment == "citrine") Platform.cpuCount else Platform.cpuCount * 2 val postgresqlSettings = listOf( "ssl=false", "assumeMinServerVersion=12.10", @@ -34,7 +35,7 @@ class BenchmarkSqlStore( ).joinToString("&") val config = HikariConfig().apply { jdbcUrl = "jdbc:postgresql://$dbHost/${settings.databaseName}?$postgresqlSettings" - maximumPoolSize = Jvm.systemSettingOrNull(Int::class, "maximumPoolSize") ?: poolSize + maximumPoolSize = Platform.systemSettingOrNull(Int::class, "maximumPoolSize") ?: poolSize driverClassName = settings.databaseDriver username = settings.databaseUsername password = settings.databasePassword @@ -63,19 +64,17 @@ class BenchmarkSqlStore( override fun replaceWorlds(worlds: List) { dataSource.connection.use { con: Connection -> val stmtSelect = con.prepareStatement(SELECT_WORLD) - val stmtUpdate = con.prepareStatement(UPDATE_WORLD) - worlds.forEach { - val worldId = it.id - val newRandomNumber = it.randomNumber - - stmtSelect.setInt(1, worldId) + stmtSelect.setInt(1, it.id) val rs = stmtSelect.executeQuery() rs.next() rs.getInt(2) // Read 'randomNumber' to comply with Test type 5, point 6 + } - stmtUpdate.setInt(1, newRandomNumber) - stmtUpdate.setInt(2, worldId) + val stmtUpdate = con.prepareStatement(UPDATE_WORLD) + worlds.forEach { + stmtUpdate.setInt(1, it.randomNumber) + stmtUpdate.setInt(2, it.id) stmtUpdate.executeUpdate() } } @@ -83,7 +82,7 @@ class BenchmarkSqlStore( override fun initWorldsCache(cache: Cache) { dataSource.connection.use { con: Connection -> - val stmtSelect = con.prepareStatement("select * from world") + val stmtSelect = con.prepareStatement(LOAD_WORLDS) val rs = stmtSelect.executeQuery() while (rs.next()) { diff --git a/frameworks/Kotlin/http4k/README.md b/frameworks/Kotlin/http4k/README.md index 58f7c5ea3c3..cf06bf0c995 100644 --- a/frameworks/Kotlin/http4k/README.md +++ b/frameworks/Kotlin/http4k/README.md @@ -3,7 +3,7 @@ ## Infrastructure Software Versions The tests were run with: -* JDK 11 +* JDK 21 * [http4k](https://http4k.org) ## Test URLs @@ -16,13 +16,14 @@ The tests were run with: - Plaintext: http://localhost:9000/plaintext ## Supported backends (w/ Postgres client) -- SunHttp/SunHttpLoom (default - bundled with core module - zero dependencies) +- SunHttp/SunHttpLoom (default - bundled with core module - zero dependencies) (+ SunHttpLoom w/GraalVM) - Apache (5) -- Apache4 -- Helidon +- Apache4 (+ w/GraalVM) +- Helidon (+ w/GraalVM) - KtorCIO - KtorNetty - Jetty/JettyLoom +- Jetty/JettyLoom (v11) - Netty - Ratpack - Undertow diff --git a/frameworks/Kotlin/http4k/benchmark_config.json b/frameworks/Kotlin/http4k/benchmark_config.json index 60fbe075918..448f868871c 100755 --- a/frameworks/Kotlin/http4k/benchmark_config.json +++ b/frameworks/Kotlin/http4k/benchmark_config.json @@ -3,51 +3,6 @@ "tests": [ { "default": { - "orm": "Raw", - "database_os": "Linux", - "cached_query_url": "/cached?queries=", - "db_url": "/db", - "json_url": "/json", - "fortune_url": "/fortunes", - "plaintext_url": "/plaintext", - "query_url": "/queries?queries=", - "update_url": "/updates?queries=", - "database": "Postgres", - "port": 9000, - "approach": "Realistic", - "classification": "Micro", - "framework": "http4k", - "language": "Kotlin", - "platform": "sunhttp", - "webserver": "None", - "os": "Linux", - "notes": "https://http4k.org", - "display_name": "http4k-sunhttp", - "versus": "servlet" - }, - "sunhttploom": { - "orm": "Raw", - "database_os": "Linux", - "cached_query_url": "/cached?queries=", - "db_url": "/db", - "json_url": "/json", - "fortune_url": "/fortunes", - "plaintext_url": "/plaintext", - "query_url": "/queries?queries=", - "database": "Postgres", - "port": 9000, - "approach": "Realistic", - "classification": "Micro", - "framework": "http4k", - "language": "Kotlin", - "platform": "sunhttp", - "webserver": "None", - "os": "Linux", - "notes": "https://http4k.org", - "display_name": "http4k-sunhttploom", - "versus": "servlet" - }, - "apache": { "orm": "Raw", "database_os": "Linux", "cached_query_url": "/cached?queries=", @@ -91,69 +46,6 @@ "notes": "https://http4k.org", "versus": "servlet" }, - "apache-graalvm": { - "orm": "Raw", - "database_os": "Linux", - "cached_query_url": "/cached?queries=", - "db_url": "/db", - "json_url": "/json", - "plaintext_url": "/plaintext", - "query_url": "/queries?queries=", - "update_url": "/updates?queries=", - "database": "Postgres", - "port": 9000, - "approach": "Realistic", - "classification": "Micro", - "framework": "http4k", - "language": "Kotlin", - "platform": "graalvm", - "webserver": "None", - "os": "Linux", - "notes": "https://http4k.org", - "versus": "servlet" - }, - "graalvm": { - "orm": "Raw", - "database_os": "Linux", - "cached_query_url": "/cached?queries=", - "db_url": "/db", - "json_url": "/json", - "plaintext_url": "/plaintext", - "query_url": "/queries?queries=", - "update_url": "/updates?queries=", - "database": "Postgres", - "port": 9000, - "approach": "Realistic", - "classification": "Micro", - "framework": "http4k", - "language": "Kotlin", - "platform": "graalvm", - "webserver": "None", - "os": "Linux", - "notes": "https://http4k.org", - "versus": "servlet" - }, - "helidon-graalvm": { - "orm": "Raw", - "database_os": "Linux", - "cached_query_url": "/cached?queries=", - "db_url": "/db", - "json_url": "/json", - "plaintext_url": "/plaintext", - "query_url": "/queries?queries=", - "update_url": "/updates?queries=", - "database": "Postgres", - "port": 9000, - "approach": "Realistic", - "classification": "Micro", - "framework": "http4k", - "language": "Kotlin", - "platform": "graalvm", - "webserver": "None", - "os": "Linux", - "notes": "https://http4k.org", - "versus": "helidon-jdbc" - }, "helidon-jdbc": { "orm": "Raw", "database_os": "Linux", @@ -242,52 +134,6 @@ "notes": "https://http4k.org", "versus": "jetty" }, - "jettyloom-pgclient": { - "orm": "Raw", - "database_os": "Linux", - "cached_query_url": "/cached?queries=", - "db_url": "/db", - "json_url": "/json", - "fortune_url": "/fortunes", - "plaintext_url": "/plaintext", - "query_url": "/queries?queries=", - "update_url": "/updates?queries=", - "database": "Postgres", - "port": 9000, - "approach": "Realistic", - "classification": "Micro", - "framework": "http4k", - "language": "Kotlin", - "platform": "jetty-loom-pgclient", - "webserver": "None", - "os": "Linux", - "notes": "https://http4k.org", - "versus": "jetty" - }, - "ktorcio": { - "orm": "Raw", - "database_os": "Linux", - "cached_query_url": "/cached?queries=", - "cached_query_url": "/cached?queries=", - "db_url": "/db", - "json_url": "/json", - "fortune_url": "/fortunes", - "plaintext_url": "/plaintext", - "query_url": "/queries?queries=", - "update_url": "/updates?queries=", - "database": "Postgres", - "port": 9000, - "approach": "Realistic", - "classification": "Micro", - "framework": "http4k", - "language": "Kotlin", - "platform": "ktor", - "webserver": "None", - "os": "Linux", - "notes": "https://http4k.org", - "versus": "ktor-cio", - "tags": ["broken"] - }, "ktornetty": { "orm": "Raw", "database_os": "Linux", diff --git a/frameworks/Kotlin/http4k/build.gradle.kts b/frameworks/Kotlin/http4k/build.gradle.kts index 3e2cebabc3c..37e2ce6aca6 100644 --- a/frameworks/Kotlin/http4k/build.gradle.kts +++ b/frameworks/Kotlin/http4k/build.gradle.kts @@ -1,9 +1,10 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar import org.gradle.api.JavaVersion.* import org.jetbrains.kotlin.gradle.tasks.KotlinCompile +import org.jetbrains.kotlin.js.translate.context.Namer.kotlin plugins { - kotlin("jvm") version "1.9.20" + kotlin("jvm") version "1.9.23" application } @@ -34,14 +35,14 @@ allprojects { } java { - sourceCompatibility = VERSION_20 - targetCompatibility = VERSION_20 + sourceCompatibility = VERSION_21 + targetCompatibility = VERSION_21 } tasks { withType { kotlinOptions { - jvmTarget = "20" + jvmTarget = "21" allWarningsAsErrors = true } } diff --git a/frameworks/Kotlin/http4k/config.toml b/frameworks/Kotlin/http4k/config.toml index 3033ee189fa..e61586ecd1b 100644 --- a/frameworks/Kotlin/http4k/config.toml +++ b/frameworks/Kotlin/http4k/config.toml @@ -54,41 +54,6 @@ platform = "ktor" webserver = "None" versus = "ktor-netty" -[main] -urls.cached_query = "/cached?queries=" -urls.db = "/db" -urls.fortune = "/fortunes" -urls.json = "/json" -urls.plaintext = "/plaintext" -urls.query = "/queries?queries=" -urls.update = "/updates?queries=" -approach = "Realistic" -classification = "Micro" -database = "Postgres" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "sunhttp" -webserver = "None" -versus = "servlet" - -[sunhttploom] -urls.cached_query = "/cached?queries=" -urls.db = "/db" -urls.fortune = "/fortunes" -urls.json = "/json" -urls.plaintext = "/plaintext" -urls.query = "/queries?queries=" -approach = "Realistic" -classification = "Micro" -database = "Postgres" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "sunhttp" -webserver = "None" -versus = "servlet" - [apache4] urls.cached_query = "/cached?queries=" urls.db = "/db" @@ -143,24 +108,6 @@ platform = "jetty-loom-jdbc" webserver = "None" versus = "jetty" -[jettyloom-pgclient] -urls.cached_query = "/cached?queries=" -urls.db = "/db" -urls.fortune = "/fortunes" -urls.json = "/json" -urls.plaintext = "/plaintext" -urls.query = "/queries?queries=" -urls.update = "/updates?queries=" -approach = "Realistic" -classification = "Micro" -database = "Postgres" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "jetty-loom-pgclient" -webserver = "None" -versus = "jetty" - [helidon-jdbc] urls.cached_query = "/cached?queries=" urls.db = "/db" @@ -215,75 +162,6 @@ platform = "apache-httpcore" webserver = "None" versus = "servlet" -[helidon-graalvm] -urls.cached_query = "/cached?queries=" -urls.db = "/db" -urls.json = "/json" -urls.plaintext = "/plaintext" -urls.query = "/queries?queries=" -urls.update = "/updates?queries=" -approach = "Realistic" -classification = "Micro" -database = "Postgres" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "graalvm" -webserver = "None" -versus = "helidon-jdbc" - -[apache-graalvm] -urls.cached_query = "/cached?queries=" -urls.db = "/db" -urls.json = "/json" -urls.plaintext = "/plaintext" -urls.query = "/queries?queries=" -urls.update = "/updates?queries=" -approach = "Realistic" -classification = "Micro" -database = "Postgres" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "graalvm" -webserver = "None" -versus = "servlet" - -[graalvm] -urls.cached_query = "/cached?queries=" -urls.db = "/db" -urls.json = "/json" -urls.plaintext = "/plaintext" -urls.query = "/queries?queries=" -urls.update = "/updates?queries=" -approach = "Realistic" -classification = "Micro" -database = "Postgres" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "graalvm" -webserver = "None" -versus = "servlet" - -[ktorcio] -urls.cached_query = "/cached?queries=" -urls.db = "/db" -urls.fortune = "/fortunes" -urls.json = "/json" -urls.plaintext = "/plaintext" -urls.query = "/queries?queries=" -urls.update = "/updates?queries=" -approach = "Realistic" -classification = "Micro" -database = "Postgres" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "ktor" -webserver = "None" -versus = "ktor-cio" - [ratpack] urls.cached_query = "/cached?queries=" urls.db = "/db" diff --git a/frameworks/Kotlin/http4k/core-jdbc/build.gradle.kts b/frameworks/Kotlin/http4k/core-jdbc/build.gradle.kts index 1aa1eb417b6..68e2916ec1a 100644 --- a/frameworks/Kotlin/http4k/core-jdbc/build.gradle.kts +++ b/frameworks/Kotlin/http4k/core-jdbc/build.gradle.kts @@ -1,5 +1,5 @@ dependencies { api(project(":core")) - api("com.zaxxer:HikariCP:5.0.1") - api("org.postgresql:postgresql:42.5.0") + api("com.zaxxer:HikariCP:5.1.0") + api("org.postgresql:postgresql:42.7.3") } diff --git a/frameworks/Kotlin/http4k/core-pgclient/src/main/kotlin/PostgresDatabase.kt b/frameworks/Kotlin/http4k/core-pgclient/src/main/kotlin/PostgresDatabase.kt index e9b55d4c177..377d72aff87 100644 --- a/frameworks/Kotlin/http4k/core-pgclient/src/main/kotlin/PostgresDatabase.kt +++ b/frameworks/Kotlin/http4k/core-pgclient/src/main/kotlin/PostgresDatabase.kt @@ -1,6 +1,4 @@ import io.vertx.core.Future -import io.vertx.core.Vertx -import io.vertx.core.VertxOptions import io.vertx.pgclient.PgConnectOptions import io.vertx.pgclient.PgPool.client import io.vertx.sqlclient.PoolOptions @@ -11,13 +9,7 @@ import java.util.Random class PostgresDatabase : Database { - private val queryPool: SqlClient - private val updatePool: SqlClient - - private val random = Random() - - init { - val vertx = Vertx.vertx(VertxOptions().setPreferNativeTransport(true)) + private val dbPool = run { val connectOptions = PgConnectOptions().apply { port = 5432 cachePreparedStatements = true @@ -26,52 +18,53 @@ class PostgresDatabase : Database { user = "benchmarkdbuser" password = "benchmarkdbpass" } - val clientOptions = PoolOptions().setMaxSize(64) - queryPool = client(vertx, connectOptions, clientOptions) - updatePool = client(vertx, connectOptions, clientOptions) + client(connectOptions, PoolOptions().apply { maxSize = 64 }) } - override fun findWorld() = - queryPool.findWorld(random.world()).toCompletionStage().toCompletableFuture().get() + private val random = Random() + + override fun findWorld() = dbPool.findWorld(random.world()) - override fun loadAll() = queryPool.preparedQuery("SELECT id, randomnumber FROM world ") + override fun loadAll() = dbPool.preparedQuery("SELECT id, randomnumber FROM world") .execute() .map { it.map(::toWorld) } - .toCompletionStage().toCompletableFuture().get() + .awaitComplete() - override fun findWorlds(count: Int) = - Future - .all( - (1..count).map { queryPool.findWorld(random.world()) } - ).toCompletionStage().toCompletableFuture().get().list() + override fun findWorlds(count: Int) = (1..count) + .map { dbPool.findWorld(random.world()) } - override fun updateWorlds(count: Int) = (1..count).map { - queryPool.findWorld(random.world()) - .flatMap { world -> - updatePool.preparedQuery("UPDATE world SET randomnumber = $1 WHERE id = $2") - .execute(Tuple.of(random.world(), world.first)) - .map { world } + override fun updateWorlds(count: Int) = (1..count) + .map { World(random.world(), random.world()) } + .onEach { + dbPool + .preparedQuery("SELECT id, randomnumber FROM world WHERE id = $1") + .execute(Tuple.of(it.first)) + .map { rowSet -> + val row = rowSet.iterator().next() + row.getInteger(1) + dbPool + .preparedQuery("UPDATE world SET randomnumber = $1 WHERE id = $2") + .execute(Tuple.of(it.second, it.first)) } - .toCompletionStage() - .toCompletableFuture() - .get() + .awaitComplete() } - override fun fortunes() = queryPool.preparedQuery("SELECT id, message FROM fortune") + override fun fortunes() = dbPool.preparedQuery("SELECT id, message FROM fortune") .execute() - .map { it.map(::toFortune) } + .map { it.map { Fortune(it.getInteger(0), it.getString(1)) } } .map { (it + Fortune(0, "Additional fortune added at request time.")) } .map { it.sortedBy { it.message } } - .toCompletionStage().toCompletableFuture().get() + .awaitComplete() companion object { private fun SqlClient.findWorld(id: Int) = preparedQuery("SELECT id, randomnumber FROM world WHERE id = $1") .execute(Tuple.of(id)) - .map { toWorld(it.single()) } + .map { it.map(::toWorld).first() } + .awaitComplete() } } private fun toWorld(r: Row) = r.getInteger("id") to r.getInteger("randomnumber") -private fun toFortune(it: Row) = Fortune(it.getInteger(0), it.getString(1)) +private fun Future.awaitComplete(): T = toCompletionStage().toCompletableFuture().get() \ No newline at end of file diff --git a/frameworks/Kotlin/http4k/core/build.gradle.kts b/frameworks/Kotlin/http4k/core/build.gradle.kts index f205c09bc25..9cd7e8f5269 100644 --- a/frameworks/Kotlin/http4k/core/build.gradle.kts +++ b/frameworks/Kotlin/http4k/core/build.gradle.kts @@ -4,16 +4,16 @@ plugins { } dependencies { - api(platform("org.http4k:http4k-bom:5.10.2.0")) - api("org.jetbrains.kotlin:kotlin-stdlib:1.9.20") - api("org.jetbrains.kotlin:kotlin-reflect:1.9.20") + api(platform("org.http4k:http4k-bom:5.14.4.0")) + api("org.jetbrains.kotlin:kotlin-stdlib:1.9.23") + api("org.jetbrains.kotlin:kotlin-reflect:1.9.23") api("org.http4k:http4k-core") api("org.http4k:http4k-format-argo") api("org.http4k:http4k-template-rocker") - api("org.apache.commons:commons-lang3:3.12.0") + api("org.apache.commons:commons-lang3:3.14.0") api("org.cache2k:cache2k-core:2.6.1.Final") - compileOnly("com.fizzed:rocker-compiler:1.3.0") + compileOnly("com.fizzed:rocker-compiler:1.4.0") } rocker { diff --git a/frameworks/Kotlin/http4k/graalvm/src/main/kotlin/http4k/Http4kGraalVMBenchmarkServer.kt b/frameworks/Kotlin/http4k/graalvm/src/main/kotlin/http4k/Http4kGraalVMBenchmarkServer.kt index 20a8d1eb566..a94b241d3f0 100644 --- a/frameworks/Kotlin/http4k/graalvm/src/main/kotlin/http4k/Http4kGraalVMBenchmarkServer.kt +++ b/frameworks/Kotlin/http4k/graalvm/src/main/kotlin/http4k/Http4kGraalVMBenchmarkServer.kt @@ -1,5 +1,5 @@ -import org.http4k.server.SunHttp +import org.http4k.server.SunHttpLoom fun main() { - Http4kBenchmarkServer(PostgresDatabase()).start(SunHttp(9000)) + Http4kBenchmarkServer(PostgresDatabase()).start(SunHttpLoom(9000)) } diff --git a/frameworks/Kotlin/http4k/gradle/wrapper/gradle-wrapper.properties b/frameworks/Kotlin/http4k/gradle/wrapper/gradle-wrapper.properties index 3fa8f862f75..b82aa23a4f0 100644 --- a/frameworks/Kotlin/http4k/gradle/wrapper/gradle-wrapper.properties +++ b/frameworks/Kotlin/http4k/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/frameworks/Kotlin/http4k/http4k-apache-graalvm.dockerfile b/frameworks/Kotlin/http4k/http4k-apache-graalvm.dockerfile index a8fa54b4fcc..51132613c98 100644 --- a/frameworks/Kotlin/http4k/http4k-apache-graalvm.dockerfile +++ b/frameworks/Kotlin/http4k/http4k-apache-graalvm.dockerfile @@ -1,4 +1,4 @@ -FROM gradle:8.4.0-jdk21 as gradle +FROM gradle:8.7.0-jdk21 as gradle USER root WORKDIR /http4k COPY build.gradle.kts build.gradle.kts @@ -10,16 +10,21 @@ COPY core-pgclient core-pgclient COPY apache-graalvm apache-graalvm RUN gradle --quiet --no-daemon apache-graalvm:shadowJar -FROM ghcr.io/graalvm/graalvm-community:21.0.0-ol9-20230919 as graalvm + +FROM ghcr.io/graalvm/native-image-community:21 as graalvm COPY --from=gradle /http4k/core/src/main/resources/* /home/app/http4k-apache-graalvm/ COPY --from=gradle /http4k/apache-graalvm/build/libs/http4k-benchmark.jar /home/app/http4k-apache-graalvm/ COPY --from=gradle /http4k/apache-graalvm/config/*.json /home/app/http4k-apache-graalvm/ -WORKDIR /home/app/http4k-apache-graalvm + RUN native-image \ - -H:ReflectionConfigurationFiles=reflect-config.json \ - -H:ResourceConfigurationFiles=resource-config.json \ + --static --no-fallback \ + -H:+UnlockExperimentalVMOptions \ + -H:ReflectionConfigurationFiles=/home/app/http4k-apache-graalvm/reflect-config.json \ + -H:ResourceConfigurationFiles=/home/app/http4k-apache-graalvm/resource-config.json \ --initialize-at-build-time="org.slf4j.LoggerFactory,org.slf4j.simple.SimpleLogger,org.slf4j.impl.StaticLoggerBinder" \ - --no-fallback -cp http4k-benchmark.jar Http4kGraalVMBenchmarkServerKt + -cp /home/app/http4k-apache-graalvm/http4k-benchmark.jar Http4kGraalVMBenchmarkServerKt +FROM frolvlad/alpine-glibc +COPY --from=graalvm /app/http4kgraalvmbenchmarkserverkt /http4kgraalvmbenchmarkserverkt EXPOSE 9000 -ENTRYPOINT ["/home/app/http4k-apache-graalvm/http4kgraalvmbenchmarkserverkt"] \ No newline at end of file +ENTRYPOINT ["/http4kgraalvmbenchmarkserverkt"] \ No newline at end of file diff --git a/frameworks/Kotlin/http4k/http4k-apache.dockerfile b/frameworks/Kotlin/http4k/http4k-apache.dockerfile index 559b490293c..de62168324d 100644 --- a/frameworks/Kotlin/http4k/http4k-apache.dockerfile +++ b/frameworks/Kotlin/http4k/http4k-apache.dockerfile @@ -1,4 +1,4 @@ -FROM gradle:8.4.0-jdk21 +FROM gradle:8.7.0-jdk21 USER root WORKDIR /http4k COPY build.gradle.kts build.gradle.kts diff --git a/frameworks/Kotlin/http4k/http4k-apache4.dockerfile b/frameworks/Kotlin/http4k/http4k-apache4.dockerfile index 4b61309baef..840bc34ca4a 100644 --- a/frameworks/Kotlin/http4k/http4k-apache4.dockerfile +++ b/frameworks/Kotlin/http4k/http4k-apache4.dockerfile @@ -1,4 +1,4 @@ -FROM gradle:8.4.0-jdk21 +FROM gradle:8.7.0-jdk21 USER root WORKDIR /http4k COPY build.gradle.kts build.gradle.kts diff --git a/frameworks/Kotlin/http4k/http4k-graalvm.dockerfile b/frameworks/Kotlin/http4k/http4k-graalvm.dockerfile index b59cae84fd3..e2688ac80a4 100644 --- a/frameworks/Kotlin/http4k/http4k-graalvm.dockerfile +++ b/frameworks/Kotlin/http4k/http4k-graalvm.dockerfile @@ -1,4 +1,4 @@ -FROM gradle:8.4.0-jdk21 as gradle +FROM gradle:8.7.0-jdk21 as gradle USER root WORKDIR /http4k COPY build.gradle.kts build.gradle.kts @@ -7,19 +7,23 @@ COPY core core COPY core-jdbc core-jdbc COPY core-pgclient core-pgclient COPY graalvm graalvm -COPY sunhttp sunhttp RUN gradle --quiet --no-daemon graalvm:shadowJar -FROM ghcr.io/graalvm/graalvm-community:21.0.0-ol9-20230919 as graalvm + +FROM ghcr.io/graalvm/native-image-community:21 as graalvm COPY --from=gradle /http4k/core/src/main/resources/* /home/app/http4k-graalvm/ COPY --from=gradle /http4k/graalvm/build/libs/http4k-benchmark.jar /home/app/http4k-graalvm/ COPY --from=gradle /http4k/graalvm/config/*.json /home/app/http4k-graalvm/ -WORKDIR /home/app/http4k-graalvm + RUN native-image \ - -H:ReflectionConfigurationFiles=reflect-config.json \ - -H:ResourceConfigurationFiles=resource-config.json \ + --static --no-fallback \ + -H:+UnlockExperimentalVMOptions \ + -H:ReflectionConfigurationFiles=/home/app/http4k-graalvm/reflect-config.json \ + -H:ResourceConfigurationFiles=/home/app/http4k-graalvm/resource-config.json \ --initialize-at-build-time="org.slf4j.LoggerFactory,org.slf4j.simple.SimpleLogger,org.slf4j.impl.StaticLoggerBinder" \ - --no-fallback -cp http4k-benchmark.jar Http4kGraalVMBenchmarkServerKt + -cp /home/app/http4k-graalvm/http4k-benchmark.jar Http4kGraalVMBenchmarkServerKt +FROM frolvlad/alpine-glibc +COPY --from=graalvm /app/http4kgraalvmbenchmarkserverkt /http4kgraalvmbenchmarkserverkt EXPOSE 9000 -ENTRYPOINT ["/home/app/http4k-graalvm/http4kgraalvmbenchmarkserverkt"] +ENTRYPOINT ["/http4kgraalvmbenchmarkserverkt"] \ No newline at end of file diff --git a/frameworks/Kotlin/http4k/http4k-helidon-graalvm.dockerfile b/frameworks/Kotlin/http4k/http4k-helidon-graalvm.dockerfile index 833b73497c1..650f8dfc528 100644 --- a/frameworks/Kotlin/http4k/http4k-helidon-graalvm.dockerfile +++ b/frameworks/Kotlin/http4k/http4k-helidon-graalvm.dockerfile @@ -1,4 +1,4 @@ -FROM gradle:8.4.0-jdk21 as gradle +FROM gradle:8.7.0-jdk21 as gradle USER root WORKDIR /http4k COPY build.gradle.kts build.gradle.kts @@ -10,16 +10,21 @@ COPY helidon-jdbc helidon-jdbc COPY helidon-graalvm helidon-graalvm RUN gradle --quiet --no-daemon helidon-graalvm:shadowJar -FROM ghcr.io/graalvm/graalvm-community:21.0.0-ol9-20230919 as graalvm + +FROM ghcr.io/graalvm/native-image-community:21 as graalvm COPY --from=gradle /http4k/core/src/main/resources/* /home/app/http4k-helidon-graalvm/ COPY --from=gradle /http4k/helidon-graalvm/build/libs/http4k-benchmark.jar /home/app/http4k-helidon-graalvm/ COPY --from=gradle /http4k/helidon-graalvm/config/*.json /home/app/http4k-helidon-graalvm/ -WORKDIR /home/app/http4k-helidon-graalvm + RUN native-image \ - -H:ReflectionConfigurationFiles=reflect-config.json \ - -H:ResourceConfigurationFiles=resource-config.json \ + --static --no-fallback \ + -H:+UnlockExperimentalVMOptions \ + -H:ReflectionConfigurationFiles=/home/app/http4k-helidon-graalvm/reflect-config.json \ + -H:ResourceConfigurationFiles=/home/app/http4k-helidon-graalvm/resource-config.json \ --initialize-at-build-time="org.slf4j.LoggerFactory,org.slf4j.simple.SimpleLogger,org.slf4j.impl.StaticLoggerBinder" \ - --no-fallback -cp http4k-benchmark.jar Http4kGraalVMBenchmarkServerKt + -cp /home/app/http4k-helidon-graalvm/http4k-benchmark.jar Http4kGraalVMBenchmarkServerKt +FROM frolvlad/alpine-glibc +COPY --from=graalvm /app/http4kgraalvmbenchmarkserverkt /http4kgraalvmbenchmarkserverkt EXPOSE 9000 -ENTRYPOINT ["/home/app/http4k-helidon-graalvm/http4kgraalvmbenchmarkserverkt"] \ No newline at end of file +ENTRYPOINT ["/http4kgraalvmbenchmarkserverkt"] \ No newline at end of file diff --git a/frameworks/Kotlin/http4k/http4k-helidon-jdbc.dockerfile b/frameworks/Kotlin/http4k/http4k-helidon-jdbc.dockerfile index 4e447003e55..f8a49b8b7dd 100644 --- a/frameworks/Kotlin/http4k/http4k-helidon-jdbc.dockerfile +++ b/frameworks/Kotlin/http4k/http4k-helidon-jdbc.dockerfile @@ -1,4 +1,4 @@ -FROM gradle:8.4.0-jdk21 +FROM gradle:8.7.0-jdk21 USER root WORKDIR /http4k COPY build.gradle.kts build.gradle.kts diff --git a/frameworks/Kotlin/http4k/http4k-helidon-pgclient.dockerfile b/frameworks/Kotlin/http4k/http4k-helidon-pgclient.dockerfile index 0425f9da4e3..7e36fa04a8b 100644 --- a/frameworks/Kotlin/http4k/http4k-helidon-pgclient.dockerfile +++ b/frameworks/Kotlin/http4k/http4k-helidon-pgclient.dockerfile @@ -1,4 +1,4 @@ -FROM gradle:8.4.0-jdk21 +FROM gradle:8.7.0-jdk21 USER root WORKDIR /http4k COPY build.gradle.kts build.gradle.kts diff --git a/frameworks/Kotlin/http4k/http4k-jetty.dockerfile b/frameworks/Kotlin/http4k/http4k-jetty.dockerfile index cafa466fabf..674a7f34bba 100644 --- a/frameworks/Kotlin/http4k/http4k-jetty.dockerfile +++ b/frameworks/Kotlin/http4k/http4k-jetty.dockerfile @@ -1,4 +1,4 @@ -FROM gradle:8.4.0-jdk21 +FROM gradle:8.7.0-jdk21 USER root WORKDIR /http4k COPY build.gradle.kts build.gradle.kts diff --git a/frameworks/Kotlin/http4k/http4k-jetty11.dockerfile b/frameworks/Kotlin/http4k/http4k-jetty11.dockerfile new file mode 100644 index 00000000000..d9c785409f0 --- /dev/null +++ b/frameworks/Kotlin/http4k/http4k-jetty11.dockerfile @@ -0,0 +1,14 @@ +FROM gradle:8.7.0-jdk21 +USER root +WORKDIR /http4k +COPY build.gradle.kts build.gradle.kts +COPY settings.gradle.kts settings.gradle.kts +COPY core core +COPY core-jdbc core-jdbc +COPY core-pgclient core-pgclient +COPY jetty11 jetty11 +RUN gradle --quiet --no-daemon jetty11:shadowJar + +EXPOSE 9000 + +CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AlwaysPreTouch", "-jar", "jetty11/build/libs/http4k-benchmark.jar"] diff --git a/frameworks/Kotlin/http4k/http4k-jetty11loom-jdbc.dockerfile b/frameworks/Kotlin/http4k/http4k-jetty11loom-jdbc.dockerfile new file mode 100644 index 00000000000..d085a9b1913 --- /dev/null +++ b/frameworks/Kotlin/http4k/http4k-jetty11loom-jdbc.dockerfile @@ -0,0 +1,13 @@ +FROM gradle:8.7.0-jdk21 +USER root +WORKDIR /http4k +COPY build.gradle.kts build.gradle.kts +COPY settings.gradle.kts settings.gradle.kts +COPY core core +COPY core-jdbc core-jdbc +COPY jetty11loom-jdbc jetty11loom-jdbc +RUN gradle --quiet --no-daemon jetty11loom-jdbc:shadowJar + +EXPOSE 9000 + +CMD ["java", "-server", "-XX:+UseNUMA", "--enable-preview", "-XX:+UseParallelGC", "-XX:+AlwaysPreTouch", "-jar", "jetty11loom-jdbc/build/libs/http4k-benchmark.jar"] diff --git a/frameworks/Kotlin/http4k/http4k-jetty11loom-pgclient.dockerfile b/frameworks/Kotlin/http4k/http4k-jetty11loom-pgclient.dockerfile new file mode 100644 index 00000000000..d2cd8bc3c65 --- /dev/null +++ b/frameworks/Kotlin/http4k/http4k-jetty11loom-pgclient.dockerfile @@ -0,0 +1,13 @@ +FROM gradle:8.7.0-jdk21 +USER root +WORKDIR /http4k +COPY build.gradle.kts build.gradle.kts +COPY settings.gradle.kts settings.gradle.kts +COPY core core +COPY core-pgclient core-pgclient +COPY jetty11loom-pgclient jetty11loom-pgclient +RUN gradle --quiet --no-daemon jetty11loom-pgclient:shadowJar + +EXPOSE 9000 + +CMD ["java", "-server", "-XX:+UseNUMA", "--enable-preview", "-XX:+UseParallelGC", "-XX:+AlwaysPreTouch", "-jar", "jetty11loom-pgclient/build/libs/http4k-benchmark.jar"] diff --git a/frameworks/Kotlin/http4k/http4k-jettyloom-jdbc.dockerfile b/frameworks/Kotlin/http4k/http4k-jettyloom-jdbc.dockerfile index 9f69eef32e6..a3837e51fa6 100644 --- a/frameworks/Kotlin/http4k/http4k-jettyloom-jdbc.dockerfile +++ b/frameworks/Kotlin/http4k/http4k-jettyloom-jdbc.dockerfile @@ -1,4 +1,4 @@ -FROM gradle:8.4.0-jdk21 +FROM gradle:8.7.0-jdk21 USER root WORKDIR /http4k COPY build.gradle.kts build.gradle.kts diff --git a/frameworks/Kotlin/http4k/http4k-jettyloom-pgclient.dockerfile b/frameworks/Kotlin/http4k/http4k-jettyloom-pgclient.dockerfile index 2751bfa30d8..7259d27378a 100644 --- a/frameworks/Kotlin/http4k/http4k-jettyloom-pgclient.dockerfile +++ b/frameworks/Kotlin/http4k/http4k-jettyloom-pgclient.dockerfile @@ -1,4 +1,4 @@ -FROM gradle:8.4.0-jdk21 +FROM gradle:8.7.0-jdk21 USER root WORKDIR /http4k COPY build.gradle.kts build.gradle.kts diff --git a/frameworks/Kotlin/http4k/http4k-ktorcio.dockerfile b/frameworks/Kotlin/http4k/http4k-ktorcio.dockerfile index 11849d31a41..ff2a0ed08b5 100644 --- a/frameworks/Kotlin/http4k/http4k-ktorcio.dockerfile +++ b/frameworks/Kotlin/http4k/http4k-ktorcio.dockerfile @@ -1,4 +1,4 @@ -FROM gradle:8.4.0-jdk21 +FROM gradle:8.7.0-jdk21 USER root WORKDIR /http4k COPY build.gradle.kts build.gradle.kts diff --git a/frameworks/Kotlin/http4k/http4k-ktornetty.dockerfile b/frameworks/Kotlin/http4k/http4k-ktornetty.dockerfile index e36719d5348..ed9db5cdae8 100644 --- a/frameworks/Kotlin/http4k/http4k-ktornetty.dockerfile +++ b/frameworks/Kotlin/http4k/http4k-ktornetty.dockerfile @@ -1,4 +1,4 @@ -FROM gradle:8.4.0-jdk21 +FROM gradle:8.7.0-jdk21 USER root WORKDIR /http4k COPY build.gradle.kts build.gradle.kts diff --git a/frameworks/Kotlin/http4k/http4k-netty.dockerfile b/frameworks/Kotlin/http4k/http4k-netty.dockerfile index d7221f8d8b6..37dea590804 100644 --- a/frameworks/Kotlin/http4k/http4k-netty.dockerfile +++ b/frameworks/Kotlin/http4k/http4k-netty.dockerfile @@ -1,4 +1,4 @@ -FROM gradle:8.4.0-jdk21 +FROM gradle:8.7.0-jdk21 USER root WORKDIR /http4k COPY build.gradle.kts build.gradle.kts diff --git a/frameworks/Kotlin/http4k/http4k-ratpack.dockerfile b/frameworks/Kotlin/http4k/http4k-ratpack.dockerfile index 62e01176850..6e496eb8501 100644 --- a/frameworks/Kotlin/http4k/http4k-ratpack.dockerfile +++ b/frameworks/Kotlin/http4k/http4k-ratpack.dockerfile @@ -1,4 +1,4 @@ -FROM gradle:8.4.0-jdk21 +FROM gradle:8.7.0-jdk21 USER root WORKDIR /http4k COPY build.gradle.kts build.gradle.kts diff --git a/frameworks/Kotlin/http4k/http4k-sunhttploom.dockerfile b/frameworks/Kotlin/http4k/http4k-sunhttploom.dockerfile index a07a6c1fcd4..3fa136cb9fc 100644 --- a/frameworks/Kotlin/http4k/http4k-sunhttploom.dockerfile +++ b/frameworks/Kotlin/http4k/http4k-sunhttploom.dockerfile @@ -1,4 +1,4 @@ -FROM gradle:8.4.0-jdk21 +FROM gradle:8.7.0-jdk21 USER root WORKDIR /http4k COPY build.gradle.kts build.gradle.kts diff --git a/frameworks/Kotlin/http4k/http4k-undertow.dockerfile b/frameworks/Kotlin/http4k/http4k-undertow.dockerfile index 7e29e7c091c..3f0ab95fc50 100644 --- a/frameworks/Kotlin/http4k/http4k-undertow.dockerfile +++ b/frameworks/Kotlin/http4k/http4k-undertow.dockerfile @@ -1,4 +1,4 @@ -FROM gradle:8.4.0-jdk21 +FROM gradle:8.7.0-jdk21 USER root WORKDIR /http4k COPY build.gradle.kts build.gradle.kts diff --git a/frameworks/Kotlin/http4k/http4k.dockerfile b/frameworks/Kotlin/http4k/http4k.dockerfile index 18ad4598276..ec643dda001 100644 --- a/frameworks/Kotlin/http4k/http4k.dockerfile +++ b/frameworks/Kotlin/http4k/http4k.dockerfile @@ -1,4 +1,4 @@ -FROM gradle:8.4.0-jdk21 +FROM gradle:8.7.0-jdk21 USER root WORKDIR /http4k COPY build.gradle.kts build.gradle.kts diff --git a/frameworks/Kotlin/http4k/jetty11/build.gradle.kts b/frameworks/Kotlin/http4k/jetty11/build.gradle.kts new file mode 100644 index 00000000000..c01bec2dafa --- /dev/null +++ b/frameworks/Kotlin/http4k/jetty11/build.gradle.kts @@ -0,0 +1,6 @@ +application.mainClass.set("Http4kJettyServerKt") + +dependencies { + api(project(":core-jdbc")) + api("org.http4k:http4k-server-jetty11") +} \ No newline at end of file diff --git a/frameworks/Kotlin/http4k/jetty11/src/main/kotlin/Http4kJettyServer.kt b/frameworks/Kotlin/http4k/jetty11/src/main/kotlin/Http4kJettyServer.kt new file mode 100644 index 00000000000..e157e9033d8 --- /dev/null +++ b/frameworks/Kotlin/http4k/jetty11/src/main/kotlin/Http4kJettyServer.kt @@ -0,0 +1,5 @@ +import org.http4k.server.Jetty11 + +fun main() { + Http4kBenchmarkServer(PostgresDatabase(), false).start(Jetty11(9000)) +} \ No newline at end of file diff --git a/frameworks/Kotlin/http4k/jetty11loom-jdbc/build.gradle.kts b/frameworks/Kotlin/http4k/jetty11loom-jdbc/build.gradle.kts new file mode 100644 index 00000000000..e367717c6ef --- /dev/null +++ b/frameworks/Kotlin/http4k/jetty11loom-jdbc/build.gradle.kts @@ -0,0 +1,6 @@ +application.mainClass.set("Http4kJettyLoomServerKt") + +dependencies { + api(project(":core-jdbc")) + api("org.http4k:http4k-server-jetty11") +} \ No newline at end of file diff --git a/frameworks/Kotlin/http4k/jetty11loom-jdbc/src/main/kotlin/Http4kJettyLoomServer.kt b/frameworks/Kotlin/http4k/jetty11loom-jdbc/src/main/kotlin/Http4kJettyLoomServer.kt new file mode 100644 index 00000000000..d23f47c4ef9 --- /dev/null +++ b/frameworks/Kotlin/http4k/jetty11loom-jdbc/src/main/kotlin/Http4kJettyLoomServer.kt @@ -0,0 +1,5 @@ +import org.http4k.server.Jetty11Loom + +fun main() { + Http4kBenchmarkServer(PostgresDatabase(), false).start(Jetty11Loom(9000)) +} \ No newline at end of file diff --git a/frameworks/Kotlin/http4k/jetty11loom-pgclient/build.gradle.kts b/frameworks/Kotlin/http4k/jetty11loom-pgclient/build.gradle.kts new file mode 100644 index 00000000000..3c555b12ac4 --- /dev/null +++ b/frameworks/Kotlin/http4k/jetty11loom-pgclient/build.gradle.kts @@ -0,0 +1,6 @@ +application.mainClass.set("Http4kJettyLoomServerKt") + +dependencies { + api(project(":core-pgclient")) + api("org.http4k:http4k-server-jetty11") +} \ No newline at end of file diff --git a/frameworks/Kotlin/http4k/jetty11loom-pgclient/src/main/kotlin/Http4kJettyLoomServer.kt b/frameworks/Kotlin/http4k/jetty11loom-pgclient/src/main/kotlin/Http4kJettyLoomServer.kt new file mode 100644 index 00000000000..d23f47c4ef9 --- /dev/null +++ b/frameworks/Kotlin/http4k/jetty11loom-pgclient/src/main/kotlin/Http4kJettyLoomServer.kt @@ -0,0 +1,5 @@ +import org.http4k.server.Jetty11Loom + +fun main() { + Http4kBenchmarkServer(PostgresDatabase(), false).start(Jetty11Loom(9000)) +} \ No newline at end of file diff --git a/frameworks/Kotlin/http4k/settings.gradle.kts b/frameworks/Kotlin/http4k/settings.gradle.kts index 61d5ec3c132..d00bf33bbe8 100644 --- a/frameworks/Kotlin/http4k/settings.gradle.kts +++ b/frameworks/Kotlin/http4k/settings.gradle.kts @@ -23,20 +23,15 @@ rootProject.name = "http4k-benchmark" include("core") include("core-jdbc") include("core-pgclient") + + include("apache") -include("apache-graalvm") include("apache4") -include("graalvm") include("jetty") include("jettyloom-jdbc") -include("jettyloom-pgclient") include("helidon-jdbc") include("helidon-pgclient") -include("helidon-graalvm") -include("ktorcio") include("ktornetty") include("netty") include("ratpack") -include("sunhttp") -include("sunhttploom") include("undertow") diff --git a/frameworks/Kotlin/kooby/benchmark_config.json b/frameworks/Kotlin/kooby/benchmark_config.json index 08782f2bf2b..0d0f5e499dd 100644 --- a/frameworks/Kotlin/kooby/benchmark_config.json +++ b/frameworks/Kotlin/kooby/benchmark_config.json @@ -14,15 +14,15 @@ "framework": "kooby: jooby+kotlin", "language": "Kotlin", "flavor": "None", - "platform": "Undertow", + "platform": "Netty", "database": "Postgres", "database_os": "Linux", "orm": "Raw", "webserver": "None", "os": "Linux", - "notes": "Jooby with Kotlin and Undertow", + "notes": "Jooby with Kotlin and Netty", "display_name": "kooby", - "versus": "undertow" + "versus": "netty" } }] } diff --git a/frameworks/Kotlin/kooby/config.toml b/frameworks/Kotlin/kooby/config.toml index f2434cf8daf..137149046d6 100644 --- a/frameworks/Kotlin/kooby/config.toml +++ b/frameworks/Kotlin/kooby/config.toml @@ -14,6 +14,6 @@ database = "Postgres" database_os = "Linux" os = "Linux" orm = "Raw" -platform = "Undertow" +platform = "Netty" webserver = "None" -versus = "undertow" +versus = "netty" diff --git a/frameworks/Kotlin/kooby/kooby.dockerfile b/frameworks/Kotlin/kooby/kooby.dockerfile index 56c278c467a..d337708c0df 100644 --- a/frameworks/Kotlin/kooby/kooby.dockerfile +++ b/frameworks/Kotlin/kooby/kooby.dockerfile @@ -1,4 +1,4 @@ -FROM maven:3.9.0-eclipse-temurin-17 +FROM maven:3.9.11-eclipse-temurin-25-noble as maven WORKDIR /kooby COPY pom.xml pom.xml COPY src src @@ -8,4 +8,4 @@ RUN mvn package -q EXPOSE 8080 -CMD ["java", "-server", "-Xms2g", "-Xmx2g", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-Dio.netty.disableHttpHeadersValidation=true", "-Dio.netty.buffer.checkBounds=false", "-Dio.netty.buffer.checkAccessible=false", "-jar", "target/kooby.jar"] +CMD ["java", "-server", "-Xms2g", "-Xmx2g", "-XX:+UseNUMA", "-XX:+UseParallelGC", "--enable-native-access=ALL-UNNAMED", "--add-opens=java.base/java.lang=ALL-UNNAMED", "--sun-misc-unsafe-memory-access=allow", "-Dio.netty.disableHttpHeadersValidation=true", "-Dio.netty.buffer.checkBounds=false", "-Dio.netty.buffer.checkAccessible=false", "-Dio.netty.noUnsafe=false", "-Dio.netty.eventLoopGroup=single", "-jar", "target/kooby.jar"] diff --git a/frameworks/Kotlin/kooby/pom.xml b/frameworks/Kotlin/kooby/pom.xml index b5396de42a9..3255a6f63a5 100644 --- a/frameworks/Kotlin/kooby/pom.xml +++ b/frameworks/Kotlin/kooby/pom.xml @@ -7,17 +7,17 @@ kooby com.techempower - 3.0 + 4.0 kooby: jooby+kotlin - 3.0.5 - 42.6.0 + 4.0.11 + 42.7.7 UTF-8 - 17 - 17 - 1.8.21 + 25 + 25 + 2.2.0 kooby.AppKt @@ -47,14 +47,6 @@ jooby-rocker
- - - - com.mysql - mysql-connector-j - 8.0.33 - - org.postgresql @@ -77,7 +69,7 @@ com.fizzed rocker-maven-plugin - 1.3.0 + 2.2.1 generate-rocker-templates @@ -98,7 +90,7 @@ kotlin-maven-plugin ${kotlin.version} - 17 + 22 @@ -127,7 +119,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.11.0 + 3.14.0 @@ -159,7 +151,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.2.4 + 3.6.0 uber-jar diff --git a/frameworks/Kotlin/kooby/src/main/kotlin/kooby/App.kt b/frameworks/Kotlin/kooby/src/main/kotlin/kooby/App.kt index edc43137b1b..e024fd386a5 100644 --- a/frameworks/Kotlin/kooby/src/main/kotlin/kooby/App.kt +++ b/frameworks/Kotlin/kooby/src/main/kotlin/kooby/App.kt @@ -33,7 +33,7 @@ fun main(args: Array) { runApp(args, EVENT_LOOP) { /** Template engine: */ - install(RockerModule().reuseBuffer(true)) + install(RockerModule()) /** JSON: */ install(JacksonModule()) @@ -43,8 +43,9 @@ fun main(args: Array) { install(HikariModule()) val ds = require(DataSource::class) + val message = outputFactory.wrap(MESSAGE_BYTES); get("/plaintext") { - ctx.send(MESSAGE_BYTES) + ctx.send(message) } get("/json") { @@ -158,6 +159,6 @@ private fun nextRandom(rnd: Random): Int { fun Context.queries() = try { this.query("queries").intValue(1).coerceIn(1, 500) -} catch (x: BadRequestException) { +} catch (_: BadRequestException) { 1 } diff --git a/frameworks/Kotlin/ktor/Readme.md b/frameworks/Kotlin/ktor/Readme.md index 80366c2f893..a0e83a1e29e 100644 --- a/frameworks/Kotlin/ktor/Readme.md +++ b/frameworks/Kotlin/ktor/Readme.md @@ -1,4 +1,7 @@ See subprojects * [Ktor](ktor/) Ktor using traditional JDBC using various servers -* [Ktor-asyncdb](ktor-asyncdb/) Ktor with Netty-based PostgreSQL clients \ No newline at end of file +* [Ktor-jasync](ktor-asyncdb/) Ktor with Netty-based PostgreSQL clients +* [Ktor-r2dbc](ktor-r2dbc/) Ktor with R2DBC for reactive database access +* [Ktor-exposed](ktor-exposed/) Ktor with the Exposed database abstraction library +* [Ktor-pgclient](ktor-pgclient/) Ktor with Reactive PostgreSQL Client \ No newline at end of file diff --git a/frameworks/Kotlin/ktor/benchmark_config.json b/frameworks/Kotlin/ktor/benchmark_config.json index f675237f4b9..17373df20ee 100644 --- a/frameworks/Kotlin/ktor/benchmark_config.json +++ b/frameworks/Kotlin/ktor/benchmark_config.json @@ -25,7 +25,7 @@ "notes": "http://ktor.io/", "versus": "netty" }, - "jetty": { + "r2dbc": { "plaintext_url": "/plaintext", "json_url": "/json", "db_url": "/db", @@ -40,15 +40,15 @@ "framework": "ktor", "language": "Kotlin", "orm": "Raw", - "platform": "Jetty", + "platform": "Netty", "webserver": "None", "os": "Linux", "database_os": "Linux", - "display_name": "ktor-jetty", + "display_name": "ktor-netty-r2dbc", "notes": "http://ktor.io/", - "versus": "servlet" + "versus": "netty" }, - "cio": { + "jetty": { "plaintext_url": "/plaintext", "json_url": "/json", "db_url": "/db", @@ -63,45 +63,45 @@ "framework": "ktor", "language": "Kotlin", "orm": "Raw", - "platform": "ktor", + "platform": "Jetty", "webserver": "None", "os": "Linux", "database_os": "Linux", - "display_name": "ktor-cio", + "display_name": "ktor-jetty", "notes": "http://ktor.io/", - "versus": "" + "versus": "servlet" }, - "jasync": { - "json_url": "/json", + "cio": { "plaintext_url": "/plaintext", + "json_url": "/json", "db_url": "/db", - "query_url": "/query/?queries=", - "fortune_url": "/fortunes", + "query_url": "/queries?queries=", "update_url": "/updates?queries=", - "port": 8080, + "fortune_url": "/fortunes", + + "port": 9090, "approach": "Realistic", - "classification": "Fullstack", + "classification": "Micro", "database": "Postgres", - "framework": "Ktor", + "framework": "ktor", "language": "Kotlin", - "flavor": "None", "orm": "Raw", - "platform": "None", + "platform": "ktor", "webserver": "None", "os": "Linux", "database_os": "Linux", - "display_name": "Ktor-jasync", - "notes": "", - "versus": "netty" + "display_name": "ktor-cio", + "notes": "http://ktor.io/", + "versus": "" }, - "reactivepg": { + "jasync": { "json_url": "/json", "plaintext_url": "/plaintext", "db_url": "/db", "query_url": "/query/?queries=", "fortune_url": "/fortunes", "update_url": "/updates?queries=", - "port": 8080, + "port": 9090, "approach": "Realistic", "classification": "Fullstack", "database": "Postgres", @@ -113,7 +113,7 @@ "webserver": "None", "os": "Linux", "database_os": "Linux", - "display_name": "Ktor-reactivepg", + "display_name": "Ktor-jasync", "notes": "", "versus": "netty" }, @@ -125,7 +125,7 @@ "update_url": "/updates?queries=", "fortune_url": "/fortunes", - "port": 8080, + "port": 9090, "approach": "Realistic", "classification": "Micro", "database": "Postgres", @@ -145,7 +145,7 @@ "query_url": "/queries?queries=", "update_url": "/updates?queries=", "fortune_url": "/fortunes", - "port": 8080, + "port": 9090, "approach": "Realistic", "classification": "Micro", "database": "postgres", @@ -164,7 +164,7 @@ "exposed-dao": { "db_url": "/db", "fortune_url": "/fortunes", - "port": 8080, + "port": 9090, "approach": "Realistic", "classification": "Micro", "database": "postgres", diff --git a/frameworks/Kotlin/ktor/config.toml b/frameworks/Kotlin/ktor/config.toml index 6077323686d..1c58e63c73f 100644 --- a/frameworks/Kotlin/ktor/config.toml +++ b/frameworks/Kotlin/ktor/config.toml @@ -35,23 +35,6 @@ platform = "None" webserver = "None" versus = "netty" -[reactivepg] -urls.plaintext = "/plaintext" -urls.json = "/json" -urls.db = "/db" -urls.query = "/query/?queries=" -urls.update = "/updates?queries=" -urls.fortune = "/fortunes" -approach = "Realistic" -classification = "Fullstack" -database = "Postgres" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "None" -webserver = "None" -versus = "netty" - [cio] urls.plaintext = "/plaintext" urls.json = "/json" diff --git a/frameworks/Kotlin/ktor/ktor-asyncdb/build.gradle b/frameworks/Kotlin/ktor/ktor-asyncdb/build.gradle deleted file mode 100644 index 9a7b3bf67ee..00000000000 --- a/frameworks/Kotlin/ktor/ktor-asyncdb/build.gradle +++ /dev/null @@ -1,41 +0,0 @@ -plugins { - id "java" - id "application" - id 'org.jetbrains.kotlin.jvm' - id 'kotlinx-serialization' - id 'com.github.johnrengelman.shadow' version '4.0.3' -} - -group 'org.jetbrains.ktor' -version '1.0-SNAPSHOT' - -mainClassName = "MainKt" - -repositories { - mavenCentral() - jcenter() - maven { url "https://kotlin.bintray.com/kotlinx" } -} - -dependencies { - compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8" - compile "org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.9.1" - compile "io.ktor:ktor-server-netty:$ktor_version" - compile "io.ktor:ktor-html-builder:$ktor_version" - compile "com.github.jasync-sql:jasync-postgresql:0.9.39" - compile "io.reactiverse:reactive-pg-client:0.11.3" - compile 'io.vertx:vertx-lang-kotlin-coroutines:3.7.0' -} - -compileKotlin { - kotlinOptions.jvmTarget = "1.8" -} -compileTestKotlin { - kotlinOptions.jvmTarget = "1.8" -} - -shadowJar { - baseName = "bench" - classifier = null - version = null -} diff --git a/frameworks/Kotlin/ktor/ktor-asyncdb/build.gradle.kts b/frameworks/Kotlin/ktor/ktor-asyncdb/build.gradle.kts new file mode 100644 index 00000000000..0622963101a --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-asyncdb/build.gradle.kts @@ -0,0 +1,42 @@ +plugins { + application + kotlin("jvm") version "2.0.21" + kotlin("plugin.serialization") version "2.0.0" + id("com.github.johnrengelman.shadow") version "8.1.0" +} + +group = "org.jetbrains.ktor" +version = "1.0-SNAPSHOT" + +repositories { + mavenCentral() +} + +application { + mainClass = "io.ktor.server.netty.EngineMain" +} + +val ktor_version = "3.1.2" +val kotlinx_serialization_version = "1.8.1" + +dependencies { + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlinx_serialization_version") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1") + implementation("io.ktor:ktor-server-netty:$ktor_version") + implementation("io.ktor:ktor-server-default-headers:$ktor_version") + implementation("io.ktor:ktor-server-html-builder:$ktor_version") + implementation("com.github.jasync-sql:jasync-postgresql:2.2.4") + implementation("ch.qos.logback:logback-classic:1.5.12") +} + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } +} + +tasks.shadowJar { + archiveBaseName.set("ktor-asyncdb") + archiveClassifier.set("") + archiveVersion.set("") +} diff --git a/frameworks/Kotlin/ktor/ktor-asyncdb/gradle.properties b/frameworks/Kotlin/ktor/ktor-asyncdb/gradle.properties index f8ca4442eea..9408f64fb4d 100644 --- a/frameworks/Kotlin/ktor/ktor-asyncdb/gradle.properties +++ b/frameworks/Kotlin/ktor/ktor-asyncdb/gradle.properties @@ -1,4 +1,4 @@ kotlin.code.style=official -kotlin_version=1.3.31 -ktor_version=1.2.0 +kotlin_version=2.0.21 +ktor_version=2.3.12 diff --git a/frameworks/Kotlin/ktor/ktor-asyncdb/gradle/wrapper/gradle-wrapper.properties b/frameworks/Kotlin/ktor/ktor-asyncdb/gradle/wrapper/gradle-wrapper.properties index e15293214f9..c6a2952d3c1 100644 --- a/frameworks/Kotlin/ktor/ktor-asyncdb/gradle/wrapper/gradle-wrapper.properties +++ b/frameworks/Kotlin/ktor/ktor-asyncdb/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Fri Dec 07 21:01:17 MST 2018 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.10-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip diff --git a/frameworks/Kotlin/ktor/ktor-asyncdb/settings.gradle b/frameworks/Kotlin/ktor/ktor-asyncdb/settings.gradle deleted file mode 100644 index d58b02872bf..00000000000 --- a/frameworks/Kotlin/ktor/ktor-asyncdb/settings.gradle +++ /dev/null @@ -1,14 +0,0 @@ -pluginManagement { - resolutionStrategy { - eachPlugin { - if (requested.id.id == "org.jetbrains.kotlin.jvm") { - useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version") - } - if (requested.id.id == "kotlinx-serialization") { - useModule("org.jetbrains.kotlin:kotlin-serialization:$kotlin_version") - } - } - } -} - -rootProject.name = 'tech-empower-framework-benchmark' \ No newline at end of file diff --git a/frameworks/Kotlin/ktor/ktor-asyncdb/settings.gradle.kts b/frameworks/Kotlin/ktor/ktor-asyncdb/settings.gradle.kts new file mode 100644 index 00000000000..fd565dc83c5 --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-asyncdb/settings.gradle.kts @@ -0,0 +1 @@ +rootProject.name = "tech-empower-framework-benchmark" \ No newline at end of file diff --git a/frameworks/Kotlin/ktor/ktor-asyncdb/src/main/kotlin/Models.kt b/frameworks/Kotlin/ktor/ktor-asyncdb/src/main/kotlin/Models.kt new file mode 100644 index 00000000000..72db920aefb --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-asyncdb/src/main/kotlin/Models.kt @@ -0,0 +1,10 @@ +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) \ No newline at end of file diff --git a/frameworks/Kotlin/ktor/ktor-asyncdb/src/main/kotlin/Responses.kt b/frameworks/Kotlin/ktor/ktor-asyncdb/src/main/kotlin/Responses.kt new file mode 100644 index 00000000000..9a1a92b7071 --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-asyncdb/src/main/kotlin/Responses.kt @@ -0,0 +1,20 @@ +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 + )) +} \ No newline at end of file diff --git a/frameworks/Kotlin/ktor/ktor-asyncdb/src/main/kotlin/main.kt b/frameworks/Kotlin/ktor/ktor-asyncdb/src/main/kotlin/main.kt index ca7d9e5713e..488dced6cec 100644 --- a/frameworks/Kotlin/ktor/ktor-asyncdb/src/main/kotlin/main.kt +++ b/frameworks/Kotlin/ktor/ktor-asyncdb/src/main/kotlin/main.kt @@ -1,40 +1,18 @@ import com.github.jasync.sql.db.ConnectionPoolConfiguration +import com.github.jasync.sql.db.QueryResult import com.github.jasync.sql.db.SuspendingConnection import com.github.jasync.sql.db.asSuspending import com.github.jasync.sql.db.postgresql.PostgreSQLConnectionBuilder -import io.ktor.application.call -import io.ktor.application.install -import io.ktor.features.DefaultHeaders -import io.ktor.html.Placeholder -import io.ktor.html.Template -import io.ktor.html.insert -import io.ktor.html.respondHtmlTemplate -import io.ktor.http.ContentType -import io.ktor.response.respondText -import io.ktor.routing.get -import io.ktor.routing.routing -import io.ktor.server.engine.embeddedServer -import io.ktor.server.netty.Netty -import io.reactiverse.kotlin.pgclient.getConnectionAwait -import io.reactiverse.kotlin.pgclient.preparedBatchAwait -import io.reactiverse.kotlin.pgclient.preparedQueryAwait -import io.reactiverse.pgclient.* +import io.ktor.server.application.* +import io.ktor.server.html.* +import io.ktor.server.plugins.defaultheaders.* +import io.ktor.server.response.* +import io.ktor.server.routing.* +import kotlinx.coroutines.* import kotlinx.html.* -import kotlinx.serialization.Serializable -import kotlinx.serialization.json.JSON -import kotlinx.serialization.list -import java.lang.IllegalArgumentException import kotlin.random.Random import kotlin.random.nextInt -@Serializable -data class Message(val message: String) - -@Serializable -data class World(val id: Int, val randomNumber: Int) - -data class Fortune(val id: Int, val message: String) - val rand = Random(1) interface Repository { @@ -44,73 +22,48 @@ interface Repository { } class JasyncRepository() : Repository { - private val dbConfig: ConnectionPoolConfiguration - private val db: SuspendingConnection - - init { - dbConfig = ConnectionPoolConfiguration( - "tfb-database", - database = "hello_world", - username = "benchmarkdbuser", - password = "benchmarkdbpass", - maxActiveConnections = 64 - ) - db = PostgreSQLConnectionBuilder.createConnectionPool(dbConfig).asSuspending + companion object { + const val WORLD_QUERY = "select id, randomNumber from world where id = ?" + const val FORTUNES_QUERY = "select id, message from fortune" + const val UPDATE_QUERY = "update world set randomNumber = ? where id = ?" } + private val dbConfig: ConnectionPoolConfiguration = ConnectionPoolConfiguration( + "tfb-database", + database = "hello_world", + username = "benchmarkdbuser", + password = "benchmarkdbpass", + maxActiveConnections = 64 + ) + private val db: SuspendingConnection = PostgreSQLConnectionBuilder.createConnectionPool(dbConfig).asSuspending + override suspend fun getWorld(): World { val worldId = rand.nextInt(1, 10000) - val result = db.sendPreparedStatement("select id, randomNumber from world where id = ?", listOf(worldId)) + val result = db.sendPreparedStatement(WORLD_QUERY, listOf(worldId)) val row = result.rows.first() return World(row.getInt(0)!!, row.getInt(1)!!) } override suspend fun getFortunes(): List { - val results = db.sendPreparedStatement("select id, message from fortune") + val results = db.sendPreparedStatement(FORTUNES_QUERY) return results.rows.map { Fortune(it.getInt(0)!!, it.getString(1)!!) } } override suspend fun updateWorlds(worlds: List) { - worlds.forEach { world -> - db.sendPreparedStatement( - "update world set randomNumber = ? where id = ?", - listOf(world.randomNumber, world.id) - ) - } - } -} + coroutineScope { + val jobs = ArrayList>(worlds.size) + worlds.forEach { world -> + val deferred = async(Dispatchers.IO) { + db.sendPreparedStatement( + UPDATE_QUERY, + listOf(world.randomNumber, world.id) + ) + } + jobs.add(deferred) + } -class ReactivePGRepository : Repository { - private val db: PgPool - - init { - val poolOptions = PgPoolOptions() - poolOptions.apply { - host = "tfb-database" - database = "hello_world" - user = "benchmarkdbuser" - password = "benchmarkdbpass" - maxSize = 64 - cachePreparedStatements = true + jobs.awaitAll() } - db = PgClient.pool(poolOptions) - } - - override suspend fun getFortunes(): List { - val results = db.preparedQueryAwait("select id, message from fortune") - return results.map { Fortune(it.getInteger(0), it.getString(1)) } - } - - override suspend fun getWorld(): World { - val worldId = rand.nextInt(1, 10000) - val result = db.preparedQueryAwait("select id, randomNumber from world where id = $1", Tuple.of(worldId)) - val row = result.first() - return World(row.getInteger(0), row.getInteger(1)!!) - } - - override suspend fun updateWorlds(worlds: List) { - val batch = worlds.map { Tuple.of(it.id, it.randomNumber) } - db.preparedBatchAwait("update world set randomNumber = $1 where id = $2", batch) } } @@ -132,7 +85,7 @@ class MainTemplate : Template { } } -class FortuneTemplate(val fortunes: List, val main: MainTemplate = MainTemplate()) : Template { +class FortuneTemplate(private val fortunes: List, private val main: MainTemplate = MainTemplate()) : Template { override fun HTML.apply() { insert(main) { content { @@ -153,61 +106,46 @@ class FortuneTemplate(val fortunes: List, val main: MainTemplate = Main } } -fun main(args: Array) { - val db = when(args.firstOrNull()) { - "jasync-sql" -> JasyncRepository() - "reactive-pg" -> ReactivePGRepository() - else -> throw IllegalArgumentException("Must specify a postgres client") - } +fun Application.main() { - val messageSerializer = Message.serializer() - val worldSerializer = World.serializer() + val db = JasyncRepository() - val server = embeddedServer(Netty, 8080, configure = { - shareWorkGroup = true - }) { - install(DefaultHeaders) - routing { - get("/plaintext") { - call.respondText("Hello, World!") - } + install(DefaultHeaders) + routing { + get("/plaintext") { + call.respondText("Hello, World!") + } - get("/json") { - call.respondText( - JSON.stringify(messageSerializer, Message("Hello, World!")), - ContentType.Application.Json - ) - } + get("/json") { + call.respondJson(Message("Hello, World!")) + } - get("/db") { - call.respondText(JSON.stringify(worldSerializer, db.getWorld()), ContentType.Application.Json) - } + get("/db") { + call.respondJson(db.getWorld()) + } - get("/query/") { - val queries = call.parameters["queries"]?.toBoxedInt(1..500) ?: 1 - val worlds = (1..queries).map { db.getWorld() } - call.respondText(JSON.stringify(worldSerializer.list, worlds), ContentType.Application.Json) - } + get("/query/") { + val queries = call.parameters["queries"]?.toBoxedInt(1..500) ?: 1 + val worlds = (1..queries).map { db.getWorld() } + call.respondJson(worlds) + } - get("/fortunes") { - val newFortune = Fortune(0, "Additional fortune added at request time.") - val fortunes = db.getFortunes().toMutableList() - fortunes.add(newFortune) - fortunes.sortBy { it.message } - call.respondHtmlTemplate(FortuneTemplate(fortunes)) { } - } + get("/fortunes") { + val newFortune = Fortune(0, "Additional fortune added at request time.") + val fortunes = db.getFortunes().toMutableList() + fortunes.add(newFortune) + fortunes.sortBy { it.message } + call.respondHtmlTemplate(FortuneTemplate(fortunes)) { } + } - get("/updates") { - val queries = call.parameters["queries"]?.toBoxedInt(1..500) ?: 1 - val worlds = (1..queries).map { db.getWorld() } - val newWorlds = worlds.map { it.copy(randomNumber = rand.nextInt(1..10000)) } + get("/updates") { + val queries = call.parameters["queries"]?.toBoxedInt(1..500) ?: 1 + val worlds = (1..queries).map { db.getWorld() } + val newWorlds = worlds.map { it.copy(randomNumber = rand.nextInt(1..10000)) } - db.updateWorlds(newWorlds) + db.updateWorlds(newWorlds) - call.respondText(JSON.stringify(worldSerializer.list, newWorlds), ContentType.Application.Json) - } + call.respondJson(newWorlds) } } - - server.start(wait = true) } diff --git a/frameworks/Kotlin/ktor/ktor-asyncdb/src/main/resources/application.conf b/frameworks/Kotlin/ktor/ktor-asyncdb/src/main/resources/application.conf new file mode 100644 index 00000000000..ad95fb429f0 --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-asyncdb/src/main/resources/application.conf @@ -0,0 +1,12 @@ +ktor { + deployment { + port = 9090 + autoreload = false + watch = [ ] + shareWorkGroup = true + } + + application { + modules = [MainKt.main] + } +} diff --git a/frameworks/Kotlin/ktor/ktor-asyncdb/src/main/resources/logback.xml b/frameworks/Kotlin/ktor/ktor-asyncdb/src/main/resources/logback.xml new file mode 100644 index 00000000000..5aa05dbf60c --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-asyncdb/src/main/resources/logback.xml @@ -0,0 +1,21 @@ + + + + %d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + true + + + + + + + + + + + + diff --git a/frameworks/Kotlin/ktor/ktor-cio.dockerfile b/frameworks/Kotlin/ktor/ktor-cio.dockerfile index 6ba40b6eccc..7443aed952f 100644 --- a/frameworks/Kotlin/ktor/ktor-cio.dockerfile +++ b/frameworks/Kotlin/ktor/ktor-cio.dockerfile @@ -1,13 +1,13 @@ -FROM maven:3.6.1-jdk-11-slim as maven +FROM maven:3.9.9-amazoncorretto-21-debian-bookworm as maven WORKDIR /ktor COPY ktor/pom.xml pom.xml COPY ktor/src src RUN mvn clean package -q -FROM openjdk:11.0.3-jdk-stretch +FROM amazoncorretto:21-al2023-headless WORKDIR /ktor COPY --from=maven /ktor/target/tech-empower-framework-benchmark-1.0-SNAPSHOT-cio-bundle.jar app.jar EXPOSE 9090 -CMD ["java", "-jar", "app.jar"] +CMD ["java", "-server","-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AlwaysPreTouch", "-jar", "app.jar"] diff --git a/frameworks/Kotlin/ktor/ktor-exposed-dao.dockerfile b/frameworks/Kotlin/ktor/ktor-exposed-dao.dockerfile index 9867cf2931c..417c0358735 100644 --- a/frameworks/Kotlin/ktor/ktor-exposed-dao.dockerfile +++ b/frameworks/Kotlin/ktor/ktor-exposed-dao.dockerfile @@ -1,9 +1,9 @@ -FROM gradle:8.0.2-jdk11 +FROM gradle:jdk21 WORKDIR /ktor-exposed COPY ktor-exposed/settings.gradle.kts settings.gradle.kts COPY ktor-exposed/app app -RUN gradle shadowJar +RUN gradle --no-daemon shadowJar EXPOSE 8080 diff --git a/frameworks/Kotlin/ktor/ktor-exposed-dsl.dockerfile b/frameworks/Kotlin/ktor/ktor-exposed-dsl.dockerfile index 5b7f7fe722a..d89f899a9d1 100644 --- a/frameworks/Kotlin/ktor/ktor-exposed-dsl.dockerfile +++ b/frameworks/Kotlin/ktor/ktor-exposed-dsl.dockerfile @@ -1,10 +1,10 @@ -FROM gradle:8.0.2-jdk11 +FROM gradle:jdk21 WORKDIR /ktor-exposed COPY ktor-exposed/settings.gradle.kts settings.gradle.kts COPY ktor-exposed/app app -RUN gradle shadowJar +RUN gradle --no-daemon shadowJar EXPOSE 8080 -CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AlwaysPreTouch", "-jar", "app/build/libs/app-all.jar", "Dsl"] +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/app/build.gradle.kts b/frameworks/Kotlin/ktor/ktor-exposed/app/build.gradle.kts index 4d798b53bcf..1ce1ba7f1fb 100644 --- a/frameworks/Kotlin/ktor/ktor-exposed/app/build.gradle.kts +++ b/frameworks/Kotlin/ktor/ktor-exposed/app/build.gradle.kts @@ -1,7 +1,7 @@ plugins { - kotlin("jvm") version "1.8.10" - kotlin("plugin.serialization") version "1.8.10" application + kotlin("jvm") version "2.1.21" + kotlin("plugin.serialization") version "2.1.21" id("com.github.johnrengelman.shadow") version "8.1.0" } @@ -9,9 +9,9 @@ repositories { mavenCentral() } -val ktorVersion = "2.2.3" -val kotlinxSerializationVersion = "1.5.0" -val exposedVersion = "0.41.1" +val ktorVersion = "3.1.3" +val kotlinxSerializationVersion = "1.8.1" +val exposedVersion = "0.61.0" dependencies { implementation("io.ktor:ktor-server-core:$ktorVersion") @@ -25,8 +25,8 @@ dependencies { implementation("org.jetbrains.exposed:exposed-dao:$exposedVersion") implementation("org.jetbrains.exposed:exposed-jdbc:$exposedVersion") - implementation("org.postgresql:postgresql:42.5.4") - implementation("com.zaxxer:HikariCP:5.0.1") + implementation("org.postgresql:postgresql:42.7.5") + implementation("com.zaxxer:HikariCP:5.1.0") runtimeOnly("org.slf4j:slf4j-simple:1.7.36") } 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 c284ecd7b17..50ffd37975d 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 @@ -13,15 +13,17 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import kotlinx.html.* import kotlinx.serialization.Serializable -import kotlinx.serialization.encodeToString 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.* +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.transactions.transaction +import org.jetbrains.exposed.sql.update import java.util.concurrent.ThreadLocalRandom @Serializable @@ -67,7 +69,7 @@ enum class ExposedMode { fun main(args: Array) { val exposedMode = valueOf(args.first()) - embeddedServer(Netty, port = 8080) { module(exposedMode) }.start(wait = true) + embeddedServer(Netty, port = 9090) { module(exposedMode) }.start(wait = true) } fun Application.module(exposedMode: ExposedMode) { @@ -82,7 +84,7 @@ fun Application.module(exposedMode: ExposedMode) { routing { fun selectWorldsWithIdQuery(id: Int) = - WorldTable.slice(WorldTable.id, WorldTable.randomNumber).select(WorldTable.id eq id) + WorldTable.select(WorldTable.id, WorldTable.randomNumber).where(WorldTable.id eq id) fun ResultRow.toWorld() = World(this[WorldTable.id].value, this[WorldTable.randomNumber]) @@ -129,7 +131,7 @@ fun Application.module(exposedMode: ExposedMode) { get("/fortunes") { val result = withDatabaseContextAndTransaction { when (exposedMode) { - Dsl -> FortuneTable.slice(FortuneTable.id, FortuneTable.message).selectAll() + Dsl -> FortuneTable.select(FortuneTable.id, FortuneTable.message) .asSequence().map { it.toFortune() } Dao -> FortuneDao.all().asSequence().map { it.toFortune() } 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 bdc9a83b1e6..18362b78bde 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,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/frameworks/Kotlin/ktor/ktor-jasync.dockerfile b/frameworks/Kotlin/ktor/ktor-jasync.dockerfile index 38649f62693..be5f6dd4606 100644 --- a/frameworks/Kotlin/ktor/ktor-jasync.dockerfile +++ b/frameworks/Kotlin/ktor/ktor-jasync.dockerfile @@ -1,13 +1,15 @@ -FROM openjdk:11.0.3-jdk-stretch +FROM gradle:jdk21 as build WORKDIR /app COPY ktor-asyncdb/gradle gradle -COPY ktor-asyncdb/build.gradle build.gradle -COPY ktor-asyncdb/gradle.properties gradle.properties +COPY ktor-asyncdb/build.gradle.kts build.gradle.kts COPY ktor-asyncdb/gradlew gradlew -COPY ktor-asyncdb/settings.gradle settings.gradle COPY ktor-asyncdb/src src RUN /app/gradlew --no-daemon shadowJar +FROM amazoncorretto:21-al2023-headless +WORKDIR /app +COPY --from=build /app/build/libs/ktor-asyncdb.jar ktor-asyncdb.jar + EXPOSE 9090 -CMD ["java", "-server", "-XX:+UseParallelGC", "-Xms2G","-Xmx2G", "-jar", "/app/build/libs/bench.jar", "jasync-sql"] +CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AlwaysPreTouch", "-jar", "ktor-asyncdb.jar", "jasync-sql"] diff --git a/frameworks/Kotlin/ktor/ktor-jetty.dockerfile b/frameworks/Kotlin/ktor/ktor-jetty.dockerfile index 3976e5f2df9..52855ab4a55 100644 --- a/frameworks/Kotlin/ktor/ktor-jetty.dockerfile +++ b/frameworks/Kotlin/ktor/ktor-jetty.dockerfile @@ -1,13 +1,13 @@ -FROM maven:3.6.1-jdk-11-slim as maven +FROM maven:3.9.9-amazoncorretto-21-debian-bookworm as maven WORKDIR /ktor COPY ktor/pom.xml pom.xml COPY ktor/src src RUN mvn clean package -q -FROM openjdk:11.0.3-jdk-stretch +FROM amazoncorretto:21-al2023-headless WORKDIR /ktor COPY --from=maven /ktor/target/tech-empower-framework-benchmark-1.0-SNAPSHOT-jetty-bundle.jar app.jar EXPOSE 9090 -CMD ["java", "-jar", "app.jar"] +CMD ["java", "-server","-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AlwaysPreTouch", "-jar", "app.jar"] diff --git a/frameworks/Kotlin/ktor/ktor-pgclient.dockerfile b/frameworks/Kotlin/ktor/ktor-pgclient.dockerfile index be123f07e6f..dfee699ede7 100644 --- a/frameworks/Kotlin/ktor/ktor-pgclient.dockerfile +++ b/frameworks/Kotlin/ktor/ktor-pgclient.dockerfile @@ -1,4 +1,4 @@ -FROM openjdk:11.0.3-jdk-stretch as build +FROM gradle:jdk21 as build WORKDIR /app COPY ktor-pgclient/gradle gradle COPY ktor-pgclient/build.gradle.kts build.gradle.kts @@ -6,10 +6,10 @@ COPY ktor-pgclient/gradlew gradlew COPY ktor-pgclient/src src RUN /app/gradlew --no-daemon shadowJar -FROM openjdk:11.0.3-jdk-slim +FROM amazoncorretto:21-al2023-headless WORKDIR /app COPY --from=build /app/build/libs/ktor-pgclient.jar ktor-pgclient.jar -EXPOSE 8080 +EXPOSE 9090 -CMD ["java", "-server", "-XX:MaxRAMFraction=1", "-XX:-UseBiasedLocking", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AlwaysPreTouch", "-jar", "ktor-pgclient.jar"] +CMD ["java", "-server","-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AlwaysPreTouch", "-jar", "ktor-pgclient.jar"] diff --git a/frameworks/Kotlin/ktor/ktor-pgclient/README.md b/frameworks/Kotlin/ktor/ktor-pgclient/README.md index a1e9827a659..024a9950fc6 100755 --- a/frameworks/Kotlin/ktor/ktor-pgclient/README.md +++ b/frameworks/Kotlin/ktor/ktor-pgclient/README.md @@ -7,27 +7,27 @@ The client features batching, pipelining and supports coroutines. ### Plain Text Test - http://localhost:8080/plaintext + http://localhost:9090/plaintext ### JSON Encoding Test - http://localhost:8080/json + http://localhost:9090/json ### Single Query Test - http://localhost:8080/db + http://localhost:9090/db ### Multiple Queries Test - http://localhost:8080/query?queries= + http://localhost:9090/query?queries= ### Database updates Test - http://localhost:8080/updates?queries= + http://localhost:9090/updates?queries= ### Fortunes Test - http://localhost:8080/fortunes + http://localhost:9090/fortunes ## build diff --git a/frameworks/Kotlin/ktor/ktor-pgclient/build.gradle.kts b/frameworks/Kotlin/ktor/ktor-pgclient/build.gradle.kts index f57c372b49f..c98ef463979 100644 --- a/frameworks/Kotlin/ktor/ktor-pgclient/build.gradle.kts +++ b/frameworks/Kotlin/ktor/ktor-pgclient/build.gradle.kts @@ -1,8 +1,8 @@ plugins { application - kotlin("jvm") version "1.6.10" - id("org.jetbrains.kotlin.plugin.serialization") version "1.6.21" - id("com.github.johnrengelman.shadow") version "7.1.2" + kotlin("jvm") version "2.0.21" + kotlin("plugin.serialization") version "2.0.0" + id("com.github.johnrengelman.shadow") version "8.1.0" } group = "org.jetbrains.ktor" @@ -13,22 +13,27 @@ repositories { } application { - mainClass.set("MainKt") + mainClass = "io.ktor.server.netty.EngineMain" } +val ktor_version = "3.1.2" +val vertx_version = "4.5.11" + dependencies { - implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") - implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.2") - implementation("io.ktor:ktor-server-netty:2.0.1") - implementation("io.ktor:ktor-server-html-builder-jvm:2.0.1") - implementation("io.ktor:ktor-server-default-headers-jvm:2.0.1") - implementation("io.vertx:vertx-pg-client:4.2.3") - implementation("io.vertx:vertx-lang-kotlin:4.2.3") - implementation("io.vertx:vertx-lang-kotlin-coroutines:4.2.3") + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.8.1") + implementation("io.ktor:ktor-server-netty:$ktor_version") + implementation("io.ktor:ktor-server-html-builder-jvm:$ktor_version") + implementation("io.ktor:ktor-server-default-headers-jvm:$ktor_version") + implementation("io.vertx:vertx-pg-client:$vertx_version") + implementation("io.vertx:vertx-lang-kotlin:$vertx_version") + implementation("io.vertx:vertx-lang-kotlin-coroutines:$vertx_version") + implementation("ch.qos.logback:logback-classic:1.5.12") } -tasks.withType().configureEach { - kotlinOptions.jvmTarget = "11" +java { + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } } tasks.shadowJar { diff --git a/frameworks/Kotlin/ktor/ktor-pgclient/gradle/wrapper/gradle-wrapper.properties b/frameworks/Kotlin/ktor/ktor-pgclient/gradle/wrapper/gradle-wrapper.properties index aa991fceae6..81aa1c0448a 100644 --- a/frameworks/Kotlin/ktor/ktor-pgclient/gradle/wrapper/gradle-wrapper.properties +++ b/frameworks/Kotlin/ktor/ktor-pgclient/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/frameworks/Kotlin/ktor/ktor-pgclient/src/main/kotlin/Models.kt b/frameworks/Kotlin/ktor/ktor-pgclient/src/main/kotlin/Models.kt new file mode 100644 index 00000000000..72db920aefb --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-pgclient/src/main/kotlin/Models.kt @@ -0,0 +1,10 @@ +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) \ No newline at end of file diff --git a/frameworks/Kotlin/ktor/ktor-pgclient/src/main/kotlin/Responses.kt b/frameworks/Kotlin/ktor/ktor-pgclient/src/main/kotlin/Responses.kt new file mode 100644 index 00000000000..9a1a92b7071 --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-pgclient/src/main/kotlin/Responses.kt @@ -0,0 +1,20 @@ +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 + )) +} \ No newline at end of file diff --git a/frameworks/Kotlin/ktor/ktor-pgclient/src/main/kotlin/main.kt b/frameworks/Kotlin/ktor/ktor-pgclient/src/main/kotlin/main.kt index b4f7dc89615..1afafc28fcd 100644 --- a/frameworks/Kotlin/ktor/ktor-pgclient/src/main/kotlin/main.kt +++ b/frameworks/Kotlin/ktor/ktor-pgclient/src/main/kotlin/main.kt @@ -1,30 +1,16 @@ -import io.ktor.http.* import io.ktor.server.application.* -import io.ktor.server.engine.* import io.ktor.server.html.* -import io.ktor.server.netty.* import io.ktor.server.plugins.defaultheaders.* import io.ktor.server.response.* import io.ktor.server.routing.* -import io.vertx.kotlin.coroutines.await +import io.vertx.kotlin.coroutines.coAwait +import io.vertx.pgclient.PgBuilder import io.vertx.pgclient.PgConnectOptions -import io.vertx.pgclient.PgPool import io.vertx.sqlclient.PoolOptions import io.vertx.sqlclient.Tuple import kotlinx.html.* -import kotlinx.serialization.Serializable -import kotlinx.serialization.encodeToString -import kotlinx.serialization.json.Json import java.util.concurrent.ThreadLocalRandom -@Serializable -data class Message(val message: String) - -@Serializable -data class World(val id: Int, val randomNumber: Int) - -data class Fortune(val id: Int, val message: String) - val rand: ThreadLocalRandom get() = ThreadLocalRandom.current() @@ -35,6 +21,12 @@ interface Repository { } class PgclientRepository : Repository { + companion object { + private const val FORTUNES_QUERY = "select id, message from FORTUNE" + private const val SELECT_WORLD_QUERY = "SELECT id, randomnumber from WORLD where id=$1" + private const val UPDATE_WORLD_QUERY = "UPDATE WORLD SET randomnumber=$1 WHERE id=$2" + } + private val connectOptions = PgConnectOptions().apply { port = 5432 @@ -47,21 +39,23 @@ class PgclientRepository : Repository { } private val poolOptions = PoolOptions() - private val client = ThreadLocal.withInitial { PgPool.client(connectOptions, poolOptions) } - private fun client() = client.get() + private val client = PgBuilder.client() + .with(poolOptions) + .connectingTo(connectOptions) + .build() override suspend fun getFortunes(): List { - val results = client().preparedQuery("select id, message from fortune").execute().await() + val results = client.preparedQuery(FORTUNES_QUERY).execute().coAwait() return results.map { Fortune(it.getInteger(0), it.getString(1)) } } override suspend fun getWorld(): World { val worldId = rand.nextInt(1, 10001) val result = - client() - .preparedQuery("select id, randomNumber from world where id = $1") + client + .preparedQuery(SELECT_WORLD_QUERY) .execute(Tuple.of(worldId)) - .await() + .coAwait() val row = result.first() return World(row.getInteger(0), row.getInteger(1)!!) } @@ -69,10 +63,10 @@ class PgclientRepository : Repository { override suspend fun updateWorlds(worlds: List) { // Worlds should be sorted before being batch-updated with to avoid data race and deadlocks. val batch = worlds.sortedBy { it.id }.map { Tuple.of(it.randomNumber, it.id) } - client() - .preparedQuery("update world set randomNumber = $1 where id = $2") + client + .preparedQuery(UPDATE_WORLD_QUERY) .executeBatch(batch) - .await() + .coAwait() } } @@ -115,54 +109,45 @@ class FortuneTemplate( } } -fun main() { +fun Application.main() { val db = PgclientRepository() - val server = embeddedServer(Netty, 8080, configure = { - shareWorkGroup = true - }) { - install(DefaultHeaders) - routing { - get("/plaintext") { - call.respondText("Hello, World!") - } + install(DefaultHeaders) + routing { + get("/plaintext") { + call.respondText("Hello, World!") + } - get("/json") { - call.respondText( - Json.encodeToString(Message("Hello, World!")), - ContentType.Application.Json - ) - } + get("/json") { + call.respondJson(Message("Hello, World!")) + } - get("/db") { - call.respondText(Json.encodeToString(db.getWorld()), ContentType.Application.Json) - } + get("/db") { + call.respondJson(db.getWorld()) + } - get("/query") { - val queries = call.parameters["queries"]?.toBoxedInt(1..500) ?: 1 - val worlds = List(queries) { db.getWorld() } - call.respondText(Json.encodeToString(worlds), ContentType.Application.Json) - } + get("/query") { + val queries = call.parameters["queries"]?.toBoxedInt(1..500) ?: 1 + val worlds = List(queries) { db.getWorld() } + call.respondJson(worlds) + } - get("/fortunes") { - val newFortune = Fortune(0, "Additional fortune added at request time.") - val fortunes = db.getFortunes().toMutableList() - fortunes.add(newFortune) - fortunes.sortBy { it.message } - call.respondHtmlTemplate(FortuneTemplate(fortunes)) { } - } + get("/fortunes") { + val newFortune = Fortune(0, "Additional fortune added at request time.") + val fortunes = db.getFortunes().toMutableList() + fortunes.add(newFortune) + fortunes.sortBy { it.message } + call.respondHtmlTemplate(FortuneTemplate(fortunes)) { } + } - get("/updates") { - val queries = call.parameters["queries"]?.toBoxedInt(1..500) ?: 1 - val worlds = List(queries) { db.getWorld() } - val newWorlds = worlds.map { it.copy(randomNumber = rand.nextInt(1, 10001)) } + get("/updates") { + val queries = call.parameters["queries"]?.toBoxedInt(1..500) ?: 1 + val worlds = List(queries) { db.getWorld() } + val newWorlds = worlds.map { it.copy(randomNumber = rand.nextInt(1, 10001)) } - db.updateWorlds(newWorlds) + db.updateWorlds(newWorlds) - call.respondText(Json.encodeToString(newWorlds), ContentType.Application.Json) - } + call.respondJson(newWorlds) } } - - server.start(wait = true) } diff --git a/frameworks/Kotlin/ktor/ktor-pgclient/src/main/resources/application.conf b/frameworks/Kotlin/ktor/ktor-pgclient/src/main/resources/application.conf new file mode 100644 index 00000000000..ad95fb429f0 --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-pgclient/src/main/resources/application.conf @@ -0,0 +1,12 @@ +ktor { + deployment { + port = 9090 + autoreload = false + watch = [ ] + shareWorkGroup = true + } + + application { + modules = [MainKt.main] + } +} diff --git a/frameworks/Kotlin/ktor/ktor-pgclient/src/main/resources/logback.xml b/frameworks/Kotlin/ktor/ktor-pgclient/src/main/resources/logback.xml new file mode 100644 index 00000000000..5aa05dbf60c --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-pgclient/src/main/resources/logback.xml @@ -0,0 +1,21 @@ + + + + %d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + true + + + + + + + + + + + + diff --git a/frameworks/Kotlin/ktor/ktor-r2dbc.dockerfile b/frameworks/Kotlin/ktor/ktor-r2dbc.dockerfile new file mode 100644 index 00000000000..0c7fc7c2e15 --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-r2dbc.dockerfile @@ -0,0 +1,13 @@ +FROM maven:3.9.9-amazoncorretto-21-debian-bookworm as maven +WORKDIR /ktor-r2dbc +COPY ktor-r2dbc/pom.xml pom.xml +COPY ktor-r2dbc/src src +RUN mvn clean package -q + +FROM amazoncorretto:21-al2023-headless +WORKDIR /ktor-r2dbc +COPY --from=maven /ktor-r2dbc/target/tech-empower-framework-benchmark-1.0-SNAPSHOT-netty-bundle.jar app.jar + +EXPOSE 9090 + +CMD ["java", "-server","-XX:+UseNUMA", "-XX:+UseG1GC", "-XX:+AlwaysPreTouch", "-jar", "app.jar"] diff --git a/frameworks/Kotlin/ktor/ktor-r2dbc/README.md b/frameworks/Kotlin/ktor/ktor-r2dbc/README.md new file mode 100644 index 00000000000..5b758d68dbd --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-r2dbc/README.md @@ -0,0 +1,50 @@ +# Ktor + +Ktor is a framework for building servers and clients in connected systems using Kotlin programming language. +More information is available at [ktor.io](http://ktor.io). + +# Setup + +* Java 21 +* Postgres server + +# Requirements + +* Maven 3 +* JDK 21 +* Kotlin +* ktor +* netty +* R2DBC + +Maven is downloaded automatically via Maven Wrapper script (`mvnw`), add dependencies are specified in `pom.xml` so will be downloaded automatically from maven central and jcenter repositories. + +# Deployment + +Run maven to build a bundle + +```bash +./mvnw package +``` + +Once bundle build complete and mysql server is running you can launch the application + +```bash +java -jar target/tech-empower-framework-benchmark-1.0-SNAPSHOT.jar +``` + +Please note that the server holds tty so you may need nohup. See `setup.sh` for details. + +# Contact + +[Leonid Stashevsky](https://github.com/e5l) + +[Sergey Mashkov](https://github.com/cy6erGn0m) + +[Ilya Ryzhenkov](https://github.com/orangy) + +[Ilya Nemtsev](https://github.com/inemtsev) + +Slack ktor channel https://kotlinlang.slack.com/messages/ktor (you need an [invite](http://slack.kotlinlang.org/) to join) + + diff --git a/frameworks/Kotlin/ktor/ktor-r2dbc/pom.xml b/frameworks/Kotlin/ktor/ktor-r2dbc/pom.xml new file mode 100644 index 00000000000..9f0754b9512 --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-r2dbc/pom.xml @@ -0,0 +1,179 @@ + + + + 4.0.0 + + org.jetbrains.ktor + tech-empower-framework-benchmark + 1.0-SNAPSHOT + jar + + org.jetbrains.ktor tech-empower-framework-benchmark + + + 2.1.21 + 1.10.1 + 3.1.3 + 1.8.1 + 0.12.0 + UTF-8 + 1.5.13 + 3.7.1 + 42.7.5 + 1.0.7.RELEASE + 1.0.2.RELEASE + + + + + + org.jetbrains.kotlin + kotlin-reflect + ${kotlin.version} + + + org.jetbrains.kotlinx + kotlinx-serialization-core + ${serialization.version} + + + org.jetbrains.kotlinx + kotlinx-serialization-json + ${serialization.version} + + + org.jetbrains.kotlinx + kotlinx-serialization-json-io + ${serialization.version} + + + org.jetbrains.kotlinx + kotlinx-html-jvm + ${kotlinx.html.version} + + + org.jetbrains.kotlinx + kotlinx-coroutines-core + ${kotlin.coroutines.version} + + + org.jetbrains.kotlinx + kotlinx-coroutines-reactor + ${kotlin.coroutines.version} + + + io.ktor + ktor-server-default-headers-jvm + ${ktor.version} + + + io.ktor + ktor-server-html-builder-jvm + ${ktor.version} + + + org.postgresql + r2dbc-postgresql + ${r2dbc.version} + + + io.r2dbc + r2dbc-pool + ${r2dbc.pool.version} + + + io.projectreactor + reactor-core + ${reactor.version} + + + ch.qos.logback + logback-classic + ${logback.version} + + + io.ktor + ktor-server-netty-jvm + ${ktor.version} + + + + + src/main/kotlin + + + + org.jetbrains.kotlin + kotlin-maven-plugin + ${kotlin.version} + + + compile + compile + + compile + + + + test-compile + test-compile + + test-compile + + + + + + kotlinx-serialization + + + + + org.jetbrains.kotlin + kotlin-maven-serialization + ${kotlin.version} + + + + + maven-jar-plugin + + true + + + + default-jar + none + + + + + maven-assembly-plugin + 3.7.1 + + + + netty + + single + + + package + + + + src/main/assembly/netty-bundle.xml + + + + io.ktor.server.netty.EngineMain + + + + + + + + + diff --git a/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/assembly/netty-bundle.xml b/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/assembly/netty-bundle.xml new file mode 100644 index 00000000000..58ff7cff593 --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/assembly/netty-bundle.xml @@ -0,0 +1,29 @@ + + netty-bundle + + + jar + + + false + + + + true + runtime + + + *:ktor-server-jetty + *:ktor-server-cio + + + + + + + ${project.build.outputDirectory} + / + + + \ No newline at end of file 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 new file mode 100644 index 00000000000..b0a05351157 --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/kotlin/org/jetbrains/ktor/benchmarks/Hello.kt @@ -0,0 +1,184 @@ +package org.jetbrains.ktor.benchmarks + +import io.ktor.http.* +import io.ktor.http.content.* +import io.ktor.server.application.* +import io.ktor.server.config.* +import io.ktor.server.html.respondHtml +import io.ktor.server.plugins.defaultheaders.* +import io.ktor.server.response.* +import io.ktor.server.routing.* +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.Connection +import io.r2dbc.spi.ConnectionFactory +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.reactive.awaitFirst +import kotlinx.coroutines.reactive.awaitFirstOrNull +import kotlinx.html.* +import reactor.core.publisher.Flux +import reactor.core.publisher.Mono +import java.time.Duration +import kotlin.random.Random + +const val HELLO_WORLD = "Hello, World!" +const val WORLD_QUERY = "SELECT id, randomnumber FROM world WHERE id = $1" +const val FORTUNES_QUERY = "SELECT id, message FROM fortune" +const val UPDATE_QUERY = "UPDATE world SET randomnumber = $1 WHERE id = $2" +const val DB_ROWS = 10000 + +fun Application.main() { + val config = ApplicationConfig("application.conf") + val dbConnFactory = configurePostgresR2DBC(config) + + val helloWorldContent = TextContent("Hello, World!", ContentType.Text.Plain) + val random = Random.Default + + install(DefaultHeaders) + + routing { + get("/plaintext") { + call.respond(helloWorldContent) + } + + get("/json") { + call.respondJson(Message(HELLO_WORLD)) + } + + get("/db") { + val request = getWorld(dbConnFactory, random) + val result = request.awaitFirstOrNull() + + call.respondJson(result) + } + + fun selectWorlds(queries: Int, random: Random): Flow = flow { + repeat(queries) { + emit(getWorld(dbConnFactory, random).awaitFirst()) + } + } + + get("/queries") { + val queries = call.queries() + + val result = buildList { + selectWorlds(queries, random).collect { + add(it) + } + } + + call.respondJson(result) + } + + get("/fortunes") { + val result = mutableListOf() + + val request = Flux.usingWhen(dbConnFactory.create(), { connection -> + Flux.from(connection.createStatement(FORTUNES_QUERY).execute()).flatMap { r -> + Flux.from(r.map { row, _ -> + Fortune( + row.get(0, Int::class.java)!!, row.get(1, String::class.java)!! + ) + }) + } + }, { connection -> connection.close() }) + + request.collectList().awaitFirstOrNull()?.let { result.addAll(it) } + + 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 worlds = selectWorlds(queries, random) + + val worldsUpdated = buildList { + worlds.collect { world -> + world.randomNumber = random.nextInt(DB_ROWS) + 1 + add(world) + + Mono.usingWhen(dbConnFactory.create(), { connection -> + Mono.from( + connection.createStatement(UPDATE_QUERY) + .bind(0, world.randomNumber) + .bind(1, world.id) + .execute() + ).flatMap { Mono.from(it.rowsUpdated) } + }, Connection::close).awaitFirstOrNull() + } + } + + call.respondJson(worldsUpdated) + } + } +} + +private fun getWorld( + dbConnFactory: ConnectionFactory, random: Random +): Mono = Mono.usingWhen(dbConnFactory.create(), { connection -> + Mono.from(connection.createStatement(WORLD_QUERY) + .bind("$1", random.nextInt(DB_ROWS) + 1) + .execute()) + .flatMap { r -> + Mono.from(r.map { row, _ -> + val id = row.get(0, Int::class.java) + val randomNumber = row.get(1, Int::class.java) + if (id != null && randomNumber != null) { + World(id, randomNumber) + } else { + throw IllegalStateException("Database returned null values for required fields") + } + }) + } +}, Connection::close) + +private fun configurePostgresR2DBC(config: ApplicationConfig): ConnectionFactory { + val cfo = PostgresqlConnectionConfiguration.builder() + .host(config.property("db.host").getString()) + .port(config.property("db.port").getString().toInt()) + .database(config.property("db.database").getString()) + .username(config.property("db.username").getString()) + .password(config.property("db.password").getString()) + .loopResources { NioClientEventLoopResources(Runtime.getRuntime().availableProcessors()).cacheLoops() } + .sslMode(SSLMode.DISABLE) + .tcpKeepAlive(true) + .tcpNoDelay(true) + .build() + + val cf = PostgresqlConnectionFactory(cfo) + + val cp = ConnectionPoolConfiguration.builder(cf) + .initialSize(config.property("db.initPoolSize").getString().toInt()) + .maxSize(config.property("db.maxPoolSize").getString().toInt()) + .maxIdleTime(Duration.ofSeconds(30)) + .maxAcquireTime(Duration.ofSeconds(5)) + .validationQuery("SELECT 1") + .build() + + return ConnectionPool(cp) +} + +private fun ApplicationCall.queries() = request.queryParameters["queries"]?.toIntOrNull()?.coerceIn(1, 500) ?: 1 \ No newline at end of file diff --git a/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/kotlin/org/jetbrains/ktor/benchmarks/Models.kt b/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/kotlin/org/jetbrains/ktor/benchmarks/Models.kt new file mode 100644 index 00000000000..b4325257282 --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-r2dbc/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) \ No newline at end of file diff --git a/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/kotlin/org/jetbrains/ktor/benchmarks/NioClientEventLoopResources.java b/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/kotlin/org/jetbrains/ktor/benchmarks/NioClientEventLoopResources.java new file mode 100644 index 00000000000..d0e03bb6b5e --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/kotlin/org/jetbrains/ktor/benchmarks/NioClientEventLoopResources.java @@ -0,0 +1,123 @@ +package org.jetbrains.ktor.benchmarks; + +import io.netty.channel.Channel; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.DatagramChannel; +import io.netty.channel.socket.ServerSocketChannel; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioDatagramChannel; +import io.netty.channel.socket.nio.NioServerSocketChannel; +import io.netty.channel.socket.nio.NioSocketChannel; +import io.netty.util.concurrent.DefaultThreadFactory; +import io.netty.util.concurrent.Future; +import io.netty.util.concurrent.ThreadPerTaskExecutor; +import reactor.core.publisher.Mono; +import reactor.netty.FutureMono; +import reactor.netty.resources.LoopResources; + +import java.time.Duration; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; + +/** + * Copied from GitHub issue comment: https://github.com/r2dbc/r2dbc-pool/issues/190#issuecomment-1566845190 + */ +public class NioClientEventLoopResources implements LoopResources { + public static final String THREAD_PREFIX = "prefix-"; + final int threads; + final AtomicReference loops = new AtomicReference<>(); + final AtomicBoolean running; + + NioClientEventLoopResources(int threads) { + this.running = new AtomicBoolean(true); + this.threads = threads; + } + + + @Override + @SuppressWarnings("unchecked") + public Mono disposeLater(Duration quietPeriod, Duration timeout) { + return Mono.defer(() -> { + long quietPeriodMillis = quietPeriod.toMillis(); + long timeoutMillis = timeout.toMillis(); + EventLoopGroup serverLoopsGroup = loops.get(); + Mono slMono = Mono.empty(); + if (running.compareAndSet(true, false)) { + if (serverLoopsGroup != null) { + slMono = FutureMono.from((Future) serverLoopsGroup.shutdownGracefully( + quietPeriodMillis, timeoutMillis, TimeUnit.MILLISECONDS)); + } + } + return Mono.when(slMono); + }); + } + + @Override + public boolean isDisposed() { + return !running.get(); + } + + @Override + public EventLoopGroup onClient(boolean useNative) { + return cacheLoops(); + } + + @Override + public EventLoopGroup onServer(boolean useNative) { + throw new UnsupportedOperationException("This event loop is designed only for client DB calls."); + } + + @Override + public EventLoopGroup onServerSelect(boolean useNative) { + throw new UnsupportedOperationException("This event loop is designed only for client DB calls."); + } + + @Override + public CHANNEL onChannel(Class channelType, EventLoopGroup group) { + if (channelType.equals(SocketChannel.class)) { + return (CHANNEL) new NioSocketChannel(); + } + if (channelType.equals(ServerSocketChannel.class)) { + return (CHANNEL) new NioServerSocketChannel(); + } + if (channelType.equals(DatagramChannel.class)) { + return (CHANNEL) new NioDatagramChannel(); + } + throw new IllegalArgumentException("Unsupported channel type: " + channelType.getSimpleName()); + } + + @Override + public Class onChannelClass(Class channelType, + EventLoopGroup group) { + if (channelType.equals(SocketChannel.class)) { + return (Class) NioSocketChannel.class; + } + if (channelType.equals(ServerSocketChannel.class)) { + return (Class) NioServerSocketChannel.class; + } + if (channelType.equals(DatagramChannel.class)) { + return (Class) NioDatagramChannel.class; + } + throw new IllegalArgumentException("Unsupported channel type: " + channelType.getSimpleName()); + } + + @SuppressWarnings("FutureReturnValueIgnored") + EventLoopGroup cacheLoops() { + EventLoopGroup eventLoopGroup = loops.get(); + if (null == eventLoopGroup) { + EventLoopGroup newEventLoopGroup = createNewEventLoopGroup(); + if (!loops.compareAndSet(null, newEventLoopGroup)) { + //"FutureReturnValueIgnored" this is deliberate + newEventLoopGroup.shutdownGracefully(0, 0, TimeUnit.MILLISECONDS); + } + eventLoopGroup = cacheLoops(); + } + return eventLoopGroup; + } + + private NioEventLoopGroup createNewEventLoopGroup() { + return new NioEventLoopGroup(threads, new ThreadPerTaskExecutor(new DefaultThreadFactory(THREAD_PREFIX))); + } +} \ No newline at end of file diff --git a/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/kotlin/org/jetbrains/ktor/benchmarks/Responses.kt b/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/kotlin/org/jetbrains/ktor/benchmarks/Responses.kt new file mode 100644 index 00000000000..07f21a06cf0 --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-r2dbc/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 + )) +} \ No newline at end of file diff --git a/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/resources/application.conf b/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/resources/application.conf new file mode 100644 index 00000000000..fe2031a7699 --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/resources/application.conf @@ -0,0 +1,26 @@ +ktor { + deployment { + port = 9090 + autoreload = false + watch = [ ] + shareWorkGroup = true + } + + application { + modules = [ org.jetbrains.ktor.benchmarks.HelloKt.main ] + } +} + +db { + driver = "pool" + protocol = "postgresql" + ssl = "false" + host = "tfb-database" + port = 5432 + database = "hello_world" + initPoolSize = 512 + maxPoolSize = 512 + 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-r2dbc/src/main/resources/logback.xml b/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/resources/logback.xml new file mode 100644 index 00000000000..4a21e8cd962 --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/resources/logback.xml @@ -0,0 +1,21 @@ + + + + %msg%n + + + + + true + + + + + + + + + + + + diff --git a/frameworks/Kotlin/ktor/ktor-reactivepg.dockerfile b/frameworks/Kotlin/ktor/ktor-reactivepg.dockerfile deleted file mode 100644 index 41476da82ba..00000000000 --- a/frameworks/Kotlin/ktor/ktor-reactivepg.dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM openjdk:11.0.3-jdk-stretch -WORKDIR /app -COPY ktor-asyncdb/gradle gradle -COPY ktor-asyncdb/build.gradle build.gradle -COPY ktor-asyncdb/gradle.properties gradle.properties -COPY ktor-asyncdb/gradlew gradlew -COPY ktor-asyncdb/settings.gradle settings.gradle -COPY ktor-asyncdb/src src -RUN /app/gradlew --no-daemon shadowJar - -EXPOSE 9090 - -CMD ["java", "-server", "-XX:+UseParallelGC", "-Xms2G","-Xmx2G", "-jar", "/app/build/libs/bench.jar", "reactive-pg"] diff --git a/frameworks/Kotlin/ktor/ktor.dockerfile b/frameworks/Kotlin/ktor/ktor.dockerfile index 36aa32fd8c2..c2624695540 100644 --- a/frameworks/Kotlin/ktor/ktor.dockerfile +++ b/frameworks/Kotlin/ktor/ktor.dockerfile @@ -1,13 +1,13 @@ -FROM maven:3.6.1-jdk-11-slim as maven +FROM maven:3.9.9-amazoncorretto-21-debian-bookworm as maven WORKDIR /ktor COPY ktor/pom.xml pom.xml COPY ktor/src src RUN mvn clean package -q -FROM openjdk:11.0.3-jdk-stretch +FROM amazoncorretto:21-al2023-headless WORKDIR /ktor COPY --from=maven /ktor/target/tech-empower-framework-benchmark-1.0-SNAPSHOT-netty-bundle.jar app.jar EXPOSE 9090 -CMD ["java", "-server","-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AggressiveOpts", "-XX:+AlwaysPreTouch", "-jar", "app.jar"] +CMD ["java", "-server","-XX:+UseNUMA", "-XX:+UseG1GC", "-XX:+AlwaysPreTouch", "-jar", "app.jar"] diff --git a/frameworks/Kotlin/ktor/ktor/README.md b/frameworks/Kotlin/ktor/ktor/README.md index 07cb92359c2..02a13760b07 100644 --- a/frameworks/Kotlin/ktor/ktor/README.md +++ b/frameworks/Kotlin/ktor/ktor/README.md @@ -5,13 +5,13 @@ More information is available at [ktor.io](http://ktor.io). # Setup -* Java 8 -* MySQL server +* Java 21 +* Postgres server # Requirements * Maven 3 -* JDK 8 +* JDK 21 * Kotlin * ktor * netty @@ -39,6 +39,8 @@ Please note that the server holds tty so you may need nohup. See `setup.sh` for [Leonid Stashevsky](https://github.com/e5l) +[Bruce Hamilton](https://github.com/bjhham) + [Sergey Mashkov](https://github.com/cy6erGn0m) [Ilya Ryzhenkov](https://github.com/orangy) diff --git a/frameworks/Kotlin/ktor/ktor/pom.xml b/frameworks/Kotlin/ktor/ktor/pom.xml index 07db44a67ed..a6adb0a651b 100644 --- a/frameworks/Kotlin/ktor/ktor/pom.xml +++ b/frameworks/Kotlin/ktor/ktor/pom.xml @@ -12,28 +12,24 @@ org.jetbrains.ktor tech-empower-framework-benchmark - 1.6.21 - 2.0.1 - 1.3.2 - 0.7.3 + 2.1.21 + 3.1.3 + 1.8.1 + 0.12.0 UTF-8 - 5.0.0 - 1.2.4 - 8.0.28 - 42.4.3 + 5.1.0 + 1.5.13 + 8.0.33 + 42.7.5 org.jetbrains.kotlin - kotlin-stdlib-jdk8 - ${kotlin.version} - - - org.jetbrains.kotlin - kotlin-reflect + kotlin-stdlib ${kotlin.version} + org.jetbrains.kotlinx kotlinx-serialization-core @@ -85,17 +81,17 @@ io.ktor ktor-server-netty-jvm - 2.0.0 + ${ktor.version} io.ktor ktor-server-jetty-jvm - 2.0.0 + ${ktor.version} io.ktor ktor-server-cio-jvm - 2.0.0 + ${ktor.version} @@ -150,7 +146,7 @@ maven-assembly-plugin - 3.0.0 + 3.7.1 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 new file mode 100644 index 00000000000..ee57ad5126d --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor/src/main/kotlin/org/jetbrains/ktor/benchmarks/Database.kt @@ -0,0 +1,32 @@ +package org.jetbrains.ktor.benchmarks + +import com.zaxxer.hikari.HikariConfig + +fun HikariConfig.configurePostgres(poolSize: Int) { + jdbcUrl = "jdbc:postgresql://tfb-database/hello_world?useSSL=false" + 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 +} + +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) +} \ No newline at end of file diff --git a/frameworks/Kotlin/ktor/ktor/src/main/kotlin/org/jetbrains/ktor/benchmarks/Hello.kt b/frameworks/Kotlin/ktor/ktor/src/main/kotlin/org/jetbrains/ktor/benchmarks/Hello.kt deleted file mode 100644 index b767e0605f5..00000000000 --- a/frameworks/Kotlin/ktor/ktor/src/main/kotlin/org/jetbrains/ktor/benchmarks/Hello.kt +++ /dev/null @@ -1,184 +0,0 @@ -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.html.* -import io.ktor.server.plugins.defaultheaders.* -import io.ktor.server.response.* -import io.ktor.server.routing.* -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import kotlinx.html.* -import kotlinx.serialization.Serializable -import kotlinx.serialization.encodeToString -import kotlinx.serialization.json.Json -import java.sql.Connection -import java.util.concurrent.ThreadLocalRandom - -@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) - -fun Application.main() { - val dbRows = 10000 - val poolSize = 48 - val pool by lazy { HikariDataSource(HikariConfig().apply { configurePostgres(poolSize) }) } - val databaseDispatcher = Dispatchers.IO - - install(DefaultHeaders) - - val helloWorldContent = TextContent("Hello, World!", ContentType.Text.Plain).also { it.contentLength } - - routing { - get("/plaintext") { - call.respond(helloWorldContent) - } - - get("/json") { - call.respondText(Json.encodeToString(Message("Hello, world!")), ContentType.Application.Json) - } - - get("/db") { - val random = ThreadLocalRandom.current() - - val world = withContext(databaseDispatcher) { - pool.connection.use { connection -> - connection.prepareStatement("SELECT id, randomNumber FROM World WHERE id = ?").use { statement -> - statement.setInt(1, random.nextInt(dbRows) + 1) - - statement.executeQuery().use { rs -> - rs.next() - World(rs.getInt(1), rs.getInt(2)) - } - } - } - } - - call.respondText(Json.encodeToString(world), ContentType.Application.Json) - } - - fun Connection.selectWorlds(queries: Int, random: ThreadLocalRandom): List { - val result = ArrayList(queries) - prepareStatement("SELECT id, randomNumber FROM World WHERE id = ?").use { statement -> - repeat(queries) { - statement.setInt(1, random.nextInt(dbRows) + 1) - - statement.executeQuery().use { rs -> - rs.next() - result += World(rs.getInt(1), rs.getInt(2)) - } - } - } - - return result - } - - get("/queries") { - val queries = call.queries() - val random = ThreadLocalRandom.current() - - val result = withContext(databaseDispatcher) { - pool.connection.use { it.selectWorlds(queries, random) } - } - - call.respondText(Json.encodeToString(result), ContentType.Application.Json) - } - - get("/fortunes") { - val result = mutableListOf() - withContext(databaseDispatcher) { - pool.connection.use { connection -> - connection.prepareStatement("SELECT id, message FROM fortune").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.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: List - - withContext(databaseDispatcher) { - pool.connection.use { connection -> - result = connection.selectWorlds(queries, random) - - result.forEach { it.randomNumber = random.nextInt(dbRows) + 1 } - - connection.prepareStatement("UPDATE World SET randomNumber = ? WHERE id = ?") - .use { updateStatement -> - for ((id, randomNumber) in result) { - updateStatement.setInt(1, randomNumber) - updateStatement.setInt(2, id) - - updateStatement.executeUpdate() - } - } - } - } - - call.respondText(Json.encodeToString(result), ContentType.Application.Json) - } - } -} - -fun HikariConfig.configurePostgres(poolSize: Int) { - jdbcUrl = "jdbc:postgresql://tfb-database/hello_world?useSSL=false" - 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 = 10000 - maximumPoolSize = poolSize - minimumIdle = poolSize -} - -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) -} - -fun ApplicationCall.queries() = - request.queryParameters["queries"]?.toIntOrNull()?.coerceIn(1, 500) ?: 1 diff --git a/frameworks/Kotlin/ktor/ktor/src/main/kotlin/org/jetbrains/ktor/benchmarks/Models.kt b/frameworks/Kotlin/ktor/ktor/src/main/kotlin/org/jetbrains/ktor/benchmarks/Models.kt new file mode 100644 index 00000000000..b4325257282 --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor/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) \ No newline at end of file diff --git a/frameworks/Kotlin/ktor/ktor/src/main/kotlin/org/jetbrains/ktor/benchmarks/Responses.kt b/frameworks/Kotlin/ktor/ktor/src/main/kotlin/org/jetbrains/ktor/benchmarks/Responses.kt new file mode 100644 index 00000000000..07f21a06cf0 --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor/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 + )) +} \ No newline at end of file diff --git a/frameworks/Kotlin/ktor/ktor/src/main/kotlin/org/jetbrains/ktor/benchmarks/main.kt b/frameworks/Kotlin/ktor/ktor/src/main/kotlin/org/jetbrains/ktor/benchmarks/main.kt new file mode 100644 index 00000000000..eea3566b953 --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor/src/main/kotlin/org/jetbrains/ktor/benchmarks/main.kt @@ -0,0 +1,151 @@ +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.html.respondHtml +import io.ktor.server.plugins.defaultheaders.* +import io.ktor.server.response.* +import io.ktor.server.routing.* +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.withContext +import kotlinx.html.* +import java.sql.Connection +import java.util.StringJoiner +import kotlin.random.Random + +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) + val random = Random.Default + + install(DefaultHeaders) + + routing { + get("/plaintext") { + call.respond(helloWorldContent) + } + + get("/json") { + call.respondJson(Message(HELLO_WORLD)) + } + + get("/db") { + val world = withContext(databaseDispatcher) { + pool.connection.use { connection -> + connection.prepareStatement(WORLD_QUERY).use { statement -> + statement.setInt(1, random.nextInt(DB_ROWS) + 1) + statement.executeQuery().use { rs -> + rs.next() + World(rs.getInt(1), rs.getInt(2)) + } + } + } + } + call.respondJson(world) + } + + fun Connection.selectWorlds(queries: Int): Array = + prepareStatement(WORLD_QUERY).use { statement -> + Array(queries) { i -> + statement.setInt(1, random.nextInt(DB_ROWS) + 1) + statement.executeQuery().use { rs -> + rs.next() + World(rs.getInt(1), rs.getInt(2)) + } + } + } + + get("/queries") { + val queries = call.queries() + val result = withContext(databaseDispatcher) { + pool.connection.use { it.selectWorlds(queries) } + } + 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.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 result: Array + + withContext(databaseDispatcher) { + pool.connection.use { connection -> + result = connection.selectWorlds(queries) + + val updateSql = StringJoiner( + ", ", + "UPDATE World SET randomNumber = temp.randomNumber FROM (VALUES ", + " ORDER BY 1) AS temp(id, randomNumber) WHERE temp.id = World.id" + ) + + for (i in result.indices) { + result[i].randomNumber = random.nextInt(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) + } + } +} + + +fun ApplicationCall.queries() = + request.queryParameters["queries"]?.toIntOrNull()?.coerceIn(1, 500) ?: 1 diff --git a/frameworks/Kotlin/ktor/ktor/src/main/resources/application.conf b/frameworks/Kotlin/ktor/ktor/src/main/resources/application.conf index 8faba62906a..ad26f4f1ddc 100644 --- a/frameworks/Kotlin/ktor/ktor/src/main/resources/application.conf +++ b/frameworks/Kotlin/ktor/ktor/src/main/resources/application.conf @@ -7,6 +7,6 @@ ktor { } application { - modules = [ org.jetbrains.ktor.benchmarks.HelloKt.main ] + modules = [org.jetbrains.ktor.benchmarks.MainKt.main] } } diff --git a/frameworks/Kotlin/ktor/ktor/src/main/resources/logback.xml b/frameworks/Kotlin/ktor/ktor/src/main/resources/logback.xml index 9fd0f518971..5aa05dbf60c 100644 --- a/frameworks/Kotlin/ktor/ktor/src/main/resources/logback.xml +++ b/frameworks/Kotlin/ktor/ktor/src/main/resources/logback.xml @@ -11,11 +11,11 @@ - + - - + + diff --git a/frameworks/Kotlin/pellet/pellet.dockerfile b/frameworks/Kotlin/pellet/pellet.dockerfile index cb96c1079c5..3600569ea35 100644 --- a/frameworks/Kotlin/pellet/pellet.dockerfile +++ b/frameworks/Kotlin/pellet/pellet.dockerfile @@ -1,10 +1,10 @@ -FROM gradle:jdk18 as gradle +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:18-jdk-buster +FROM openjdk:22-jdk-buster WORKDIR /sample COPY --from=gradle /sample/build/libs/sample-1.0.0-all.jar app.jar diff --git a/frameworks/Kotlin/pellet/sample/build.gradle.kts b/frameworks/Kotlin/pellet/sample/build.gradle.kts index a41736ca3a7..f12dad8adbd 100644 --- a/frameworks/Kotlin/pellet/sample/build.gradle.kts +++ b/frameworks/Kotlin/pellet/sample/build.gradle.kts @@ -1,8 +1,8 @@ plugins { application id("com.github.johnrengelman.shadow") version "7.1.0" - kotlin("jvm") version "1.7.10" - kotlin("plugin.serialization") version "1.7.10" + kotlin("jvm") version "1.9.23" + kotlin("plugin.serialization") version "1.9.23" id("nu.studer.rocker") version "3.0.4" } @@ -25,31 +25,27 @@ rocker { } dependencies { - implementation(platform("dev.pellet:pellet-bom:0.0.15")) + 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.4.0-RC") + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3") implementation(platform(kotlin("bom"))) implementation(kotlin("stdlib-jdk8")) - implementation(platform("org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.6.4")) - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-jdk8") - implementation("io.vertx:vertx-pg-client:4.3.2") + 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") - implementation("io.vertx:vertx-lang-kotlin:4.3.2") - implementation("io.vertx:vertx-lang-kotlin-coroutines:4.3.2") } java { toolchain { - sourceCompatibility = JavaVersion.VERSION_18 - targetCompatibility = JavaVersion.VERSION_18 + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 } } tasks.withType { - kotlinOptions.jvmTarget = "18" + kotlinOptions.jvmTarget = "21" } application { diff --git a/frameworks/Kotlin/pellet/sample/src/main/kotlin/benchmark/Benchmark.kt b/frameworks/Kotlin/pellet/sample/src/main/kotlin/benchmark/Benchmark.kt index b756c01f476..51dd307d511 100644 --- a/frameworks/Kotlin/pellet/sample/src/main/kotlin/benchmark/Benchmark.kt +++ b/frameworks/Kotlin/pellet/sample/src/main/kotlin/benchmark/Benchmark.kt @@ -10,7 +10,6 @@ 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.coroutines.runBlocking import kotlinx.serialization.json.Json import java.time.Instant import java.time.ZoneId @@ -25,7 +24,7 @@ val jsonEncoder = Json { prettyPrint = false } -fun main() = runBlocking { +fun main() { val sharedRouter = httpRouter { get("/plaintext", ::handlePlain) get("/json", ::handleJson) @@ -44,14 +43,14 @@ fun main() = runBlocking { router = sharedRouter } } - pellet.start().join() + pellet.start() } val dateFormatter = DateTimeFormatter .ofPattern("EEE, dd MMM yyyy HH:mm:ss z", Locale.ENGLISH) .withZone(ZoneId.of("GMT")) -private suspend fun handlePlain( +private fun handlePlain( context: PelletHTTPRouteContext ): HTTPRouteResponse { return HTTPRouteResponse.Builder() @@ -67,7 +66,7 @@ data class ResponseBody( val message: String ) -private suspend fun handleJson( +private fun handleJson( context: PelletHTTPRouteContext ): HTTPRouteResponse { val responseBody = ResponseBody(message = "Hello, World!") @@ -81,7 +80,7 @@ private suspend fun handleJson( private val repository = TFBRepository() -private suspend fun handleDb( +private fun handleDb( context: PelletHTTPRouteContext ): HTTPRouteResponse { val result = repository.fetchWorld() @@ -93,7 +92,7 @@ private suspend fun handleDb( .build() } -private suspend fun handleQuery( +private fun handleQuery( context: PelletHTTPRouteContext ): HTTPRouteResponse { val rawQueries = context.firstQueryParameter("queries").getOrNull() @@ -110,7 +109,7 @@ private suspend fun handleQuery( .build() } -private suspend fun handleUpdates( +private fun handleUpdates( context: PelletHTTPRouteContext ): HTTPRouteResponse { val rawQueries = context.firstQueryParameter("queries").getOrNull() @@ -133,7 +132,7 @@ private suspend fun handleUpdates( .build() } -private suspend fun handleFortunes( +private fun handleFortunes( context: PelletHTTPRouteContext ): HTTPRouteResponse { val newFortune = Fortune(0, "Additional fortune added at request time.") 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 index 889c42ad809..2413066f829 100644 --- a/frameworks/Kotlin/pellet/sample/src/main/kotlin/benchmark/data/FortuneDAO.kt +++ b/frameworks/Kotlin/pellet/sample/src/main/kotlin/benchmark/data/FortuneDAO.kt @@ -2,5 +2,5 @@ package benchmark.data interface FortuneDAO { - suspend fun fetchFortunes(): List + 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 index c73285c8df5..75357a462de 100644 --- a/frameworks/Kotlin/pellet/sample/src/main/kotlin/benchmark/data/TFBRepository.kt +++ b/frameworks/Kotlin/pellet/sample/src/main/kotlin/benchmark/data/TFBRepository.kt @@ -1,8 +1,7 @@ package benchmark.data -import io.vertx.kotlin.coroutines.await +import io.vertx.pgclient.PgBuilder import io.vertx.pgclient.PgConnectOptions -import io.vertx.pgclient.PgPool import io.vertx.sqlclient.PoolOptions import io.vertx.sqlclient.Tuple import java.util.concurrent.ThreadLocalRandom @@ -20,14 +19,19 @@ class TFBRepository: WorldDAO, FortuneDAO { } private val poolOptions = PoolOptions() - private val client = PgPool.client(connectOptions, poolOptions) + private val client = PgBuilder.client() + .with(poolOptions) + .connectingTo(connectOptions) + .build() - override suspend fun fetchWorld(): WorldDTO { + 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)) - .await() + .toCompletionStage() + .toCompletableFuture() + .get() val row = result.first() return WorldDTO( row.getInteger(0), @@ -35,20 +39,24 @@ class TFBRepository: WorldDAO, FortuneDAO { ) } - override suspend fun updateWorlds(worlds: List) { + 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) - .await() + .toCompletionStage() + .toCompletableFuture() + .get() } - override suspend fun fetchFortunes(): List { + override fun fetchFortunes(): List { val results = client.preparedQuery("select id, message from fortune") .execute() - .await() + .toCompletionStage() + .toCompletableFuture() + .get() return results.map { Fortune( it.getInteger(0), 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 index 20324a49fb2..fd91eb40d1a 100644 --- a/frameworks/Kotlin/pellet/sample/src/main/kotlin/benchmark/data/WorldDAO.kt +++ b/frameworks/Kotlin/pellet/sample/src/main/kotlin/benchmark/data/WorldDAO.kt @@ -2,6 +2,6 @@ package benchmark.data interface WorldDAO { - suspend fun fetchWorld(): WorldDTO - suspend fun updateWorlds(worlds: List) + fun fetchWorld(): WorldDTO + fun updateWorlds(worlds: List) } \ No newline at end of file diff --git a/frameworks/Kotlin/vertx-web-kotlin-coroutines/benchmark_config.json b/frameworks/Kotlin/vertx-web-kotlin-coroutines/benchmark_config.json index d2bab14abb7..6697013773f 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-coroutines/benchmark_config.json +++ b/frameworks/Kotlin/vertx-web-kotlin-coroutines/benchmark_config.json @@ -18,8 +18,8 @@ "database_os": "Linux", "display_name": "vertx-web-kotlin-coroutines", "notes": "", - "versus": "vertx-web", - "tags": ["broken"] + "tags": ["broken"], + "versus": "vertx-web" }, "postgres": { "db_url": "/db", diff --git a/frameworks/Kotlin/vertx-web-kotlin-coroutines/build.gradle.kts b/frameworks/Kotlin/vertx-web-kotlin-coroutines/build.gradle.kts index 584f6102956..973bf6d8116 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-coroutines/build.gradle.kts +++ b/frameworks/Kotlin/vertx-web-kotlin-coroutines/build.gradle.kts @@ -1,34 +1,37 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar -import org.jetbrains.kotlin.gradle.dsl.JvmTarget -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile tasks.wrapper { distributionType = Wrapper.DistributionType.ALL } plugins { - kotlin("jvm") version "1.8.10" + kotlin("jvm") version "2.0.21" application id("nu.studer.rocker") version "3.0.4" - id("com.github.johnrengelman.shadow") version "7.1.2" + id("com.gradleup.shadow") version "8.3.4" } group = "io.vertx" -version = "4.3.8" +version = "4.3.8" // 4.5.10 is available, but this is not updated to be kept consistent with the "vert-web" portion repositories { mavenCentral() } dependencies { - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0") implementation(platform("io.vertx:vertx-stack-depchain:$version")) implementation("io.vertx:vertx-core") - implementation("com.fasterxml.jackson.module:jackson-module-blackbird:2.14.2") + 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-web") implementation("io.vertx:vertx-pg-client") implementation("io.vertx:vertx-web-templ-rocker") - implementation("io.netty", "netty-transport-native-epoll", classifier = "linux-x86_64") + 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") + */ implementation("io.vertx:vertx-lang-kotlin") implementation("io.vertx:vertx-lang-kotlin-coroutines") } @@ -38,14 +41,12 @@ rocker { create("main") { templateDir.set(file("src/main/resources")) optimize.set(true) - javaVersion.set("17") + javaVersion.set("17") // kept consistent with the "vert-web" portion } } } -tasks.withType { - compilerOptions.jvmTarget.set(JvmTarget.JVM_17) -} +kotlin.jvmToolchain(17) // kept consistent with the "vert-web" portion // content below copied from the project generated by the app generator 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 943f0cbfa75..a4b76b9530d 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 2b22d057a07..79eb9d003fe 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,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/frameworks/Kotlin/vertx-web-kotlin-coroutines/gradlew b/frameworks/Kotlin/vertx-web-kotlin-coroutines/gradlew old mode 100644 new mode 100755 index 65dcd68d65c..f5feea6d6b1 --- a/frameworks/Kotlin/vertx-web-kotlin-coroutines/gradlew +++ b/frameworks/Kotlin/vertx-web-kotlin-coroutines/gradlew @@ -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,9 @@ 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 +' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -133,10 +134,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 +148,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 +156,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 @@ -197,11 +201,15 @@ 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, 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" \ diff --git a/frameworks/Kotlin/vertx-web-kotlin-coroutines/gradlew.bat b/frameworks/Kotlin/vertx-web-kotlin-coroutines/gradlew.bat index 93e3f59f135..9d21a21834d 100644 --- a/frameworks/Kotlin/vertx-web-kotlin-coroutines/gradlew.bat +++ b/frameworks/Kotlin/vertx-web-kotlin-coroutines/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,11 +59,11 @@ 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 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 0703722b599..dfcc87cb4bb 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,10 +1,8 @@ -FROM gradle:7.6-jdk17 as gradle +FROM gradle:8.10.2-jdk17 as gradle WORKDIR /vertx-web-kotlin-coroutines -COPY gradle gradle COPY src src COPY build.gradle.kts build.gradle.kts COPY gradle.properties gradle.properties -COPY gradlew gradlew COPY settings.gradle.kts settings.gradle.kts RUN gradle shadowJar 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 5c9e6378404..dfcc87cb4bb 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:7.6-jdk17 as gradle +FROM gradle:8.10.2-jdk17 as gradle WORKDIR /vertx-web-kotlin-coroutines COPY src src COPY build.gradle.kts build.gradle.kts diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/.gitattributes b/frameworks/Kotlin/vertx-web-kotlin-dsljson/.gitattributes new file mode 100644 index 00000000000..097f9f98d9e --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/.gitattributes @@ -0,0 +1,9 @@ +# +# https://help.github.com/articles/dealing-with-line-endings/ +# +# Linux start script should use lf +/gradlew text eol=lf + +# These are Windows script files and should use crlf +*.bat text eol=crlf + diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/README.md b/frameworks/Kotlin/vertx-web-kotlin-dsljson/README.md new file mode 100644 index 00000000000..2cb792746e2 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/README.md @@ -0,0 +1,42 @@ +# Vert.x-Web Kotlin Dsljson Benchmarking Test + +Vert.x-Web in Kotlin with Dsljson serialization + +The code is written as a realistic server implementation: +- Code is organized logically into packages +- Repositories are created for each database entity to handler all operations pertaining to a specific table +- Handlers map to the logical entities which they serve +- JSON serialization is provided via Dsljson + - Doing this effectively required a custom Vert.x Buffer implementation that also extended OutputStream in order to rely on the efficient Vert.x heap memory pool instead of building a novel implementation. + +## Test URLs + +### JSON + +http://localhost:8080/json + +### PLAINTEXT + +http://localhost:8080/plaintext + +### DB + +http://localhost:8080/db + +### QUERY + +http://localhost:8080/query?queries= + +### UPDATE + +http://localhost:8080/update?queries= + + +Testing: + +```shell +../../../tfb \ + --mode benchmark \ + --test vertx-web-kotlin-dsljson \ + --type json +``` \ No newline at end of file diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/benchmark_config.json b/frameworks/Kotlin/vertx-web-kotlin-dsljson/benchmark_config.json new file mode 100644 index 00000000000..0625b6406be --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/benchmark_config.json @@ -0,0 +1,46 @@ +{ + "framework": "vertx-web-kotlin-dsljson", + "tests": [ + { + "default": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "None", + "framework": "vertx-web", + "language": "Kotlin", + "flavor": "None", + "orm": "Raw", + "platform": "Vert.x", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "vertx-web-kotlin-dsljson", + "notes": "", + "versus": "vertx-web" + }, + "postgresql": { + "db_url": "/db", + "query_url": "/queries?queries=", + "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-kotlin-dsljson-postgresql", + "notes": "", + "versus": "vertx-web-postgres" + } + } + ] +} diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/build.gradle.kts b/frameworks/Kotlin/vertx-web-kotlin-dsljson/build.gradle.kts new file mode 100644 index 00000000000..03517f3a9a7 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/build.gradle.kts @@ -0,0 +1,116 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget + +plugins { + alias(libs.plugins.kotlin.jvm) + alias(libs.plugins.kotlin.kapt) + alias(libs.plugins.shadow) + application +} + +group = "com.example" +version = "1.0.0-SNAPSHOT" + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(25)) + } +} + +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", + "-Xlambdas=indy", + "-Xjdk-release=25" + )) + } + jvmToolchain(25) +} + +application { + mainClass = "com.example.starter.AppKt" +} + +dependencies { + // Kotlin + implementation(libs.kotlin.stdlib) + implementation(libs.kotlin.reflect) + + // Vert.x + implementation(platform(libs.vertx.bom)) + implementation(libs.vertx.core) + implementation(libs.vertx.web) + 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)) + resolvePlatformSpecificNettyDependencies(libs.versions.netty.get()) + .forEach { implementation(it) } + + // DSL-JSON + implementation(libs.dsl.json) + kapt(libs.dsl.json) + + // Log4j + implementation(libs.log4j.core) + implementation(libs.log4j.api) + implementation(libs.log4j.api.kotlin) + implementation(libs.disruptor) +} + +tasks { + register("server") { + dependsOn(this@tasks.classes) + + mainClass.set(application.mainClass.get()) + classpath = sourceSets.main.get().runtimeClasspath + + jvmArgs = listOf( + "-server", + "--enable-native-access=ALL-UNNAMED", + "--add-opens=java.base/java.lang=ALL-UNNAMED", + "--sun-misc-unsafe-memory-access=allow", + "-Xms2G", + "-Xmx2G", + "-XX:+AlwaysPreTouch", + "-XX:+UseParallelGC", + "-XX:InitialCodeCacheSize=512m", + "-XX:ReservedCodeCacheSize=512m", + "-XX:MaxInlineLevel=20", + "-XX:+UseNUMA", + "-XX:-UseCodeCacheFlushing", + "-XX:AutoBoxCacheMax=10001", + "-XX:+UseCompactObjectHeaders", + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+DebugNonSafepoints", + "-Djava.net.preferIPv4Stack=true", + "-Dvertx.disableMetrics=true", + "-Dvertx.disableWebsockets=true", + "-Dvertx.disableContextTimings=true", + "-Dvertx.cacheImmutableHttpResponseHeaders=true", + "-Dvertx.internCommonHttpRequestHeadersToLowerCase=true", + "-Dvertx.disableHttpHeadersValidation=true", + "-Dio.netty.noUnsafe=false", + "-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", + "-Dtfb.type=basic", + ) + } + + shadowJar { + archiveClassifier = "fat" + mergeServiceFiles() + } +} diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/buildSrc/build.gradle.kts b/frameworks/Kotlin/vertx-web-kotlin-dsljson/buildSrc/build.gradle.kts new file mode 100644 index 00000000000..4a87641372c --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/buildSrc/build.gradle.kts @@ -0,0 +1,7 @@ +plugins { + `kotlin-dsl` +} + +repositories { + mavenCentral() +} \ No newline at end of file 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 new file mode 100644 index 00000000000..99d81bec357 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/buildSrc/src/main/kotlin/Helper.kt @@ -0,0 +1,58 @@ +enum class SystemType { + LINUX_X86_64, + LINUX_AMD64, + LINUX_AARCH64, + OSX_X86_64, + OSX_AARCH64, + WINDOWS_AMD64, + WINDOWS_AARCH64, + UNKNOWN, +} + +data class SystemInfo( + val type: SystemType, + val os: OperatingSystem, +) { + data class OperatingSystem( + val name: String, + val arch: String, + ) +} + +val CURRENT_SYSTEM_INFO by lazy { + val os = System.getProperty("os.name").lowercase() + val arch = System.getProperty("os.arch").lowercase() + val type = when { + os.startsWith("linux") && arch == "x86_64" -> SystemType.LINUX_X86_64 + os.startsWith("linux") && arch == "amd64" -> SystemType.LINUX_AMD64 + os.startsWith("linux") && arch == "aarch64" -> SystemType.LINUX_AARCH64 + os.startsWith("mac") && arch == "x86_64" -> SystemType.OSX_X86_64 + os.startsWith("mac") && arch == "aarch64" -> SystemType.OSX_AARCH64 + os.startsWith("windows") && arch == "amd64" -> SystemType.WINDOWS_AMD64 + os.startsWith("windows") && arch == "aarch64" -> SystemType.WINDOWS_AARCH64 + else -> SystemType.UNKNOWN + } + + SystemInfo( + type = type, + os = SystemInfo.OperatingSystem( + name = os, + arch = arch, + ) + ) +} + +fun resolvePlatformSpecificNettyDependencies(version: String) = when (CURRENT_SYSTEM_INFO.type) { + SystemType.LINUX_X86_64, + SystemType.LINUX_AMD64 -> arrayOf( + "io.netty:netty-transport-native-io_uring:$version:linux-x86_64", + ) + SystemType.LINUX_AARCH64 -> arrayOf( + "io.netty:netty-transport-native-io_uring:$version:linux-aarch_64", + ) + SystemType.OSX_AARCH64 -> arrayOf( + "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") +} \ 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 new file mode 100755 index 00000000000..6b8380b9308 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/configuration/scripts/server.sh @@ -0,0 +1,94 @@ +#!/bin/bash + +set -euo pipefail + +if [ -f /proc/cpuinfo ]; then + CPU_COUNT=$(grep --count ^processor /proc/cpuinfo) +else + CPU_COUNT=$(sysctl -n hw.ncpu 2>/dev/null || echo 1) +fi + +JAR_PATH="./build/libs/vertx-web-kotlin-dsljson-benchmark-1.0.0-SNAPSHOT-fat.jar" +PG_DOCKER_PATH="../../../toolset/databases/postgres" + +HAS_DB=false +while [[ $# -gt 0 ]]; do + case $1 in + -db) + HAS_DB=true + ;; + esac + shift +done + +if [ "$HAS_DB" = true ]; then + docker image inspect tfb-postgres >/dev/null 2>&1 || \ + docker build -f "$PG_DOCKER_PATH/postgres.dockerfile" -t tfb-postgres "$PG_DOCKER_PATH" + + # ensure no old container blocks name reuse + docker rm -f tfb-postgres >/dev/null 2>&1 || true + + docker run --rm --name tfb-postgres -p 5432:5432 -d tfb-postgres + + until PGPASSWORD=benchmarkdbpass psql -h "0.0.0.0" -U benchmarkdbuser -d hello_world -c '\dt' > /dev/null 2>&1; do + sleep 1 + done +fi + +cleanup() { + echo "Caught termination signal. Cleaning up..." + if [ -n "${JAVA_PID:-}" ]; then + kill -SIGTERM "$JAVA_PID" 2>/dev/null || true + wait "$JAVA_PID" 2>/dev/null || true + fi + + if [ "$HAS_DB" = true ]; then + echo "Stopping postgres container..." + docker stop tfb-postgres >/dev/null 2>&1 || true + docker rm -f tfb-postgres >/dev/null 2>&1 || true + fi +} + +trap cleanup SIGINT SIGTERM EXIT + +java \ + -server \ + --enable-native-access=ALL-UNNAMED \ + --add-opens=java.base/java.lang=ALL-UNNAMED \ + -Xms2G \ + -Xmx2G \ + -XX:+AlwaysPreTouch \ + -XX:+UseZGC \ + -XX:+ZUncommit \ + -XX:+DisableExplicitGC \ + -XX:+UseLargePages \ + -XX:+UseStringDeduplication \ + -XX:+EnableDynamicAgentLoading \ + -XX:InitialCodeCacheSize=512m \ + -XX:ReservedCodeCacheSize=512m \ + -XX:MaxInlineLevel=20 \ + -XX:+UseNUMA \ + -XX:-UseCodeCacheFlushing \ + -XX:AutoBoxCacheMax=10001 \ + -Djava.net.preferIPv4Stack=true \ + -Dvertx.disableMetrics=true \ + -Dvertx.disableDnsResolver=true \ + -Dvertx.disableWebsockets=true \ + -Dvertx.disableContextTimings=true \ + -Dvertx.cacheImmutableHttpResponseHeaders=true \ + -Dvertx.internCommonHttpRequestHeadersToLowerCase=true \ + -Dvertx.disableHttpHeadersValidation=true \ + -Dio.netty.noUnsafe=false \ + -Dio.netty.buffer.checkBounds=false \ + -Dio.netty.buffer.checkAccessible=false \ + -Dio.netty.recycler.maxCapacity.default=0 \ + -Dio.netty.maxDirectMemory=0 \ + "-Dtfb.hasDB=$HAS_DB" \ + "-Dtfb.pgHostOverride=0.0.0.0" \ + -jar "$JAR_PATH" & + +JAVA_PID=$! + +echo "Server PID: $JAVA_PID" + +wait "$JAVA_PID" diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradle.properties b/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradle.properties new file mode 100644 index 00000000000..f97ebb7d334 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradle.properties @@ -0,0 +1 @@ +org.gradle.parallel=true diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradle/libs.versions.toml b/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradle/libs.versions.toml new file mode 100644 index 00000000000..42556c390c6 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradle/libs.versions.toml @@ -0,0 +1,44 @@ +[versions] +kotlin = "2.3.0-Beta2" +shadow = "9.2.2" +vertx = "5.0.5" +micrometer = "1.16.0" +netty = "4.2.7.Final" +dsljson = "2.0.2" +log4j = "2.25.2" +log4j-kotlin = "1.5.0" +disruptor = "4.0.0" + +[libraries] +# Kotlin +kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib-jdk8", version.ref = "kotlin" } +kotlin-reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin" } + +# Vert.x +vertx-bom = { module = "io.vertx:vertx-stack-depchain", version.ref = "vertx" } +vertx-core = { module = "io.vertx:vertx-core" } +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" } + +# DSL-JSON +dsl-json = { module = "com.dslplatform:dsl-json", version.ref = "dsljson" } + +# Logging +log4j-core = { module = "org.apache.logging.log4j:log4j-core", version.ref = "log4j" } +log4j-api = { module = "org.apache.logging.log4j:log4j-api", version.ref = "log4j" } +log4j-api-kotlin = { module = "org.apache.logging.log4j:log4j-api-kotlin", version.ref = "log4j-kotlin" } +disruptor = { module = "com.lmax:disruptor", version.ref = "disruptor" } + +[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" } diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradle/wrapper/gradle-wrapper.jar b/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000000..8bdaf60c75a Binary files /dev/null and b/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradle/wrapper/gradle-wrapper.jar differ diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradle/wrapper/gradle-wrapper.properties b/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000000..bad7c2462f5 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.0-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradlew b/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradlew new file mode 100755 index 00000000000..adff685a034 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradlew @@ -0,0 +1,248 @@ +#!/bin/sh + +# +# 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. +# You may obtain a copy of the License at +# +# https://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. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# 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/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# 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\n' "$PWD" ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# 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 ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + + + +# 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 + 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. +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=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# 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" \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradlew.bat b/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradlew.bat new file mode 100644 index 00000000000..c4bdd3ab8e3 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/gradlew.bat @@ -0,0 +1,93 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@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 ########################################################################## +@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=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@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="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +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 + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +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 + + + +@rem Execute Gradle +"%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 +if %ERRORLEVEL% equ 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! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/settings.gradle.kts b/frameworks/Kotlin/vertx-web-kotlin-dsljson/settings.gradle.kts new file mode 100644 index 00000000000..a9e579940ea --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/settings.gradle.kts @@ -0,0 +1,15 @@ +pluginManagement { + repositories { + gradlePluginPortal() + mavenCentral() + } +} + +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 new file mode 100644 index 00000000000..21b08c43611 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/App.kt @@ -0,0 +1,80 @@ +package com.example.starter + +import com.example.starter.helpers.PeriodicResolver +import com.example.starter.helpers.Properties +import com.example.starter.utils.block +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 + +private val LOGGER = logger("App") + +fun main(): Unit = runBlocking { + val vertx = Vertx.vertx( + vertxOptionsOf( + eventLoopPoolSize = Properties.EVENT_LOOP_POOL_SIZE, + 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 + ) + ) + + if (!vertx.isNativeTransportEnabled) { + throw IllegalStateException( + "Native transport not enabled; missing required dependencies", + vertx.unavailableNativeTransportCause(), + ) + } + + vertx.exceptionHandler { + LOGGER.error("Vertx unexpected exception", it) + } + + Runtime.getRuntime().addShutdownHook( + Thread { + vertx.close().block(5.seconds) + } + ) + + PeriodicResolver.init(vertx) + + val options = deploymentOptionsOf( + instances = Properties.EVENT_LOOP_POOL_SIZE, + ) + + val deployment = when (Properties.TYPE) { + "basic" -> vertx.deployVerticle( + BasicVerticle::class.java, + options + ) + "postgres" -> vertx.deployVerticle( + PostgresVerticle::class.java, + options + ) + "all" -> vertx.deployVerticle( + ServerVerticle::class.java, + options + ) + else -> throw IllegalStateException("Unknown deployment type: ${Properties.TYPE}") + } + + deployment.coAwait() + + LOGGER.info("${Properties.SERVER_NAME} started.") +} 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 new file mode 100644 index 00000000000..0a20956558e --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/BasicVerticle.kt @@ -0,0 +1,46 @@ +package com.example.starter + +import com.example.starter.handlers.DefaultHandler +import com.example.starter.handlers.MessageHandler +import com.example.starter.helpers.Properties +import com.example.starter.utils.isConnectionReset +import io.vertx.kotlin.coroutines.CoroutineVerticle +import io.vertx.kotlin.coroutines.coAwait +import org.apache.logging.log4j.kotlin.Logging + +class BasicVerticle : CoroutineVerticle() { + override suspend fun start() { + val defaultHandler = DefaultHandler() + val messageHandler = MessageHandler() + + val server = vertx + .createHttpServer(Properties.HTTP) + .requestHandler { + val path = it.path() + val code = when (path.length) { + 10 -> if (path == PLAINTEXT_PATH) 1 else 0 + 5 -> if (path == JSON_PATH) 2 else 0 + else -> 0 + } + when (code) { + 1 -> defaultHandler.plaintext(it) + 2 -> messageHandler.readDefaultMessage(it) + else -> it.response().setStatusCode(404).end() + } + } + .exceptionHandler { + if (!it.isConnectionReset()) { + logger.error("Exception in HttpServer", it) + } + } + .listen() + .coAwait() + + logger.info("HTTP server started on port ${server.actualPort()}") + } + + 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 new file mode 100644 index 00000000000..5d31eb03bc4 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/PostgresVerticle.kt @@ -0,0 +1,63 @@ +package com.example.starter + +import com.example.starter.db.FortuneRepository +import com.example.starter.db.WorldRepository +import com.example.starter.handlers.FortuneHandler +import com.example.starter.handlers.WorldHandler +import com.example.starter.helpers.Properties +import com.example.starter.utils.isConnectionReset +import io.vertx.kotlin.coroutines.CoroutineVerticle +import io.vertx.kotlin.coroutines.coAwait +import io.vertx.pgclient.PgConnection +import org.apache.logging.log4j.kotlin.Logging + +class PostgresVerticle : CoroutineVerticle() { + override suspend fun start() { + val conn = PgConnection.connect(vertx, Properties.PG_CONNECT).coAwait() + + val fortuneRepository = FortuneRepository.init(conn) + val worldRepository = WorldRepository.init(conn) + + val fortuneHandler = FortuneHandler(fortuneRepository.coAwait()) + val worldHandler = WorldHandler(worldRepository.coAwait()) + + val server = vertx + .createHttpServer(Properties.HTTP) + .requestHandler { + val path = it.path() + val code = when (path.length) { + 9 -> if (path == FORTUNES_PATH) 1 else 0 + 3 -> if (path == DB_PATH) 2 else 0 + 8 -> when (path) { + QUERIES_PATH -> 3 + UPDATES_PATH -> 4 + else -> 0 + } + else -> 0 + } + when (code) { + 1 -> fortuneHandler.templateFortunes(it) + 2 -> worldHandler.readRandomWorld(it) + 3 -> worldHandler.readRandomWorlds(it) + 4 -> worldHandler.updateRandomWorlds(it) + else -> it.response().setStatusCode(404).end() + } + } + .exceptionHandler { + if (!it.isConnectionReset()) { + logger.error("Exception in HttpServer", it) + } + } + .listen() + .coAwait() + + logger.info("HTTP server started on port ${server.actualPort()}") + } + + companion object : Logging { + private const val FORTUNES_PATH = "/fortunes" + private const val DB_PATH = "/db" + private const val QUERIES_PATH = "/queries" + private const val UPDATES_PATH = "/updates" + } +} 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 new file mode 100644 index 00000000000..c86ea244774 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/ServerVerticle.kt @@ -0,0 +1,91 @@ +package com.example.starter + +import com.example.starter.db.FortuneRepository +import com.example.starter.db.WorldRepository +import com.example.starter.handlers.DefaultHandler +import com.example.starter.handlers.FortuneHandler +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() { + override suspend fun start() { + val conn = PgConnection.connect(vertx, Properties.PG_CONNECT).coAwait() + + val fortuneRepository = FortuneRepository.init(conn) + val worldRepository = WorldRepository.init(conn) + + val fortuneHandler = FortuneHandler(fortuneRepository.coAwait()) + val worldHandler = WorldHandler(worldRepository.coAwait()) + + 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 { + val path = it.path() + val code = when (path.length) { + 10 -> if (path == PLAINTEXT_PATH) 1 else 0 + 5 -> if (path == JSON_PATH) 2 else 0 + 9 -> if (path == FORTUNES_PATH) 3 else 0 + 3 -> if (path == DB_PATH) 4 else 0 + 8 -> when (path) { + QUERIES_PATH -> 5 + UPDATES_PATH -> 6 + METRICS_PATH -> 7 + else -> 0 + } + else -> 0 + } + when (code) { + 1 -> defaultHandler.plaintext(it) + 2 -> messageHandler.readDefaultMessage(it) + 3 -> fortuneHandler.templateFortunes(it) + 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() + } + } + .exceptionHandler { + if (!it.isConnectionReset()) { + logger.error("Exception in HttpServer", it) + } + } + .listen() + .coAwait() + + logger.info("HTTP server started on port ${server.actualPort()}") + } + + companion object : Logging { + private const val METRICS_PATH = "/metrics" + private const val PLAINTEXT_PATH = "/plaintext" + private const val JSON_PATH = "/json" + private const val FORTUNES_PATH = "/fortunes" + private const val DB_PATH = "/db" + private const val QUERIES_PATH = "/queries" + private const val UPDATES_PATH = "/updates" + } +} diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/db/AbstractRepository.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/db/AbstractRepository.kt new file mode 100644 index 00000000000..f2dec9a5f84 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/db/AbstractRepository.kt @@ -0,0 +1,7 @@ +package com.example.starter.db + +import io.vertx.pgclient.PgConnection + +abstract class AbstractRepository( + protected val conn: PgConnection +) \ No newline at end of file diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/db/FortuneRepository.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/db/FortuneRepository.kt new file mode 100644 index 00000000000..a3c0831f3aa --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/db/FortuneRepository.kt @@ -0,0 +1,39 @@ +package com.example.starter.db + +import com.example.starter.models.Fortune +import com.example.starter.utils.mapToArray + +import io.vertx.core.Future +import io.vertx.pgclient.PgConnection +import io.vertx.sqlclient.PreparedQuery +import io.vertx.sqlclient.Row +import io.vertx.sqlclient.RowSet + +@Suppress("NOTHING_TO_INLINE") +class FortuneRepository( + conn: PgConnection, + private val selectFortunesQuery: PreparedQuery>, +) : AbstractRepository(conn) { + + fun selectFortunes(): Future> = selectFortunesQuery + .execute() + .map { it.mapToArray(FortuneRepository::map) } + + companion object { + private const val SELECT_FORTUNES_SQL = "SELECT id, message FROM fortune" + + private inline fun map(row: Row): Fortune = Fortune( + row.getInteger(0), + row.getString(1), + ) + + fun init(conn: PgConnection): Future = conn.let { conn -> + conn.prepare(SELECT_FORTUNES_SQL).map { ps -> + FortuneRepository( + conn, + ps.query(), + ) + } + } + } +} \ No newline at end of file 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 new file mode 100644 index 00000000000..e12717e7228 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/db/WorldRepository.kt @@ -0,0 +1,115 @@ +package com.example.starter.db + +import com.example.starter.models.World +import io.vertx.core.Future +import io.vertx.core.Promise +import io.vertx.core.impl.future.CompositeFutureImpl +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 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( + conn: PgConnection, + private val selectWorldQuery: PreparedQuery>, + private val updateWorldQueries: Array>>, +) : AbstractRepository(conn) { + fun selectRandomWorld(): Future = selectWorldQuery + .execute(Tuple.of(randomWorld())) + .map { map(it.first()) } + + fun selectRandomWorlds(numWorlds: Int): Future> { + val promise = Promise.promise>() + val arr = arrayOfNulls(numWorlds) + val count = AtomicInteger(0) + (this.conn as SqlClientInternal).group { c -> + val query = c.preparedQuery(SELECT_WORLD_SQL) + repeat(numWorlds) { _ -> + query.execute(Tuple.of(randomWorld())) + .onComplete { ar -> + when { + ar.succeeded() -> { + val result = ar.result() + val index = count.getAndIncrement() + arr[index] = map(result.iterator().next()) + if (index == numWorlds - 1) { + promise.complete(arr as Array) + } + } + else -> promise.fail(ar.cause()) + } + } + } + } + return promise.future() + } + + fun updateRandomWorlds(numWorlds: Int): Future> = selectRandomWorlds(numWorlds) + .flatMap { worlds -> + val params = ArrayTuple(worlds.size * 3) + worlds.forEach { + it.randomNumber = randomWorld() + params.addValue(it.id) + params.addValue(it.randomNumber) + } + worlds.forEach { + params.addValue(it.id) + } + updateWorldQueries[numWorlds - 1].execute(params).map { worlds } + } + + companion object { + 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), + ) + + fun init(conn: PgConnection): Future = conn.let { conn -> + val selectWorldQuery = conn.prepare(SELECT_WORLD_SQL).map { ps -> ps.query() } + val updateWorldQueries = run { + val queries = arrayOfNulls>>(500) + Array(500) { num -> + val count = num + 1 + var paramIndex = 1 + val sb = StringBuilder() + sb.append("UPDATE world SET randomnumber = CASE id ") + repeat(count) { + sb.append("WHEN $${paramIndex++} THEN $${paramIndex++} ") + } + sb.append("ELSE randomnumber END WHERE id IN (") + repeat(count) { + sb.append("$${paramIndex++},") + } + sb[sb.length - 1] = ')' + + conn + .prepare(sb.toString()) + .map { ps -> + queries[num] = ps.query() + } + }.let { + CompositeFutureImpl.all(*it).map { + queries as Array>> + } + } + } + + CompositeFutureImpl.all(selectWorldQuery, updateWorldQueries).map { + WorldRepository( + conn, + selectWorldQuery.result(), + updateWorldQueries.result(), + ) + } + } + } +} 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 new file mode 100644 index 00000000000..d34e72b5598 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/AbstractHandler.kt @@ -0,0 +1,52 @@ +package com.example.starter.handlers + +import com.example.starter.helpers.PeriodicResolver +import com.example.starter.helpers.Properties +import io.netty.handler.codec.http.HttpHeaderNames +import io.netty.handler.codec.http.HttpHeaderValues +import io.vertx.core.Future +import io.vertx.core.MultiMap +import io.vertx.core.buffer.Buffer +import io.vertx.core.http.HttpHeaders +import io.vertx.core.http.HttpServerRequest +import io.vertx.core.http.HttpServerResponse +import io.vertx.core.internal.buffer.BufferInternal + +@Suppress("NOTHING_TO_INLINE") +abstract class AbstractHandler { + protected companion object { + val SOMETHING_WENT_WRONG: Buffer = BufferInternal.buffer("Something went wrong") + + // Headers + val SERVER: CharSequence = HttpHeaders.createOptimized(Properties.SERVER_NAME) + + inline fun MultiMap.common(): MultiMap = this + .add(HttpHeaderNames.SERVER, SERVER) + .add(HttpHeaderNames.DATE, PeriodicResolver.current) + + inline fun HttpServerRequest.json(): HttpServerResponse = response() + .apply { + headers() + .common() + .add(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.APPLICATION_JSON) + } + + inline fun HttpServerRequest.plaintext(): HttpServerResponse = response() + .apply { + headers() + .common() + .add(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN) + } + + inline fun HttpServerRequest.html(): HttpServerResponse = response() + .apply { + headers() + .common() + .add(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_HTML) + } + + inline fun HttpServerRequest.error(): Future = plaintext() + .setStatusCode(500) + .end(SOMETHING_WENT_WRONG) + } +} \ No newline at end of file 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 new file mode 100644 index 00000000000..7f981320192 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/DefaultHandler.kt @@ -0,0 +1,19 @@ +package com.example.starter.handlers + +import com.example.starter.helpers.PeriodicResolver +import io.vertx.core.Future +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) + } + .end(MESSAGE_BUFFER) + + companion object { + const val MESSAGE: String = "Hello, World!" + val MESSAGE_BUFFER: Buffer = Buffer.buffer(MESSAGE, "UTF-8") + } +} 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 new file mode 100644 index 00000000000..029026dab4c --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/FortuneHandler.kt @@ -0,0 +1,40 @@ +package com.example.starter.handlers + +import com.example.starter.db.FortuneRepository +import com.example.starter.models.Fortune +import io.vertx.core.http.HttpServerRequest +import java.lang.Exception +import org.apache.logging.log4j.kotlin.Logging + +class FortuneHandler(private val repository: FortuneRepository) : AbstractHandler() { + fun templateFortunes(req: HttpServerRequest) { + repository + .selectFortunes() + .onComplete { ar -> + 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) + } catch (ex: Exception) { + logger.error(SOMETHING_WENT_WRONG, ex) + req.error() + } + } + else -> { + logger.error(SOMETHING_WENT_WRONG, ar.cause()) + req.error() + } + } + } + } + + private companion object : Logging { + private fun renderFortunes(fortunes: Array): String { + throw NotImplementedError("Not implemented") + } + } +} 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 new file mode 100644 index 00000000000..0a91afea21e --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/MessageHandler.kt @@ -0,0 +1,20 @@ +package com.example.starter.handlers + +import com.example.starter.helpers.PeriodicResolver +import com.example.starter.models.Message +import com.example.starter.utils.serialize +import io.vertx.core.Future +import io.vertx.core.http.HttpServerRequest + +class MessageHandler : AbstractHandler() { + fun readDefaultMessage(req: HttpServerRequest): Future = req + .response().apply { + headers().setAll(PeriodicResolver.json) + } + .end(Message(MESSAGE).serialize()) + + 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/handlers/WorldHandler.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/WorldHandler.kt new file mode 100644 index 00000000000..c8152dda51f --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/handlers/WorldHandler.kt @@ -0,0 +1,59 @@ +package com.example.starter.handlers + +import com.example.starter.db.WorldRepository +import com.example.starter.utils.serialize +import io.vertx.core.http.HttpServerRequest +import org.apache.logging.log4j.kotlin.Logging + +class WorldHandler(private val repository: WorldRepository) : AbstractHandler() { + fun readRandomWorld(req: HttpServerRequest) { + repository + .selectRandomWorld() + .onComplete { ar -> + when { + ar.succeeded() -> req.json().end(ar.result().serialize()) + else -> { + logger.error(SOMETHING_WENT_WRONG, ar.cause()) + req.error() + } + } + } + } + + fun readRandomWorlds(req: HttpServerRequest) { + repository + .selectRandomWorlds(req.queries()) + .onComplete { ar -> + when { + ar.succeeded() -> req.json().end(ar.result().serialize()) + else -> { + logger.error(SOMETHING_WENT_WRONG, ar.cause()) + req.error() + } + } + } + } + + fun updateRandomWorlds(req: HttpServerRequest) { + repository + .updateRandomWorlds(req.queries()) + .onComplete { ar -> + when { + ar.succeeded() -> req.json().end(ar.result().serialize()) + else -> { + logger.error(SOMETHING_WENT_WRONG, ar.cause()) + req.error() + } + } + } + } + + private companion object : Logging { + private const val QUERIES_PARAM_NAME = "queries" + + @Suppress("NOTHING_TO_INLINE") + private inline fun HttpServerRequest.queries(): Int = getParam(QUERIES_PARAM_NAME) + ?.toIntOrNull() + ?.coerceIn(1, 500) ?: 1 + } +} \ No newline at end of file diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/helpers/BufferOutputStream.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/helpers/BufferOutputStream.kt new file mode 100644 index 00000000000..162feef9cd6 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/helpers/BufferOutputStream.kt @@ -0,0 +1,386 @@ +package com.example.starter.helpers + +import io.netty.buffer.ByteBuf +import io.vertx.core.buffer.Buffer +import io.vertx.core.internal.buffer.BufferInternal +import io.vertx.core.json.JsonArray +import io.vertx.core.json.JsonObject +import java.io.IOException +import java.io.OutputStream +import java.nio.ByteBuffer +import java.nio.charset.Charset + +class BufferOutputStream(initialSizeHint: Int = 256) : BufferInternal, OutputStream() { + private val buffer: BufferInternal = BufferInternal.buffer(initialSizeHint) + + @Throws(IOException::class) + override fun write(b: Int) { + buffer.appendByte(b.toByte()) + } + + @Throws(IOException::class) + override fun write(bytes: ByteArray) { + buffer.appendBytes(bytes) + } + + @Throws(IOException::class) + override fun write(bytes: ByteArray, offset: Int, len: Int) { + buffer.appendBytes(bytes, offset, len) + } + + override fun toString(enc: String): String { + return buffer.toString(enc) + } + + override fun toString(enc: Charset): String { + return buffer.toString(enc) + } + + override fun copy(): BufferInternal { + return buffer.copy() + } + + override fun toJsonObject(): JsonObject { + return buffer.toJsonObject() + } + + override fun toJsonArray(): JsonArray { + return buffer.toJsonArray() + } + + override fun getByte(pos: Int): Byte { + return buffer.getByte(pos) + } + + override fun getUnsignedByte(pos: Int): Short { + return buffer.getUnsignedByte(pos) + } + + override fun getInt(pos: Int): Int { + return buffer.getInt(pos) + } + + override fun getIntLE(pos: Int): Int { + return buffer.getIntLE(pos) + } + + override fun getUnsignedInt(pos: Int): Long { + return buffer.getUnsignedInt(pos) + } + + override fun getUnsignedIntLE(pos: Int): Long { + return buffer.getUnsignedIntLE(pos) + } + + override fun getLong(pos: Int): Long { + return buffer.getLong(pos) + } + + override fun getLongLE(pos: Int): Long { + return buffer.getLongLE(pos) + } + + override fun getDouble(pos: Int): Double { + return buffer.getDouble(pos) + } + + override fun getDoubleLE(pos: Int): Double { + return buffer.getDoubleLE(pos) + } + + override fun getFloat(pos: Int): Float { + return buffer.getFloat(pos) + } + + override fun getFloatLE(pos: Int): Float { + return buffer.getFloatLE(pos) + } + + override fun getShort(pos: Int): Short { + return buffer.getShort(pos) + } + + override fun getShortLE(pos: Int): Short { + return buffer.getShortLE(pos) + } + + override fun getUnsignedShort(pos: Int): Int { + return buffer.getUnsignedShort(pos) + } + + override fun getUnsignedShortLE(pos: Int): Int { + return buffer.getUnsignedShortLE(pos) + } + + override fun getMedium(pos: Int): Int { + return buffer.getMedium(pos) + } + + override fun getMediumLE(pos: Int): Int { + return buffer.getMediumLE(pos) + } + + override fun getUnsignedMedium(pos: Int): Int { + return buffer.getUnsignedMedium(pos) + } + + override fun getUnsignedMediumLE(pos: Int): Int { + return buffer.getUnsignedMediumLE(pos) + } + + override fun getBytes(): ByteArray { + return buffer.bytes + } + + override fun getBytes(start: Int, end: Int): ByteArray { + return buffer.getBytes(start, end) + } + + override fun getBytes(dst: ByteArray): Buffer { + return buffer.getBytes(dst) + } + + override fun getBytes(dst: ByteArray, dstIndex: Int): Buffer { + return buffer.getBytes(dst, dstIndex) + } + + override fun getBytes(start: Int, end: Int, dst: ByteArray): Buffer { + return buffer.getBytes(start, end, dst) + } + + override fun getBytes(start: Int, end: Int, dst: ByteArray, dstIndex: Int): Buffer { + return buffer.getBytes(start, end, dst, dstIndex) + } + + override fun getBuffer(start: Int, end: Int): Buffer { + return buffer.getBuffer(start, end) + } + + override fun getString(start: Int, end: Int, enc: String): String { + return buffer.getString(start, end, enc) + } + + override fun getString(start: Int, end: Int): String { + return buffer.getString(start, end) + } + + override fun appendBuffer(b: Buffer): BufferInternal { + return buffer.appendBuffer(b) + } + + override fun appendBuffer(b: Buffer, offset: Int, len: Int): BufferInternal { + return buffer.appendBuffer(b, offset, len) + } + + override fun appendBytes(bytes: ByteArray): BufferInternal { + return buffer.appendBytes(bytes) + } + + override fun appendBytes(bytes: ByteArray, offset: Int, len: Int): BufferInternal { + return buffer.appendBytes(bytes, offset, len) + } + + override fun appendByte(b: Byte): BufferInternal { + return buffer.appendByte(b) + } + + override fun appendUnsignedByte(b: Short): BufferInternal { + return buffer.appendUnsignedByte(b) + } + + override fun appendInt(i: Int): BufferInternal { + return buffer.appendInt(i) + } + + override fun appendIntLE(i: Int): BufferInternal { + return buffer.appendIntLE(i) + } + + override fun appendUnsignedInt(i: Long): BufferInternal { + return buffer.appendUnsignedInt(i) + } + + override fun appendUnsignedIntLE(i: Long): BufferInternal { + return buffer.appendUnsignedIntLE(i) + } + + override fun appendMedium(i: Int): BufferInternal { + return buffer.appendMedium(i) + } + + override fun appendMediumLE(i: Int): BufferInternal { + return buffer.appendMediumLE(i) + } + + override fun appendLong(l: Long): BufferInternal { + return buffer.appendLong(l) + } + + override fun appendLongLE(l: Long): BufferInternal { + return buffer.appendLongLE(l) + } + + override fun appendShort(s: Short): BufferInternal { + return buffer.appendShort(s) + } + + override fun appendShortLE(s: Short): BufferInternal { + return buffer.appendShortLE(s) + } + + override fun appendUnsignedShort(s: Int): BufferInternal { + return buffer.appendUnsignedShort(s) + } + + override fun appendUnsignedShortLE(s: Int): BufferInternal { + return buffer.appendUnsignedShortLE(s) + } + + override fun appendFloat(f: Float): BufferInternal { + return buffer.appendFloat(f) + } + + override fun appendFloatLE(f: Float): BufferInternal { + return buffer.appendFloatLE(f) + } + + override fun appendDouble(d: Double): BufferInternal { + return buffer.appendDouble(d) + } + + override fun appendDoubleLE(d: Double): BufferInternal { + return buffer.appendDoubleLE(d) + } + + override fun appendString(str: String, enc: String): BufferInternal { + return buffer.appendString(str, enc) + } + + override fun appendString(str: String): BufferInternal { + return buffer.appendString(str) + } + + override fun setByte(pos: Int, b: Byte): BufferInternal { + return buffer.setByte(pos, b) + } + + override fun setUnsignedByte(pos: Int, b: Short): BufferInternal { + return buffer.setUnsignedByte(pos, b) + } + + override fun setInt(pos: Int, i: Int): BufferInternal { + return buffer.setInt(pos, i) + } + + override fun setIntLE(pos: Int, i: Int): BufferInternal { + return buffer.setIntLE(pos, i) + } + + override fun setUnsignedInt(pos: Int, i: Long): BufferInternal { + return buffer.setUnsignedInt(pos, i) + } + + override fun setUnsignedIntLE(pos: Int, i: Long): BufferInternal { + return buffer.setUnsignedIntLE(pos, i) + } + + override fun setMedium(pos: Int, i: Int): BufferInternal { + return buffer.setMedium(pos, i) + } + + override fun setMediumLE(pos: Int, i: Int): BufferInternal { + return buffer.setMediumLE(pos, i) + } + + override fun setLong(pos: Int, l: Long): BufferInternal { + return buffer.setLong(pos, l) + } + + override fun setLongLE(pos: Int, l: Long): BufferInternal { + return buffer.setLongLE(pos, l) + } + + override fun setDouble(pos: Int, d: Double): BufferInternal { + return buffer.setDouble(pos, d) + } + + override fun setDoubleLE(pos: Int, d: Double): BufferInternal { + return buffer.setDoubleLE(pos, d) + } + + override fun setFloat(pos: Int, f: Float): BufferInternal { + return buffer.setFloat(pos, f) + } + + override fun setFloatLE(pos: Int, f: Float): BufferInternal { + return buffer.setFloatLE(pos, f) + } + + override fun setShort(pos: Int, s: Short): BufferInternal { + return buffer.setShort(pos, s) + } + + override fun setShortLE(pos: Int, s: Short): BufferInternal { + return buffer.setShortLE(pos, s) + } + + override fun setUnsignedShort(pos: Int, s: Int): BufferInternal { + return buffer.setUnsignedShort(pos, s) + } + + override fun setUnsignedShortLE(pos: Int, s: Int): BufferInternal { + return buffer.setUnsignedShortLE(pos, s) + } + + override fun setBuffer(pos: Int, b: Buffer): BufferInternal { + return buffer.setBuffer(pos, b) + } + + override fun setBuffer(pos: Int, b: Buffer, offset: Int, len: Int): BufferInternal { + return buffer.setBuffer(pos, b, offset, len) + } + + override fun setBytes(pos: Int, b: ByteBuffer): BufferInternal { + return buffer.setBytes(pos, b) + } + + override fun setBytes(pos: Int, b: ByteArray): BufferInternal { + return buffer.setBytes(pos, b) + } + + override fun setBytes(pos: Int, b: ByteArray, offset: Int, len: Int): BufferInternal { + return buffer.setBytes(pos, b, offset, len) + } + + override fun setString(pos: Int, str: String): BufferInternal { + return buffer.setString(pos, str) + } + + override fun setString(pos: Int, str: String, enc: String): BufferInternal { + return buffer.setString(pos, str, enc) + } + + override fun length(): Int { + return buffer.length() + } + + override fun slice(): BufferInternal { + return buffer.slice() + } + + override fun slice(start: Int, end: Int): BufferInternal { + return buffer.slice(start, end) + } + + override fun getByteBuf(): ByteBuf { + return buffer.byteBuf + } + + override fun writeToBuffer(b: Buffer) { + return buffer.writeToBuffer(b) + } + + override fun readFromBuffer(pos: Int, b: Buffer): Int { + return buffer.readFromBuffer(pos, b) + } +} \ 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 new file mode 100644 index 00000000000..4e08f883e23 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/helpers/PeriodicResolver.kt @@ -0,0 +1,61 @@ +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 +import java.time.Instant +import java.time.ZoneOffset +import java.time.format.DateTimeFormatter + +private val FORMATTER = DateTimeFormatter.RFC_1123_DATE_TIME.withZone(ZoneOffset.UTC) +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 { + @Volatile + var current: CharSequence = next() + private set + + @Volatile + var plaintext: MultiMap = nextPlaintext() + private set + + @Volatile + var json: MultiMap = nextJson() + private set + + fun init(vertx: Vertx) { + vertx.setPeriodic(1_000L) { + current = next() + plaintext = nextPlaintext() + json = nextJson() + } + } + + private fun next(): CharSequence = HttpHeaders.createOptimized( + FORMATTER.format(Instant.now()) + ) + + private fun nextPlaintext(): MultiMap = HttpHeaders + .headers() + .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 + .headers() + .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 new file mode 100644 index 00000000000..ca72dd8a61c --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/helpers/Properties.kt @@ -0,0 +1,171 @@ +package com.example.starter.helpers + +import io.netty.util.internal.SystemPropertyUtil +import io.vertx.core.impl.cpu.CpuCoreSensor +import io.vertx.core.tracing.TracingPolicy +import io.vertx.kotlin.core.http.httpServerOptionsOf +import io.vertx.kotlin.pgclient.pgConnectOptionsOf + +object Properties { + + /** + * The server name (used in headers and logging). + * Default: `Vert.x-Web` + */ + val SERVER_NAME: String = SystemPropertyUtil.get("tfb.serverName", "Vert.x-Web") + + /** + * Type of verticle to deploy. + * Default: all ([com.example.starter.ServerVerticle]) + */ + val TYPE: String = SystemPropertyUtil.get("tfb.type", "all") + + /** + * Number of event loop threads. + * Default: [io.vertx.core.impl.cpu.CpuCoreSensor.availableProcessors] + */ + 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) + */ + val PG_USER: String = SystemPropertyUtil.get("tfb.pg.user", "benchmarkdbuser") + + /** + * PostgreSQL password used for connections. + * Default: benchmarkdbpass (tfb.pg.password) + */ + val PG_PASSWORD: String = SystemPropertyUtil.get("tfb.pg.password", "benchmarkdbpass") + + /** + * PostgreSQL host used for connections. + * Default: tfb.pgHostOverride system property, otherwise "tfb-database". + * Property: tfb.pg.host + */ + val PG_HOST: String = SystemPropertyUtil.get("tfb.pg.host", System.getProperty("tfb.pgHostOverride") ?: "tfb-database") + + /** + * PostgreSQL port used for connections. + * Default: 5432 (tfb.pg.port) + */ + val PG_PORT: Int = SystemPropertyUtil.getInt("tfb.pg.port", 5432) + + /** + * PostgreSQL database name used for connections. + * Default: hello_world (tfb.pg.database) + */ + val PG_DATABASE: String = SystemPropertyUtil.get("tfb.pg.database", "hello_world") + + /** + * Enables prepared statement caching on the PostgreSQL client. + * Default: true (tfb.pg.cachePreparedStatements) + */ + val PG_CACHE_PREPARED_STATEMENTS: Boolean = SystemPropertyUtil.getBoolean("tfb.pg.cachePreparedStatements", true) + + /** + * Maximum size of the prepared statement cache. + * Default: 1024 (tfb.pg.preparedStatementCacheMaxSize) + */ + val PG_PREPARED_STATEMENT_CACHE_MAX_SIZE: Int = + SystemPropertyUtil.getInt("tfb.pg.preparedStatementCacheMaxSize", 1024) + + /** + * Max number of in-flight pipelined requests per connection. + * Default: 1024 (tfb.pg.pipeliningLimit) + */ + val PG_PIPELINING_LIMIT: Int = SystemPropertyUtil.getInt("tfb.pg.pipeliningLimit", 1024) + + 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, + strictThreadMode = true, + ) + } + + val PG_CONNECT by lazy { + pgConnectOptionsOf( + user = PG_USER, + password = PG_PASSWORD, + host = PG_HOST, + port = PG_PORT, + database = PG_DATABASE, + cachePreparedStatements = PG_CACHE_PREPARED_STATEMENTS, + preparedStatementCacheMaxSize = PG_PREPARED_STATEMENT_CACHE_MAX_SIZE, + tracingPolicy = TracingPolicy.IGNORE, + pipeliningLimit = PG_PIPELINING_LIMIT + ) + } +} diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/models/Fortune.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/models/Fortune.kt new file mode 100644 index 00000000000..f9293258ed9 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/models/Fortune.kt @@ -0,0 +1,14 @@ +package com.example.starter.models + +import com.dslplatform.json.CompiledJson +import com.dslplatform.json.JsonAttribute + +@CompiledJson +class Fortune( + @field:JsonAttribute(nullable = false) val id: Int, + @field:JsonAttribute(nullable = false) val message: String, +) : Comparable { + override fun compareTo(other: Fortune): Int { + return message.compareTo(other.message) + } +} diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/models/Message.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/models/Message.kt new file mode 100644 index 00000000000..1953c10cfcb --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/models/Message.kt @@ -0,0 +1,7 @@ +package com.example.starter.models + +import com.dslplatform.json.CompiledJson +import com.dslplatform.json.JsonAttribute + +@CompiledJson +class Message(@field:JsonAttribute(nullable = false) val message: String) diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/models/World.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/models/World.kt new file mode 100644 index 00000000000..030f96ed314 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/models/World.kt @@ -0,0 +1,12 @@ +package com.example.starter.models + +import com.dslplatform.json.CompiledJson +import com.dslplatform.json.JsonAttribute + +@CompiledJson +class World( + @field:JsonAttribute(nullable = false) val id: Int, + @field:JsonAttribute(nullable = false) var randomNumber: Int, +) : Comparable { + override fun compareTo(other: World): Int = id - other.id +} diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/FutureExtensions.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/FutureExtensions.kt new file mode 100644 index 00000000000..1b9ce713000 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/FutureExtensions.kt @@ -0,0 +1,14 @@ +package com.example.starter.utils + +import io.vertx.core.Future +import io.vertx.kotlin.coroutines.coAwait +import kotlin.time.Duration +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.withTimeout + +@Suppress("NOTHING_TO_INLINE") +inline fun > T.block(duration: Duration): R = runBlocking { + withTimeout(duration) { + coAwait() + } +} \ No newline at end of file diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/JsonExtensions.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/JsonExtensions.kt new file mode 100644 index 00000000000..f7793af1509 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/JsonExtensions.kt @@ -0,0 +1,18 @@ +package com.example.starter.utils + +import com.dslplatform.json.DslJson +import com.dslplatform.json.runtime.Settings +import com.example.starter.helpers.BufferOutputStream +import io.vertx.core.buffer.Buffer + +val DSL_JSON: DslJson = DslJson( + Settings.withRuntime() + .includeServiceLoader() +) + +@Suppress("NOTHING_TO_INLINE") +inline fun T.serialize(initialSizeHint: Int = 128): Buffer { + val output = BufferOutputStream(initialSizeHint) + DSL_JSON.serialize(this, output) + return output +} diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/RowSetExtensions.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/RowSetExtensions.kt new file mode 100644 index 00000000000..7f7fcc84ab4 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/RowSetExtensions.kt @@ -0,0 +1,12 @@ +package com.example.starter.utils + +import io.vertx.sqlclient.Row +import io.vertx.sqlclient.RowSet + +// This extension relies on the assumption the mapper never returns null, as it is defined. Otherwise, +// we prevent the overhead from having to do another iteration over the loop for a `filterNotNull` check. +@Suppress("UNCHECKED_CAST", "NOTHING_TO_INLINE") +inline fun RowSet.mapToArray(mapper: (Row) -> U): Array { + val iterator = iterator() + return Array(size()) { mapper(iterator.next()) } +} diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/ThrowableExtensions.kt b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/ThrowableExtensions.kt new file mode 100644 index 00000000000..3f31f9720a9 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/kotlin/com/example/starter/utils/ThrowableExtensions.kt @@ -0,0 +1,14 @@ +package com.example.starter.utils + +import io.netty.channel.unix.Errors +import io.netty.channel.unix.Errors.NativeIoException +import java.net.SocketException + +const val CONNECTION_RESET_MESSAGE = "Connection reset" + +@Suppress("NOTHING_TO_INLINE") +inline fun Throwable.isConnectionReset(): Boolean = when (this) { + is NativeIoException if this.expectedErr() == Errors.ERRNO_ECONNRESET_NEGATIVE -> true + is SocketException if this.message == CONNECTION_RESET_MESSAGE -> true + else -> false +} diff --git a/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/resources/log4j2.xml b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..ebe0ad3cb74 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/src/main/resources/log4j2.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + 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 new file mode 100644 index 00000000000..b7157b37da2 --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/vertx-web-kotlin-dsljson-postgresql.dockerfile @@ -0,0 +1,56 @@ +# --- Build stage with JDK 25 --- +FROM gradle:9.2-jdk25-corretto AS builder + +WORKDIR /vertx-web-kotlin-dsljson + +COPY src src +COPY buildSrc buildSrc +COPY build.gradle.kts build.gradle.kts +COPY settings.gradle.kts settings.gradle.kts +COPY gradle.properties gradle.properties +COPY gradle/libs.versions.toml gradle/libs.versions.toml + +RUN gradle shadowJar --no-daemon + +# --- Runtime stage using Amazon Corretto 25 --- +FROM amazoncorretto:25 + +WORKDIR /app + +COPY --from=builder \ + /vertx-web-kotlin-dsljson/build/libs/vertx-web-kotlin-dsljson-benchmark-1.0.0-SNAPSHOT-fat.jar \ + vertx-web-kotlin-dsljson.jar + +EXPOSE 8080 + +CMD java \ + -server \ + --enable-native-access=ALL-UNNAMED \ + --add-opens=java.base/java.lang=ALL-UNNAMED \ + --sun-misc-unsafe-memory-access=allow \ + -Xms2G \ + -Xmx2G \ + -XX:+AlwaysPreTouch \ + -XX:+UseParallelGC \ + -XX:InitialCodeCacheSize=512m \ + -XX:ReservedCodeCacheSize=512m \ + -XX:MaxInlineLevel=20 \ + -XX:+UseNUMA \ + -XX:-UseCodeCacheFlushing \ + -XX:AutoBoxCacheMax=10001 \ + -XX:+UseCompactObjectHeaders \ + -Djava.net.preferIPv4Stack=true \ + -Dvertx.disableMetrics=true \ + -Dvertx.disableWebsockets=true \ + -Dvertx.disableContextTimings=true \ + -Dvertx.cacheImmutableHttpResponseHeaders=true \ + -Dvertx.internCommonHttpRequestHeadersToLowerCase=true \ + -Dvertx.disableHttpHeadersValidation=true \ + -Dio.netty.noUnsafe=false \ + -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 \ + -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 new file mode 100644 index 00000000000..c69e49fbbfd --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlin-dsljson/vertx-web-kotlin-dsljson.dockerfile @@ -0,0 +1,56 @@ +# --- Build stage with JDK 25 --- +FROM gradle:9.2-jdk25-corretto AS builder + +WORKDIR /vertx-web-kotlin-dsljson + +COPY src src +COPY buildSrc buildSrc +COPY build.gradle.kts build.gradle.kts +COPY settings.gradle.kts settings.gradle.kts +COPY gradle.properties gradle.properties +COPY gradle/libs.versions.toml gradle/libs.versions.toml + +RUN gradle shadowJar --no-daemon + +# --- Runtime stage using Amazon Corretto 25 --- +FROM amazoncorretto:25 + +WORKDIR /app + +COPY --from=builder \ + /vertx-web-kotlin-dsljson/build/libs/vertx-web-kotlin-dsljson-benchmark-1.0.0-SNAPSHOT-fat.jar \ + vertx-web-kotlin-dsljson.jar + +EXPOSE 8080 + +CMD java \ + -server \ + --enable-native-access=ALL-UNNAMED \ + --add-opens=java.base/java.lang=ALL-UNNAMED \ + --sun-misc-unsafe-memory-access=allow \ + -Xms2G \ + -Xmx2G \ + -XX:+AlwaysPreTouch \ + -XX:+UseParallelGC \ + -XX:InitialCodeCacheSize=512m \ + -XX:ReservedCodeCacheSize=512m \ + -XX:MaxInlineLevel=20 \ + -XX:+UseNUMA \ + -XX:-UseCodeCacheFlushing \ + -XX:AutoBoxCacheMax=10001 \ + -XX:+UseCompactObjectHeaders \ + -Djava.net.preferIPv4Stack=true \ + -Dvertx.disableMetrics=true \ + -Dvertx.disableWebsockets=true \ + -Dvertx.disableContextTimings=true \ + -Dvertx.cacheImmutableHttpResponseHeaders=true \ + -Dvertx.internCommonHttpRequestHeadersToLowerCase=true \ + -Dvertx.disableHttpHeadersValidation=true \ + -Dio.netty.noUnsafe=false \ + -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 \ + -Dtfb.type=basic \ + -jar /app/vertx-web-kotlin-dsljson.jar diff --git a/frameworks/Kotlin/vertx-web-kotlinx/README.md b/frameworks/Kotlin/vertx-web-kotlinx/README.md index 6c1d6caa252..b9fe8d87eef 100755 --- a/frameworks/Kotlin/vertx-web-kotlinx/README.md +++ b/frameworks/Kotlin/vertx-web-kotlinx/README.md @@ -2,7 +2,7 @@ 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, 17. +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, 21. ## Test Type Implementation Source Code @@ -27,6 +27,7 @@ The tests were run with: * [Vert.x Reactive PostgreSQL Client](https://vertx.io/docs/vertx-pg-client/java/) * [kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) * [kotlinx.serialization](https://github.com/Kotlin/kotlinx.serialization) +* [kotlinx-io](https://github.com/Kotlin/kotlinx-io) * [kotlinx.html](https://github.com/Kotlin/kotlinx.html) ## Test URLs diff --git a/frameworks/Kotlin/vertx-web-kotlinx/build.gradle.kts b/frameworks/Kotlin/vertx-web-kotlinx/build.gradle.kts index 232eadaf821..2e0035ab3e7 100644 --- a/frameworks/Kotlin/vertx-web-kotlinx/build.gradle.kts +++ b/frameworks/Kotlin/vertx-web-kotlinx/build.gradle.kts @@ -1,12 +1,9 @@ -import org.jetbrains.kotlin.gradle.dsl.JvmTarget -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile - tasks.wrapper { distributionType = Wrapper.DistributionType.ALL } plugins { - val kotlinVersion = "1.8.10" + val kotlinVersion = "2.0.21" kotlin("jvm") version kotlinVersion kotlin("plugin.serialization") version kotlinVersion application @@ -16,7 +13,8 @@ repositories { mavenCentral() } -val vertxVersion = "4.3.8" +val vertxVersion = "4.5.10" +val kotlinxSerializationVersion = "1.7.3" dependencies { implementation(platform("io.vertx:vertx-stack-depchain:$vertxVersion")) implementation("io.vertx:vertx-web") @@ -24,15 +22,20 @@ dependencies { implementation("io.netty", "netty-transport-native-epoll", classifier = "linux-x86_64") implementation("io.vertx:vertx-lang-kotlin") implementation("io.vertx:vertx-lang-kotlin-coroutines") + runtimeOnly("io.vertx:vertx-io_uring-incubator") + // This dependency has to be added for io_uring to work. + runtimeOnly("io.netty.incubator:netty-incubator-transport-native-io_uring:0.0.25.Final:linux-x86_64") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4") - implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.1") - implementation("org.jetbrains.kotlinx:kotlinx-html:0.8.0") - //implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.4.0") -} + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0") -tasks.withType { - compilerOptions.jvmTarget.set(JvmTarget.JVM_17) + 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.5.4") + + implementation("org.jetbrains.kotlinx:kotlinx-html:0.11.0") + //implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.4.0") // the latest version is 0.6.1 } +kotlin.jvmToolchain(21) + application.mainClass.set("MainKt") 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 ccebba7710d..a4b76b9530d 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 284897427bc..79eb9d003fe 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,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/frameworks/Kotlin/vertx-web-kotlinx/gradlew b/frameworks/Kotlin/vertx-web-kotlinx/gradlew index 79a61d421cc..f5feea6d6b1 100755 --- a/frameworks/Kotlin/vertx-web-kotlinx/gradlew +++ b/frameworks/Kotlin/vertx-web-kotlinx/gradlew @@ -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,9 @@ 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 +' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -133,10 +134,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 +148,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 +156,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 @@ -197,11 +201,15 @@ 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, 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" \ diff --git a/frameworks/Kotlin/vertx-web-kotlinx/gradlew.bat b/frameworks/Kotlin/vertx-web-kotlinx/gradlew.bat index 93e3f59f135..9d21a21834d 100644 --- a/frameworks/Kotlin/vertx-web-kotlinx/gradlew.bat +++ b/frameworks/Kotlin/vertx-web-kotlinx/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,11 +59,11 @@ 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 diff --git a/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/KotlinxIo.kt b/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/KotlinxIo.kt new file mode 100644 index 00000000000..6427b91e85e --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/KotlinxIo.kt @@ -0,0 +1,47 @@ +import io.vertx.core.streams.WriteStream +import io.vertx.kotlin.coroutines.coAwait +import kotlinx.coroutines.runBlocking +import kotlinx.io.RawSink +import kotlinx.io.readByteArray +import io.vertx.core.buffer.Buffer as VertxBuffer +import kotlinx.io.Buffer as KotlinxIoBuffer + +@Suppress("NOTHING_TO_INLINE") +private inline fun Long.toIntOrThrow(): Int { + require(this in Int.MIN_VALUE.toLong()..Int.MAX_VALUE.toLong()) + return toInt() +} + +@JvmInline +value class VertxBufferWriteStreamRawSink(val writeStream: WriteStream) : RawSink { + override fun write(source: KotlinxIoBuffer, byteCount: Long) { + runBlocking { + writeStream.write(VertxBuffer.buffer(source.readByteArray(byteCount.toIntOrThrow()))).coAwait() + } + } + + override fun flush() {} + + override fun close() { + writeStream.end() + } +} + +// not used currently +fun WriteStream.toRawSink(): RawSink = + VertxBufferWriteStreamRawSink(this) + + +@JvmInline +value class VertxBufferRawSink(val vertxBuffer: VertxBuffer) : RawSink { + override fun write(source: KotlinxIoBuffer, byteCount: Long) { + vertxBuffer.appendBytes(source.readByteArray(byteCount.toIntOrThrow())) + } + + override fun flush() {} + + override fun close() {} +} + +fun VertxBuffer.toRawSink(): RawSink = + VertxBufferRawSink(this) diff --git a/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/Main.kt b/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/Main.kt index 75cbd79e3cd..987c22162b3 100644 --- a/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/Main.kt +++ b/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/Main.kt @@ -2,10 +2,10 @@ 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.await +import io.vertx.kotlin.coroutines.coAwait import java.util.logging.Logger -const val SERVER_NAME = "Vert.x-Web Kotlinx Benchmark" +const val SERVER_NAME = "Vert.x-Web Kotlinx Benchmark server" val logger = Logger.getLogger("Vert.x-Web Kotlinx Benchmark") suspend fun main(args: Array) { @@ -19,6 +19,6 @@ suspend fun main(args: Array) { it.printStackTrace() } vertx.deployVerticle({ MainVerticle(hasDb) }, deploymentOptionsOf(instances = CpuCoreSensor.availableProcessors())) - .await() + .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 index 9d16710709e..4dce51388ae 100644 --- a/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/MainVerticle.kt +++ b/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/MainVerticle.kt @@ -1,4 +1,5 @@ import io.netty.channel.unix.Errors.NativeIoException +import io.vertx.core.buffer.Buffer import io.vertx.core.http.HttpHeaders import io.vertx.core.http.HttpServer import io.vertx.core.http.HttpServerRequest @@ -7,39 +8,28 @@ 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.await +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.* +import kotlinx.coroutines.Dispatchers import kotlinx.html.* import kotlinx.html.stream.appendHTML +import kotlinx.io.buffered +import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.Serializable -import kotlinx.serialization.encodeToString +import kotlinx.serialization.SerializationStrategy import kotlinx.serialization.json.Json -import java.net.SocketException +import kotlinx.serialization.json.io.encodeToSink import java.time.ZonedDateTime import java.time.format.DateTimeFormatter -class MainVerticle(val hasDb: Boolean) : CoroutineVerticle() { - inline fun Route.checkedCoroutineHandlerUnconfined(crossinline requestHandler: suspend (RoutingContext) -> Unit): Route = - handler { ctx -> - /* 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`. */ - launch(Dispatchers.Unconfined) { - try { - requestHandler(ctx) - } catch (t: Throwable) { - ctx.fail(t) - } - } - } - +class MainVerticle(val hasDb: Boolean) : CoroutineVerticle(), CoroutineRouterSupport { // `PgConnection`s as used in the "vertx" portion offers better performance than `PgPool`s. lateinit var pgConnection: PgConnection lateinit var date: String @@ -68,7 +58,7 @@ class MainVerticle(val hasDb: Boolean) : CoroutineVerticle() { cachePreparedStatements = true, pipeliningLimit = 100000 ) - ).await() + ).coAwait() selectWorldQuery = pgConnection.preparedQuery(SELECT_WORLD_SQL) selectFortuneQuery = pgConnection.preparedQuery(SELECT_FORTUNE_SQL) @@ -81,15 +71,19 @@ class MainVerticle(val hasDb: Boolean) : CoroutineVerticle() { .requestHandler(Router.router(vertx).apply { routes() }) .exceptionHandler { // wrk resets the connections when benchmarking is finished. - if ((it is NativeIoException && it.message == "recvAddress(..) failed: Connection reset by peer") - || (it is SocketException && it.message == "Connection reset") + if ( + // for epoll + /*(it is NativeIoException && it.message == "recvAddress(..) failed: Connection reset by peer") + || (it is SocketException && it.message == "Connection reset")*/ + // for io_uring + it is NativeIoException && it.message == "io_uring read(..) failed: Connection reset by peer" ) return@exceptionHandler logger.info("Exception in HttpServer: $it") it.printStackTrace() } - .listen().await() + .listen().coAwait() } @@ -110,14 +104,46 @@ class MainVerticle(val hasDb: Boolean) : CoroutineVerticle() { putHeader(HttpHeaders.CONTENT_TYPE, "application/json") } - inline fun Route.jsonResponseHandler(crossinline requestHandler: suspend (RoutingContext) -> @Serializable T) = - checkedCoroutineHandlerUnconfined { + + 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 { putJsonResponseHeader() - end(Json.encodeToString(requestHandler(it)))/*.await()*/ + + /* + // 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())) @@ -126,23 +152,23 @@ class MainVerticle(val hasDb: Boolean) : CoroutineVerticle() { } fun Router.routes() { - get("/json").jsonResponseHandler { - jsonSerializationMessage + get("/json").jsonResponseCoHandler(Serializers.message) { + Message("Hello, World!") } - get("/db").jsonResponseHandler { - val rowSet = selectWorldQuery.execute(Tuple.of(randomIntBetween1And10000())).await() + get("/db").jsonResponseCoHandler(Serializers.world) { + val rowSet = selectWorldQuery.execute(Tuple.of(randomIntBetween1And10000())).coAwait() rowSet.single().toWorld() } - get("/queries").jsonResponseHandler { + get("/queries").jsonResponseCoHandler(Serializers.worlds) { val queries = it.request().getQueries() selectRandomWorlds(queries) } - get("/fortunes").checkedCoroutineHandlerUnconfined { + get("/fortunes").coHandlerUnconfined { val fortunes = mutableListOf() - selectFortuneQuery.execute().await() + selectFortuneQuery.execute().coAwait() .mapTo(fortunes) { it.toFortune() } fortunes.add(Fortune(0, "Additional fortune added at request time.")) @@ -173,11 +199,11 @@ class MainVerticle(val hasDb: Boolean) : CoroutineVerticle() { it.response().run { putCommonHeaders() putHeader(HttpHeaders.CONTENT_TYPE, "text/html; charset=utf-8") - end(htmlString)/*.await()*/ + end(htmlString)/*.coAwait()*/ } } - get("/updates").jsonResponseHandler { + get("/updates").jsonResponseCoHandler(Serializers.worlds) { val queries = it.request().getQueries() val worlds = selectRandomWorlds(queries) val updatedWorlds = worlds.map { it.copy(randomNumber = randomIntBetween1And10000()) } @@ -185,7 +211,7 @@ class MainVerticle(val hasDb: Boolean) : CoroutineVerticle() { // Approach 1 // The updated worlds need to be sorted first to avoid deadlocks. updateWordQuery - .executeBatch(updatedWorlds.sortedBy { it.id }.map { Tuple.of(it.randomNumber, it.id) }).await() + .executeBatch(updatedWorlds.sortedBy { it.id }.map { Tuple.of(it.randomNumber, it.id) }).coAwait() /* // Approach 2, worse performance @@ -197,11 +223,11 @@ class MainVerticle(val hasDb: Boolean) : CoroutineVerticle() { updatedWorlds } - get("/plaintext").checkedCoroutineHandlerUnconfined { + get("/plaintext").coHandlerUnconfined { it.response().run { putCommonHeaders() putHeader(HttpHeaders.CONTENT_TYPE, "text/plain") - end("Hello, World!")/*.await()*/ + end("Hello, World!")/*.coAwait()*/ } } } diff --git a/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/Models.kt b/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/Models.kt index fc64e2926ec..ae32b278863 100644 --- a/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/Models.kt +++ b/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/Models.kt @@ -4,8 +4,6 @@ import kotlin.random.Random @Serializable class Message(val message: String) -val jsonSerializationMessage = Message("Hello, World!") - @Serializable data class World(val id: Int, val randomNumber: Int) diff --git a/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/Serializers.kt b/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/Serializers.kt new file mode 100644 index 00000000000..c975fc07fdd --- /dev/null +++ b/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/Serializers.kt @@ -0,0 +1,7 @@ +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/src/main/kotlin/VertxCoroutine.kt b/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/VertxCoroutine.kt index bb8d419d399..d6230fef7f7 100644 --- a/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/VertxCoroutine.kt +++ b/frameworks/Kotlin/vertx-web-kotlinx/src/main/kotlin/VertxCoroutine.kt @@ -1,6 +1,5 @@ -import io.vertx.core.CompositeFuture import io.vertx.core.Future -import io.vertx.kotlin.coroutines.await +import io.vertx.kotlin.coroutines.coAwait suspend fun List>.awaitAll(): List = - CompositeFuture.all(this).await().list() + Future.all(this).coAwait().list() 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 55c7c2c6803..17b43ebcb5c 100644 --- a/frameworks/Kotlin/vertx-web-kotlinx/vertx-web-kotlinx-postgresql.dockerfile +++ b/frameworks/Kotlin/vertx-web-kotlinx/vertx-web-kotlinx-postgresql.dockerfile @@ -1,12 +1,11 @@ -FROM gradle:8.0-jdk17 +FROM gradle:8.10.2-jdk21 WORKDIR /vertx-web-kotlinx COPY build.gradle.kts build.gradle.kts COPY settings.gradle.kts settings.gradle.kts COPY gradle.properties gradle.properties COPY src src -RUN gradle assembleDist -RUN tar -xf build/distributions/vertx-web-kotlinx-benchmark.tar +RUN gradle --no-daemon installDist EXPOSE 8080 @@ -25,4 +24,4 @@ CMD export JAVA_OPTS=" \ -Dio.netty.buffer.checkBounds=false \ -Dio.netty.buffer.checkAccessible=false \ " && \ - vertx-web-kotlinx-benchmark/bin/vertx-web-kotlinx-benchmark true + build/install/vertx-web-kotlinx-benchmark/bin/vertx-web-kotlinx-benchmark true diff --git a/frameworks/Kotlin/vertx-web-kotlinx/vertx-web-kotlinx.dockerfile b/frameworks/Kotlin/vertx-web-kotlinx/vertx-web-kotlinx.dockerfile index 63d2d4a68ad..4bdc993707d 100644 --- a/frameworks/Kotlin/vertx-web-kotlinx/vertx-web-kotlinx.dockerfile +++ b/frameworks/Kotlin/vertx-web-kotlinx/vertx-web-kotlinx.dockerfile @@ -1,12 +1,11 @@ -FROM gradle:8.0-jdk17 +FROM gradle:8.10.2-jdk21 WORKDIR /vertx-web-kotlinx COPY build.gradle.kts build.gradle.kts COPY settings.gradle.kts settings.gradle.kts COPY gradle.properties gradle.properties COPY src src -RUN gradle assembleDist -RUN tar -xf build/distributions/vertx-web-kotlinx-benchmark.tar +RUN gradle --no-daemon installDist EXPOSE 8080 @@ -25,4 +24,4 @@ CMD export JAVA_OPTS=" \ -Dio.netty.buffer.checkBounds=false \ -Dio.netty.buffer.checkAccessible=false \ " && \ - vertx-web-kotlinx-benchmark/bin/vertx-web-kotlinx-benchmark false + build/install/vertx-web-kotlinx-benchmark/bin/vertx-web-kotlinx-benchmark false diff --git a/frameworks/Lua/luxure/README.md b/frameworks/Lua/luxure/README.md deleted file mode 100755 index 5518b909a56..00000000000 --- a/frameworks/Lua/luxure/README.md +++ /dev/null @@ -1,22 +0,0 @@ -# Luxure Benchmarking Test - -### Test Type Implementation Source Code - -* [JSON](./server.lua) -* [PLAINTEXT](./server.lua) - -## Important Libraries -The tests were run with: -* [luasocket](https://www.github.com/lunarmodules/luasocket) -* [cosock](https://www.github.com/cosock/cosock) -* [luncheon](https://www.github.com/cosock/luncheon) -* [dkjson](https://github.com/LuaDist/dkjson) - -## Test URLs -### JSON - -http://localhost:8080/json - -### PLAINTEXT - -http://localhost:8080/plaintext diff --git a/frameworks/Lua/luxure/benchmark_config.json b/frameworks/Lua/luxure/benchmark_config.json deleted file mode 100755 index 50717aa6951..00000000000 --- a/frameworks/Lua/luxure/benchmark_config.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "framework": "luxure", - "tests": [ - { - "default": { - "json_url": "/json", - "plaintext_url": "/plaintext", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "None", - "framework": "Luxure", - "language": "Lua", - "flavor": "None", - "orm": "None", - "platform": "None", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "Luxure", - "notes": "", - "versus": "Express" - } - } - ] -} diff --git a/frameworks/Lua/luxure/luxure.dockerfile b/frameworks/Lua/luxure/luxure.dockerfile deleted file mode 100644 index b509fa37309..00000000000 --- a/frameworks/Lua/luxure/luxure.dockerfile +++ /dev/null @@ -1,36 +0,0 @@ -FROM ubuntu:22.04 - -COPY ./server.lua / - -RUN DEBIAN_FRONTEND=noninteractiv \ - apt-get update \ - && apt-get install -y \ - build-essential \ - libreadline-dev \ - unzip \ - curl \ - wget \ - libssl-dev \ - && curl -R -O http://www.lua.org/ftp/lua-5.3.5.tar.gz \ - && tar -zxf lua-5.3.5.tar.gz \ - && cd lua-5.3.5 \ - && make linux test \ - && make install \ - && cd .. \ - && rm -rf lua-5.3.5 \ - && rm ./lua-5.3.5.tar.gz \ - && wget https://luarocks.org/releases/luarocks-3.8.0.tar.gz \ - && tar zxpf luarocks-3.8.0.tar.gz \ - && cd luarocks-3.8.0 \ - && ./configure --with-lua-include=/usr/local/include \ - && make \ - && make install \ - && cd .. \ - && rm -rf ./luarocks-3.8.0 \ - && rm luarocks-3.8.0.tar.gz \ - && luarocks install luxure \ - && luarocks install dkjson - -EXPOSE 8080 - -CMD lua /server.lua diff --git a/frameworks/Lua/luxure/server.lua b/frameworks/Lua/luxure/server.lua deleted file mode 100644 index e9a6fe106d8..00000000000 --- a/frameworks/Lua/luxure/server.lua +++ /dev/null @@ -1,22 +0,0 @@ -local lux = require "luxure" -local dkjson = require "dkjson" -local server = lux.Server.new() - -server:use(function(req, res, next) - res:add_header("server", "luxure") - res:add_header("date", os.date("!%a, %d %b %Y %X GMT")) - next(req, res) -end) - -server:get("/json", function(req, res) - res:add_header("content-type", "application/json") - res:send(dkjson.encode({ message = "Hello, World!" })) -end) - -server:get("/plaintext", function(req,res) - res:add_header("content-type", "text/plain") - res:send("Hello, World!") -end) - -server:listen(8080) -server:run() diff --git a/frameworks/Lua/octopus/README.md b/frameworks/Lua/octopus/README.md deleted file mode 100644 index 64df0adbd75..00000000000 --- a/frameworks/Lua/octopus/README.md +++ /dev/null @@ -1,35 +0,0 @@ -# Octopus (Nginx + LuaJIT) Benchmark Test - -The test lua app is inside [app](app) directory. -The configuration is in [config.lua](config.lua). -Clones, compiles and runs nginx with ngx_lua module, see [openresty.org](http://openresty.org). -Prerequisites: ```libssl-dev gcc g++ build-essential```. -Requires [git](https://git-scm.com). -Requires postgresql hostname specified as IP address, if not possible then add resolver conf to [config.lua](config.lua). -The Octopus benchmark is using its ORM, and no raw queries. - - -## Test URLs -### Plaintext URL - -http://localhost:8080/plaintext - -### JSON Encoding - -http://localhost:8080/json - -### Single Row Random Query - -http://localhost:8080/db - -### Multiple Row Query Test - -http://localhost:8080/queries?queries=2 - -### Fortune URL - -http://localhost:8080/fortunes - -### DB Updates URL - -http://localhost:8080/update?queries=2 diff --git a/frameworks/Lua/octopus/app/config.lua b/frameworks/Lua/octopus/app/config.lua deleted file mode 100644 index d230c3fafeb..00000000000 --- a/frameworks/Lua/octopus/app/config.lua +++ /dev/null @@ -1,16 +0,0 @@ -local config = {} -- extension configuration - -config.locations = { - {name = "/plaintext", script = "PlaintextController.lua"}, - {name = "/json", script = "JsonSerializationController.lua"}, - {name = "/db", script = "SingleQueryController.lua"}, - {name = "/queries", script = "MultipleQueriesController.lua"}, - {name = "/fortunes", script = "FortunesController.lua"}, - {name = "/update", script = "UpdateController.lua"}, -} - -config.types = { - "types.lua" -} - -return config -- return extension configuration \ No newline at end of file diff --git a/frameworks/Lua/octopus/app/src/FortunesController.lua b/frameworks/Lua/octopus/app/src/FortunesController.lua deleted file mode 100644 index ed3dfd4bfac..00000000000 --- a/frameworks/Lua/octopus/app/src/FortunesController.lua +++ /dev/null @@ -1,34 +0,0 @@ -local json = require "json" -local database = require "database" -local exit = require "exit" - -local template = require'template' -template.caching(false) --- Compile template, disable cache, enable plain text view to skip filesystem loading -local view = template.compile([[Fortunes{% for _,f in ipairs(fortunes) do %}{% end %}
idmessage
{{ f.id }}{{ f.message }}
]], nil, true) - - -local function process (db) - local fortunes = db:find({Fortune = {}}) - table.insert(fortunes, {id = 0, message = "Additional fortune added at request time."}) - table.sort(fortunes, function(a, b) - return a.message < b.message - end) - return fortunes -end - - -local status, db = pcall(database.connect) -if not status then exit(db) end - -local status, res = pcall(process, db) -db:close() - -if status then - local html = view({fortunes = res}) - ngx.header.content_type = 'text/html; charset=utf-8' - ngx.header.content_length = #html - ngx.print(html) -else - exit(res) -end \ No newline at end of file diff --git a/frameworks/Lua/octopus/app/src/JsonSerializationController.lua b/frameworks/Lua/octopus/app/src/JsonSerializationController.lua deleted file mode 100644 index 258a95265e9..00000000000 --- a/frameworks/Lua/octopus/app/src/JsonSerializationController.lua +++ /dev/null @@ -1,4 +0,0 @@ -local json = require "json" - -ngx.header.content_type = 'application/json' -ngx.print(json.encode({message = "Hello, World!"})) \ No newline at end of file diff --git a/frameworks/Lua/octopus/app/src/MultipleQueriesController.lua b/frameworks/Lua/octopus/app/src/MultipleQueriesController.lua deleted file mode 100644 index 0afa4af7640..00000000000 --- a/frameworks/Lua/octopus/app/src/MultipleQueriesController.lua +++ /dev/null @@ -1,36 +0,0 @@ -local json = require "json" -local database = require "database" -local param = require "param" -local exit = require "exit" - - -local function process (db) - local op = db:operators() - - local num_queries = tonumber(param.queries) or 1 - if num_queries < 1 then - num_queries = 1 - elseif num_queries > 500 then - num_queries = 500 - end - - local worlds = {} - for i=1, num_queries do - worlds[#worlds + 1] = db:findOne({World = {id = op.equal(math.random(1,10000))}}) - end - return worlds -end - - -local status, db = pcall(database.connect) -if not status then exit(db) end - -local status, res = pcall(process, db) -db:close() - -if status then - ngx.header.content_type = 'application/json' - ngx.print(json.encode(res)) -else - exit(res) -end \ No newline at end of file diff --git a/frameworks/Lua/octopus/app/src/PlaintextController.lua b/frameworks/Lua/octopus/app/src/PlaintextController.lua deleted file mode 100644 index a5f6fadf29d..00000000000 --- a/frameworks/Lua/octopus/app/src/PlaintextController.lua +++ /dev/null @@ -1,2 +0,0 @@ -ngx.header.content_type = 'text/plain' -ngx.print("Hello, World!") \ No newline at end of file diff --git a/frameworks/Lua/octopus/app/src/SingleQueryController.lua b/frameworks/Lua/octopus/app/src/SingleQueryController.lua deleted file mode 100644 index 1e93e998010..00000000000 --- a/frameworks/Lua/octopus/app/src/SingleQueryController.lua +++ /dev/null @@ -1,24 +0,0 @@ -local json = require "json" -local database = require "database" -local exit = require "exit" - - -local function process (db) - local op = db:operators() - - return db:findOne({World = {id = op.equal(math.random(1,10000))}}) -end - - -local status, db = pcall(database.connect) -if not status then exit(db) end - -local status, res = pcall(process, db) -db:close() - -if status then - ngx.header.content_type = 'application/json' - ngx.print(json.encode(res)) -else - exit(res) -end \ No newline at end of file diff --git a/frameworks/Lua/octopus/app/src/UpdateController.lua b/frameworks/Lua/octopus/app/src/UpdateController.lua deleted file mode 100644 index 8e7c2f9017c..00000000000 --- a/frameworks/Lua/octopus/app/src/UpdateController.lua +++ /dev/null @@ -1,39 +0,0 @@ -local json = require "json" -local database = require "database" -local param = require "param" -local exit = require "exit" - - -local function process (db) - local op = db:operators() - - local num_queries = tonumber(param.queries) or 1 - if num_queries < 1 then - num_queries = 1 - elseif num_queries > 500 then - num_queries = 500 - end - - local worlds = {} - for i=1, num_queries do - local world = db:findOne({World = {id = op.equal(math.random(1,10000))}}) - world.randomNumber = math.random(1,10000) - db:update({World = world}) - worlds[#worlds + 1] = world - end - return worlds -end - - -local status, db = pcall(database.connect) -if not status then exit(db) end - -local status, res = pcall(process, db) -db:close() - -if status then - ngx.header.content_type = 'application/json' - ngx.print(json.encode(res)) -else - exit(res) -end \ No newline at end of file diff --git a/frameworks/Lua/octopus/app/src/types.lua b/frameworks/Lua/octopus/app/src/types.lua deleted file mode 100644 index be7cf95f0d8..00000000000 --- a/frameworks/Lua/octopus/app/src/types.lua +++ /dev/null @@ -1,12 +0,0 @@ -return { - - World = { - -- id field is implicitly defined by the ORM - randomNumber = "integer", - }, - - Fortune = { - -- id field is implicitly defined by the ORM - message = "string", - }, -} \ No newline at end of file diff --git a/frameworks/Lua/octopus/benchmark_config.json b/frameworks/Lua/octopus/benchmark_config.json deleted file mode 100644 index 2f31b882350..00000000000 --- a/frameworks/Lua/octopus/benchmark_config.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "framework": "octopus", - "tests": [{ - "default": { - "plaintext_url": "/plaintext", - "json_url": "/json", - "db_url": "/db", - "query_url": "/queries?queries=", - "fortune_url": "/fortunes", - "update_url": "/update?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "MySQL", - "framework": "Octopus", - "language": "Lua", - "orm": "Full", - "platform": "OpenResty", - "webserver": "nginx", - "os": "Linux", - "database_os": "Linux", - "display_name": "Octopus", - "notes": "", - "versus": "openresty", - "tags": ["broken"] - } - }] -} diff --git a/frameworks/Lua/octopus/config.lua b/frameworks/Lua/octopus/config.lua deleted file mode 100644 index 80276c4b277..00000000000 --- a/frameworks/Lua/octopus/config.lua +++ /dev/null @@ -1,39 +0,0 @@ -return { - extensions = { - {octopusExtensionsDir, "core"}, - {octopusExtensionsDir, "baseline"}, - {octopusExtensionsDir, "orm"}, - {octopusExtensionsDir, "app"}, - }, - - octopusExtensionsDir = octopusExtensionsDir, - octopusHostDir = octopusHostDir, - port = 8080, - securePort = 38080, - luaCodeCache = "on", - serverName = "tfb-server", - errorLog = "error_log logs/error.log;", - accessLog = "access_log logs/access.log;", - includeDrop = [[#include drop.conf;]], - maxBodySize = "50k", - minifyJavaScript = false, - minifyCommand = [[java -jar ../yuicompressor-2.4.8.jar %s -o %s]], - - databaseConnection = { - rdbms = "mysql", - host = "DBHOSTNAME", - port = 3306, - database = "hello_world", - user = "benchmarkdbuser", - password = "benchmarkdbpass", - compact = false - }, - - globalParameters = { - octopusHostDir = octopusHostDir, - sourceCtxPath = "", - requireSecurity = false, - sessionTimeout = 3600, - usePreparedStatement = false, - }, -} diff --git a/frameworks/Lua/octopus/config.toml b/frameworks/Lua/octopus/config.toml deleted file mode 100644 index 30b1d7f6cfb..00000000000 --- a/frameworks/Lua/octopus/config.toml +++ /dev/null @@ -1,19 +0,0 @@ -[framework] -name = "octopus" - -[main] -urls.plaintext = "/plaintext" -urls.json = "/json" -urls.db = "/db" -urls.query = "/queries?queries=" -urls.update = "/update?queries=" -urls.fortune = "/fortunes" -approach = "Realistic" -classification = "Fullstack" -database = "MySQL" -database_os = "Linux" -os = "Linux" -orm = "Full" -platform = "OpenResty" -webserver = "nginx" -versus = "openresty" diff --git a/frameworks/Lua/octopus/octopus.dockerfile b/frameworks/Lua/octopus/octopus.dockerfile deleted file mode 100644 index b2c13b02473..00000000000 --- a/frameworks/Lua/octopus/octopus.dockerfile +++ /dev/null @@ -1,56 +0,0 @@ -FROM buildpack-deps:xenial - -ENV LUA_VERSION="5.1" -ENV LUA_MICRO="5" - -RUN apt-get update -yqq && apt-get install -yqq unzip - -RUN wget https://github.com/LuaDist/lua/archive/$LUA_VERSION.$LUA_MICRO.tar.gz -RUN tar xf $LUA_VERSION.$LUA_MICRO.tar.gz - -ENV LUA_HOME=/lua-$LUA_VERSION.$LUA_MICRO - -RUN cd $LUA_HOME && \ - cp src/luaconf.h.orig src/luaconf.h && \ - make linux && \ - cd src && \ - mkdir ../bin ../include ../lib && \ - install -p -m 0755 lua luac ../bin && \ - install -p -m 0644 lua.h luaconf.h lualib.h lauxlib.h ../include && \ - install -p -m 0644 liblua.a ../lib - -ENV LUA=/lua${LUA_VERSION}.${LUA_MICRO} -ENV PATH=${LUA_HOME}/bin:${PATH} -ENV LUA_PATH="./?.lua;./?.lc;$LUA_HOME/share/lua/5.1/?/init.lua;$LUA_HOME/share/lua/5.1/?.lua;$LUA_HOME/lib/lua/5.1/?/init.lua;$LUA_HOME/lib/lua/5.1/?.lua" -ENV LUA_CPATH="./?.lua;./?.lc;$LUA_HOME/share/lua/5.1/?/init.so;$LUA_HOME/share/lua/5.1/?.so;$LUA_HOME/lib/lua/5.1/?/init.so;$LUA_HOME/lib/lua/5.1/?.so" - -WORKDIR /octo - -RUN git clone https://github.com/cyberz-eu/octopus.git - -WORKDIR /octo/octopus -# Dec 8th, 2017 -RUN git checkout 44c7e7ecdfd9e95703e73df85815c0cca4b441e8 - -WORKDIR /octo - -ADD ./ /octo - -RUN cp -avr app octopus/extensions -RUN cp -vf config.lua octopus/extensions - -WORKDIR /octo/octopus/bin/unix - -RUN chmod +x *.sh - -RUN sed -i 's|wget|wget -q|g' server.sh -RUN sed -i 's|-c nginx.conf|-c nginx.conf -g "daemon off;"|g' server.sh - -RUN ./server.sh install -RUN ./server.sh build - -EXPOSE 8080 - -CMD export DBIP=`getent hosts tfb-database | awk '{ print $1 }'` && \ - sed -i "s|DBHOSTNAME|$DBIP|g" /octo/octopus/extensions/build/src/types.lua && \ - ./server.sh start diff --git a/frameworks/Lua/openresty/benchmark_config.json b/frameworks/Lua/openresty/benchmark_config.json index 6b32f71f3de..7fa51aa4a95 100644 --- a/frameworks/Lua/openresty/benchmark_config.json +++ b/frameworks/Lua/openresty/benchmark_config.json @@ -20,6 +20,7 @@ "database_os": "Linux", "display_name": "openresty", "notes": "", + "tags": ["broken"], "versus": "openresty" } }] diff --git a/frameworks/Lua/openresty/openresty.dockerfile b/frameworks/Lua/openresty/openresty.dockerfile index 1777000e241..83283446c19 100644 --- a/frameworks/Lua/openresty/openresty.dockerfile +++ b/frameworks/Lua/openresty/openresty.dockerfile @@ -1,4 +1,4 @@ -FROM openresty/openresty:1.19.9.1-focal +FROM openresty/openresty:1.25.3.1-2-jammy ADD ./nginx.conf /openresty/ ADD ./app.lua /openresty/ diff --git a/frameworks/Luau/lute/README.md b/frameworks/Luau/lute/README.md new file mode 100755 index 00000000000..53dcca2b161 --- /dev/null +++ b/frameworks/Luau/lute/README.md @@ -0,0 +1,12 @@ +# Lute Benchmarking Test + +[Lute](https://github.com/aatxe/lute) is a runtime for [Luau](https://luau.org/), a typed scripting language derived from Lua. + +## Test URLs +### JSON + +http://localhost:3000/json + +### PLAINTEXT + +http://localhost:3000/plaintext diff --git a/frameworks/Luau/lute/benchmark_config.json b/frameworks/Luau/lute/benchmark_config.json new file mode 100755 index 00000000000..201399976ee --- /dev/null +++ b/frameworks/Luau/lute/benchmark_config.json @@ -0,0 +1,26 @@ +{ + "framework": "lute", + "tests": [ + { + "default": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 3000, + "approach": "Realistic", + "classification": "Platform", + "database": "None", + "framework": "None", + "language": "Luau", + "flavor": "None", + "orm": "None", + "platform": "None", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "Lute", + "notes": "", + "versus": "None" + } + } + ] +} diff --git a/frameworks/Luau/lute/lute.dockerfile b/frameworks/Luau/lute/lute.dockerfile new file mode 100644 index 00000000000..9a0e49c640d --- /dev/null +++ b/frameworks/Luau/lute/lute.dockerfile @@ -0,0 +1,19 @@ +FROM ubuntu:24.04 + +EXPOSE 3000 + +WORKDIR /app + +RUN apt-get update && apt-get install -y curl unzip + +COPY rokit.toml . + +RUN curl -sSf https://raw.githubusercontent.com/rojo-rbx/rokit/main/scripts/install.sh | bash + +ENV PATH="/root/.rokit/bin:${PATH}" + +RUN rokit install --no-trust-check + +COPY ./src . + +CMD ["sh", "-c", "lute parallel.luau"] diff --git a/frameworks/Luau/lute/rokit.toml b/frameworks/Luau/lute/rokit.toml new file mode 100644 index 00000000000..4b4d444e71c --- /dev/null +++ b/frameworks/Luau/lute/rokit.toml @@ -0,0 +1,7 @@ +# This file lists tools managed by Rokit, a toolchain manager for Roblox projects. +# For more information, see https://github.com/rojo-rbx/rokit + +# New tools can be added by running `rokit add ` in a terminal. + +[tools] +lute = "luau-lang/lute@0.1.0-nightly.20250506" diff --git a/frameworks/Luau/lute/src/json.luau b/frameworks/Luau/lute/src/json.luau new file mode 100644 index 00000000000..a4ba7becbf6 --- /dev/null +++ b/frameworks/Luau/lute/src/json.luau @@ -0,0 +1,197 @@ +--!native +local COMMA = 44 +local QUOTATION = 34 +local OPEN_BRACKET = 91 +local CLOSE_BRACKET = 93 +local OPEN_BRACE = 123 +local CLOSE_BRACE = 125 +local BACKSLASH = 92 + +-- used for string serialization +local ESCAPE_MAP = { + [0x5C] = string.byte("\\"), -- 5C = '\' + [0x08] = string.byte("b"), + [0x0C] = string.byte("f"), + [0x0A] = string.byte("n"), + [0x0D] = string.byte("r"), + [0x09] = string.byte("t"), +} + +local types = require("./types") + +local buff: buffer = buffer.create(1024) +local size = 1024 +local cursor = 0 + +local function alloc(len: number) + if cursor + len < size then + return + end + + while cursor + len > size do + size *= 2 + end + + local newbuff = buffer.create(size) + buffer.copy(newbuff, 0, buff) + buff = newbuff +end + +local function WRITE_QUOTATION() + buffer.writeu8(buff, cursor, QUOTATION) + cursor += 1 +end + +local function WRITE_COMMA() + buffer.writeu8(buff, cursor, COMMA) + cursor += 1 +end + +local function writeString(str: string) + local len = #str + alloc(len) + + buffer.writestring(buff, cursor, str) + + cursor += len +end + +local function serializeUnicode(codepoint: number) + if codepoint >= 0x10000 then + local high = ((codepoint - 0x10000) // 0x400) + 0xD800 + local low = ((codepoint - 0x10000) % 0x400) + 0xDC00 + return string.format("\\u%04x\\u%04x", high, low) + end + + return string.format("\\u%04x", codepoint) +end + +local function serializeString(str: string) + -- covers the quotations & utf + alloc((#str * 4) + 2) + + WRITE_QUOTATION() + + for pos, codepoint in utf8.codes(str) do + if ESCAPE_MAP[codepoint] then + -- write \ + buffer.writeu8(buff, cursor, BACKSLASH) + cursor += 1 + + buffer.writeu8(buff, cursor, ESCAPE_MAP[codepoint]) + cursor += 1 + elseif codepoint < 32 or codepoint > 126 then + writeString(serializeUnicode(codepoint)) + else + -- we are in ascii + + buffer.writeu8(buff, cursor, codepoint) + cursor += 1 + end + end + + WRITE_QUOTATION() +end + +local serializeAny: (value: types.Value) -> () + +local function serializeArray(array: types.Array) + -- open close bracket + -- 1 comma for each array element + alloc(2 + #array) + + -- write [ + buffer.writeu8(buff, cursor, OPEN_BRACKET) + cursor += 1 + + for _, value in array do + serializeAny(value) + WRITE_COMMA() + end + + -- get rid of comma + cursor -= 1 + + -- write ] + buffer.writeu8(buff, cursor, CLOSE_BRACKET) + cursor += 1 +end + +local function serializeTable(object: types.Object) + -- openbrace, newline + alloc(2) + + -- write { + buffer.writeu8(buff, cursor, OPEN_BRACE) + cursor += 1 + + for key, value in object do + -- quotation 2x, colon and comma + alloc(4) + + WRITE_QUOTATION() + buffer.writestring(buff, cursor, key) + cursor += #key + 2 + + buffer.writestring(buff, cursor - 2, '":') + + serializeAny(value) + + WRITE_COMMA() + end + + -- get rid of the comma + cursor -= 1 + + -- write } + buffer.writeu8(buff, cursor, CLOSE_BRACE) + cursor += 1 +end + +serializeAny = function(value: types.Value) + local valueType = type(value) + + if valueType == "string" then + serializeString(value :: string) + elseif valueType == "table" then + if #(value :: {}) == 0 then + serializeTable(value :: types.Object) + else + serializeArray(value :: types.Array) + end + elseif valueType == "number" then + local numstr = tostring(value) + + buffer.writestring(buff, cursor, numstr) + cursor += #numstr + elseif value == types.NULL then + -- null as u32 + buffer.writeu32(buff, cursor, 1819047278) + cursor += 4 + elseif value == true then + -- true as u32 + buffer.writeu32(buff, cursor, 1702195828) + cursor += 4 + elseif value == false then + -- false as u32 + u8 + buffer.writeu32(buff, cursor, 1936482662) + buffer.writeu8(buff, cursor + 4, 101) + cursor += 5 + else + error("Unknown value", 2) + end +end + +local function serialize(data: types.Value) + buff = buffer.create(1024) + size = 1024 + cursor = 0 + + serializeAny(data) + + return buffer.readstring(buff, 0, cursor) +end + +return { + serialize = serialize, +} diff --git a/frameworks/Luau/lute/src/parallel.luau b/frameworks/Luau/lute/src/parallel.luau new file mode 100644 index 00000000000..557c4dd0326 --- /dev/null +++ b/frameworks/Luau/lute/src/parallel.luau @@ -0,0 +1,10 @@ +local vm = require("@lute/vm") +local system = require("@lute/system") + +local threadCount = system.threadcount() + +for _ = 1, threadCount do + coroutine.resume(coroutine.create(vm.create("./serve").serve)) +end + +print(`Created {threadCount} server threads`) diff --git a/frameworks/Luau/lute/src/serve.luau b/frameworks/Luau/lute/src/serve.luau new file mode 100644 index 00000000000..1cb525512ad --- /dev/null +++ b/frameworks/Luau/lute/src/serve.luau @@ -0,0 +1,35 @@ +local net = require("@lute/net") +local json = require("./json") + +local plaintext = { + status = 200, + headers = { + ["Content-Type"] = "text/plain", + ["Server"] = "Lute", + }, + body = "Hello, world!", +} + +return { + serve = function() + net.serve(function(req) + if req.path == "/plaintext" then + return plaintext + elseif req.path == "/json" then + return { + status = 200, + headers = { + ["Content-Type"] = "application/json", + ["Server"] = "Lute", + }, + body = json.serialize({ message = "Hello, world!" }), + } + else + return { + status = 404, + body = "Not Found", + } + end + end) + end, +} diff --git a/frameworks/Luau/lute/src/types.luau b/frameworks/Luau/lute/src/types.luau new file mode 100644 index 00000000000..bf3a5ce3771 --- /dev/null +++ b/frameworks/Luau/lute/src/types.luau @@ -0,0 +1,9 @@ +export type JSONPrimitive = nil | number | string | boolean +export type Object = { [string]: Value } +export type Array = { Value } + +export type Value = JSONPrimitive | Array | Object + +return { + NULL = newproxy() :: nil, +} diff --git a/frameworks/Nim/basolato/.gitignore b/frameworks/Nim/basolato/.gitignore deleted file mode 100644 index 80fd75dc186..00000000000 --- a/frameworks/Nim/basolato/.gitignore +++ /dev/null @@ -1,14 +0,0 @@ -# Binaries -* -!*.* -!*/ - -# Test coverage -coverage/* -lcov.info - -logs/* -# config.nims -*.sqlite3 -*.db -*.db.bak diff --git a/frameworks/Nim/basolato/README.md b/frameworks/Nim/basolato/README.md index 3f8bc7ed7df..ab9292e0893 100755 --- a/frameworks/Nim/basolato/README.md +++ b/frameworks/Nim/basolato/README.md @@ -2,17 +2,16 @@ ### Test Type Implementation Source Code -* [JSON](./app/controllers/benchmark_controller.nim) -* [PLAINTEXT](./app/controllers/benchmark_controller.nim) -* [DB](./app/controllers/benchmark_controller.nim) -* [QUERY](./app/controllers/benchmark_controller.nim) -* [UPDATE](./app/controllers/benchmark_controller.nim) -* [FORTUNES](./app/controllers/benchmark_controller.nim) +* [JSON](./app/http/controllers/benchmark_controller.nim) +* [PLAINTEXT](./app/http/controllers/benchmark_controller.nim) +* [DB](./app/http/controllers/benchmark_controller.nim) +* [QUERY](./app/http/controllers/benchmark_controller.nim) +* [UPDATE](./app/http/controllers/benchmark_controller.nim) +* [FORTUNES](./app/http/controllers/benchmark_controller.nim) ## Important Libraries The tests were run with: * [Software](https://github.com/itsumura-h/nim-basolato) -* [Example](https://github.com/itsumura-h/nim-basolato/tree/master/examples) ## Test URLs ### JSON @@ -29,11 +28,11 @@ http://localhost:8080/db ### QUERY -http://localhost:8080/query?queries= +http://localhost:8080/queries?queries=1 ### UPDATE -http://localhost:8080/update?queries= +http://localhost:8080/updates?queries=1 ### FORTUNES diff --git a/frameworks/Nim/basolato/app/controllers/benchmark_controller.nim b/frameworks/Nim/basolato/app/controllers/benchmark_controller.nim deleted file mode 100644 index 2221c9ddc3f..00000000000 --- a/frameworks/Nim/basolato/app/controllers/benchmark_controller.nim +++ /dev/null @@ -1,81 +0,0 @@ -import json, random, algorithm, cgi, sugar, sequtils -from strutils import parseInt -# framework -import basolato/controller -import allographer/query_builder -# view -import ../../resources/pages/fortune_view - -type BenchmarkController* = ref object of Controller - -proc newBenchmarkController*(request:Request):BenchmarkController = - randomize() - return BenchmarkController.newController(request) - - -proc json*(this:BenchmarkController):Response = - return render(%*{"message":"Hello, World!"}) - -proc plainText*(this:BenchmarkController):Response = - var headers = newHeaders() - headers.set("Content-Type", "text/plain; charset=UTF-8") - return render("Hello, World!").setHeader(headers) - -proc db*(this:BenchmarkController):Response = - let i = rand(1..10000) - let response = RDB().table("world").find(i) - return render(%*response) - -proc query*(this:BenchmarkController):Response = - var countNum:int - try: - countNum = this.request.params["queries"].parseInt() - except: - countNum = 1 - - if countNum < 1: - countNum = 1 - elif countNum > 500: - countNum = 500 - - var response = newJArray() - for _ in 1..countNum: - let i = rand(1..10000) - let data = RDB().table("world").find(i) - response.add(data) - return render(%*response) - -proc fortune*(this:BenchmarkController):Response = - var rows = RDB().table("Fortune").orderBy("message", Asc).get() - rows = rows.mapIt(%*{ - "id": it["id"], - "message": xmlEncode(it["message"].getStr) - }) - rows.add(%*{ - "id": 0, - "message": "Additional fortune added at request time."} - ) - rows = rows.sortedByIt(it["message"].getStr) - return render(this.view.fortuneView(rows)) - -proc update*(this:BenchmarkController):Response = - var countNum:int - try: - countNum = this.request.params["queries"].parseInt() - except: - countNum = 1 - - if countNum < 1: - countNum = 1 - elif countNum > 500: - countNum = 500 - - var response = newJArray() - transaction: - for _ in 1..countNum: - let i = rand(1..10000) - let newRandomNumber = rand(1..10000) - discard RDB().table("world").find(i) - RDB().table("world").where("id", "=", i).update(%*{"randomNumber": newRandomNumber}) - response.add(%*{"id":i, "randomNumber": newRandomNumber}) - return render(response) diff --git a/frameworks/Nim/basolato/app/http/controllers/benchmark_controller.nim b/frameworks/Nim/basolato/app/http/controllers/benchmark_controller.nim new file mode 100644 index 00000000000..fefbc0644dd --- /dev/null +++ b/frameworks/Nim/basolato/app/http/controllers/benchmark_controller.nim @@ -0,0 +1,102 @@ +import std/algorithm +import std/json +import std/random +import std/strutils +import std/sequtils +# framework +import basolato/controller +# databse +import db_connector/db_postgres +import allographer/query_builder +import ../../../config/database +# model +import ../../models/fortune +# view +import ../views/pages/fortune_scf_view + + +const range1_10000 = 1..10000 +let getFirstPrepare = stdRdb.prepare("getFirst", sql""" SELECT * FROM "World" WHERE id = $1 LIMIT 1 """, 1) +let getFortunePrepare = stdRdb.prepare("getFortunes", sql""" SELECT * FROM "Fortune" ORDER BY message ASC """, 0) + + +proc plaintext*(context:Context, params:Params):Future[Response] {.async.} = + let headers = newHttpHeaders() + headers.add("Content-Type", "text/plain; charset=UTF-8") + return render("Hello, World!", headers) + + +proc json*(context:Context, params:Params):Future[Response] {.async.} = + return render(%*{"message":"Hello, World!"}) + + +proc db*(context:Context, params:Params):Future[Response] {.async.} = + let i = rand(1..10000) + let res = stdRdb.getRow(getFirstPrepare, i) + return render(%*{"id": res[0].parseInt, "randomNumber": res[1].parseInt}) + + +proc query*(context:Context, params:Params):Future[Response] {.async.} = + var countNum = + try: + params.getInt("queries") + except: + 1 + if countNum < 1: + countNum = 1 + elif countNum > 500: + countNum = 500 + + var resp:seq[Row] + for i in 1..countNum: + let n = rand(range1_10000) + resp.add(stdRdb.getRow(getFirstPrepare, n)) + + let response = resp.map( + proc(x:Row):JsonNode = + %*{"id": x[0].parseInt, "randomNumber": x[1].parseInt} + ) + return render(%response) + + +proc fortune*(context:Context, params:Params):Future[Response] {.async.} = + let results = stdRdb.getAllRows(getFortunePrepare) + var rows = results.map( + proc(x:seq[string]):Fortune = + return Fortune(id: x[0].parseInt, message: x[1]) + ) + rows.add( + Fortune( + id: 0, + message: "Additional fortune added at request time." + ) + ) + rows = rows.sortedByIt(it.message) + return render(fortuneScfView(rows).await) + + +proc update*(context:Context, params:Params):Future[Response] {.async.} = + var countNum = + try: + params.getInt("queries") + except: + 1 + if countNum < 1: + countNum = 1 + elif countNum > 500: + countNum = 500 + + var response = newSeq[JsonNode](countNum) + var futures = newSeq[Future[void]](countNum) + for i in 1..countNum: + let index = rand(range1_10000) + let number = rand(range1_10000) + response[i-1] = %*{"id": index, "randomNumber": number} + futures[i-1] = ( + proc():Future[void] {.async.} = + discard stdRdb.getRow(getFirstPrepare, i) + rdb.raw(""" UPDATE "World" SET "randomnumber" = ? WHERE id = ? """, %*[number, index]).exec() + )() + all(futures).await + + return render(%response) diff --git a/frameworks/Nim/basolato/app/http/views/pages/fortune_scf_view.nim b/frameworks/Nim/basolato/app/http/views/pages/fortune_scf_view.nim new file mode 100644 index 00000000000..7f4dc2b4552 --- /dev/null +++ b/frameworks/Nim/basolato/app/http/views/pages/fortune_scf_view.nim @@ -0,0 +1,29 @@ +#? stdtmpl(toString="toString") | standard +#import std/asyncdispatch +#import basolato/view +#import ../../../models/fortune +#proc fortuneScfView*(rows:seq[Fortune]):Future[Component] {.async.} = +# result = Component.new() + + + + + Fortunes + + + + + + + + + #for row in rows: + + + + + #end for +
idmessage
${row.id}${row.message}
+ + + diff --git a/frameworks/Nim/basolato/app/middlewares/framework_middleware.nim b/frameworks/Nim/basolato/app/middlewares/framework_middleware.nim deleted file mode 100644 index 9d6c527fc3c..00000000000 --- a/frameworks/Nim/basolato/app/middlewares/framework_middleware.nim +++ /dev/null @@ -1,11 +0,0 @@ -import re -import basolato/middleware -import basolato/routing -from custom_headers_middleware import corsHeader - -template framework*() = - if request.path.match(re"^(?!.*\.).*$"): - checkCsrfToken(request).catch() - checkAuthToken(request).catch(ErrorAuthRedirect, "/login") - if request.reqMethod == HttpOptions: - route(render(""), [corsHeader()]) diff --git a/frameworks/Nim/basolato/app/models/fortune.nim b/frameworks/Nim/basolato/app/models/fortune.nim new file mode 100644 index 00000000000..33cb0950a31 --- /dev/null +++ b/frameworks/Nim/basolato/app/models/fortune.nim @@ -0,0 +1,3 @@ +type Fortune* = object + id*:int + message*:string diff --git a/frameworks/Nim/basolato/basolato.dockerfile b/frameworks/Nim/basolato/basolato.dockerfile index 495c1766dbc..1e2baf2a0c9 100644 --- a/frameworks/Nim/basolato/basolato.dockerfile +++ b/frameworks/Nim/basolato/basolato.dockerfile @@ -1,27 +1,73 @@ -FROM nimlang/nim:alpine +FROM ubuntu:22.04 AS build -ENV PATH $PATH:/root/.nimble/bin +# prevent timezone dialogue +ENV DEBIAN_FRONTEND=noninteractive -RUN echo http://dl-cdn.alpinelinux.org/alpine/edge/testing >> /etc/apk/repositories -RUN apk update && \ - apk upgrade --no-cache && \ - apk add --no-cache \ - openssh-client \ +RUN apt update && \ + apt upgrade -y +RUN apt install -y --fix-missing \ + gcc \ + xz-utils \ ca-certificates \ - openssl \ - pcre \ - bsd-compat-headers \ - lcov \ - sqlite mariadb-dev libpq && \ - rm /usr/lib/mysqld* -fr && rm /usr/bin/mysql* -fr && \ - update-ca-certificates + curl \ + git + +ARG VERSION="2.0.2" +WORKDIR /root +RUN curl https://nim-lang.org/choosenim/init.sh -o init.sh +RUN sh init.sh -y +RUN rm -f init.sh +ENV PATH $PATH:/root/.nimble/bin +RUN choosenim ${VERSION} + +ENV PATH $PATH:/root/.nimble/bin ADD ./ /basolato WORKDIR /basolato RUN nimble install -y -RUN ducere build +RUN ducere build -p:8080 -o:speed + + +FROM ubuntu:22.04 AS runtime + +# prevent timezone dialogue +ENV DEBIAN_FRONTEND=noninteractive + +RUN apt update && \ + apt upgrade -y +RUN apt install -y --fix-missing \ + xz-utils \ + ca-certificates \ + libpq-dev + +WORKDIR /basolato +COPY --from=build /basolato/main . +RUN chmod 111 main +COPY --from=build /basolato/startServer.sh . +RUN chmod 111 startServer.sh + + +# Secret +ENV SECRET_KEY="pZWEVzA7h2FcKLgVM3ec5Eiik7eU9Ehpf0uLdYOZDgr0uZKIo5LdQE9sjIub3IDkUTrf3X2Jsh1Uw8b02GtAfWRn4C9NptfdSyoK" +# DB Connection +ENV DB_DATABASE="hello_world" +ENV DB_USER="benchmarkdbuser" +ENV DB_PASSWORD="benchmarkdbpass" +ENV DB_HOST="tfb-database" +ENV DB_PORT=5432 +ENV DB_MAX_CONNECTION=2000 +ENV DB_TIMEOUT=30 +# Logging +ENV LOG_IS_DISPLAY=false +ENV LOG_IS_FILE=false +ENV LOG_IS_ERROR_FILE=false +# Session db +# Session type, file or redis, is defined in config.nims +ENV SESSION_TIME=20160 +ENV LOCALE=en + EXPOSE 8080 -CMD ./main +CMD ./startServer.sh diff --git a/frameworks/Nim/basolato/basolato.nimble b/frameworks/Nim/basolato/basolato.nimble new file mode 100644 index 00000000000..34274ee7b07 --- /dev/null +++ b/frameworks/Nim/basolato/basolato.nimble @@ -0,0 +1,22 @@ +# Package +version = "0.1.0" +author = "Anonymous" +description = "A new awesome basolato package" +license = "MIT" +srcDir = "." +bin = @["main"] +backend = "c" + +# Dependencies +requires "nim >= 2.0.0" +requires "https://github.com/itsumura-h/nim-basolato == 0.15.0" +requires "allographer == 0.29.1" +requires "interface_implements >= 0.2.2" +requires "bcrypt >= 0.2.1" +requires "cligen >= 1.5.9" +requires "redis >= 0.3.0" +requires "sass >= 0.1.0" + +task test, "run testament": + echo staticExec("testament p \"./tests/test_*.nim\"") + discard staticExec("find tests/ -type f ! -name \"*.*\" -delete 2> /dev/null") diff --git a/frameworks/Nim/basolato/benchmark_config.json b/frameworks/Nim/basolato/benchmark_config.json index 76b42b1c2dd..e0f90c90dcc 100755 --- a/frameworks/Nim/basolato/benchmark_config.json +++ b/frameworks/Nim/basolato/benchmark_config.json @@ -7,8 +7,8 @@ "plaintext_url": "/plaintext", "db_url": "/db", "query_url": "/queries?queries=", - "fortune_url": "/fortunes", "update_url": "/updates?queries=", + "fortune_url": "/fortunes", "port": 8080, "approach": "Realistic", "classification": "Fullstack", @@ -17,14 +17,14 @@ "language": "Nim", "flavor": "None", "orm": "Full", - "platform": "httpbeast", + "platform": "asynchttpserver", "webserver": "None", "os": "Linux", "database_os": "Linux", "display_name": "Basolato", "notes": "", - "versus": "jester", - "tags": ["broken"] + "tags": ["broken"], + "versus": "httpbeast, prologue" } } ] diff --git a/frameworks/Nim/basolato/config.nims b/frameworks/Nim/basolato/config.nims index 1df9e31ff0d..17fb53724ab 100644 --- a/frameworks/Nim/basolato/config.nims +++ b/frameworks/Nim/basolato/config.nims @@ -1,20 +1,9 @@ -import os - -# DB Connection -putEnv("DB_DRIVER", "postgres") -putEnv("DB_CONNECTION", "tfb-database:5432") -putEnv("DB_USER", "benchmarkdbuser") -putEnv("DB_PASSWORD", "benchmarkdbpass") -putEnv("DB_DATABASE", "hello_world") - -# Logging -putEnv("LOG_IS_DISPLAY", "false") -putEnv("LOG_IS_FILE", "false") -putEnv("LOG_DIR", "/basolato/logs") - -# Security -putEnv("SECRET_KEY", "1p>G= 1.2.4" -requires "https://github.com/itsumura-h/nim-basolato >= 0.5.5" -requires "httpbeast >= 0.2.2" -requires "cligen >= 0.9.41" -requires "templates >= 0.5" -requires "bcrypt >= 0.2.1" -requires "nimAES >= 0.1.2" -requires "flatdb >= 0.2.4" -requires "allographer >= 0.9.0" -requires "faker >= 0.12.1" diff --git a/frameworks/Nim/basolato/resources/pages/fortune_view.nim b/frameworks/Nim/basolato/resources/pages/fortune_view.nim deleted file mode 100644 index 0e1c3b3df2b..00000000000 --- a/frameworks/Nim/basolato/resources/pages/fortune_view.nim +++ /dev/null @@ -1,32 +0,0 @@ -import json -import basolato/view - -proc impl(title:string, data:seq[JsonNode]):string = tmpli html""" - - - - - $title - - - - - - - - - $for row in data{ - - - - - } -
idmessage
$(row["id"].get)$(row["message"].get)
- - - -""" - -proc fortuneView*(this:View, data=newSeq[JsonNode]()):string = - let title = "Fortunes" - return impl(title, data) diff --git a/frameworks/Nim/httpbeast/benchmark_config.json b/frameworks/Nim/httpbeast/benchmark_config.json index be0ab4480b8..7aa8ac8fc19 100755 --- a/frameworks/Nim/httpbeast/benchmark_config.json +++ b/frameworks/Nim/httpbeast/benchmark_config.json @@ -19,6 +19,7 @@ "database_os": "Linux", "display_name": "HttpBeast", "notes": "", + "tags": ["broken"], "versus": "None" } } diff --git a/frameworks/Nim/jester/benchmark_config.json b/frameworks/Nim/jester/benchmark_config.json index b5795fba053..61499a79da1 100644 --- a/frameworks/Nim/jester/benchmark_config.json +++ b/frameworks/Nim/jester/benchmark_config.json @@ -19,6 +19,7 @@ "database_os": "Linux", "display_name": "Jester", "notes": "", + "tags": ["broken"], "versus": "httpbeast" } } diff --git a/frameworks/Nim/nim-stdlib/benchmark_config.json b/frameworks/Nim/nim-stdlib/benchmark_config.json index acd5712689a..710cb9996ea 100644 --- a/frameworks/Nim/nim-stdlib/benchmark_config.json +++ b/frameworks/Nim/nim-stdlib/benchmark_config.json @@ -23,6 +23,7 @@ "database_os": "Linux", "display_name": "nim-stdlib", "notes": "", + "tags": ["broken"], "versus": "httpbeast" } } diff --git a/frameworks/Nim/scorper/benchmark_config.json b/frameworks/Nim/scorper/benchmark_config.json index 77669f6cad2..6a365398a14 100755 --- a/frameworks/Nim/scorper/benchmark_config.json +++ b/frameworks/Nim/scorper/benchmark_config.json @@ -19,6 +19,7 @@ "database_os": "Linux", "display_name": "scorper", "notes": "", + "tags": ["broken"], "versus": "httpbeast" } } diff --git a/frameworks/OCaml/dream/README.md b/frameworks/OCaml/dream/README.md new file mode 100755 index 00000000000..86e484bc978 --- /dev/null +++ b/frameworks/OCaml/dream/README.md @@ -0,0 +1,35 @@ +# Dream + +## Overview + +Most of all of the code is inside of `test_dream/bin/main.ml` file. + +## Implemented tests + +| Test Name | Endpoint | +|------------|-------------------------------| +| Plain text | http://0.0.0.0:8080/plaintext | +| Json | http://0.0.0.0:8080/json | + +## Headers + +A simple middleware was added that adds the required headers for the Techempower Benchmarks. +The date header is refreshed only once per second as allowed by the rules for performance. + +## Dependencies + +The `test_dream/dune-project` and `test_dream/bin/dune` are where dependencies are managed +for this project. If you add a dependency to those locations and then run the following: + +``` +cd test_dream +dune build test_dream.opam +opam install --yes --deps-only . +``` + +You will update the opam package list and install your changes locally. + +## Running tests + +$ tfb --mode verify --test dream + diff --git a/frameworks/OCaml/dream/benchmark_config.json b/frameworks/OCaml/dream/benchmark_config.json new file mode 100755 index 00000000000..d5d83b838f4 --- /dev/null +++ b/frameworks/OCaml/dream/benchmark_config.json @@ -0,0 +1,26 @@ +{ + "framework": "dream", + "tests": [ + { + "default": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "database": "postgres", + "framework": "Dream", + "language": "OCaml", + "flavor": "None", + "orm": "Micro", + "platform": "http/af", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "Dream", + "notes": "", + "versus": "httpaf" + } + } + ] +} diff --git a/frameworks/OCaml/dream/dream.dockerfile b/frameworks/OCaml/dream/dream.dockerfile new file mode 100644 index 00000000000..8a806026a4e --- /dev/null +++ b/frameworks/OCaml/dream/dream.dockerfile @@ -0,0 +1,12 @@ +FROM ocaml/opam:debian-ocaml-5.1 +COPY ./dream_test/ /app +WORKDIR /app +USER root +RUN apt install -y libgmp-dev libev-dev pkg-config libssl-dev +RUN opam install --yes --deps-only . +RUN opam install dune +RUN eval $(opam env) +RUN opam exec -- dune build --profile release +CMD [ "./_build/default/bin/main.exe" ] +EXPOSE 8080 + diff --git a/frameworks/OCaml/dream/dream_test/bin/dune b/frameworks/OCaml/dream/dream_test/bin/dune new file mode 100755 index 00000000000..171e6829182 --- /dev/null +++ b/frameworks/OCaml/dream/dream_test/bin/dune @@ -0,0 +1,5 @@ +(executable + (public_name dream_test) + (name main) + (preprocess (pps lwt_ppx ppx_yojson_conv)) + (libraries dream_test dream ppx_yojson_conv calendar)) diff --git a/frameworks/OCaml/dream/dream_test/bin/main.ml b/frameworks/OCaml/dream/dream_test/bin/main.ml new file mode 100755 index 00000000000..4c5ac18c30c --- /dev/null +++ b/frameworks/OCaml/dream/dream_test/bin/main.ml @@ -0,0 +1,53 @@ +open Ppx_yojson_conv_lib.Yojson_conv.Primitives + +type message_object = { + message : string; +} [@@deriving yojson] + +let time_cache = Atomic.make false;; +let time_ref = ref("None");; + +let time () = + if not @@ Atomic.get time_cache + then begin + time_ref := CalendarLib.Printer.Calendar.sprint "%a, %d %b %Y %H:%M:%S UTC" @@ CalendarLib.Calendar.now (); + Atomic.set time_cache true; + (!time_ref) + end + else + (!time_ref);; + +let tech_empower_headers (inner_handler: Dream.handler) = + (fun (req) -> + let%lwt res = inner_handler req in + Dream.set_header res "Server" "dream"; + Dream.set_header res "Date" @@ time (); + Lwt.return res + );; + +let rec timer () = + Unix.sleepf 0.9; + Atomic.set time_cache false; + timer();; + +let () = + let time_invalidator = Domain.spawn(fun () -> timer ()) in + Dream.run ~interface: "0.0.0.0" + @@ tech_empower_headers + @@ Dream.router [ + Dream.get "/" (fun _ -> + Dream.html "Hello, world!" + ); + Dream.get "/plaintext" (fun _ -> + Dream.response ~headers: [("Content-Type", "text/plain")] + "Hello, world!" + |> Lwt.return + ); + Dream.get "/json" (fun _ -> + { message = "Hello, world!" } + |> yojson_of_message_object + |> Yojson.Safe.to_string + |> Dream.json + ); + ]; + Domain.join time_invalidator;; diff --git a/frameworks/OCaml/dream/dream_test/dream_test.opam b/frameworks/OCaml/dream/dream_test/dream_test.opam new file mode 100644 index 00000000000..b9db80a34bd --- /dev/null +++ b/frameworks/OCaml/dream/dream_test/dream_test.opam @@ -0,0 +1,35 @@ +# This file is generated by dune, edit dune-project instead +opam-version: "2.0" +synopsis: "A short synopsis" +description: "A longer description" +maintainer: ["Maintainer Name"] +authors: ["Author Name"] +license: "LICENSE" +tags: ["topics" "to describe" "your" "project"] +homepage: "https://github.com/username/reponame" +doc: "https://url/to/documentation" +bug-reports: "https://github.com/username/reponame/issues" +depends: [ + "ocaml" + "dune" {>= "3.14"} + "dream" + "lwt" + "ppx_yojson_conv" + "calendar" + "odoc" {with-doc} +] +build: [ + ["dune" "subst"] {dev} + [ + "dune" + "build" + "-p" + name + "-j" + jobs + "@install" + "@runtest" {with-test} + "@doc" {with-doc} + ] +] +dev-repo: "git+https://github.com/username/reponame.git" diff --git a/frameworks/OCaml/dream/dream_test/dune-project b/frameworks/OCaml/dream/dream_test/dune-project new file mode 100755 index 00000000000..aaeaf8c0df8 --- /dev/null +++ b/frameworks/OCaml/dream/dream_test/dune-project @@ -0,0 +1,26 @@ +(lang dune 3.14) + +(name dream_test) + +(generate_opam_files true) + +(source + (github username/reponame)) + +(authors "Author Name") + +(maintainers "Maintainer Name") + +(license LICENSE) + +(documentation https://url/to/documentation) + +(package + (name dream_test) + (synopsis "A short synopsis") + (description "A longer description") + (depends ocaml dune dream lwt ppx_yojson_conv calendar) + (tags + (topics "to describe" your project))) + +; See the complete stanza docs at https://dune.readthedocs.io/en/stable/dune-files.html#dune-project diff --git a/frameworks/OCaml/dream/dream_test/lib/dune b/frameworks/OCaml/dream/dream_test/lib/dune new file mode 100755 index 00000000000..b8d991f91da --- /dev/null +++ b/frameworks/OCaml/dream/dream_test/lib/dune @@ -0,0 +1,2 @@ +(library + (name dream_test)) diff --git a/frameworks/OCaml/dream/dream_test/test/dune b/frameworks/OCaml/dream/dream_test/test/dune new file mode 100755 index 00000000000..434f4a8ee36 --- /dev/null +++ b/frameworks/OCaml/dream/dream_test/test/dune @@ -0,0 +1,2 @@ +(test + (name test_dream_test)) diff --git a/frameworks/Go/martini/README.md b/frameworks/OCaml/dream/dream_test/test/test_dream_test.ml old mode 100644 new mode 100755 similarity index 100% rename from frameworks/Go/martini/README.md rename to frameworks/OCaml/dream/dream_test/test/test_dream_test.ml diff --git a/frameworks/OCaml/httpaf/dune b/frameworks/OCaml/httpaf/dune index cf1034755fc..53113e9c4fa 100644 --- a/frameworks/OCaml/httpaf/dune +++ b/frameworks/OCaml/httpaf/dune @@ -1,3 +1,3 @@ (executable (name httpaf_unix) - (libraries httpaf httpaf-lwt-unix lwt lwt.unix yojson)) + (libraries httpaf httpaf-lwt-unix lwt lwt.unix yojson unix)) diff --git a/frameworks/OCaml/httpaf/dune-project b/frameworks/OCaml/httpaf/dune-project index 45acd3f0884..f8af889136b 100644 --- a/frameworks/OCaml/httpaf/dune-project +++ b/frameworks/OCaml/httpaf/dune-project @@ -1 +1 @@ -(lang dune 2.7) +(lang dune 3.9) diff --git a/frameworks/OCaml/httpaf/httpaf.dockerfile b/frameworks/OCaml/httpaf/httpaf.dockerfile index 6ed2757d48a..905be838567 100644 --- a/frameworks/OCaml/httpaf/httpaf.dockerfile +++ b/frameworks/OCaml/httpaf/httpaf.dockerfile @@ -2,7 +2,7 @@ # https://github.com/rbjorklin/techempower-ocaml-image # Use pre-built image with all dependencies for faster test times -FROM rbjorklin/techempower-ocaml-image:4.14.1-4bf86567 +FROM rbjorklin/techempower-ocaml-image:5.3.0-e8949511 # https://caml.inria.fr/pub/docs/manual-ocaml/libref/Gc.html # https://linux.die.net/man/1/ocamlrun diff --git a/frameworks/OCaml/httpaf/httpaf_unix.ml b/frameworks/OCaml/httpaf/httpaf_unix.ml index 44aa15693d0..9fba87e2f61 100644 --- a/frameworks/OCaml/httpaf/httpaf_unix.ml +++ b/frameworks/OCaml/httpaf/httpaf_unix.ml @@ -170,7 +170,7 @@ let main () = accept_loop socket handler); let forever, _ = Lwt.wait () in Lwt_main.run forever; - exit 0 ) + exit 0) done; while true do diff --git a/frameworks/OCaml/webmachine/src/dune-project b/frameworks/OCaml/webmachine/src/dune-project index 661d1e52345..51333bb4e2c 100644 --- a/frameworks/OCaml/webmachine/src/dune-project +++ b/frameworks/OCaml/webmachine/src/dune-project @@ -1,4 +1,4 @@ -(lang dune 2.7) +(lang dune 3.9) (name webmachine-tfb) (generate_opam_files true) diff --git a/frameworks/OCaml/webmachine/src/lib.opam b/frameworks/OCaml/webmachine/src/lib.opam index 33e1ae6314d..30749f8a281 100644 --- a/frameworks/OCaml/webmachine/src/lib.opam +++ b/frameworks/OCaml/webmachine/src/lib.opam @@ -6,7 +6,7 @@ license: "MIT" homepage: "https://github.com/TechEmpower/FrameworkBenchmarks" bug-reports: "https://github.com/TechEmpower/FrameworkBenchmarks/issues" depends: [ - "dune" {>= "2.7" & >= "2.8.5"} + "dune" {>= "3.9" & >= "2.8.5"} "biniou" {>= "1.2.1"} "yojson" {>= "1.7.0"} "atd" {>= "2.2.1"} diff --git a/frameworks/OCaml/webmachine/src/src/bin/dune b/frameworks/OCaml/webmachine/src/src/bin/dune index ccf1f4dfeea..bd8333f4c19 100644 --- a/frameworks/OCaml/webmachine/src/src/bin/dune +++ b/frameworks/OCaml/webmachine/src/src/bin/dune @@ -1,5 +1,5 @@ (executable - (libraries webmachine lwt cohttp-lwt-unix caqti caqti-lwt caqti-driver-postgresql yojson atdgen-runtime lib) + (libraries webmachine lwt cohttp-lwt-unix caqti caqti-lwt caqti-driver-postgresql yojson atdgen-runtime lib unix) (preprocess (pps lwt_ppx)) (public_name tfb) (package tfb) diff --git a/frameworks/OCaml/webmachine/src/src/bin/tfb.ml b/frameworks/OCaml/webmachine/src/src/bin/tfb.ml index 4cdd891a077..62ec6626ff1 100644 --- a/frameworks/OCaml/webmachine/src/src/bin/tfb.ml +++ b/frameworks/OCaml/webmachine/src/src/bin/tfb.ml @@ -39,14 +39,13 @@ let or_error m = Error (Database_error (Caqti_error.show err)) |> Lwt.return let select_random = - Caqti_request.find Caqti_type.int - Caqti_type.(tup2 int int) + let open Caqti_request.Infix in + Caqti_type.(int ->! tup2 int int) "SELECT id, randomNumber FROM World WHERE id = $1" class hello = object (self) inherit [Cohttp_lwt.Body.t] Wm.resource - method! allowed_methods rd = Wm.continue [ `GET ] rd method content_types_provided rd = @@ -68,7 +67,6 @@ class hello = class db = object (self) inherit [Cohttp_lwt.Body.t] Wm.resource - method! allowed_methods rd = Wm.continue [ `GET ] rd method content_types_provided rd = @@ -228,7 +226,7 @@ let main () = Lwt.async (fun () -> Server.create ~mode:(`TCP (`Socket socket)) config); let forever, _ = Lwt.wait () in Lwt_main.run forever; - exit 0 ) + exit 0) done; while true do Unix.pause () diff --git a/frameworks/OCaml/webmachine/src/src/lib/dune b/frameworks/OCaml/webmachine/src/src/lib/dune index b67e786ee29..a9ced8d93a2 100644 --- a/frameworks/OCaml/webmachine/src/src/lib/dune +++ b/frameworks/OCaml/webmachine/src/src/lib/dune @@ -1,7 +1,7 @@ (library (name lib) (public_name lib) - (libraries yojson atdgen-runtime) + (libraries yojson atdgen-runtime unix) (preprocess (pps lwt_ppx))) (rule diff --git a/frameworks/OCaml/webmachine/src/tfb.opam b/frameworks/OCaml/webmachine/src/tfb.opam index d587a0d7eba..ebbb400201e 100644 --- a/frameworks/OCaml/webmachine/src/tfb.opam +++ b/frameworks/OCaml/webmachine/src/tfb.opam @@ -6,7 +6,7 @@ license: "MIT" homepage: "https://github.com/TechEmpower/FrameworkBenchmarks" bug-reports: "https://github.com/TechEmpower/FrameworkBenchmarks/issues" depends: [ - "dune" {>= "2.7" & >= "2.8.5"} + "dune" {>= "3.9" & >= "2.8.5"} "webmachine" {>= "0.7.0"} "lwt" {>= "5.4.1"} "conf-libev" {>= "4-12"} diff --git a/frameworks/OCaml/webmachine/webmachine.dockerfile b/frameworks/OCaml/webmachine/webmachine.dockerfile index b0059706392..ac3a1fab080 100644 --- a/frameworks/OCaml/webmachine/webmachine.dockerfile +++ b/frameworks/OCaml/webmachine/webmachine.dockerfile @@ -1,6 +1,6 @@ # https://github.com/rbjorklin/techempower-ocaml-image # Use pre-built image with all dependencies for faster test times -FROM rbjorklin/techempower-ocaml-image:4.14.1-4bf86567 +FROM rbjorklin/techempower-ocaml-image:5.3.0-e8949511 ENV DIR project diff --git a/frameworks/PHP/amp/amp.dockerfile b/frameworks/PHP/amp/amp.dockerfile index 08058b50d22..240db763cec 100644 --- a/frameworks/PHP/amp/amp.dockerfile +++ b/frameworks/PHP/amp/amp.dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:22.04 +FROM ubuntu:24.04 ARG DEBIAN_FRONTEND=noninteractive @@ -6,20 +6,19 @@ RUN apt-get update -yqq && apt-get install -yqq software-properties-common > /de RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php RUN apt-get update -yqq > /dev/null && \ apt-get install -yqq git unzip wget curl build-essential \ - php8.2-cli php8.2-mbstring php8.2-dev php8.2-xml php8.2-curl > /dev/null + php8.4-cli php8.4-mbstring php8.4-dev php8.4-xml php8.4-curl > /dev/null # An extension is required! # We deal with concurrencies over 1k, which stream_select doesn't support. RUN wget http://pear.php.net/go-pear.phar --quiet && php go-pear.phar #RUN apt-get install -y libuv1-dev > /dev/null RUN apt-get install -y libevent-dev > /dev/null -#RUN pecl install uv-0.2.4 > /dev/null && echo "extension=uv.so" > /etc/php/8.2/cli/conf.d/uv.ini -RUN pecl install event-3.0.8 > /dev/null && echo "extension=event.so" > /etc/php/8.2/cli/conf.d/event.ini +#RUN pecl install uv-0.2.4 > /dev/null && echo "extension=uv.so" > /etc/php/8.4/cli/conf.d/uv.ini +RUN pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.4/cli/conf.d/event.ini -ADD ./ /amp WORKDIR /amp - -COPY deploy/conf/* /etc/php/8.2/cli/conf.d/ +COPY --link . . +COPY deploy/conf/* /etc/php/8.4/cli/conf.d/ COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer diff --git a/frameworks/PHP/cakephp/cakephp-workerman.dockerfile b/frameworks/PHP/cakephp/cakephp-workerman.dockerfile index 0339af783c9..ce77247eb6c 100644 --- a/frameworks/PHP/cakephp/cakephp-workerman.dockerfile +++ b/frameworks/PHP/cakephp/cakephp-workerman.dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:22.04 +FROM ubuntu:24.04 ARG DEBIAN_FRONTEND=noninteractive @@ -7,26 +7,24 @@ 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 install -yqq git unzip \ - php8.3-cli php8.3-mysql php8.3-mbstring php8.3-intl php8.3-xml php8.3-curl > /dev/null + php8.4-cli php8.4-mysql php8.4-mbstring php8.4-intl php8.4-xml php8.4-curl > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -RUN apt-get install -y php-pear php8.3-dev libevent-dev > /dev/null -RUN pecl install event-3.0.8 > /dev/null && echo "extension=event.so" > /etc/php/8.3/cli/conf.d/event.ini +RUN apt-get install -y php-pear php8.4-dev libevent-dev > /dev/null +RUN pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.4/cli/conf.d/event.ini EXPOSE 8080 ADD ./ /cakephp WORKDIR /cakephp -RUN composer require joanhey/adapterman:^0.6 +RUN composer require joanhey/adapterman:^0.7 RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet RUN chmod -R 777 /cakephp -#ENV XDEBUG_CONFIG="remote_host=$(ipconfig getifaddr en0)" -ENV XDEBUG_SESSION=xdebug_is_great -#COPY deploy/conf/cli-php.ini /etc/php/8.3/cli/php.ini +#COPY deploy/conf/cli-php.ini /etc/php/8.4/cli/php.ini CMD php -c deploy/conf/cli-php.ini \ server.php start diff --git a/frameworks/PHP/cakephp/cakephp.dockerfile b/frameworks/PHP/cakephp/cakephp.dockerfile index 438d467b820..d5d39a7ea65 100644 --- a/frameworks/PHP/cakephp/cakephp.dockerfile +++ b/frameworks/PHP/cakephp/cakephp.dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:22.04 +FROM ubuntu:24.04 ARG DEBIAN_FRONTEND=noninteractive @@ -7,22 +7,22 @@ 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 install -yqq nginx git unzip \ - php8.3-fpm php8.3-mysql php8.3-xml php8.3-mbstring php8.3-intl php8.3-dev php8.3-curl php-xdebug > /dev/null + php8.4-fpm php8.4-mysql php8.4-xml php8.4-mbstring php8.4-intl php8.4-dev php8.4-curl > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -COPY deploy/conf/* /etc/php/8.3/fpm/ -COPY deploy/conf/* /etc/php/8.3/cli/ +COPY deploy/conf/* /etc/php/8.4/fpm/ +COPY deploy/conf/* /etc/php/8.4/cli/ ADD ./ /cakephp WORKDIR /cakephp -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.3/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.4/fpm/php-fpm.conf ; fi; -RUN composer install --optimize-autoloader --classmap-authoritative --no-dev +RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet RUN chmod -R 777 /cakephp -CMD service php8.3-fpm start && \ +CMD service php8.4-fpm start && \ nginx -c /cakephp/deploy/nginx.conf diff --git a/frameworks/PHP/cakephp/deploy/conf/cli-php.ini b/frameworks/PHP/cakephp/deploy/conf/cli-php.ini index bcccffbc63b..e03b6e352a9 100644 --- a/frameworks/PHP/cakephp/deploy/conf/cli-php.ini +++ b/frameworks/PHP/cakephp/deploy/conf/cli-php.ini @@ -13,4 +13,4 @@ memory_limit = 512M opcache.jit_buffer_size = 128M opcache.jit = tracing -disable_functions=header,header_remove,headers_sent,http_response_code,setcookie,session_create_id,session_id,session_name,session_save_path,session_status,session_start,session_write_close,session_regenerate_id,set_time_limit +disable_functions=header,header_remove,headers_sent,headers_list,http_response_code,setcookie,session_create_id,session_id,session_name,session_save_path,session_status,session_start,session_write_close,session_regenerate_id,session_unset,session_get_cookie_params,session_set_cookie_params,set_time_limit diff --git a/frameworks/PHP/cakephp/server.php b/frameworks/PHP/cakephp/server.php index 5a6a09ae35d..820e178205d 100644 --- a/frameworks/PHP/cakephp/server.php +++ b/frameworks/PHP/cakephp/server.php @@ -2,13 +2,14 @@ require_once __DIR__.'/vendor/autoload.php'; use Adapterman\Adapterman; -use Workerman\Lib\Timer; +use Workerman\Timer; use Workerman\Worker; Adapterman::init(); $http_worker = new Worker('http://0.0.0.0:8080'); $http_worker->count = (int) shell_exec('nproc') * 4; +$http_worker->reusePort = true; $http_worker->name = 'AdapterMan-CakePHP'; $http_worker->onWorkerStart = static function () { @@ -36,9 +37,9 @@ class HeaderDate public static function init(): void { - self::$date = self::NAME.gmdate('D, d M Y H:i:s').' GMT'; + self::$date = self::NAME.gmdate(DATE_RFC7231); Timer::add(1, static function () { - self::$date = self::NAME.gmdate('D, d M Y H:i:s').' GMT'; + self::$date = self::NAME.gmdate(DATE_RFC7231); }); } } diff --git a/frameworks/PHP/codeigniter/codeigniter.dockerfile b/frameworks/PHP/codeigniter/codeigniter.dockerfile index e04cf572ab6..097ea60514d 100644 --- a/frameworks/PHP/codeigniter/codeigniter.dockerfile +++ b/frameworks/PHP/codeigniter/codeigniter.dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:22.04 +FROM ubuntu:24.04 ARG DEBIAN_FRONTEND=noninteractive @@ -7,16 +7,16 @@ 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.3-cli php8.3-fpm php8.3-mysql php8.3-mbstring php8.3-intl php8.3-curl > /dev/null + php8.4-cli php8.4-fpm php8.4-mysql php8.4-mbstring php8.4-intl php8.4-curl > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -COPY deploy/conf/* /etc/php/8.3/fpm/ +COPY deploy/conf/* /etc/php/8.4/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.3/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.4/fpm/php-fpm.conf ; fi; RUN composer install --optimize-autoloader --classmap-authoritative --no-dev #--quiet @@ -25,5 +25,5 @@ RUN chmod -R 777 writable EXPOSE 8080 -CMD service php8.3-fpm start && \ +CMD service php8.4-fpm start && \ nginx -c /codeigniter/deploy/nginx.conf diff --git a/frameworks/PHP/codeigniter/public/index.php b/frameworks/PHP/codeigniter/public/index.php index 81e10b96dfc..df2853effed 100644 --- a/frameworks/PHP/codeigniter/public/index.php +++ b/frameworks/PHP/codeigniter/public/index.php @@ -1,9 +1,17 @@ systemDirectory, '\\/ ') . DIRECTORY_SEPARATOR . 'bootstrap.php'; - -// Load environment settings from .env files into $_SERVER and $_ENV -require_once SYSTEMPATH . 'Config/DotEnv.php'; -(new CodeIgniter\Config\DotEnv(ROOTPATH))->load(); - -// Define ENVIRONMENT -if (! defined('ENVIRONMENT')) { - define('ENVIRONMENT', env('CI_ENVIRONMENT', 'production')); -} - -// Load Config Cache -// $factoriesCache = new \CodeIgniter\Cache\FactoriesCache(); -// $factoriesCache->load('config'); -// ^^^ Uncomment these lines if you want to use Config Caching. - -/* - * --------------------------------------------------------------- - * GRAB OUR CODEIGNITER INSTANCE - * --------------------------------------------------------------- - * - * The CodeIgniter class contains the core functionality to make - * the application run, and does all the dirty work to get - * the pieces all working together. - */ - -$app = Config\Services::codeigniter(); -$app->initialize(); -//$context = is_cli() ? 'php-cli' : 'web'; -$app->setContext('web'); - -/* - *--------------------------------------------------------------- - * LAUNCH THE APPLICATION - *--------------------------------------------------------------- - * Now that everything is set up, it's time to actually fire - * up the engines and make this app do its thang. - */ - -$app->run(); - -// Save Config Cache -// $factoriesCache->save('config'); -// ^^^ Uncomment this line if you want to use Config Caching. +// LOAD THE FRAMEWORK BOOTSTRAP FILE +require $paths->systemDirectory . '/Boot.php'; -// Exits the application, setting the exit code for CLI-based applications -// that might be watching. -exit(EXIT_SUCCESS); +exit(CodeIgniter\Boot::bootWeb($paths)); diff --git a/frameworks/PHP/comet/app.php b/frameworks/PHP/comet/app.php index 51300a8f213..857853bc9ec 100644 --- a/frameworks/PHP/comet/app.php +++ b/frameworks/PHP/comet/app.php @@ -24,9 +24,9 @@ $app->init( function() { ORM::init(); - Storage::$date = gmdate('D, d M Y H:i:s').' GMT'; + Storage::$date = gmdate(DATE_RFC7231); Timer::add(1, function() { - Storage::$date = gmdate('D, d M Y H:i:s').' GMT'; + Storage::$date = gmdate(DATE_RFC7231); }); }); diff --git a/frameworks/PHP/comet/comet-mysql.dockerfile b/frameworks/PHP/comet/comet-mysql.dockerfile index 9d694c24d99..2adc4d70f81 100644 --- a/frameworks/PHP/comet/comet-mysql.dockerfile +++ b/frameworks/PHP/comet/comet-mysql.dockerfile @@ -11,7 +11,7 @@ RUN apt-get install -yqq php8.3-cli php8.3-xml php8.3-mysql php8.3-mbstring > /d COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer RUN apt-get install -y php-pear php8.3-dev libevent-dev git > /dev/null -RUN pecl install event-3.0.8 > /dev/null && echo "extension=event.so" > /etc/php/8.3/cli/conf.d/event.ini +RUN pecl install event-3.1.3 > /dev/null && echo "extension=event.so" > /etc/php/8.3/cli/conf.d/event.ini COPY php.ini /etc/php/8.3/cli/php.ini diff --git a/frameworks/PHP/comet/comet.dockerfile b/frameworks/PHP/comet/comet.dockerfile index 545a4abcaba..2cfbc0935c6 100644 --- a/frameworks/PHP/comet/comet.dockerfile +++ b/frameworks/PHP/comet/comet.dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:22.04 +FROM ubuntu:24.04 ARG DEBIAN_FRONTEND=noninteractive @@ -6,14 +6,14 @@ RUN apt-get update -yqq && apt-get install -yqq software-properties-common > /de 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 install -yqq php8.3-cli php8.3-pgsql php8.3-xml php8.3-mbstring > /dev/null +RUN apt-get install -yqq php8.4-cli php8.4-pgsql php8.4-xml php8.4-mbstring > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -RUN apt-get install -y php-pear php8.3-dev libevent-dev git > /dev/null -RUN pecl install event-3.0.8 > /dev/null && echo "extension=event.so" > /etc/php/8.3/cli/conf.d/event.ini +RUN apt-get install -y php-pear php8.4-dev libevent-dev git > /dev/null +RUN pecl install event-3.1.3 > /dev/null && echo "extension=event.so" > /etc/php/8.4/cli/conf.d/event.ini -COPY php.ini /etc/php/8.3/cli/php.ini +COPY php.ini /etc/php/8.4/cli/php.ini ADD ./ /comet WORKDIR /comet diff --git a/frameworks/PHP/duckphp/duckphp.dockerfile b/frameworks/PHP/duckphp/duckphp.dockerfile index f81fcdb546f..ae97dfc8cf6 100644 --- a/frameworks/PHP/duckphp/duckphp.dockerfile +++ b/frameworks/PHP/duckphp/duckphp.dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:22.04 +FROM ubuntu:24.04 ARG DEBIAN_FRONTEND=noninteractive @@ -6,18 +6,18 @@ RUN apt-get update -yqq && apt-get install -yqq software-properties-common > /de RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php RUN apt-get update -yqq > /dev/null && \ apt-get install -yqq nginx git unzip \ - php8.3-cli php8.3-fpm php8.3-mysql php8.3-dev > /dev/null + php8.4-cli php8.4-fpm php8.4-mysql php8.4-dev > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -COPY deploy/conf/* /etc/php/8.3/fpm/ +COPY deploy/conf/* /etc/php/8.4/fpm/ -ADD ./ /duckphp WORKDIR /duckphp +COPY --link . . -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.3/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.4/fpm/php-fpm.conf ; fi; RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet -CMD service php8.3-fpm start && \ +CMD service php8.4-fpm start && \ nginx -c /duckphp/deploy/nginx.conf diff --git a/frameworks/PHP/fat-free/composer.json b/frameworks/PHP/fat-free/composer.json index db779e5a04b..ba4b6413103 100644 --- a/frameworks/PHP/fat-free/composer.json +++ b/frameworks/PHP/fat-free/composer.json @@ -1,5 +1,5 @@ { "require": { - "bcosca/fatfree-core": "3.8.0" + "bcosca/fatfree-core": "^3.8" } -} \ No newline at end of file +} diff --git a/frameworks/PHP/fat-free/deploy/conf/php.ini b/frameworks/PHP/fat-free/deploy/conf/php.ini index d2e924cf326..82133535145 100644 --- a/frameworks/PHP/fat-free/deploy/conf/php.ini +++ b/frameworks/PHP/fat-free/deploy/conf/php.ini @@ -1909,6 +1909,9 @@ opcache.huge_code_pages=1 ; SSL stream context option. ;openssl.capath= +opcache.jit_buffer_size = 128M +opcache.jit = tracing + ; Local Variables: ; tab-width: 4 ; End: \ No newline at end of file diff --git a/frameworks/PHP/fat-free/fat-free-raw.dockerfile b/frameworks/PHP/fat-free/fat-free-raw.dockerfile index 29ae8ba95a3..9038161bb87 100644 --- a/frameworks/PHP/fat-free/fat-free-raw.dockerfile +++ b/frameworks/PHP/fat-free/fat-free-raw.dockerfile @@ -1,16 +1,16 @@ -FROM ubuntu:20.04 +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 > /dev/null && \ - apt-get install -yqq nginx git unzip php8.1 php8.1-common php8.1-cli php8.1-fpm php8.1-mysql > /dev/null + apt-get install -yqq nginx git unzip php8.4 php8.4-common php8.4-cli php8.4-fpm php8.4-mysql > /dev/null -COPY deploy/conf/* /etc/php/8.1/fpm/ +COPY deploy/conf/* /etc/php/8.4/fpm/ -ADD ./ /fat-free WORKDIR /fat-free +COPY --link . . ENV F3DIR="/fat-free/src" @@ -18,11 +18,11 @@ COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.1/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.4/fpm/php-fpm.conf ; fi; RUN chmod -R 777 /fat-free EXPOSE 8080 -CMD service php8.1-fpm start && \ +CMD service php8.4-fpm start && \ nginx -c /fat-free/deploy/nginx.conf diff --git a/frameworks/PHP/fat-free/fat-free.dockerfile b/frameworks/PHP/fat-free/fat-free.dockerfile index 8d75cb82cf3..3a91f8cc194 100644 --- a/frameworks/PHP/fat-free/fat-free.dockerfile +++ b/frameworks/PHP/fat-free/fat-free.dockerfile @@ -1,16 +1,16 @@ -FROM ubuntu:20.04 +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 > /dev/null && \ - apt-get install -yqq nginx git unzip php8.1 php8.1-common php8.1-cli php8.1-fpm php8.1-mysql > /dev/null + apt-get install -yqq nginx git unzip php8.4 php8.4-common php8.4-cli php8.4-fpm php8.4-mysql > /dev/null -COPY deploy/conf/* /etc/php/8.1/fpm/ +COPY deploy/conf/* /etc/php/8.4/fpm/ -ADD ./ /fat-free WORKDIR /fat-free +COPY --link . . ENV F3DIR="/fat-free/src" @@ -18,13 +18,12 @@ ENV F3DIR="/fat-free/src" COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet -#RUN git clone -b 3.7.2 --single-branch --depth 1 "https://github.com/bcosca/fatfree-core.git" src -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.1/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.4/fpm/php-fpm.conf ; fi; RUN chmod -R 777 /fat-free EXPOSE 8080 -CMD service php8.1-fpm start && \ +CMD service php8.4-fpm start && \ nginx -c /fat-free/deploy/nginx.conf diff --git a/frameworks/PHP/flight/benchmark_config.json b/frameworks/PHP/flight/benchmark_config.json index fb9ad136d4a..5a2cb9f89fb 100644 --- a/frameworks/PHP/flight/benchmark_config.json +++ b/frameworks/PHP/flight/benchmark_config.json @@ -23,6 +23,29 @@ "display_name": "flight", "notes": "", "versus": "php" - } + }, + "workerman": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "db_url": "/db", + "fortune_url": "/fortunes", + "query_url": "/db-multiple?queries=", + "update_url": "/updates?queries=", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "MySQL", + "framework": "Flight", + "language": "PHP", + "flavor": "PHP8", + "orm": "Raw", + "platform": "workerman", + "webserver": "none", + "os": "Linux", + "database_os": "Linux", + "display_name": "flight [workerman]", + "notes": "", + "versus": "php" + } }] } diff --git a/frameworks/PHP/flight/composer.json b/frameworks/PHP/flight/composer.json index 87ce7604b0a..507b168e5a2 100644 --- a/frameworks/PHP/flight/composer.json +++ b/frameworks/PHP/flight/composer.json @@ -1,5 +1,5 @@ { "require": { - "mikecao/flight": "^2.0" + "flightphp/core": "^3.14" } -} \ No newline at end of file +} diff --git a/frameworks/PHP/flight/deploy/conf/cli-php.ini b/frameworks/PHP/flight/deploy/conf/cli-php.ini new file mode 100644 index 00000000000..9f0f3171834 --- /dev/null +++ b/frameworks/PHP/flight/deploy/conf/cli-php.ini @@ -0,0 +1,16 @@ +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.huge_code_pages=1 + +mysqlnd.collect_statistics = Off +memory_limit = 512M + +opcache.jit_buffer_size=128M +opcache.jit=tracing + +disable_functions=header,header_remove,headers_sent,headers_list,http_response_code,setcookie,session_create_id,session_id,session_name,session_save_path,session_status,session_start,session_write_close,session_regenerate_id,session_unset,session_get_cookie_params,session_set_cookie_params,set_time_limit diff --git a/frameworks/PHP/flight/flight-workerman.dockerfile b/frameworks/PHP/flight/flight-workerman.dockerfile new file mode 100644 index 00000000000..ebaa2098243 --- /dev/null +++ b/frameworks/PHP/flight/flight-workerman.dockerfile @@ -0,0 +1,32 @@ +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 > /dev/null && \ + apt-get install -yqq nginx git unzip php8.4 php8.4-common php8.4-cli php8.4-fpm php8.4-mysql > /dev/null + +COPY deploy/conf/* /etc/php/8.4/fpm/ + +WORKDIR /flight +COPY . . + +ENV FLIGHT_DIR="/flight/src" + +COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer + +RUN apt-get install -y php-pear php8.4-dev libevent-dev php8.4-xml > /dev/null +RUN pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.4/cli/conf.d/event.ini + +RUN composer require joanhey/adapterman:^0.7 +RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet + +RUN sed -i "s|Flight::start() ;|//Flight::start() ;|g" index.php + +RUN chmod -R 777 /flight + +EXPOSE 8080 + +CMD php -c deploy/conf/cli-php.ini \ + server.php start diff --git a/frameworks/PHP/flight/flight.dockerfile b/frameworks/PHP/flight/flight.dockerfile index 07dbf7670c9..60b2b3ebc7a 100644 --- a/frameworks/PHP/flight/flight.dockerfile +++ b/frameworks/PHP/flight/flight.dockerfile @@ -1,16 +1,16 @@ -FROM ubuntu:22.04 +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 > /dev/null && \ - apt-get install -yqq nginx git unzip php8.3 php8.3-common php8.3-cli php8.3-fpm php8.3-mysql > /dev/null + apt-get install -yqq nginx git unzip php8.4 php8.4-common php8.4-cli php8.4-fpm php8.4-mysql > /dev/null -COPY deploy/conf/* /etc/php/8.3/fpm/ +COPY deploy/conf/* /etc/php/8.4/fpm/ -ADD ./ /flight WORKDIR /flight +COPY --link . . ENV FLIGHT_DIR="/flight/src" @@ -18,11 +18,11 @@ COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.3/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.4/fpm/php-fpm.conf ; fi; RUN chmod -R 777 /flight EXPOSE 8080 -CMD service php8.3-fpm start && \ +CMD service php8.4-fpm start && \ nginx -c /flight/deploy/nginx.conf diff --git a/frameworks/PHP/flight/index.php b/frameworks/PHP/flight/index.php index 48c77996905..c2cc5dee02d 100644 --- a/frameworks/PHP/flight/index.php +++ b/frameworks/PHP/flight/index.php @@ -3,6 +3,7 @@ error_reporting(-1); +Flight::set('flight.content_length', false); Flight::register('db', PDO::class, [ 'mysql:host=tfb-database;port=3306;dbname=hello_world', 'benchmarkdbuser', 'benchmarkdbpass', [ \PDO::ATTR_PERSISTENT => TRUE ] ]); // JSON test @@ -13,9 +14,8 @@ // Plaintext test Flight::route('/plaintext', function() { Flight::response() - ->header('Content-Type', 'text/plain') - ->write('Hello, World!') - ->send(); + ->header('Content-Type', 'text/plain'); + echo 'Hello, World!'; }); // DB test @@ -103,4 +103,13 @@ Flight::render('fortunes.php', [ 'fortunes' => $fortunes ]); }); -Flight::start(); +Flight::start() ; + +// Workerman +function run() +{ + ob_start(); + Flight::start(); + header(HeaderDate::$date); // To pass the bench, nginx auto add it + return ob_get_clean(); +} diff --git a/frameworks/PHP/flight/server.php b/frameworks/PHP/flight/server.php new file mode 100644 index 00000000000..826e74e38ec --- /dev/null +++ b/frameworks/PHP/flight/server.php @@ -0,0 +1,45 @@ +count = (int) shell_exec('nproc') * 4; +$http_worker->reusePort = true; +$http_worker->name = 'AdapterMan-Flight'; + +$http_worker->onWorkerStart = static function () { + HeaderDate::init(); + require __DIR__.'/index.php'; +}; + +$http_worker->onMessage = static function ($connection) { + + $connection->send(run()); +}; + +Worker::runAll(); + +class HeaderDate +{ + const NAME = 'Date: '; + + /** + * Date header + * + * @var string + */ + public static $date; + + public static function init(): void + { + self::$date = self::NAME . gmdate(DATE_RFC7231); + Timer::add(1, static function () { + self::$date = self::NAME . gmdate(DATE_RFC7231); + }); + } +} diff --git a/frameworks/PHP/fomo/.env b/frameworks/PHP/fomo/.env new file mode 100644 index 00000000000..9e3a7f21887 --- /dev/null +++ b/frameworks/PHP/fomo/.env @@ -0,0 +1,21 @@ +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 new file mode 100644 index 00000000000..a757318145d --- /dev/null +++ b/frameworks/PHP/fomo/.gitignore @@ -0,0 +1,12 @@ +.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 new file mode 100644 index 00000000000..31c6ddcbed1 --- /dev/null +++ b/frameworks/PHP/fomo/README.md @@ -0,0 +1,26 @@ +# 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 new file mode 100644 index 00000000000..a4cff760343 --- /dev/null +++ b/frameworks/PHP/fomo/app/Exceptions/Handler.php @@ -0,0 +1,30 @@ +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 new file mode 100755 index 00000000000..817107d03d2 --- /dev/null +++ b/frameworks/PHP/fomo/benchmark_config.json @@ -0,0 +1,31 @@ +{ + "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 new file mode 100644 index 00000000000..ea983317469 --- /dev/null +++ b/frameworks/PHP/fomo/composer.json @@ -0,0 +1,45 @@ +{ + "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 new file mode 100644 index 00000000000..1067719fe39 --- /dev/null +++ b/frameworks/PHP/fomo/config.toml @@ -0,0 +1,19 @@ +[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 new file mode 100644 index 00000000000..0f6c003a1a6 --- /dev/null +++ b/frameworks/PHP/fomo/config/app.php @@ -0,0 +1,8 @@ + 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 new file mode 100644 index 00000000000..004a473cc99 --- /dev/null +++ b/frameworks/PHP/fomo/config/database.php @@ -0,0 +1,67 @@ + 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 new file mode 100755 index 00000000000..273b2cf3d4a --- /dev/null +++ b/frameworks/PHP/fomo/config/server.php @@ -0,0 +1,82 @@ + 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 new file mode 100644 index 00000000000..6c94704a357 --- /dev/null +++ b/frameworks/PHP/fomo/deploy/php-async.ini @@ -0,0 +1,13 @@ +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 new file mode 100644 index 00000000000..d5794972427 --- /dev/null +++ b/frameworks/PHP/fomo/engineer @@ -0,0 +1,98 @@ +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 new file mode 100644 index 00000000000..eee3c65e802 --- /dev/null +++ b/frameworks/PHP/fomo/fomo.dockerfile @@ -0,0 +1,22 @@ +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 new file mode 100644 index 00000000000..b0d0c5bd160 --- /dev/null +++ b/frameworks/PHP/fomo/language/validation/en/errors.php @@ -0,0 +1,30 @@ + [ + '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 new file mode 100644 index 00000000000..f711870746d --- /dev/null +++ b/frameworks/PHP/fomo/routes/api.php @@ -0,0 +1,100 @@ +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/Java/play1/public/stylesheets/main.css b/frameworks/PHP/fomo/storage/logs/.keep similarity index 100% rename from frameworks/Java/play1/public/stylesheets/main.css rename to frameworks/PHP/fomo/storage/logs/.keep diff --git a/frameworks/PHP/lumen/app/Console/Commands/.gitkeep b/frameworks/PHP/fomo/storage/routes/.keep similarity index 100% rename from frameworks/PHP/lumen/app/Console/Commands/.gitkeep rename to frameworks/PHP/fomo/storage/routes/.keep diff --git a/frameworks/PHP/fomo/storage/view/fortunes.php b/frameworks/PHP/fomo/storage/view/fortunes.php new file mode 100644 index 00000000000..3b1b2c99b5e --- /dev/null +++ b/frameworks/PHP/fomo/storage/view/fortunes.php @@ -0,0 +1,18 @@ + + + Fortunes + + + + + + + + + + + + +
idmessage
id ?>message) ?>
+ + diff --git a/frameworks/PHP/fuel/benchmark_config.json b/frameworks/PHP/fuel/benchmark_config.json index d831c427cc3..98761b3a7a4 100644 --- a/frameworks/PHP/fuel/benchmark_config.json +++ b/frameworks/PHP/fuel/benchmark_config.json @@ -20,6 +20,7 @@ "database_os": "Linux", "display_name": "fuel", "notes": "", + "tags": ["broken"], "versus": "php" } }] diff --git a/frameworks/PHP/hamlet/.gitignore b/frameworks/PHP/hamlet/.gitignore deleted file mode 100644 index d1502b087b4..00000000000 --- a/frameworks/PHP/hamlet/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -vendor/ -composer.lock diff --git a/frameworks/PHP/hamlet/Benchmark/Application.php b/frameworks/PHP/hamlet/Benchmark/Application.php deleted file mode 100644 index f4cc693e55a..00000000000 --- a/frameworks/PHP/hamlet/Benchmark/Application.php +++ /dev/null @@ -1,45 +0,0 @@ -getPath()) { - case '/plaintext': - return new HelloTextResource; - case '/json': - return new HelloJsonResource; - case '/db': - return new DbResource($this->database); - case '/queries': - return new QueriesResource($this->database); - case '/cached-worlds': - return new CachedQueriesResource($this->getCache($request), $this->database); - case '/fortunes': - return new FortuneResource($this->database); - case '/update': - return new UpdateResource($this->database); - } - return new NotFoundResource; - } - - protected function getCache(Request $request): CacheItemPoolInterface - { - if (!$this->cache) { - $this->cache = new ApcuCachePool; - } - return $this->cache; - } -} diff --git a/frameworks/PHP/hamlet/Benchmark/Entities/FortuneEntity.php b/frameworks/PHP/hamlet/Benchmark/Entities/FortuneEntity.php deleted file mode 100644 index fbdbbb27809..00000000000 --- a/frameworks/PHP/hamlet/Benchmark/Entities/FortuneEntity.php +++ /dev/null @@ -1,27 +0,0 @@ - $this->messages - ]; - } - - protected function getTemplatePath(): string - { - return __DIR__ . '/fortune.mustache'; - } - - public function getKey(): string - { - return md5(var_export($this->messages, true)); - } -} diff --git a/frameworks/PHP/hamlet/Benchmark/Entities/Message.php b/frameworks/PHP/hamlet/Benchmark/Entities/Message.php deleted file mode 100644 index c078b1b6d01..00000000000 --- a/frameworks/PHP/hamlet/Benchmark/Entities/Message.php +++ /dev/null @@ -1,29 +0,0 @@ -id; - } - - public function message(): string - { - return $this->message; - } - - public function jsonSerialize(): array - { - return [ - 'id' => $this->id, - 'message' => $this->message - ]; - } -} diff --git a/frameworks/PHP/hamlet/Benchmark/Entities/RandomNumber.php b/frameworks/PHP/hamlet/Benchmark/Entities/RandomNumber.php deleted file mode 100644 index 669f6ce773d..00000000000 --- a/frameworks/PHP/hamlet/Benchmark/Entities/RandomNumber.php +++ /dev/null @@ -1,34 +0,0 @@ -id; - } - - public function number(): int - { - return $this->randomNumber; - } - - public function withNumber(int $number): self - { - return new self($this->id, $number); - } - - public function jsonSerialize(): array - { - return [ - 'id' => $this->id, - 'randomNumber' => $this->randomNumber - ]; - } -} diff --git a/frameworks/PHP/hamlet/Benchmark/Entities/fortune.mustache b/frameworks/PHP/hamlet/Benchmark/Entities/fortune.mustache deleted file mode 100644 index 20265b750a3..00000000000 --- a/frameworks/PHP/hamlet/Benchmark/Entities/fortune.mustache +++ /dev/null @@ -1,18 +0,0 @@ - - -Fortunes - - - - - - - {{# messages }} - - - - - {{/ messages }} -
idmessage
{{ id }}{{ message }}
- - diff --git a/frameworks/PHP/hamlet/Benchmark/Repositories/FortuneRepository.php b/frameworks/PHP/hamlet/Benchmark/Repositories/FortuneRepository.php deleted file mode 100644 index a2044cab081..00000000000 --- a/frameworks/PHP/hamlet/Benchmark/Repositories/FortuneRepository.php +++ /dev/null @@ -1,21 +0,0 @@ - - */ - public function findAll(): callable - { - return fn (Session $session) => - $session->prepare('SELECT id, message FROM Fortune') - ->processAll() - ->selectAll()->cast(Message::class) - ->collectAll(); - } -} diff --git a/frameworks/PHP/hamlet/Benchmark/Repositories/WorldRepository.php b/frameworks/PHP/hamlet/Benchmark/Repositories/WorldRepository.php deleted file mode 100644 index 003a4dc7a19..00000000000 --- a/frameworks/PHP/hamlet/Benchmark/Repositories/WorldRepository.php +++ /dev/null @@ -1,34 +0,0 @@ - - $session->prepare('SELECT id, randomNumber FROM World WHERE id = ?') - ->bindInteger($id) - ->processOne() - ->selectAll()->cast(RandomNumber::class) - ->collectHead(); - } - - /** - * @return callable(Session):void - */ - public function updateNumber(RandomNumber $number): callable - { - return fn (Session $session) => - $session->prepare('UPDATE World SET randomNumber = ? WHERE id = ?') - ->bindInteger($number->number()) - ->bindInteger($number->id()) - ->execute(); - } -} diff --git a/frameworks/PHP/hamlet/Benchmark/Resources/CachedQueriesResource.php b/frameworks/PHP/hamlet/Benchmark/Resources/CachedQueriesResource.php deleted file mode 100644 index 715deacfe65..00000000000 --- a/frameworks/PHP/hamlet/Benchmark/Resources/CachedQueriesResource.php +++ /dev/null @@ -1,30 +0,0 @@ -getQueriesCount($request); - $key = 'count.' . $count; - $item = $this->cache->getItem($key); - if ($item->isHit()) { - return $item->get(); - } - $response = parent::getResponse($request); - $this->cache->save(new CacheItem($key, true, $response)); - return $response; - } -} diff --git a/frameworks/PHP/hamlet/Benchmark/Resources/DbResource.php b/frameworks/PHP/hamlet/Benchmark/Resources/DbResource.php deleted file mode 100644 index 2ef8ea8ce35..00000000000 --- a/frameworks/PHP/hamlet/Benchmark/Resources/DbResource.php +++ /dev/null @@ -1,23 +0,0 @@ -database->withSession($repository->findById($id)); - return new SimpleOKResponse(new JsonEntity($record)); - } -} diff --git a/frameworks/PHP/hamlet/Benchmark/Resources/FortuneResource.php b/frameworks/PHP/hamlet/Benchmark/Resources/FortuneResource.php deleted file mode 100644 index 48540164488..00000000000 --- a/frameworks/PHP/hamlet/Benchmark/Resources/FortuneResource.php +++ /dev/null @@ -1,23 +0,0 @@ -database->withSession($repository->findAll()); - $messages[] = new Message(0, 'Additional fortune added at request time.'); - usort($messages, function (Message $a, Message $b): int { - return $a->message() <=> $b->message(); - }); - return new SimpleOKResponse(new FortuneEntity($messages)); - } -} diff --git a/frameworks/PHP/hamlet/Benchmark/Resources/HelloJsonResource.php b/frameworks/PHP/hamlet/Benchmark/Resources/HelloJsonResource.php deleted file mode 100644 index 095c5cd77b7..00000000000 --- a/frameworks/PHP/hamlet/Benchmark/Resources/HelloJsonResource.php +++ /dev/null @@ -1,17 +0,0 @@ - 'Hello, World!']); - return new SimpleOKResponse($entity); - } -} diff --git a/frameworks/PHP/hamlet/Benchmark/Resources/HelloTextResource.php b/frameworks/PHP/hamlet/Benchmark/Resources/HelloTextResource.php deleted file mode 100644 index 3a1531288d7..00000000000 --- a/frameworks/PHP/hamlet/Benchmark/Resources/HelloTextResource.php +++ /dev/null @@ -1,17 +0,0 @@ -hasQueryParam('queries')) { - $count = $request->getQueryParam('queries', _int()); - if ($count < 1) { - return 1; - } elseif (500 < $count) { - return 500; - } else { - return $count; - } - } else { - return 1; - } - } -} diff --git a/frameworks/PHP/hamlet/Benchmark/Resources/QueriesResource.php b/frameworks/PHP/hamlet/Benchmark/Resources/QueriesResource.php deleted file mode 100644 index b4999592096..00000000000 --- a/frameworks/PHP/hamlet/Benchmark/Resources/QueriesResource.php +++ /dev/null @@ -1,24 +0,0 @@ -getQueriesCount($request); - $payload = $this->database->withSessions(array_map( - fn () => $repository->findById(mt_rand(1, 10000)), - range(1, $count) - )); - return new SimpleOKResponse(new JsonEntity($payload)); - } -} diff --git a/frameworks/PHP/hamlet/Benchmark/Resources/UpdateResource.php b/frameworks/PHP/hamlet/Benchmark/Resources/UpdateResource.php deleted file mode 100644 index e6e1b79bcc6..00000000000 --- a/frameworks/PHP/hamlet/Benchmark/Resources/UpdateResource.php +++ /dev/null @@ -1,32 +0,0 @@ -getQueriesCount($request); - $entries = $this->database->withSessions(array_map( - fn () => $repository->findById(mt_rand(1, 10000)), - range(1, $count), - )); - $modifiedEntries = array_map( - fn ($entry) => $entry->withNumber(mt_rand(1, 10000)), - $entries - ); - $this->database->withSessions(array_map( - fn ($modifiedEntry) => $repository->updateNumber($modifiedEntry), - $modifiedEntries - )); - return new SimpleOKResponse(new JsonEntity($modifiedEntries)); - } -} diff --git a/frameworks/PHP/hamlet/README.md b/frameworks/PHP/hamlet/README.md deleted file mode 100644 index 7c7c35cfc21..00000000000 --- a/frameworks/PHP/hamlet/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# Hamlet Framework Benchmarking Test - -This is the [Hamlet Framework](https://github.com/hamlet-framework) portion of a [benchmarking test suite](../) - -Current submission tests the following configurations: - -- Hamlet -- Hamlet + Swoole -- Hamlet + Workerman diff --git a/frameworks/PHP/hamlet/benchmark_config.json b/frameworks/PHP/hamlet/benchmark_config.json deleted file mode 100644 index b8fda2f4f31..00000000000 --- a/frameworks/PHP/hamlet/benchmark_config.json +++ /dev/null @@ -1,80 +0,0 @@ -{ - "framework": "hamlet", - "tests": [{ - "default": { - "plaintext_url": "/plaintext", - "json_url": "/json", - "db_url": "/db", - "query_url": "/queries?queries=", - "cached_query_url": "/cached-worlds?queries=", - "fortune_url": "/fortunes", - "update_url": "/update?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "mysql", - "framework": "hamlet", - "language": "PHP", - "flavor": "PHP8.1", - "orm": "micro", - "platform": "FPM/FastCGI", - "webserver": "nginx", - "os": "Linux", - "database_os": "Linux", - "display_name": "hamlet", - "notes": "", - "versus": "php", - "tags": ["broken"] - }, - "swoole": { - "plaintext_url": "/plaintext", - "json_url": "/json", - "db_url": "/db", - "query_url": "/queries?queries=", - "cached_query_url": "/cached-worlds?queries=", - "fortune_url": "/fortunes", - "update_url": "/update?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "mysql", - "framework": "hamlet", - "language": "PHP", - "flavor": "PHP8", - "orm": "micro", - "platform": "swoole", - "webserver": "none", - "os": "Linux", - "database_os": "Linux", - "display_name": "hamlet-swoole", - "notes": "", - "versus": "swoole", - "tags": ["broken"] - }, - "workerman": { - "plaintext_url": "/plaintext", - "json_url": "/json", - "db_url": "/db", - "query_url": "/queries?queries=", - "cached_query_url": "/cached-worlds?queries=", - "fortune_url": "/fortunes", - "update_url": "/update?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "mysql", - "framework": "hamlet", - "language": "PHP", - "flavor": "PHP8", - "orm": "micro", - "platform": "workerman", - "webserver": "none", - "os": "Linux", - "database_os": "Linux", - "display_name": "hamlet-workerman", - "notes": "", - "versus": "workerman", - "tags": ["broken"] - } - }] -} diff --git a/frameworks/PHP/hamlet/composer-swoole.json b/frameworks/PHP/hamlet/composer-swoole.json deleted file mode 100644 index edf1d00158e..00000000000 --- a/frameworks/PHP/hamlet/composer-swoole.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "config": { - "optimize-autoloader": true, - "classmap-authoritative": true - }, - "require": { - "php": "^8", - "hamlet-framework/http" : "@stable", - "hamlet-framework/http-swoole": "@stable", - "hamlet-framework/db-mysql-swoole": "@stable", - "cache/array-adapter": "@stable" - }, - "autoload": { - "psr-4": { - "Benchmark\\": "Benchmark/" - } - } -} diff --git a/frameworks/PHP/hamlet/composer-workerman.json b/frameworks/PHP/hamlet/composer-workerman.json deleted file mode 100644 index de39b11968c..00000000000 --- a/frameworks/PHP/hamlet/composer-workerman.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "config": { - "optimize-autoloader": true, - "classmap-authoritative": true - }, - "require": { - "php": "^8", - "hamlet-framework/http" : "@stable", - "hamlet-framework/http-workerman": "@stable", - "hamlet-framework/db-pdo": "@stable", - "cache/array-adapter": "@stable" - }, - "autoload": { - "psr-4": { - "Benchmark\\": "Benchmark/" - } - } -} diff --git a/frameworks/PHP/hamlet/composer.json b/frameworks/PHP/hamlet/composer.json deleted file mode 100644 index 2a8d4f7ec0e..00000000000 --- a/frameworks/PHP/hamlet/composer.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "config": { - "optimize-autoloader": true, - "classmap-authoritative": true - }, - "require": { - "php": "^8", - "hamlet-framework/http" : "@stable", - "hamlet-framework/db-pdo": "@stable", - "cache/apcu-adapter": "@stable" - }, - "autoload": { - "psr-4": { - "Benchmark\\": "Benchmark/" - } - } -} diff --git a/frameworks/PHP/hamlet/config.toml b/frameworks/PHP/hamlet/config.toml deleted file mode 100644 index 81b9f6f2509..00000000000 --- a/frameworks/PHP/hamlet/config.toml +++ /dev/null @@ -1,54 +0,0 @@ -[framework] -name = "hamlet" - -[main] -urls.plaintext = "/plaintext" -urls.json = "/json" -urls.db = "/db" -urls.query = "/queries?queries=" -urls.cached_query = "/cached-worlds?queries=" -urls.update = "/update?queries=" -urls.fortune = "/fortunes" -approach = "Realistic" -classification = "Fullstack" -database = "mysql" -database_os = "Linux" -os = "Linux" -orm = "micro" -platform = "FPM/FastCGI" -webserver = "nginx" -versus = "php" - -[workerman] -urls.plaintext = "/plaintext" -urls.json = "/json" -urls.db = "/db" -urls.query = "/queries?queries=" -urls.update = "/update?queries=" -urls.fortune = "/fortunes" -approach = "Realistic" -classification = "Fullstack" -database = "mysql" -database_os = "Linux" -os = "Linux" -orm = "micro" -platform = "workerman" -webserver = "none" -versus = "workerman" - -[swoole] -urls.plaintext = "/plaintext" -urls.json = "/json" -urls.db = "/db" -urls.query = "/queries?queries=" -urls.update = "/update?queries=" -urls.fortune = "/fortunes" -approach = "Realistic" -classification = "Fullstack" -database = "mysql" -database_os = "Linux" -os = "Linux" -orm = "micro" -platform = "swoole" -webserver = "none" -versus = "swoole" diff --git a/frameworks/PHP/hamlet/deploy/fpm/nginx.conf b/frameworks/PHP/hamlet/deploy/fpm/nginx.conf deleted file mode 100644 index 313fc4d26a9..00000000000 --- a/frameworks/PHP/hamlet/deploy/fpm/nginx.conf +++ /dev/null @@ -1,62 +0,0 @@ -user www-data; -worker_processes auto; -error_log stderr error; -worker_rlimit_nofile 200000; - -events { - worker_connections 32768; - multi_accept on; -} - -http { - access_log off; - server_tokens off; - - sendfile on; - tcp_nopush on; - tcp_nodelay on; - keepalive_timeout 65; - keepalive_disable none; - keepalive_requests 1000; - - #the bench don't use any static file - #open_file_cache max=2000 inactive=20s; - #open_file_cache_valid 60s; - #open_file_cache_min_uses 5; - #open_file_cache_errors off; - - fastcgi_buffers 256 16k; - fastcgi_buffer_size 128k; - fastcgi_connect_timeout 120s; - fastcgi_send_timeout 120s; - fastcgi_read_timeout 120s; - fastcgi_busy_buffers_size 256k; - fastcgi_temp_file_write_size 256k; - reset_timedout_connection on; - server_names_hash_bucket_size 100; - - upstream fastcgi_backend { - server unix:/var/run/php-fpm.sock; - keepalive 40; - } - - server { - listen 8080; - server_name localhost; - - root /app; - index index.php; - - location / { - try_files $uri $uri/ /index.php?$uri&$args; - } - - location ~ \.php$ { - fastcgi_pass fastcgi_backend; - fastcgi_keep_conn on; - fastcgi_index index.php; - fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; - include /etc/nginx/fastcgi_params; - } - } -} diff --git a/frameworks/PHP/hamlet/deploy/fpm/php-fpm.conf b/frameworks/PHP/hamlet/deploy/fpm/php-fpm.conf deleted file mode 100644 index bf0d342c46e..00000000000 --- a/frameworks/PHP/hamlet/deploy/fpm/php-fpm.conf +++ /dev/null @@ -1,17 +0,0 @@ -[global] -pid = /var/run/php-fpm.pid -error_log = /dev/stderr -systemd_interval = 0 - -[www] -user = www-data -group = www-data -listen = /var/run/php-fpm.sock -listen.backlog = 65535 -listen.owner = www-data -listen.group = www-data -pm = static -pm.max_children = 1024 -pm.start_servers = 512 -pm.min_spare_servers = 50 -pm.max_spare_servers = 512 diff --git a/frameworks/PHP/hamlet/deploy/fpm/php.ini b/frameworks/PHP/hamlet/deploy/fpm/php.ini deleted file mode 100644 index 498eb1221b6..00000000000 --- a/frameworks/PHP/hamlet/deploy/fpm/php.ini +++ /dev/null @@ -1,21 +0,0 @@ -opcache.enable_file_override = 1 -opcache.memory_consumption = 96 -opcache.interned_strings_buffer = 16 -opcache.max_accelerated_files = 10000 -opcache.save_comments = 1 -opcache.consistency_checks = 0 -opcache.enable = 1 -opcache.enable_cli=1 -opcache.optimization_level = 0xFFFFFFFF -opcache.huge_code_pages = 0 -opcache.validate_timestamps = 0 -opcache.jit_buffer_size = 128M -opcache.jit = 1255 - -realpath_cache_ttl = 1200 -memory_limit = 512M - -display_errors = 0 -error_reporting = E_ALL -zend.assertions = 0 -assert.exception = 0 diff --git a/frameworks/PHP/hamlet/hamlet-swoole.dockerfile b/frameworks/PHP/hamlet/hamlet-swoole.dockerfile deleted file mode 100644 index a1133c483ae..00000000000 --- a/frameworks/PHP/hamlet/hamlet-swoole.dockerfile +++ /dev/null @@ -1,25 +0,0 @@ -FROM php:8.0 - -RUN pecl install swoole > /dev/null && \ - docker-php-ext-enable swoole - -RUN docker-php-ext-install mysqli > /dev/null && \ - docker-php-ext-enable mysqli - -RUN apt-get update -yqq && \ - apt-get install -yqq git unzip - -COPY ./deploy/fpm/php.ini /usr/local/etc/php/conf.d/hamlet.ini - -RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer - -ADD ./ /php -WORKDIR /php -COPY ./composer-swoole.json composer.json -RUN chmod -R 777 /php - -RUN composer update --no-dev --quiet - -EXPOSE 8080 - -CMD php /php/swoole.php diff --git a/frameworks/PHP/hamlet/hamlet-workerman.dockerfile b/frameworks/PHP/hamlet/hamlet-workerman.dockerfile deleted file mode 100644 index e632ee1dd8a..00000000000 --- a/frameworks/PHP/hamlet/hamlet-workerman.dockerfile +++ /dev/null @@ -1,36 +0,0 @@ -FROM php:8.0-zts - -ENV PHP_VERSION 8.0 -ENV PARALLEL_VERSION 360c667b7632a639a983f17c5d97b92cbe4f7c95 - -RUN docker-php-ext-install pdo_mysql > /dev/null && docker-php-ext-enable pdo_mysql -RUN docker-php-ext-install sockets > /dev/null && docker-php-ext-enable sockets -RUN docker-php-ext-install pcntl > /dev/null && docker-php-ext-enable pcntl - -RUN apt-get update -yqq > /dev/null \ - && apt-get install -yqq git unzip libevent-dev libssl-dev > /dev/null - -RUN git clone https://github.com/krakjoe/parallel \ - && cd parallel \ - && git checkout 360c667b7632a639a983f17c5d97b92cbe4f7c95 \ - && phpize > /dev/null \ - && ./configure --enable-parallel > /dev/null \ - && make > /dev/null \ - && make install > /dev/null - -RUN pecl install event-3.0.5 > /dev/null \ - && echo "extension=event.so" > /usr/local/etc/php/conf.d/event.ini - -COPY deploy/fpm/php.ini /usr/local/etc/php/conf.d/hamlet.ini - -RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer - -ADD ./ /hamlet -WORKDIR /hamlet -COPY ./composer-workerman.json composer.json - -RUN composer update --no-dev --quiet - -EXPOSE 8080 - -CMD php /hamlet/workerman.php start diff --git a/frameworks/PHP/hamlet/hamlet.dockerfile b/frameworks/PHP/hamlet/hamlet.dockerfile deleted file mode 100644 index 9c85515a040..00000000000 --- a/frameworks/PHP/hamlet/hamlet.dockerfile +++ /dev/null @@ -1,27 +0,0 @@ -FROM ubuntu:20.04 - -ENV PHP_VERSION 8.1 -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 > /dev/null && \ - apt-get install -yqq nginx git unzip curl \ - php${PHP_VERSION}-cli php${PHP_VERSION}-fpm php${PHP_VERSION}-apcu php${PHP_VERSION}-pdo-mysql php${PHP_VERSION}-dev > /dev/null - -COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer - -ADD ./ /app -WORKDIR /app - -RUN composer update --no-dev --quiet - -COPY deploy/fpm/php-fpm.conf /etc/php/${PHP_VERSION}/fpm/php-fpm.conf -COPY deploy/fpm/php.ini /etc/php/${PHP_VERSION}/fpm/php.ini - -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/${PHP_VERSION}/fpm/php-fpm.conf ; fi; - -EXPOSE 8080 - -CMD service php${PHP_VERSION}-fpm start \ - && nginx -c /app/deploy/fpm/nginx.conf -g "daemon off;" diff --git a/frameworks/PHP/hamlet/index.php b/frameworks/PHP/hamlet/index.php deleted file mode 100644 index 09141793d1b..00000000000 --- a/frameworks/PHP/hamlet/index.php +++ /dev/null @@ -1,15 +0,0 @@ -

+ +

+Build Status +Total Downloads +Latest Stable Version +License +

+ +## Introduction + +**Hypervel** is a Laravel-style PHP framework with native coroutine support for ultra-high performance. + +Hypervel ports many core components from Laravel while maintaining familiar usage patterns, making it instantly accessible to Laravel developers. The framework combines the elegant and expressive development experience of Laravel with the powerful performance benefits of coroutine-based programming. If you're a Laravel developer, you'll feel right at home with this framework, requiring minimal learning curve. + +This is an ideal choice for building microservices, API gateways, and high-concurrency applications where traditional PHP frameworks often encounter performance constraints. + +## Why Hypervel? + +While Laravel Octane impressively enhances your Laravel application's performance, it's crucial to understand the nature of modern web applications. In most cases, the majority of latency stems from I/O operations, such as file operations, database queries, and API requests. + +However, Laravel doesn't support coroutines - the entire framework is designed for a blocking I/O environment. Applications heavily dependent on I/O operations will still face performance bottlenecks. Consider this scenario: + +Imagine building an AI-powered chatbot where each conversation API takes 3-5 seconds to respond. With 10 workers in Laravel Octane receiving 10 concurrent requests, all workers would be blocked until these requests complete. + +> You can see [benchmark comparison](https://hypervel.org/docs/introduction.html#benchmark) between Laravel Octane and Hypervel + +Even with Laravel Octane's improvements, your application's concurrent request handling capacity remains constrained by I/O operation duration. Hypervel addresses this limitation through coroutines, enabling efficient handling of concurrent I/O operations without blocking workers. This approach significantly enhances performance and concurrency for I/O-intensive applications. + +> See [this issue](https://github.com/laravel/octane/issues/765) for more discussions. + +## Documentation + +[https://hypervel.org/docs](https://hypervel.org/docs) + +Hypervel provides comprehensive and user-friendly documentation that allows you to quickly get started. From this documentation, you can learn how to use various components in Hypervel and understand the differences between this framework and Laravel. + +> Most of the content in this documentation is referenced from the official Laravel documentation. We appreciate the Laravel community's contributions. + +## License + +The Hypervel framework is open-sourced software licensed under the [MIT](https://opensource.org/licenses/MIT) license. \ No newline at end of file diff --git a/frameworks/PHP/hypervel/app/Console/Kernel.php b/frameworks/PHP/hypervel/app/Console/Kernel.php new file mode 100644 index 00000000000..920b99ae538 --- /dev/null +++ b/frameworks/PHP/hypervel/app/Console/Kernel.php @@ -0,0 +1,26 @@ +command('demo:hi')->everyFiveSeconds(); + } + + public function commands(): void + { + $this->load(__DIR__ . '/Commands'); + + require base_path('routes/console.php'); + } +} diff --git a/frameworks/PHP/hypervel/app/Exceptions/Handler.php b/frameworks/PHP/hypervel/app/Exceptions/Handler.php new file mode 100644 index 00000000000..8cdb40b9f40 --- /dev/null +++ b/frameworks/PHP/hypervel/app/Exceptions/Handler.php @@ -0,0 +1,38 @@ + + */ + protected array $dontFlash = [ + 'current_password', + 'password', + 'password_confirmation', + ]; + + /** + * Register the exception handling callbacks for the application. + */ + public function register(): void + { + // return json when path start with `api` + $this->shouldRenderJsonWhen(function (Request $request, Throwable $e) { + return str_starts_with($path = $request->path(), 'api') + && (strlen($path) === 3 || $path[3] === '/'); + }); + + $this->reportable(function (Throwable $e) { + }); + } +} diff --git a/frameworks/PHP/hypervel/app/Http/Controllers/AbstractController.php b/frameworks/PHP/hypervel/app/Http/Controllers/AbstractController.php new file mode 100644 index 00000000000..1ca5dabd22a --- /dev/null +++ b/frameworks/PHP/hypervel/app/Http/Controllers/AbstractController.php @@ -0,0 +1,9 @@ +json(['message' => 'Hello, World!']); + } + + public function db() + { + return response()->json(World::query()->find(self::randomInt())); + } + + public function queries($queries = 1) + { + $queries = self::clamp($queries); + + $rows = []; + while ($queries--) { + $rows[] = World::query()->find(self::randomInt()); + } + + return response()->json($rows); + } + + public function fortunes() + { + $rows = Fortune::all(); + + $insert = new Fortune(); + $insert->id = 0; + $insert->message = 'Additional fortune added at request time.'; + + $rows->add($insert); + $rows = $rows->sortBy('message'); + + return response(view('fortunes', ['rows' => $rows]), 200, ['Content-Type' => 'text/html; charset=UTF-8']); + } + + public function updates($queries = 1) + { + $queries = self::clamp($queries); + + $rows = []; + + while ($queries--) { + $row = World::query()->find(self::randomInt()); + while (($randomInt = self::randomInt()) === $row->randomNumber) { + } + $row->randomNumber = $randomInt; + $row->save(); + + $rows[] = $row; + } + + return response()->json($rows); + } + + public function plaintext() + { + return response('Hello, World!', 200, ['Content-Type' => 'text/plain']); + } + + private static function randomInt() + { + return random_int(1, 10000); + } + + private static function clamp($value) + { + if (!is_numeric($value) || $value < 1) { + return 1; + } + if ($value > 500) { + return 500; + } + return (int)$value; + } +} diff --git a/frameworks/PHP/hypervel/app/Http/Kernel.php b/frameworks/PHP/hypervel/app/Http/Kernel.php new file mode 100644 index 00000000000..8e0cfe0e32b --- /dev/null +++ b/frameworks/PHP/hypervel/app/Http/Kernel.php @@ -0,0 +1,73 @@ + + */ + protected array $middleware = [ + // \App\Http\Middleware\TrimStrings::class, + // \Hypervel\Http\Middleware\HandleCors::class, + // \App\Http\Middleware\ConvertEmptyStringsToNull::class + ]; + + /** + * The application's route middleware groups. + * + * @var array> + */ + protected array $middlewareGroups = [ + 'web' => [ + // \Hypervel\Router\Middleware\SubstituteBindings::class, + // \Hypervel\Cookie\Middleware\AddQueuedCookiesToResponse::class, + // \Hypervel\Session\Middleware\StartSession::class, + // \Hypervel\View\Middleware\ShareErrorsFromSession::class, + // \App\Http\Middleware\VerifyCsrfToken::class, + ], + + 'api' => [ + // 'throttle:60,1,api', + // \Hypervel\Router\Middleware\SubstituteBindings::class, + ], + ]; + + /** + * The application's middleware aliases. + * + * Aliases may be used instead of class names to conveniently assign middleware to routes and groups. + * + * @var array + */ + protected array $middlewareAliases = [ + // 'auth' => \App\Http\Middleware\Authenticate::class, + // 'can' => \Hypervel\Auth\Middleware\Authorize::class, + // 'throttle' => \Hypervel\Router\Middleware\ThrottleRequests::class, + // 'bindings' => \Hypervel\Router\Middleware\SubstituteBindings::class, + // 'signed' => \App\Http\Middleware\ValidateSignature::class, + ]; + + /** + * The priority-sorted list of middleware. + * + * Forces non-global middleware to always be in the given order. + * + * @var string[] + */ + protected array $middlewarePriority = [ + // \Hypervel\Router\Middleware\ThrottleRequests::class, + // \Hypervel\Router\Middleware\SubstituteBindings::class, + // \Hypervel\Session\Middleware\StartSession::class, + // \Hypervel\View\Middleware\ShareErrorsFromSession::class, + // \App\Http\Middleware\VerifyCsrfToken::class, + ]; +} diff --git a/frameworks/PHP/hypervel/app/Models/Fortune.php b/frameworks/PHP/hypervel/app/Models/Fortune.php new file mode 100644 index 00000000000..6ee000d9693 --- /dev/null +++ b/frameworks/PHP/hypervel/app/Models/Fortune.php @@ -0,0 +1,14 @@ + 'api'] + ); + + Route::group( + '/', + base_path('routes/web.php'), + ['middleware' => 'web'] + ); + } +} diff --git a/frameworks/PHP/hypervel/artisan b/frameworks/PHP/hypervel/artisan new file mode 100644 index 00000000000..ba8a7340ac6 --- /dev/null +++ b/frameworks/PHP/hypervel/artisan @@ -0,0 +1,26 @@ +#!/usr/bin/env php +get(Hyperf\Contract\ApplicationInterface::class); + $application->run(); +})(); diff --git a/frameworks/PHP/hypervel/benchmark_config.json b/frameworks/PHP/hypervel/benchmark_config.json new file mode 100644 index 00000000000..fae8242ba6f --- /dev/null +++ b/frameworks/PHP/hypervel/benchmark_config.json @@ -0,0 +1,28 @@ +{ + "framework": "hypervel", + "tests": [{ + "default": { + "json_url": "/json", + "db_url": "/db", + "query_url": "/queries/", + "fortune_url": "/fortunes", + "update_url": "/updates/", + "plaintext_url": "/plaintext", + "port": 9501, + "approach": "Realistic", + "classification": "Fullstack", + "database": "MySQL", + "framework": "lypervel", + "language": "PHP", + "flavor": "PHP8", + "orm": "Full", + "platform": "swoole", + "webserver": "none", + "os": "Linux", + "database_os": "Linux", + "display_name": "hypervel", + "notes": "", + "versus": "swoole" + } + }] +} diff --git a/frameworks/PHP/hypervel/bootstrap/app.php b/frameworks/PHP/hypervel/bootstrap/app.php new file mode 100644 index 00000000000..bb8615ddd96 --- /dev/null +++ b/frameworks/PHP/hypervel/bootstrap/app.php @@ -0,0 +1,40 @@ +bind( + Hypervel\Foundation\Console\Contracts\Kernel::class, + App\Console\Kernel::class +); + +$app->bind( + Hypervel\Foundation\Exceptions\Contracts\ExceptionHandler::class, + App\Exceptions\Handler::class +); + +Hypervel\Context\ApplicationContext::setContainer($app); + +return $app; diff --git a/frameworks/PHP/hypervel/composer.json b/frameworks/PHP/hypervel/composer.json new file mode 100644 index 00000000000..d877dcae4e7 --- /dev/null +++ b/frameworks/PHP/hypervel/composer.json @@ -0,0 +1,100 @@ +{ + "name": "hypervel/hypervel", + "type": "project", + "keywords": [ + "php", + "swoole", + "framework", + "hyperf", + "microservice", + "laravel", + "hypervel" + ], + "description": "A Laravel-style PHP framework with native coroutine support for ultra-high performance.", + "license": "MIT", + "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" + }, + "autoload": { + "psr-4": { + "App\\": "app/" + }, + "files": [] + }, + "autoload-dev": { + "psr-4": { + "Tests\\": "tests/" + }, + "files": [ + "tests/helpers.php" + ] + }, + "minimum-stability": "dev", + "prefer-stable": true, + "suggest": { + "ext-redis": "Required to use Redis-based drivers, such as cache, session, queue, etc.", + "ext-fileinfo": "Required to use the Filesystem class.", + "ext-ftp": "Required to use the Flysystem FTP driver.", + "ext-hash": "Required to use the Filesystem class.", + "ext-pcntl": "Required to use all features of the queue worker.", + "ext-posix": "Required to use all features of the queue worker.", + "ably/ably-php": "Required to use the Ably broadcast driver (^1.0).", + "pusher/pusher-php-server": "Required to use the Pusher broadcast driver (^6.0|^7.0).", + "league/flysystem-path-prefixing": "Required to use the scoped driver (^3.3).", + "league/flysystem-read-only": "Required to use read-only disks (^3.3)", + "league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (^3.0).", + "flysystem-google-cloud-storage": "Required to use the Flysystem Google Cloud Storage driver (^3.0).", + "league/flysystem-ftp": "Required to use the Flysystem FTP driver (^3.0).", + "league/flysystem-sftp-v3": "Required to use the Flysystem SFTP driver (^3.0).", + "aws/aws-sdk-php": "Required to use the SQS queue driver, DynamoDb failed job storage, and SES mail driver (^3.322.9).", + "symfony/http-client": "Required to use the Symfony API mail transports (^6.2).", + "symfony/mailgun-mailer": "Required to enable support for the Mailgun mail transport (^6.2).", + "symfony/postmark-mailer": "Required to enable support for the Postmark mail transport (^6.2).", + "pda/pheanstalk": "Required to use the Beanstalk queue driver (^5.0)." + }, + "config": { + "optimize-autoloader": true, + "sort-packages": true + }, + "extra": { + "hypervel": { + "dont-discover": [] + } + }, + "scripts": { + "post-root-package-install": [ + "@php -r \"file_exists('.env') || copy('.env.example', '.env');\"" + ], + "post-create-project-cmd": [ + "@php artisan key:generate --ansi", + "@php -r \"file_exists('database/database.sqlite') || touch('database/database.sqlite');\"", + "@php artisan migrate --graceful --ansi" + ], + "post-autoload-dump": [ + "rm -rf runtime/container" + ], + "test": "phpunit -c phpunit.xml.dist --colors=always", + "cs-diff": "php-cs-fixer fix --path-mode=intersection `git diff --name-only --diff-filter=ACMRTUXB origin/main..HEAD`", + "cs-fix": "php-cs-fixer fix $1", + "analyse": "phpstan analyse --memory-limit 300M -c phpstan.neon", + "start": [ + "Composer\\Config::disableProcessTimeout", + "php artisan start" + ] + } +} diff --git a/frameworks/PHP/hypervel/config.toml b/frameworks/PHP/hypervel/config.toml new file mode 100644 index 00000000000..29da2690e8d --- /dev/null +++ b/frameworks/PHP/hypervel/config.toml @@ -0,0 +1,19 @@ +[framework] +name = "hypervel" + +[hypervel] +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" diff --git a/frameworks/PHP/hypervel/config/app.php b/frameworks/PHP/hypervel/config/app.php new file mode 100644 index 00000000000..42a924312ad --- /dev/null +++ b/frameworks/PHP/hypervel/config/app.php @@ -0,0 +1,171 @@ + env('APP_NAME', 'Hypervel'), + + /* + |-------------------------------------------------------------------------- + | Application Environment + |-------------------------------------------------------------------------- + | + | This value determines the "environment" your application is currently + | running in. This may determine how you prefer to configure various + | services the application utilizes. Set "APP_ENV" in your ".env" file. + | + */ + + 'env' => env('APP_ENV', 'production'), + + /* + |-------------------------------------------------------------------------- + | Application Debug Mode + |-------------------------------------------------------------------------- + | + | When your application is in debug mode, detailed error messages with + | stack traces will be shown on every error that occurs within your + | application. If disabled, a simple generic error page is shown. + | Set "APP_DEBUG" in your ".env" file. + | + */ + + 'debug' => (bool) env('APP_DEBUG', false), + + /* + |-------------------------------------------------------------------------- + | Cacheable Flag for Annotations Scanning + |-------------------------------------------------------------------------- + | + | Enabling this option will cache the annotations scanning result. It + | can boost the performance of the framework initialization. + | Please disable it in the development environment. + | + */ + 'scan_cacheable' => env('SCAN_CACHEABLE', false), + + /* + |-------------------------------------------------------------------------- + | Log Levels for StdoutLogger + |-------------------------------------------------------------------------- + | + | This value only determines the log levels that are written to the stdout logger. + | It does not affect the log levels that are written to the other loggers. + | + */ + 'stdout_log_level' => [ + LogLevel::ALERT, + LogLevel::CRITICAL, + // LogLevel::DEBUG, + LogLevel::EMERGENCY, + LogLevel::ERROR, + LogLevel::INFO, + LogLevel::NOTICE, + LogLevel::WARNING, + ], + + /* + |-------------------------------------------------------------------------- + | Application URL + |-------------------------------------------------------------------------- + | + | This URL is used by the console to properly generate URLs when using + | the Artisan command line tool. You should set this to the root of + | your application so that it is used when running Artisan tasks. + | + */ + + 'url' => env('APP_URL', 'http://localhost'), + + /* + |-------------------------------------------------------------------------- + | Application Timezone + |-------------------------------------------------------------------------- + | + | Here you may specify the default timezone for your application, which + | will be used by the PHP date and date-time functions. We have gone + | ahead and set this to a sensible default for you out of the box. + | + */ + + 'timezone' => env('APP_TIMEZONE', 'UTC'), + + /* + |-------------------------------------------------------------------------- + | Application Locale Configuration + |-------------------------------------------------------------------------- + | + | The application locale determines the default locale that will be used + | by the translation service provider. You are free to set this value + | to any of the locales which will be supported by the application. + | + */ + + 'locale' => env('APP_LOCALE', 'en'), + + 'fallback_locale' => env('APP_FALLBACK_LOCALE', 'en'), + + /* + |-------------------------------------------------------------------------- + | Encryption Key + |-------------------------------------------------------------------------- + | + | This key is utilized by Laravel's encryption services and should be set + | to a random, 32 character string to ensure that all encrypted values + | are secure. You should do this prior to deploying the application. + | + */ + + 'cipher' => 'AES-256-CBC', + + 'key' => env('APP_KEY'), + + 'previous_keys' => [ + ...array_filter( + explode(',', env('APP_PREVIOUS_KEYS', '')) + ), + ], + + 'providers' => ServiceProvider::defaultProviders()->merge([ + /* + * Package Service Providers... + */ + + /* + * Application Service Providers... + */ + App\Providers\AppServiceProvider::class, + // App\Providers\BroadcastServiceProvider::class, + // App\Providers\EventServiceProvider::class, + App\Providers\RouteServiceProvider::class, + ])->toArray(), + + /* + |-------------------------------------------------------------------------- + | Class Aliases + |-------------------------------------------------------------------------- + | + | This array of class aliases will be registered when this application + | is started. + | + */ + + 'aliases' => Facade::defaultAliases()->merge([ + // 'Example' => App\Facades\Example::class, + ])->toArray(), +]; diff --git a/frameworks/PHP/hypervel/config/cache.php b/frameworks/PHP/hypervel/config/cache.php new file mode 100644 index 00000000000..b07273025b7 --- /dev/null +++ b/frameworks/PHP/hypervel/config/cache.php @@ -0,0 +1,103 @@ + env('CACHE_DRIVER', 'array'), + + /* + |-------------------------------------------------------------------------- + | Cache Stores + |-------------------------------------------------------------------------- + | + | Here you may define all of the cache "stores" for your application as + | well as their drivers. You may even define multiple stores for the + | same cache driver to group types of items stored in your caches. + | + | Supported drivers: "array", "file", "redis", "swoole", "stack", "null" + | + */ + + 'stores' => [ + 'array' => [ + 'driver' => 'array', + 'serialize' => false, + ], + + 'file' => [ + 'driver' => 'file', + 'path' => storage_path('cache/data'), + 'lock_path' => storage_path('cache/data'), + ], + + 'redis' => [ + 'driver' => 'redis', + 'connection' => 'default', + 'lock_connection' => 'default', + ], + + 'swoole' => [ + 'driver' => 'swoole', + 'table' => 'default', + 'memory_limit_buffer' => 0.05, + 'eviction_policy' => SwooleStore::EVICTION_POLICY_LRU, + 'eviction_proportion' => 0.05, + 'eviction_interval' => 10000, // milliseconds + ], + + 'stack' => [ + 'driver' => 'stack', + 'stores' => [ + 'swoole' => [ + 'ttl' => 3, // seconds + ], + 'redis', + ], + ], + + 'database' => [ + 'driver' => 'database', + 'connection' => env('DB_CACHE_CONNECTION', env('DB_CONNECTION', 'default')), + 'table' => env('DB_CACHE_TABLE', 'cache'), + 'lock_connection' => env('DB_CACHE_LOCK_CONNECTION'), + 'lock_table' => env('DB_CACHE_LOCK_TABLE', 'cache_locks'), + 'lock_lottery' => [2, 100], + 'lock_timeout' => 86400, + ], + ], + + 'swoole_tables' => [ + 'default' => [ + 'rows' => 1024, + 'bytes' => 10240, + 'conflict_proportion' => 0.2, + ], + ], + + /* + |-------------------------------------------------------------------------- + | Cache Key Prefix + |-------------------------------------------------------------------------- + | + | When utilizing a RAM based store such as APC or Memcached, there might + | be other applications utilizing the same cache. So, we'll specify a + | value to get prefixed to all our keys so we can avoid collisions. + | + */ + + 'prefix' => env('CACHE_PREFIX', Str::slug(env('APP_NAME', 'hypervel'), '_') . '_cache'), +]; diff --git a/frameworks/PHP/hypervel/config/database.php b/frameworks/PHP/hypervel/config/database.php new file mode 100644 index 00000000000..14f2b3ae2b4 --- /dev/null +++ b/frameworks/PHP/hypervel/config/database.php @@ -0,0 +1,137 @@ + env('DB_CONNECTION', 'mysql'), + + 'connections' => [ + 'mysql' => [ + 'driver' => env('DB_DRIVER', 'mysql'), + 'host' => env('DB_HOST', 'localhost'), + 'database' => env('DB_DATABASE', 'hypervel'), + 'port' => env('DB_PORT', 3306), + 'username' => env('DB_USERNAME', 'root'), + 'password' => env('DB_PASSWORD', ''), + 'charset' => env('DB_CHARSET', 'utf8mb4'), + 'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'), + 'prefix' => env('DB_PREFIX', ''), + 'pool' => [ + 'min_connections' => 1, + 'max_connections' => env('DB_MAX_CONNECTIONS', 10), + 'connect_timeout' => 10.0, + 'wait_timeout' => 3.0, + 'heartbeat' => -1, + 'max_idle_time' => (float) env('DB_MAX_IDLE_TIME', 60), + ], + ], + + 'pgsql' => [ + 'driver' => env('DB_DRIVER', 'pgsql'), + 'host' => env('DB_HOST', 'localhost'), + 'database' => env('DB_DATABASE', 'hypervel'), + 'schema' => env('DB_SCHEMA', 'public'), + 'port' => env('DB_PORT', 5432), + 'username' => env('DB_USERNAME', 'root'), + 'password' => env('DB_PASSWORD', ''), + 'charset' => env('DB_CHARSET', 'utf8'), + 'pool' => [ + 'min_connections' => 1, + 'max_connections' => env('DB_MAX_CONNECTIONS', 10), + 'connect_timeout' => 10.0, + 'wait_timeout' => 3.0, + 'heartbeat' => -1, + 'max_idle_time' => (float) env('DB_MAX_IDLE_TIME', 60), + ], + ], + + 'sqlite' => [ + 'driver' => 'sqlite', + 'url' => env('DATABASE_URL'), + 'database' => env('DB_DATABASE', database_path('database.sqlite')), + 'prefix' => '', + 'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true), + ], + + 'sqlite_testing' => [ + 'driver' => 'sqlite', + 'database' => ':memory:', + 'prefix' => '', + 'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true), + ], + ], + + /* + |-------------------------------------------------------------------------- + | Migration Repository Table + |-------------------------------------------------------------------------- + | + | This table keeps track of all the migrations that have already run for + | your application. Using this information, we can determine which of + | the migrations on disk haven't actually been run on the database. + | + */ + + 'migrations' => 'migrations', + + /* + |-------------------------------------------------------------------------- + | Redis Databases + |-------------------------------------------------------------------------- + | + | Redis is an open source, fast, and advanced key-value store that also + | provides a richer body of commands than a typical key-value system + | such as Memcached. You may define your connection settings here. + | + */ + + 'redis' => [ + 'options' => [ + 'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'hypervel'), '_') . '_database_'), + ], + + 'default' => [ + 'host' => env('REDIS_HOST', 'localhost'), + 'auth' => env('REDIS_AUTH', null), + 'port' => (int) env('REDIS_PORT', 6379), + 'db' => (int) env('REDIS_DB', 0), + 'pool' => [ + 'min_connections' => 1, + 'max_connections' => 10, + 'connect_timeout' => 10.0, + 'wait_timeout' => 3.0, + 'heartbeat' => -1, + 'max_idle_time' => (float) env('REDIS_MAX_IDLE_TIME', 60), + ], + ], + + 'queue' => [ + 'host' => env('REDIS_HOST', 'localhost'), + 'auth' => env('REDIS_AUTH', null), + 'port' => (int) env('REDIS_PORT', 6379), + 'db' => (int) env('REDIS_DB', 0), + 'pool' => [ + 'min_connections' => 1, + 'max_connections' => 10, + 'connect_timeout' => 10.0, + 'wait_timeout' => 3.0, + 'heartbeat' => -1, + 'max_idle_time' => (float) env('REDIS_MAX_IDLE_TIME', 60), + ], + ], + ], +]; diff --git a/frameworks/PHP/hypervel/config/logging.php b/frameworks/PHP/hypervel/config/logging.php new file mode 100644 index 00000000000..75c4b59727b --- /dev/null +++ b/frameworks/PHP/hypervel/config/logging.php @@ -0,0 +1,140 @@ + env('LOG_CHANNEL', 'stack'), + + /* + |-------------------------------------------------------------------------- + | Deprecations Log Channel + |-------------------------------------------------------------------------- + | + | This option controls the log channel that should be used to log warnings + | regarding deprecated PHP and library features. This allows you to get + | your application ready for upcoming major versions of dependencies. + | + */ + + 'deprecations' => [ + 'channel' => env('LOG_DEPRECATIONS_CHANNEL', 'null'), + 'trace' => false, + ], + + /* + |-------------------------------------------------------------------------- + | Log Channels + |-------------------------------------------------------------------------- + | + | Here you may configure the log channels for your application. Out of + | the box, Laravel uses the Monolog PHP logging library. This gives + | you a variety of powerful log handlers / formatters to utilize. + | + | Available Drivers: "single", "daily", "slack", "syslog", + | "errorlog", "monolog", + | "custom", "stack" + | + */ + + 'channels' => [ + 'stack' => [ + 'driver' => 'stack', + 'channels' => ['single'], + 'ignore_exceptions' => false, + ], + + 'single' => [ + 'driver' => 'single', + 'path' => storage_path('logs/hypervel.log'), + 'level' => env('LOG_LEVEL', 'debug'), + 'replace_placeholders' => true, + ], + + 'daily' => [ + 'driver' => 'daily', + 'path' => storage_path('logs/hypervel.log'), + 'level' => env('LOG_LEVEL', 'debug'), + 'days' => 14, + 'replace_placeholders' => true, + ], + + 'slack' => [ + 'driver' => 'slack', + 'url' => env('LOG_SLACK_WEBHOOK_URL'), + 'username' => 'Laravel Log', + 'emoji' => ':boom:', + 'level' => env('LOG_LEVEL', 'critical'), + 'replace_placeholders' => true, + ], + + 'papertrail' => [ + 'driver' => 'monolog', + 'level' => env('LOG_LEVEL', 'debug'), + 'handler' => env('LOG_PAPERTRAIL_HANDLER', SyslogUdpHandler::class), + 'handler_with' => [ + 'host' => env('PAPERTRAIL_URL'), + 'port' => env('PAPERTRAIL_PORT'), + 'connectionString' => 'tls://' . env('PAPERTRAIL_URL') . ':' . env('PAPERTRAIL_PORT'), + ], + 'processors' => [PsrLogMessageProcessor::class], + ], + + 'stdout' => [ + 'driver' => 'monolog', + 'handler' => StreamHandler::class, + 'formatter' => env('LOG_STDOUT_FORMATTER'), + 'with' => [ + 'stream' => 'php://stdout', + ], + ], + + 'stderr' => [ + 'driver' => 'monolog', + 'level' => env('LOG_LEVEL', 'debug'), + 'handler' => StreamHandler::class, + 'formatter' => env('LOG_STDERR_FORMATTER'), + 'with' => [ + 'stream' => 'php://stderr', + ], + 'processors' => [PsrLogMessageProcessor::class], + ], + + 'syslog' => [ + 'driver' => 'syslog', + 'level' => env('LOG_LEVEL', 'debug'), + 'facility' => LOG_USER, + 'replace_placeholders' => true, + ], + + 'errorlog' => [ + 'driver' => 'errorlog', + 'level' => env('LOG_LEVEL', 'debug'), + 'replace_placeholders' => true, + ], + + 'null' => [ + 'driver' => 'monolog', + 'handler' => NullHandler::class, + ], + + 'emergency' => [ + 'path' => storage_path('logs/hypervel.log'), + ], + ], +]; diff --git a/frameworks/PHP/hypervel/config/queue.php b/frameworks/PHP/hypervel/config/queue.php new file mode 100644 index 00000000000..6e3ba9be3e1 --- /dev/null +++ b/frameworks/PHP/hypervel/config/queue.php @@ -0,0 +1,137 @@ + env('QUEUE_CONNECTION', 'database'), + + /* + |-------------------------------------------------------------------------- + | Concurrency Number + |-------------------------------------------------------------------------- + | + | This value determines the number of jobs that will be processed at once + | by every worker. + | + */ + 'concurrency_number' => env('QUEUE_CONCURRENCY_NUMBER', 1), + + /* + |-------------------------------------------------------------------------- + | Queue Connections + |-------------------------------------------------------------------------- + | + | Here you may configure the connection options for every queue backend + | used by your application. An example configuration is provided for + | each backend supported by Hypervel. You're also free to add more. + | + | Drivers: "sync", "defer", "database", "beanstalkd", "sqs", "redis", "null" + | + */ + + 'connections' => [ + 'sync' => [ + 'driver' => 'sync', + ], + + 'defer' => [ + 'driver' => 'defer', + ], + + 'database' => [ + 'driver' => 'database', + 'connection' => env('DB_QUEUE_CONNECTION'), + 'table' => env('DB_QUEUE_TABLE', 'jobs'), + 'queue' => env('DB_QUEUE', 'default'), + 'retry_after' => (int) env('DB_QUEUE_RETRY_AFTER', 90), + 'after_commit' => false, + ], + + 'beanstalkd' => [ + 'driver' => 'beanstalkd', + 'host' => env('BEANSTALKD_QUEUE_HOST', 'localhost'), + 'queue' => env('BEANSTALKD_QUEUE', 'default'), + 'retry_after' => (int) env('BEANSTALKD_QUEUE_RETRY_AFTER', 90), + 'block_for' => 0, + 'after_commit' => false, + 'pool' => [ + 'min_objects' => 1, + 'max_objects' => 10, + 'wait_timeout' => 3.0, + 'max_lifetime' => 60.0, + ], + ], + + 'sqs' => [ + 'driver' => 'sqs', + 'key' => env('AWS_ACCESS_KEY_ID'), + 'secret' => env('AWS_SECRET_ACCESS_KEY'), + 'prefix' => env('SQS_PREFIX', 'https://sqs.us-east-1.amazonaws.com/your-account-id'), + 'queue' => env('SQS_QUEUE', 'default'), + 'suffix' => env('SQS_SUFFIX'), + 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), + 'after_commit' => false, + 'pool' => [ + 'min_objects' => 1, + 'max_objects' => 10, + 'wait_timeout' => 3.0, + 'max_lifetime' => 60.0, + ], + ], + + 'redis' => [ + 'driver' => 'redis', + 'connection' => env('REDIS_QUEUE_CONNECTION', 'default'), + 'queue' => env('REDIS_QUEUE', 'default'), + 'retry_after' => (int) env('REDIS_QUEUE_RETRY_AFTER', 90), + 'block_for' => null, + 'after_commit' => false, + ], + ], + + /* + |-------------------------------------------------------------------------- + | Job Batching + |-------------------------------------------------------------------------- + | + | The following options configure the database and table that store job + | batching information. These options can be updated to any database + | connection and table which has been defined by your application. + | + */ + + 'batching' => [ + 'database' => env('DB_CONNECTION', 'sqlite'), + 'table' => 'job_batches', + ], + + /* + |-------------------------------------------------------------------------- + | Failed Queue Jobs + |-------------------------------------------------------------------------- + | + | These options configure the behavior of failed queue job logging so you + | can control how and where failed jobs are stored. Hypervel ships with + | support for storing failed jobs in a simple file or in a database. + | + | Supported drivers: "database-uuids", "dynamodb", "file", "null" + | + */ + + 'failed' => [ + 'driver' => env('QUEUE_FAILED_DRIVER', 'database-uuids'), + 'database' => env('DB_CONNECTION', 'sqlite'), + 'table' => 'failed_jobs', + ], +]; diff --git a/frameworks/PHP/hypervel/config/server.php b/frameworks/PHP/hypervel/config/server.php new file mode 100644 index 00000000000..8fe740d8b54 --- /dev/null +++ b/frameworks/PHP/hypervel/config/server.php @@ -0,0 +1,45 @@ + SWOOLE_PROCESS, + 'servers' => [ + [ + 'name' => 'http', + 'type' => Server::SERVER_HTTP, + 'host' => env('HTTP_SERVER_HOST', '0.0.0.0'), + 'port' => (int) env('HTTP_SERVER_PORT', 9501), + 'sock_type' => SWOOLE_SOCK_TCP, + 'callbacks' => [ + Event::ON_REQUEST => [HttpKernel::class, 'onRequest'], + ], + ], + ], + 'kernels' => [ + 'http' => HttpKernel::class, + ], + 'settings' => [ + 'document_root' => base_path('public'), + 'enable_static_handler' => true, + Constant::OPTION_ENABLE_COROUTINE => true, + 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_MAX_COROUTINE => 100000, + Constant::OPTION_OPEN_HTTP2_PROTOCOL => true, + Constant::OPTION_MAX_REQUEST => 100000, + Constant::OPTION_SOCKET_BUFFER_SIZE => 2 * 1024 * 1024, + Constant::OPTION_BUFFER_OUTPUT_SIZE => 2 * 1024 * 1024, + ], + 'callbacks' => [ + Event::ON_WORKER_START => [Hyperf\Framework\Bootstrap\WorkerStartCallback::class, 'onWorkerStart'], + Event::ON_PIPE_MESSAGE => [Hyperf\Framework\Bootstrap\PipeMessageCallback::class, 'onPipeMessage'], + Event::ON_WORKER_EXIT => [Hyperf\Framework\Bootstrap\WorkerExitCallback::class, 'onWorkerExit'], + ], +]; diff --git a/frameworks/PHP/hypervel/config/view.php b/frameworks/PHP/hypervel/config/view.php new file mode 100644 index 00000000000..8c77d2746bc --- /dev/null +++ b/frameworks/PHP/hypervel/config/view.php @@ -0,0 +1,20 @@ + HyperfViewEngine::class, + 'mode' => Mode::SYNC, + 'config' => [ + 'view_path' => base_path('resources/views'), + 'cache_path' => storage_path('framework/views'), + ], + 'event' => [ + 'enable' => false, + ], + 'components' => [ + ], +]; diff --git a/frameworks/PHP/hypervel/config/watcher.php b/frameworks/PHP/hypervel/config/watcher.php new file mode 100644 index 00000000000..24b64d8f97f --- /dev/null +++ b/frameworks/PHP/hypervel/config/watcher.php @@ -0,0 +1,17 @@ + ScanFileDriver::class, + 'bin' => PHP_BINARY, + 'command' => 'artisan serve', + 'watch' => [ + 'dir' => ['app', 'config', 'routes', 'resources'], + 'file' => ['.env'], + 'scan_interval' => 2000, + ], + 'ext' => ['.php', '.env'], +]; diff --git a/frameworks/PHP/hypervel/database/factories/UserFactory.php b/frameworks/PHP/hypervel/database/factories/UserFactory.php new file mode 100644 index 00000000000..756ac304b55 --- /dev/null +++ b/frameworks/PHP/hypervel/database/factories/UserFactory.php @@ -0,0 +1,16 @@ +define(User::class, function (Faker $faker) { + return [ + 'name' => $faker->unique()->name(), + 'email' => $faker->unique()->safeEmail(), + 'email_verified_at' => Carbon::now(), + 'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password + ]; +}); diff --git a/frameworks/PHP/hypervel/database/migrations/2023_08_03_000000_create_users_table.php b/frameworks/PHP/hypervel/database/migrations/2023_08_03_000000_create_users_table.php new file mode 100644 index 00000000000..358effaf8b3 --- /dev/null +++ b/frameworks/PHP/hypervel/database/migrations/2023_08_03_000000_create_users_table.php @@ -0,0 +1,32 @@ +id(); + $table->string('name'); + $table->string('email')->unique(); + $table->timestamp('email_verified_at')->nullable(); + $table->string('password'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('users'); + } +}; diff --git a/frameworks/PHP/hypervel/database/seeders/DatabaseSeeder.php b/frameworks/PHP/hypervel/database/seeders/DatabaseSeeder.php new file mode 100644 index 00000000000..7da216a82b4 --- /dev/null +++ b/frameworks/PHP/hypervel/database/seeders/DatabaseSeeder.php @@ -0,0 +1,21 @@ +create(); + + // \App\Models\User::factory()->create([ + // 'name' => 'Test User', + // 'email' => 'test@example.com', + // ]); + } +} diff --git a/frameworks/PHP/hypervel/hypervel.dockerfile b/frameworks/PHP/hypervel/hypervel.dockerfile new file mode 100644 index 00000000000..8001546aab4 --- /dev/null +++ b/frameworks/PHP/hypervel/hypervel.dockerfile @@ -0,0 +1,22 @@ +FROM phpswoole/swoole:php8.4 + +RUN docker-php-ext-install pcntl opcache curl > /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 + +WORKDIR /hypervel +COPY --link . . + +RUN mkdir -p bootstrap/cache \ + storage/logs \ + storage/framework/sessions \ + storage/framework/views \ + storage/framework/cache + +RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet + +EXPOSE 9501 + +ENTRYPOINT ["php", "artisan", "serve"] diff --git a/frameworks/PHP/hypervel/lang/en/validation.php b/frameworks/PHP/hypervel/lang/en/validation.php new file mode 100644 index 00000000000..b535c494d6c --- /dev/null +++ b/frameworks/PHP/hypervel/lang/en/validation.php @@ -0,0 +1,197 @@ + 'The :attribute must be accepted.', + 'accepted_if' => 'The :attribute must be accepted when :other is :value.', + 'active_url' => 'The :attribute is not a valid URL.', + 'after' => 'The :attribute must be a date after :date.', + 'after_or_equal' => 'The :attribute must be a date after or equal to :date.', + 'alpha' => 'The :attribute may only contain letters.', + 'alpha_dash' => 'The :attribute may only contain letters, numbers, and dashes.', + 'alpha_num' => 'The :attribute may only contain letters and numbers.', + 'array' => 'The :attribute must be an array.', + 'ascii' => 'The :attribute must only contain single-byte alphanumeric characters and symbols.', + 'before' => 'The :attribute must be a date before :date.', + 'before_or_equal' => 'The :attribute must be a date before or equal to :date.', + 'between' => [ + 'numeric' => 'The :attribute must be between :min and :max.', + 'file' => 'The :attribute must be between :min and :max kilobytes.', + 'string' => 'The :attribute must be between :min and :max characters.', + 'array' => 'The :attribute must have between :min and :max items.', + ], + 'boolean' => 'The :attribute field must be true or false.', + 'confirmed' => 'The :attribute confirmation does not match.', + 'date' => 'The :attribute is not a valid date.', + 'date_equals' => 'The :attribute must be a date equal to :date.', + 'date_format' => 'The :attribute does not match the format :format.', + 'decimal' => 'The :attribute must have :decimal decimal places.', + 'declined' => 'The :attribute must be declined.', + 'declined_if' => 'The :attribute must be declined when :other is :value.', + 'different' => 'The :attribute and :other must be different.', + 'digits' => 'The :attribute must be :digits digits.', + 'digits_between' => 'The :attribute must be between :min and :max digits.', + 'dimensions' => 'The :attribute has invalid image dimensions.', + 'distinct' => 'The :attribute field has a duplicate value.', + 'doesnt_end_with' => 'The :attribute must not end with one of the following: :values.', + 'doesnt_start_with' => 'The :attribute must not start with one of the following: :values.', + 'email' => 'The :attribute must be a valid email address.', + 'ends_with' => 'The :attribute must end with one of the following: :values.', + 'exists' => 'The selected :attribute is invalid.', + 'file' => 'The :attribute must be a file.', + 'filled' => 'The :attribute field is required.', + 'gt' => [ + 'numeric' => 'The :attribute must be greater than :value', + 'file' => 'The :attribute must be greater than :value kb', + 'string' => 'The :attribute must be greater than :value characters', + 'array' => 'The :attribute must be greater than :value items', + ], + 'gte' => [ + 'numeric' => 'The :attribute must be great than or equal to :value', + 'file' => 'The :attribute must be great than or equal to :value kb', + 'string' => 'The :attribute must be great than or equal to :value characters', + 'array' => 'The :attribute must be great than or equal to :value items', + ], + 'image' => 'The :attribute must be an image.', + 'in' => 'The selected :attribute is invalid.', + 'in_array' => 'The :attribute field does not exist in :other.', + 'integer' => 'The :attribute must be an integer.', + 'ip' => 'The :attribute must be a valid IP address.', + 'ipv4' => 'The :attribute must be a valid IPv4 address.', + 'ipv6' => 'The :attribute must be a valid IPv6 address.', + 'json' => 'The :attribute must be a valid JSON string.', + 'list' => 'The :attribute must be a list.', + 'lowercase' => 'The :attribute must be lowercase.', + 'lt' => [ + 'numeric' => 'The :attribute must be less than :value', + 'file' => 'The :attribute must be less than :value kb', + 'string' => 'The :attribute must be less than :value characters', + 'array' => 'The :attribute must be less than :value items', + ], + 'lte' => [ + 'numeric' => 'The :attribute must be less than or equal to :value', + 'file' => 'The :attribute must be less than or equal to :value kb', + 'string' => 'The :attribute must be less than or equal to :value characters', + 'array' => 'The :attribute must be less than or equal to :value items', + ], + 'max' => [ + 'numeric' => 'The :attribute may not be greater than :max.', + 'file' => 'The :attribute may not be greater than :max kilobytes.', + 'string' => 'The :attribute may not be greater than :max characters.', + 'array' => 'The :attribute may not have more than :max items.', + ], + 'max_digits' => 'The :attribute must not have more than :max digits.', + 'mimes' => 'The :attribute must be a file of type: :values.', + 'mimetypes' => 'The :attribute must be a file of type: :values.', + 'min' => [ + 'numeric' => 'The :attribute must be at least :min.', + 'file' => 'The :attribute must be at least :min kilobytes.', + 'string' => 'The :attribute must be at least :min characters.', + 'array' => 'The :attribute must have at least :min items.', + ], + 'min_digits' => 'The :attribute must have at least :min digits.', + 'missing' => 'The :attribute must be missing.', + 'missing_if' => 'The :attribute must be missing when :other is :value.', + 'missing_unless' => 'The :attribute must be missing unless :other is :value.', + 'missing_with' => 'The :attribute must be missing when :values is present.', + 'missing_with_all' => 'The :attribute must be missing when :values are present.', + 'multiple_of' => 'The :attribute must be a multiple of :value.', + 'not_in' => 'The selected :attribute is invalid.', + 'not_regex' => 'The :attribute cannot match a given regular rule.', + 'numeric' => 'The :attribute must be a number.', + 'present' => 'The :attribute field must be present.', + 'prohibits' => 'The :attribute field must be present.', + 'regex' => 'The :attribute format is invalid.', + 'required' => 'The :attribute field is required.', + 'required_if' => 'The :attribute field is required when :other is :value.', + 'required_unless' => 'The :attribute field is required unless :other is in :values.', + 'required_with' => 'The :attribute field is required when :values is present.', + 'required_with_all' => 'The :attribute field is required when :values is present.', + 'required_without' => 'The :attribute field is required when :values is not present.', + 'required_without_all' => 'The :attribute field is required when none of :values are present.', + 'exclude' => 'The :attribute field is excluded.', + 'exclude_if' => 'The :attribute field is excluded when :other is :value.', + 'exclude_unless' => 'The :attribute field is excluded unless :other is in :values.', + 'exclude_with' => 'The :attribute field is excluded when :values is present.', + 'exclude_without' => 'The :attribute field is excluded when :values is not present.', + 'same' => 'The :attribute and :other must match.', + 'size' => [ + 'numeric' => 'The :attribute must be :size.', + 'file' => 'The :attribute must be :size kilobytes.', + 'string' => 'The :attribute must be :size characters.', + 'array' => 'The :attribute must contain :size items.', + ], + 'starts_with' => 'The :attribute must be start with :values ', + 'string' => 'The :attribute must be a string.', + 'timezone' => 'The :attribute must be a valid zone.', + 'unique' => 'The :attribute has already been taken.', + 'uploaded' => 'The :attribute failed to upload.', + 'uppercase' => 'The :attribute must be uppercase.', + 'url' => 'The :attribute format is invalid.', + 'ulid' => 'The :attribute must be a valid ULID.', + 'uuid' => 'The :attribute is invalid UUID.', + 'max_if' => [ + 'numeric' => 'The :attribute may not be greater than :max when :other is :value.', + 'file' => 'The :attribute may not be greater than :max kilobytes when :other is :value.', + 'string' => 'The :attribute may not be greater than :max characters when :other is :value.', + 'array' => 'The :attribute may not have more than :max items when :other is :value.', + ], + 'min_if' => [ + 'numeric' => 'The :attribute must be at least :min when :other is :value.', + 'file' => 'The :attribute must be at least :min kilobytes when :other is :value.', + 'string' => 'The :attribute must be at least :min characters when :other is :value.', + 'array' => 'The :attribute must have at least :min items when :other is :value.', + ], + 'between_if' => [ + 'numeric' => 'The :attribute must be between :min and :max when :other is :value.', + 'file' => 'The :attribute must be between :min and :max kilobytes when :other is :value.', + 'string' => 'The :attribute must be between :min and :max characters when :other is :value.', + 'array' => 'The :attribute must have between :min and :max items when :other is :value.', + ], + /* + |-------------------------------------------------------------------------- + | Custom Validation Language Lines + |-------------------------------------------------------------------------- + | + | Here you may specify custom validation messages for attributes using the + | convention "attribute.rule" to name the lines. This makes it quick to + | specify a specific custom language line for a given attribute rule. + | + */ + + 'custom' => [ + 'attribute-name' => [ + 'rule-name' => 'custom-message', + ], + ], + + /* + |-------------------------------------------------------------------------- + | Custom Validation Attributes + |-------------------------------------------------------------------------- + | + | The following language lines are used to swap attribute place-holders + | with something more reader friendly such as E-Mail Address instead + | of "email". This simply helps us make messages a little cleaner. + | + */ + + 'attributes' => [], + 'phone_number' => 'The :attribute must be a valid phone number', + 'telephone_number' => 'The :attribute must be a valid telephone number', + + 'chinese_word' => 'The :attribute must contain valid characters(chinese/english character, number, underscore)', + 'sequential_array' => 'The :attribute must be sequential array', +]; diff --git a/frameworks/PHP/hypervel/phpunit.xml.dist b/frameworks/PHP/hypervel/phpunit.xml.dist new file mode 100644 index 00000000000..b151c4877dd --- /dev/null +++ b/frameworks/PHP/hypervel/phpunit.xml.dist @@ -0,0 +1,30 @@ + + + + + tests/Unit + + + tests/Feature + + + + + app + + + + + + + + + diff --git a/frameworks/PHP/hypervel/public/robots.txt b/frameworks/PHP/hypervel/public/robots.txt new file mode 100644 index 00000000000..6f27bb66a34 --- /dev/null +++ b/frameworks/PHP/hypervel/public/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: \ No newline at end of file diff --git a/frameworks/PHP/lumen/resources/views/fortunes.blade.php b/frameworks/PHP/hypervel/resources/views/fortunes.blade.php similarity index 100% rename from frameworks/PHP/lumen/resources/views/fortunes.blade.php rename to frameworks/PHP/hypervel/resources/views/fortunes.blade.php diff --git a/frameworks/PHP/hypervel/routes/api.php b/frameworks/PHP/hypervel/routes/api.php new file mode 100644 index 00000000000..7b15ec2dd59 --- /dev/null +++ b/frameworks/PHP/hypervel/routes/api.php @@ -0,0 +1,8 @@ +id === (int) $id; +}); diff --git a/frameworks/PHP/hypervel/routes/console.php b/frameworks/PHP/hypervel/routes/console.php new file mode 100644 index 00000000000..5f8ed15b28c --- /dev/null +++ b/frameworks/PHP/hypervel/routes/console.php @@ -0,0 +1,23 @@ +comment('Hypervel is awesome!'); +})->purpose('This is a demo closure command.'); + +// Schedule::command('hello')->everyFiveSeconds(); diff --git a/frameworks/PHP/hypervel/routes/web.php b/frameworks/PHP/hypervel/routes/web.php new file mode 100644 index 00000000000..bbc1cd97146 --- /dev/null +++ b/frameworks/PHP/hypervel/routes/web.php @@ -0,0 +1,13 @@ +get('/') + ->assertSuccessful(); + } +} diff --git a/frameworks/PHP/hypervel/tests/Feature/RefreshDatabaseTest.php b/frameworks/PHP/hypervel/tests/Feature/RefreshDatabaseTest.php new file mode 100644 index 00000000000..54f41f938a3 --- /dev/null +++ b/frameworks/PHP/hypervel/tests/Feature/RefreshDatabaseTest.php @@ -0,0 +1,39 @@ +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 new file mode 100644 index 00000000000..754c7277ca5 --- /dev/null +++ b/frameworks/PHP/hypervel/tests/TestCase.php @@ -0,0 +1,13 @@ +assertTrue(true); + } +} diff --git a/frameworks/PHP/hypervel/tests/bootstrap.php b/frameworks/PHP/hypervel/tests/bootstrap.php new file mode 100644 index 00000000000..d5afa4a9b22 --- /dev/null +++ b/frameworks/PHP/hypervel/tests/bootstrap.php @@ -0,0 +1,38 @@ +get(Hyperf\Contract\ApplicationInterface::class); diff --git a/frameworks/PHP/hypervel/tests/helpers.php b/frameworks/PHP/hypervel/tests/helpers.php new file mode 100644 index 00000000000..cbd0f353a0a --- /dev/null +++ b/frameworks/PHP/hypervel/tests/helpers.php @@ -0,0 +1,15 @@ +get(ModelFactory::class) + ->factory($class, ...$arguments); + } +} diff --git a/frameworks/PHP/imi/Listener/WorkermanWorkerStart.php b/frameworks/PHP/imi/Listener/WorkermanWorkerStart.php index 6ef1c980163..9ed362f6781 100644 --- a/frameworks/PHP/imi/Listener/WorkermanWorkerStart.php +++ b/frameworks/PHP/imi/Listener/WorkermanWorkerStart.php @@ -19,9 +19,9 @@ class WorkermanWorkerStart implements IEventListener */ public function handle(EventParam $e): void { - App::set('test_date', gmdate('D, d M Y H:i:s').' GMT'); + App::set('test_date', gmdate(DATE_RFC7231)); Timer::tick(1000, function() { - App::set('test_date', gmdate('D, d M Y H:i:s').' GMT'); + App::set('test_date', gmdate(DATE_RFC7231)); }); } diff --git a/frameworks/PHP/imi/composer.json b/frameworks/PHP/imi/composer.json index bc3795f0d07..c77718182cf 100644 --- a/frameworks/PHP/imi/composer.json +++ b/frameworks/PHP/imi/composer.json @@ -1,7 +1,7 @@ { "require": { - "imiphp/imi": "~2.1.0", - "imiphp/imi-pgsql": "~2.1.0" + "imiphp/imi": "~2.1", + "imiphp/imi-pgsql": "~2.1" }, "autoload": { "psr-4" : { diff --git a/frameworks/PHP/imi/imi-swoole.dockerfile b/frameworks/PHP/imi/imi-swoole.dockerfile index 11704d8ed3f..2cc80f2b982 100644 --- a/frameworks/PHP/imi/imi-swoole.dockerfile +++ b/frameworks/PHP/imi/imi-swoole.dockerfile @@ -1,6 +1,6 @@ -FROM php:8.2-cli +FROM php:8.3-cli -ENV SWOOLE_VERSION 5.1.0 +ENV SWOOLE_VERSION 5.1.1 ARG TFB_TEST_DATABASE ENV TFB_TEST_DATABASE=${TFB_TEST_DATABASE} @@ -22,7 +22,7 @@ RUN chmod -R ug+rwx /imi/.runtime WORKDIR /imi -RUN curl -sSL https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer +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 dumpautoload -o diff --git a/frameworks/PHP/imi/imi-workerman.dockerfile b/frameworks/PHP/imi/imi-workerman.dockerfile index 55f5cbfa592..306a2512a82 100644 --- a/frameworks/PHP/imi/imi-workerman.dockerfile +++ b/frameworks/PHP/imi/imi-workerman.dockerfile @@ -1,4 +1,4 @@ -FROM php:8.2-cli +FROM php:8.3-cli ARG TFB_TEST_DATABASE ENV TFB_TEST_DATABASE=${TFB_TEST_DATABASE} @@ -21,7 +21,7 @@ RUN chmod -R ug+rwx /imi/.runtime WORKDIR /imi -RUN curl -sSL https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer +COPY --from=composer:latest /usr/bin/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 dumpautoload -o diff --git a/frameworks/PHP/kumbiaphp/bench/app/controllers/ku_controller.php b/frameworks/PHP/kumbiaphp/bench/app/controllers/ku_controller.php index 0c545d23794..d5b09ead00f 100644 --- a/frameworks/PHP/kumbiaphp/bench/app/controllers/ku_controller.php +++ b/frameworks/PHP/kumbiaphp/bench/app/controllers/ku_controller.php @@ -1,14 +1,12 @@ execute([mt_rand(1, 10000)]); - $worlds[] = KuRaw::$random->fetch(); + $random->execute([mt_rand(1, 10000)]); + $worlds[] = $random->fetch(); } echo json_encode($worlds); } @@ -31,11 +30,12 @@ public function query($count = 1) public function update($count = 1) { $count = min(max((int) $count, 1), 500); + $random = KuRaw::$random; while ($count--) { - KuRaw::$random->execute([mt_rand(1, 10000)]); - $row = KuRaw::$random->fetch(); + $random->execute([mt_rand(1, 10000)]); + $row = $random->fetch(); $row['randomNumber'] = mt_rand(1, 10000); $worlds[] = $row; diff --git a/frameworks/PHP/kumbiaphp/bench/app/models/fortune.php b/frameworks/PHP/kumbiaphp/bench/app/models/fortune.php index 32f718d75f8..3785ee53908 100644 --- a/frameworks/PHP/kumbiaphp/bench/app/models/fortune.php +++ b/frameworks/PHP/kumbiaphp/bench/app/models/fortune.php @@ -1,5 +1,6 @@ /dev/null -RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php -RUN apt-get update -yqq > /dev/null && \ - apt-get install -yqq nginx git unzip \ - php8.1-fpm php8.1-mysql php8.1-dev > /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 -COPY deploy/conf/* /etc/php/8.1/fpm/ +RUN apt-get install -yqq nginx git unzip \ + php8.4-fpm php8.4-mysql > /dev/null -ADD ./ /kumbiaphp +COPY --link deploy/conf/* /etc/php/8.4/fpm/ WORKDIR /kumbiaphp +COPY --link . . -RUN git clone -b v1.1.4 --single-branch --depth 1 -q https://github.com/KumbiaPHP/KumbiaPHP.git vendor/Kumbia +RUN git clone -b v1.2.1 --single-branch --depth 1 -q https://github.com/KumbiaPHP/KumbiaPHP.git vendor/Kumbia -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.1/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.4/fpm/php-fpm.conf ; fi; EXPOSE 8080 -CMD service php8.1-fpm start && \ +CMD service php8.4-fpm start && \ nginx -c /kumbiaphp/deploy/nginx.conf diff --git a/frameworks/PHP/kumbiaphp/kumbiaphp-workerman-mysql.dockerfile b/frameworks/PHP/kumbiaphp/kumbiaphp-workerman-mysql.dockerfile index 7fe1f85d92d..775a825d187 100644 --- a/frameworks/PHP/kumbiaphp/kumbiaphp-workerman-mysql.dockerfile +++ b/frameworks/PHP/kumbiaphp/kumbiaphp-workerman-mysql.dockerfile @@ -1,26 +1,27 @@ -FROM ubuntu:20.04 +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 > /dev/null && \ - apt-get install -yqq git php8.1-cli php8.1-mysql php8.1-xml > /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 install -yqq git php8.4-cli php8.4-mysql php8.4-xml > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -RUN apt-get install -y php-pear php8.1-dev libevent-dev > /dev/null -RUN pecl install event-3.0.8 > /dev/null && echo "extension=event.so" > /etc/php/8.1/cli/conf.d/event.ini +RUN apt-get install -y php-pear php8.4-dev libevent-dev > /dev/null +RUN pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.4/cli/conf.d/event.ini -COPY deploy/conf/cliphp.ini /etc/php/8.1/cli/php.ini +COPY deploy/conf/cliphp.ini /etc/php/8.4/cli/conf.d/20-adapterman.ini ADD ./ /kumbiaphp WORKDIR /kumbiaphp RUN git clone -b dev --single-branch --depth 1 https://github.com/KumbiaPHP/KumbiaPHP.git vendor/Kumbia -RUN git clone -b master --single-branch --depth 1 https://github.com/KumbiaPHP/ActiveRecord.git vendor/Kumbia/ActiveRecord +RUN git clone -b dev --single-branch --depth 1 https://github.com/KumbiaPHP/ActiveRecord.git vendor/Kumbia/ActiveRecord -RUN sed -i "s|header(|\\\Workerman\\\Protocols\\\Http::header(|g" bench/app/controllers/*.php +RUN sed -i "s|KuRaw::init(|//KuRaw::init(|g" server.php RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet diff --git a/frameworks/PHP/kumbiaphp/kumbiaphp-workerman.dockerfile b/frameworks/PHP/kumbiaphp/kumbiaphp-workerman.dockerfile index dde619cb90b..9342ce03dbc 100644 --- a/frameworks/PHP/kumbiaphp/kumbiaphp-workerman.dockerfile +++ b/frameworks/PHP/kumbiaphp/kumbiaphp-workerman.dockerfile @@ -1,29 +1,24 @@ -FROM ubuntu:20.04 +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 > /dev/null && \ - apt-get install -yqq git php8.1-cli php8.1-pgsql php8.1-xml > /dev/null + apt-get install -yqq git php8.4-cli php8.4-pgsql php8.4-xml > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -RUN apt-get install -y php-pear php8.1-dev libevent-dev > /dev/null -RUN pecl install event-3.0.8 > /dev/null && echo "extension=event.so" > /etc/php/8.1/cli/conf.d/event.ini +RUN apt-get install -y php-pear php8.4-dev libevent-dev > /dev/null +RUN pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.4/cli/conf.d/event.ini -COPY deploy/conf/cliphp.ini /etc/php/8.1/cli/php.ini +COPY deploy/conf/cliphp.ini /etc/php/8.4/cli/conf.d/20-adapterman.ini ADD ./ /kumbiaphp WORKDIR /kumbiaphp RUN git clone -b dev --single-branch --depth 1 https://github.com/KumbiaPHP/KumbiaPHP.git vendor/Kumbia -#RUN sed -i "s|header(|\\\Workerman\\\Protocols\\\Http::header(|g" bench/app/controllers/{index,json}_controller.php -RUN sed -i "s|header(|\\\Workerman\\\Protocols\\\Http::header(|g" bench/app/controllers/plaintext_controller.php -RUN sed -i "s|header(|\\\Workerman\\\Protocols\\\Http::header(|g" bench/app/controllers/json_controller.php -RUN sed -i "s|//KuRaw::init(|KuRaw::init(|g" server.php - RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet EXPOSE 8080 diff --git a/frameworks/PHP/kumbiaphp/kumbiaphp.dockerfile b/frameworks/PHP/kumbiaphp/kumbiaphp.dockerfile index 21c130ec0f5..960100a6347 100644 --- a/frameworks/PHP/kumbiaphp/kumbiaphp.dockerfile +++ b/frameworks/PHP/kumbiaphp/kumbiaphp.dockerfile @@ -1,24 +1,24 @@ -FROM ubuntu:20.04 +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 > /dev/null && \ - apt-get install -yqq nginx git unzip \ - php8.1-fpm php8.1-mysql php8.1-dev > /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 -COPY deploy/conf/* /etc/php/8.1/fpm/ +RUN apt-get install -yqq nginx git unzip \ + php8.4-fpm php8.4-mysql > /dev/null -ADD ./ /kumbiaphp +COPY --link deploy/conf/* /etc/php/8.4/fpm/ WORKDIR /kumbiaphp +COPY --link . . -RUN git clone -b v1.1.4 --single-branch --depth 1 https://github.com/KumbiaPHP/KumbiaPHP.git vendor/Kumbia -RUN git clone -b dev --single-branch --depth 1 https://github.com/KumbiaPHP/ActiveRecord.git vendor/Kumbia/ActiveRecord +RUN git clone -b v1.2.1 --single-branch --depth 1 https://github.com/KumbiaPHP/KumbiaPHP.git vendor/Kumbia +RUN git clone -b master --single-branch --depth 1 https://github.com/KumbiaPHP/ActiveRecord.git vendor/Kumbia/ActiveRecord -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.1/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.4/fpm/php-fpm.conf ; fi; EXPOSE 8080 -CMD service php8.1-fpm start && \ +CMD service php8.4-fpm start && \ nginx -c /kumbiaphp/deploy/nginx.conf diff --git a/frameworks/PHP/kumbiaphp/server.php b/frameworks/PHP/kumbiaphp/server.php index 17413d0c7a1..c47e6ad3994 100644 --- a/frameworks/PHP/kumbiaphp/server.php +++ b/frameworks/PHP/kumbiaphp/server.php @@ -2,14 +2,19 @@ require_once __DIR__.'/vendor/autoload.php'; require_once __DIR__.'/bench/app/workerbootstrap.php'; +use Adapterman\Adapterman; use Workerman\Worker; -$http_worker = new Worker('http://0.0.0.0:8080'); -$http_worker->count = (int) shell_exec('nproc') * 4; -$http_worker->onWorkerStart = static function () { +Adapterman::init(); + +$http_worker = new Worker('http://0.0.0.0:8080'); +$http_worker->count = (int) shell_exec('nproc') * 4; +$http_worker->reusePort = true; +$http_worker->name = 'KumbiaPHP'; +$http_worker->onWorkerStart = static function () { kumbiaInit(); - //KuRaw::init(); + KuRaw::init(); }; $http_worker->onMessage = static function ($connection) { diff --git a/frameworks/PHP/laravel/.env b/frameworks/PHP/laravel/.env index 3bed03b2b6d..e29e1170f97 100644 --- a/frameworks/PHP/laravel/.env +++ b/frameworks/PHP/laravel/.env @@ -1,5 +1,5 @@ APP_NAME=Laravel -APP_ENV=local +APP_ENV=production APP_KEY=base64:JRW3D/imCqern1eNGYaRTmP8wixsi3gWRXTSIT1LGTQ= APP_DEBUG=false APP_URL=http://localhost diff --git a/frameworks/PHP/laravel/app/Http/Controllers/Controller.php b/frameworks/PHP/laravel/app/Http/Controllers/Controller.php index a2f98928316..bdc1312e3d4 100644 --- a/frameworks/PHP/laravel/app/Http/Controllers/Controller.php +++ b/frameworks/PHP/laravel/app/Http/Controllers/Controller.php @@ -52,7 +52,8 @@ public function updates($queries = 1) while ($queries--) { $row = World::query()->find(self::randomInt()); - $row->randomNumber = self::randomInt(); + while (($randomInt = self::randomInt()) === $row->randomNumber) {} + $row->randomNumber = $randomInt; $row->save(); $rows[] = $row; diff --git a/frameworks/PHP/laravel/benchmark_config.json b/frameworks/PHP/laravel/benchmark_config.json index 63c99532f2a..8a2f001e6c8 100644 --- a/frameworks/PHP/laravel/benchmark_config.json +++ b/frameworks/PHP/laravel/benchmark_config.json @@ -14,7 +14,7 @@ "database": "MySQL", "framework": "laravel", "language": "PHP", - "flavor": "PHP8.1", + "flavor": "PHP8", "orm": "Full", "platform": "FPM/FastCGI", "webserver": "nginx", @@ -37,13 +37,13 @@ "database": "MySQL", "framework": "laravel", "language": "PHP", - "flavor": "None", + "flavor": "PHP8", "orm": "Full", "platform": "swoole", "webserver": "none", "os": "Linux", "database_os": "Linux", - "display_name": "laravel-swoole", + "display_name": "laravel [octane,swoole]", "notes": "", "versus": "swoole" }, @@ -60,13 +60,13 @@ "database": "MySQL", "framework": "laravel", "language": "PHP", - "flavor": "None", + "flavor": "PHP8", "orm": "Full", "platform": "swoole", "webserver": "none", "os": "Linux", "database_os": "Linux", - "display_name": "laravel-laravel-s", + "display_name": "laravel [laravel-s]", "notes": "", "versus": "swoole" }, @@ -83,13 +83,13 @@ "database": "MySQL", "framework": "laravel", "language": "PHP", - "flavor": "None", + "flavor": "PHP8", "orm": "Full", "platform": "roadrunner", "webserver": "none", "os": "Linux", "database_os": "Linux", - "display_name": "laravel-roadrunner", + "display_name": "laravel [roadrunner]", "notes": "", "versus": "swoole" }, @@ -106,15 +106,62 @@ "database": "MySQL", "framework": "laravel", "language": "PHP", - "flavor": "PHP8.1", + "flavor": "PHP8", "orm": "Full", "platform": "workerman", "webserver": "None", "os": "Linux", "database_os": "Linux", - "display_name": "laravel-workerman", + "display_name": "laravel [workerman]", "notes": "", "versus": "php" + }, + "octane-frankenphp": { + "json_url": "/json", + "db_url": "/db", + "query_url": "/queries/", + "fortune_url": "/fortunes", + "update_url": "/updates/", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "database": "MySQL", + "framework": "laravel", + "language": "PHP", + "flavor": "PHP8", + "orm": "Full", + "platform": "Frankenphp", + "webserver": "caddy", + "os": "Linux", + "database_os": "Linux", + "display_name": "laravel [octane,frankenphp]", + "notes": "", + "versus": "php" + }, + "ripple": { + "json_url": "/json", + "db_url": "/db", + "query_url": "/queries/", + "fortune_url": "/fortunes", + "update_url": "/updates/", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "database": "MySQL", + "framework": "laravel", + "language": "PHP", + "flavor": "PHP8", + "orm": "Full", + "platform": "Ripple", + "webserver": "PServer", + "os": "Linux", + "database_os": "Linux", + "display_name": "laravel [ripple]", + "notes": "", + "versus": "php", + "tags": ["broken"] } }] -} \ No newline at end of file +} diff --git a/frameworks/PHP/laravel/composer.json b/frameworks/PHP/laravel/composer.json index 094026428e5..be731270c67 100644 --- a/frameworks/PHP/laravel/composer.json +++ b/frameworks/PHP/laravel/composer.json @@ -8,7 +8,7 @@ ], "license": "MIT", "require": { - "laravel/framework": "^10" + "laravel/framework": "^12" }, "config": { "optimize-autoloader": true, @@ -25,7 +25,23 @@ "App\\": "app/" } }, - "minimum-stability": "dev", + "replace": { + "symfony/polyfill-ctype": "*", + "symfony/polyfill-mbstring":"*", + "symfony/polyfill-intl-idn": "*", + "symfony/polyfill-intl-normalizer": "*", + "symfony/polyfill-intl-grapheme": "*", + "symfony/polyfill-iconv": "*", + "symfony/polyfill-php72": "*", + "symfony/polyfill-php73": "*", + "symfony/polyfill-php74": "*", + "symfony/polyfill-php80": "*", + "symfony/polyfill-php81": "*", + "symfony/polyfill-php82": "*", + "symfony/polyfill-php83": "*", + "symfony/polyfill-php84": "*" + }, + "minimum-stability": "stable", "prefer-stable": true, "scripts": { "post-autoload-dump": [ diff --git a/frameworks/PHP/laravel/config/app.php b/frameworks/PHP/laravel/config/app.php index eed03bfef75..de8547f82e1 100644 --- a/frameworks/PHP/laravel/config/app.php +++ b/frameworks/PHP/laravel/config/app.php @@ -142,7 +142,7 @@ // Illuminate\Redis\RedisServiceProvider::class, // Illuminate\Auth\Passwords\PasswordResetServiceProvider::class, // Illuminate\Session\SessionServiceProvider::class, - // Illuminate\Translation\TranslationServiceProvider::class, + Illuminate\Translation\TranslationServiceProvider::class, // Illuminate\Validation\ValidationServiceProvider::class, Illuminate\View\ViewServiceProvider::class, diff --git a/frameworks/PHP/laravel/config/octane.php b/frameworks/PHP/laravel/config/octane.php new file mode 100644 index 00000000000..9e7a655f37d --- /dev/null +++ b/frameworks/PHP/laravel/config/octane.php @@ -0,0 +1,7 @@ + [ + 'max_requests' => 10000, // Reload workers after requests + ], +]; diff --git a/frameworks/PHP/laravel/deploy/conf/cli-php.ini b/frameworks/PHP/laravel/deploy/conf/cli-php.ini index bcccffbc63b..e03b6e352a9 100644 --- a/frameworks/PHP/laravel/deploy/conf/cli-php.ini +++ b/frameworks/PHP/laravel/deploy/conf/cli-php.ini @@ -13,4 +13,4 @@ memory_limit = 512M opcache.jit_buffer_size = 128M opcache.jit = tracing -disable_functions=header,header_remove,headers_sent,http_response_code,setcookie,session_create_id,session_id,session_name,session_save_path,session_status,session_start,session_write_close,session_regenerate_id,set_time_limit +disable_functions=header,header_remove,headers_sent,headers_list,http_response_code,setcookie,session_create_id,session_id,session_name,session_save_path,session_status,session_start,session_write_close,session_regenerate_id,session_unset,session_get_cookie_params,session_set_cookie_params,set_time_limit diff --git a/frameworks/PHP/laravel/deploy/conf/php.ini b/frameworks/PHP/laravel/deploy/conf/php.ini index 82133535145..b7faa09421b 100644 --- a/frameworks/PHP/laravel/deploy/conf/php.ini +++ b/frameworks/PHP/laravel/deploy/conf/php.ini @@ -1767,17 +1767,17 @@ ldap.max_links = -1 opcache.enable=1 ; Determines if Zend OPCache is enabled for the CLI version of PHP -;opcache.enable_cli=0 +opcache.enable_cli=1 ; The OPcache shared memory storage size. -;opcache.memory_consumption=128 +opcache.memory_consumption=256 ; The amount of memory for interned strings in Mbytes. ;opcache.interned_strings_buffer=8 ; The maximum number of keys (scripts) in the OPcache hash table. ; Only numbers between 200 and 1000000 are allowed. -;opcache.max_accelerated_files=10000 +opcache.max_accelerated_files=20000 ; The maximum percentage of "wasted" memory until a restart is scheduled. ;opcache.max_wasted_percentage=5 @@ -1886,6 +1886,9 @@ opcache.huge_code_pages=1 ; Prevent name collisions in chroot'ed environment. ;opcache.validate_root=0 +opcache.preload_user=www-data +opcache.preload=/laravel/opcache_preload.php + [curl] ; A default value for the CURLOPT_CAINFO option. This is required to be an ; absolute path. diff --git a/frameworks/PHP/laravel/deploy/franken/Caddyfile b/frameworks/PHP/laravel/deploy/franken/Caddyfile new file mode 100644 index 00000000000..6c4cc54627c --- /dev/null +++ b/frameworks/PHP/laravel/deploy/franken/Caddyfile @@ -0,0 +1,24 @@ +{ + {$CADDY_GLOBAL_OPTIONS} + + admin {$CADDY_SERVER_ADMIN_HOST}:{$CADDY_SERVER_ADMIN_PORT} + + frankenphp { + worker "{$APP_PUBLIC_PATH}/frankenphp-worker.php" {$CADDY_SERVER_WORKER_COUNT} + } +} + +{$CADDY_SERVER_SERVER_NAME} { + route { + # Mercure configuration is injected here... + {$CADDY_SERVER_EXTRA_DIRECTIVES} + + # FrankenPHP! + # disable static files for this benchmark + # by using php instead of php_server + rewrite frankenphp-worker.php + php { + root "{$APP_PUBLIC_PATH}" + } + } +} diff --git a/frameworks/PHP/laravel/deploy/franken/php.ini b/frameworks/PHP/laravel/deploy/franken/php.ini new file mode 100644 index 00000000000..6254bf9b20e --- /dev/null +++ b/frameworks/PHP/laravel/deploy/franken/php.ini @@ -0,0 +1,1917 @@ +[PHP] + +;;;;;;;;;;;;;;;;;;; +; About php.ini ; +;;;;;;;;;;;;;;;;;;; +; PHP's initialization file, generally called php.ini, is responsible for +; configuring many of the aspects of PHP's behavior. + +; PHP attempts to find and load this configuration from a number of locations. +; The following is a summary of its search order: +; 1. SAPI module specific location. +; 2. The PHPRC environment variable. (As of PHP 5.2.0) +; 3. A number of predefined registry keys on Windows (As of PHP 5.2.0) +; 4. Current working directory (except CLI) +; 5. The web server's directory (for SAPI modules), or directory of PHP +; (otherwise in Windows) +; 6. The directory from the --with-config-file-path compile time option, or the +; Windows directory (C:\windows or C:\winnt) +; See the PHP docs for more specific information. +; http://php.net/configuration.file + +; The syntax of the file is extremely simple. Whitespace and lines +; beginning with a semicolon are silently ignored (as you probably guessed). +; Section headers (e.g. [Foo]) are also silently ignored, even though +; they might mean something in the future. + +; Directives following the section heading [PATH=/www/mysite] only +; apply to PHP files in the /www/mysite directory. Directives +; following the section heading [HOST=www.example.com] only apply to +; PHP files served from www.example.com. Directives set in these +; special sections cannot be overridden by user-defined INI files or +; at runtime. Currently, [PATH=] and [HOST=] sections only work under +; CGI/FastCGI. +; http://php.net/ini.sections + +; Directives are specified using the following syntax: +; directive = value +; Directive names are *case sensitive* - foo=bar is different from FOO=bar. +; Directives are variables used to configure PHP or PHP extensions. +; There is no name validation. If PHP can't find an expected +; directive because it is not set or is mistyped, a default value will be used. + +; The value can be a string, a number, a PHP constant (e.g. E_ALL or M_PI), one +; of the INI constants (On, Off, True, False, Yes, No and None) or an expression +; (e.g. E_ALL & ~E_NOTICE), a quoted string ("bar"), or a reference to a +; previously set variable or directive (e.g. ${foo}) + +; Expressions in the INI file are limited to bitwise operators and parentheses: +; | bitwise OR +; ^ bitwise XOR +; & bitwise AND +; ~ bitwise NOT +; ! boolean NOT + +; Boolean flags can be turned on using the values 1, On, True or Yes. +; They can be turned off using the values 0, Off, False or No. + +; An empty string can be denoted by simply not writing anything after the equal +; sign, or by using the None keyword: + +; foo = ; sets foo to an empty string +; foo = None ; sets foo to an empty string +; foo = "None" ; sets foo to the string 'None' + +; If you use constants in your value, and these constants belong to a +; dynamically loaded extension (either a PHP extension or a Zend extension), +; you may only use these constants *after* the line that loads the extension. + +;;;;;;;;;;;;;;;;;;; +; About this file ; +;;;;;;;;;;;;;;;;;;; +; PHP comes packaged with two INI files. One that is recommended to be used +; in production environments and one that is recommended to be used in +; development environments. + +; php.ini-production contains settings which hold security, performance and +; best practices at its core. But please be aware, these settings may break +; compatibility with older or less security conscience applications. We +; recommending using the production ini in production and testing environments. + +; php.ini-development is very similar to its production variant, except it is +; much more verbose when it comes to errors. We recommend using the +; development version only in development environments, as errors shown to +; application users can inadvertently leak otherwise secure information. + +; This is php.ini-production INI file. + +;;;;;;;;;;;;;;;;;;; +; Quick Reference ; +;;;;;;;;;;;;;;;;;;; +; The following are all the settings which are different in either the production +; or development versions of the INIs with respect to PHP's default behavior. +; Please see the actual settings later in the document for more details as to why +; we recommend these changes in PHP's behavior. + +; display_errors +; Default Value: On +; Development Value: On +; Production Value: Off + +; display_startup_errors +; Default Value: Off +; Development Value: On +; Production Value: Off + +; error_reporting +; Default Value: E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED +; Development Value: E_ALL +; Production Value: E_ALL & ~E_DEPRECATED & ~E_STRICT + +; html_errors +; Default Value: On +; Development Value: On +; Production value: On + +; log_errors +; Default Value: Off +; Development Value: On +; Production Value: On + +; max_input_time +; Default Value: -1 (Unlimited) +; Development Value: 60 (60 seconds) +; Production Value: 60 (60 seconds) + +; output_buffering +; Default Value: Off +; Development Value: 4096 +; Production Value: 4096 + +; register_argc_argv +; Default Value: On +; Development Value: Off +; Production Value: Off + +; request_order +; Default Value: None +; Development Value: "GP" +; Production Value: "GP" + +; session.gc_divisor +; Default Value: 100 +; Development Value: 1000 +; Production Value: 1000 + +; session.sid_bits_per_character +; Default Value: 4 +; Development Value: 5 +; Production Value: 5 + +; short_open_tag +; Default Value: On +; Development Value: Off +; Production Value: Off + +; track_errors +; Default Value: Off +; Development Value: On +; Production Value: Off + +; variables_order +; Default Value: "EGPCS" +; Development Value: "GPCS" +; Production Value: "GPCS" + +;;;;;;;;;;;;;;;;;;;; +; php.ini Options ; +;;;;;;;;;;;;;;;;;;;; +; Name for user-defined php.ini (.htaccess) files. Default is ".user.ini" +;user_ini.filename = ".user.ini" + +; To disable this feature set this option to empty value +;user_ini.filename = + +; TTL for user-defined php.ini files (time-to-live) in seconds. Default is 300 seconds (5 minutes) +;user_ini.cache_ttl = 300 + +;;;;;;;;;;;;;;;;;;;; +; Language Options ; +;;;;;;;;;;;;;;;;;;;; + +; Enable the PHP scripting language engine under Apache. +; http://php.net/engine +engine = On + +; This directive determines whether or not PHP will recognize code between +; tags as PHP source which should be processed as such. It is +; generally recommended that should be used and that this feature +; should be disabled, as enabling it may result in issues when generating XML +; documents, however this remains supported for backward compatibility reasons. +; Note that this directive does not control the would work. +; http://php.net/syntax-highlighting +;highlight.string = #DD0000 +;highlight.comment = #FF9900 +;highlight.keyword = #007700 +;highlight.default = #0000BB +;highlight.html = #000000 + +; If enabled, the request will be allowed to complete even if the user aborts +; the request. Consider enabling it if executing long requests, which may end up +; being interrupted by the user or a browser timing out. PHP's default behavior +; is to disable this feature. +; http://php.net/ignore-user-abort +;ignore_user_abort = On + +; Determines the size of the realpath cache to be used by PHP. This value should +; be increased on systems where PHP opens many files to reflect the quantity of +; the file operations performed. +; http://php.net/realpath-cache-size +realpath_cache_size = 4096k + +; Duration of time, in seconds for which to cache realpath information for a given +; file or directory. For systems with rarely changing files, consider increasing this +; value. +; http://php.net/realpath-cache-ttl +realpath_cache_ttl = 600 + +; Enables or disables the circular reference collector. +; http://php.net/zend.enable-gc +zend.enable_gc = On + +; If enabled, scripts may be written in encodings that are incompatible with +; the scanner. CP936, Big5, CP949 and Shift_JIS are the examples of such +; encodings. To use this feature, mbstring extension must be enabled. +; Default: Off +;zend.multibyte = Off + +; Allows to set the default encoding for the scripts. This value will be used +; unless "declare(encoding=...)" directive appears at the top of the script. +; Only affects if zend.multibyte is set. +; Default: "" +;zend.script_encoding = + +;;;;;;;;;;;;;;;;; +; Miscellaneous ; +;;;;;;;;;;;;;;;;; + +; Decides whether PHP may expose the fact that it is installed on the server +; (e.g. by adding its signature to the Web server header). It is no security +; threat in any way, but it makes it possible to determine whether you use PHP +; on your server or not. +; http://php.net/expose-php +expose_php = Off + +;;;;;;;;;;;;;;;;;;; +; Resource Limits ; +;;;;;;;;;;;;;;;;;;; + +; Maximum execution time of each script, in seconds +; http://php.net/max-execution-time +; Note: This directive is hardcoded to 0 for the CLI SAPI +max_execution_time = 30 + +; Maximum amount of time each script may spend parsing request data. It's a good +; idea to limit this time on productions servers in order to eliminate unexpectedly +; long running scripts. +; Note: This directive is hardcoded to -1 for the CLI SAPI +; Default Value: -1 (Unlimited) +; Development Value: 60 (60 seconds) +; Production Value: 60 (60 seconds) +; http://php.net/max-input-time +max_input_time = 60 + +; Maximum input variable nesting level +; http://php.net/max-input-nesting-level +;max_input_nesting_level = 64 + +; How many GET/POST/COOKIE input variables may be accepted +; max_input_vars = 1000 + +; Maximum amount of memory a script may consume (128MB) +; http://php.net/memory-limit +memory_limit = 128M + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Error handling and logging ; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +; This directive informs PHP of which errors, warnings and notices you would like +; it to take action for. The recommended way of setting values for this +; directive is through the use of the error level constants and bitwise +; operators. The error level constants are below here for convenience as well as +; some common settings and their meanings. +; By default, PHP is set to take action on all errors, notices and warnings EXCEPT +; those related to E_NOTICE and E_STRICT, which together cover best practices and +; recommended coding standards in PHP. For performance reasons, this is the +; recommend error reporting setting. Your production server shouldn't be wasting +; resources complaining about best practices and coding standards. That's what +; development servers and development settings are for. +; Note: The php.ini-development file has this setting as E_ALL. This +; means it pretty much reports everything which is exactly what you want during +; development and early testing. +; +; Error Level Constants: +; E_ALL - All errors and warnings (includes E_STRICT as of PHP 5.4.0) +; E_ERROR - fatal run-time errors +; E_RECOVERABLE_ERROR - almost fatal run-time errors +; E_WARNING - run-time warnings (non-fatal errors) +; E_PARSE - compile-time parse errors +; E_NOTICE - run-time notices (these are warnings which often result +; from a bug in your code, but it's possible that it was +; intentional (e.g., using an uninitialized variable and +; relying on the fact it is automatically initialized to an +; empty string) +; E_STRICT - run-time notices, enable to have PHP suggest changes +; to your code which will ensure the best interoperability +; and forward compatibility of your code +; E_CORE_ERROR - fatal errors that occur during PHP's initial startup +; E_CORE_WARNING - warnings (non-fatal errors) that occur during PHP's +; initial startup +; E_COMPILE_ERROR - fatal compile-time errors +; E_COMPILE_WARNING - compile-time warnings (non-fatal errors) +; E_USER_ERROR - user-generated error message +; E_USER_WARNING - user-generated warning message +; E_USER_NOTICE - user-generated notice message +; E_DEPRECATED - warn about code that will not work in future versions +; of PHP +; E_USER_DEPRECATED - user-generated deprecation warnings +; +; Common Values: +; E_ALL (Show all errors, warnings and notices including coding standards.) +; E_ALL & ~E_NOTICE (Show all errors, except for notices) +; E_ALL & ~E_NOTICE & ~E_STRICT (Show all errors, except for notices and coding standards warnings.) +; E_COMPILE_ERROR|E_RECOVERABLE_ERROR|E_ERROR|E_CORE_ERROR (Show only errors) +; Default Value: E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED +; Development Value: E_ALL +; Production Value: E_ALL & ~E_DEPRECATED & ~E_STRICT +; http://php.net/error-reporting +error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT + +; This directive controls whether or not and where PHP will output errors, +; notices and warnings too. Error output is very useful during development, but +; it could be very dangerous in production environments. Depending on the code +; which is triggering the error, sensitive information could potentially leak +; out of your application such as database usernames and passwords or worse. +; For production environments, we recommend logging errors rather than +; sending them to STDOUT. +; Possible Values: +; Off = Do not display any errors +; stderr = Display errors to STDERR (affects only CGI/CLI binaries!) +; On or stdout = Display errors to STDOUT +; Default Value: On +; Development Value: On +; Production Value: Off +; http://php.net/display-errors +display_errors = Off + +; The display of errors which occur during PHP's startup sequence are handled +; separately from display_errors. PHP's default behavior is to suppress those +; errors from clients. Turning the display of startup errors on can be useful in +; debugging configuration problems. We strongly recommend you +; set this to 'off' for production servers. +; Default Value: Off +; Development Value: On +; Production Value: Off +; http://php.net/display-startup-errors +display_startup_errors = Off + +; Besides displaying errors, PHP can also log errors to locations such as a +; server-specific log, STDERR, or a location specified by the error_log +; directive found below. While errors should not be displayed on productions +; servers they should still be monitored and logging is a great way to do that. +; Default Value: Off +; Development Value: On +; Production Value: On +; http://php.net/log-errors +log_errors = On + +; Set maximum length of log_errors. In error_log information about the source is +; added. The default is 1024 and 0 allows to not apply any maximum length at all. +; http://php.net/log-errors-max-len +log_errors_max_len = 1024 + +; Do not log repeated messages. Repeated errors must occur in same file on same +; line unless ignore_repeated_source is set true. +; http://php.net/ignore-repeated-errors +ignore_repeated_errors = Off + +; Ignore source of message when ignoring repeated messages. When this setting +; is On you will not log errors with repeated messages from different files or +; source lines. +; http://php.net/ignore-repeated-source +ignore_repeated_source = Off + +; If this parameter is set to Off, then memory leaks will not be shown (on +; stdout or in the log). This has only effect in a debug compile, and if +; error reporting includes E_WARNING in the allowed list +; http://php.net/report-memleaks +report_memleaks = On + +; This setting is on by default. +;report_zend_debug = 0 + +; Store the last error/warning message in $php_errormsg (boolean). Setting this value +; to On can assist in debugging and is appropriate for development servers. It should +; however be disabled on production servers. +; This directive is DEPRECATED. +; Default Value: Off +; Development Value: Off +; Production Value: Off +; http://php.net/track-errors +;track_errors = Off + +; Turn off normal error reporting and emit XML-RPC error XML +; http://php.net/xmlrpc-errors +;xmlrpc_errors = 0 + +; An XML-RPC faultCode +;xmlrpc_error_number = 0 + +; When PHP displays or logs an error, it has the capability of formatting the +; error message as HTML for easier reading. This directive controls whether +; the error message is formatted as HTML or not. +; Note: This directive is hardcoded to Off for the CLI SAPI +; Default Value: On +; Development Value: On +; Production value: On +; http://php.net/html-errors +html_errors = On + +; If html_errors is set to On *and* docref_root is not empty, then PHP +; produces clickable error messages that direct to a page describing the error +; or function causing the error in detail. +; You can download a copy of the PHP manual from http://php.net/docs +; and change docref_root to the base URL of your local copy including the +; leading '/'. You must also specify the file extension being used including +; the dot. PHP's default behavior is to leave these settings empty, in which +; case no links to documentation are generated. +; Note: Never use this feature for production boxes. +; http://php.net/docref-root +; Examples +;docref_root = "/phpmanual/" + +; http://php.net/docref-ext +;docref_ext = .html + +; String to output before an error message. PHP's default behavior is to leave +; this setting blank. +; http://php.net/error-prepend-string +; Example: +;error_prepend_string = "" + +; String to output after an error message. PHP's default behavior is to leave +; this setting blank. +; http://php.net/error-append-string +; Example: +;error_append_string = "" + +; Log errors to specified file. PHP's default behavior is to leave this value +; empty. +; http://php.net/error-log +; Example: +;error_log = php_errors.log +; Log errors to syslog (Event Log on Windows). +;error_log = syslog + +;windows.show_crt_warning +; Default value: 0 +; Development value: 0 +; Production value: 0 + +;;;;;;;;;;;;;;;;; +; Data Handling ; +;;;;;;;;;;;;;;;;; + +; The separator used in PHP generated URLs to separate arguments. +; PHP's default setting is "&". +; http://php.net/arg-separator.output +; Example: +;arg_separator.output = "&" + +; List of separator(s) used by PHP to parse input URLs into variables. +; PHP's default setting is "&". +; NOTE: Every character in this directive is considered as separator! +; http://php.net/arg-separator.input +; Example: +;arg_separator.input = ";&" + +; This directive determines which super global arrays are registered when PHP +; starts up. G,P,C,E & S are abbreviations for the following respective super +; globals: GET, POST, COOKIE, ENV and SERVER. There is a performance penalty +; paid for the registration of these arrays and because ENV is not as commonly +; used as the others, ENV is not recommended on productions servers. You +; can still get access to the environment variables through getenv() should you +; need to. +; Default Value: "EGPCS" +; Development Value: "GPCS" +; Production Value: "GPCS"; +; http://php.net/variables-order +variables_order = "GPCS" + +; This directive determines which super global data (G,P & C) should be +; registered into the super global array REQUEST. If so, it also determines +; the order in which that data is registered. The values for this directive +; are specified in the same manner as the variables_order directive, +; EXCEPT one. Leaving this value empty will cause PHP to use the value set +; in the variables_order directive. It does not mean it will leave the super +; globals array REQUEST empty. +; Default Value: None +; Development Value: "GP" +; Production Value: "GP" +; http://php.net/request-order +request_order = "GP" + +; This directive determines whether PHP registers $argv & $argc each time it +; runs. $argv contains an array of all the arguments passed to PHP when a script +; is invoked. $argc contains an integer representing the number of arguments +; that were passed when the script was invoked. These arrays are extremely +; useful when running scripts from the command line. When this directive is +; enabled, registering these variables consumes CPU cycles and memory each time +; a script is executed. For performance reasons, this feature should be disabled +; on production servers. +; Note: This directive is hardcoded to On for the CLI SAPI +; Default Value: On +; Development Value: Off +; Production Value: Off +; http://php.net/register-argc-argv +register_argc_argv = Off + +; When enabled, the ENV, REQUEST and SERVER variables are created when they're +; first used (Just In Time) instead of when the script starts. If these +; variables are not used within a script, having this directive on will result +; in a performance gain. The PHP directive register_argc_argv must be disabled +; for this directive to have any affect. +; http://php.net/auto-globals-jit +auto_globals_jit = On + +; Whether PHP will read the POST data. +; This option is enabled by default. +; Most likely, you won't want to disable this option globally. It causes $_POST +; and $_FILES to always be empty; the only way you will be able to read the +; POST data will be through the php://input stream wrapper. This can be useful +; to proxy requests or to process the POST data in a memory efficient fashion. +; http://php.net/enable-post-data-reading +;enable_post_data_reading = Off + +; Maximum size of POST data that PHP will accept. +; Its value may be 0 to disable the limit. It is ignored if POST data reading +; is disabled through enable_post_data_reading. +; http://php.net/post-max-size +post_max_size = 8M + +; Automatically add files before PHP document. +; http://php.net/auto-prepend-file +auto_prepend_file = + +; Automatically add files after PHP document. +; http://php.net/auto-append-file +auto_append_file = + +; By default, PHP will output a media type using the Content-Type header. To +; disable this, simply set it to be empty. +; +; PHP's built-in default media type is set to text/html. +; http://php.net/default-mimetype +default_mimetype = "text/html" + +; PHP's default character set is set to UTF-8. +; http://php.net/default-charset +default_charset = "UTF-8" + +; PHP internal character encoding is set to empty. +; If empty, default_charset is used. +; http://php.net/internal-encoding +;internal_encoding = + +; PHP input character encoding is set to empty. +; If empty, default_charset is used. +; http://php.net/input-encoding +;input_encoding = + +; PHP output character encoding is set to empty. +; If empty, default_charset is used. +; See also output_buffer. +; http://php.net/output-encoding +;output_encoding = + +;;;;;;;;;;;;;;;;;;;;;;;;; +; Paths and Directories ; +;;;;;;;;;;;;;;;;;;;;;;;;; + +; UNIX: "/path1:/path2" +;include_path = ".:/usr/share/php" +; +; Windows: "\path1;\path2" +;include_path = ".;c:\php\includes" +; +; PHP's default setting for include_path is ".;/path/to/php/pear" +; http://php.net/include-path + +; The root of the PHP pages, used only if nonempty. +; if PHP was not compiled with FORCE_REDIRECT, you SHOULD set doc_root +; if you are running php as a CGI under any web server (other than IIS) +; see documentation for security issues. The alternate is to use the +; cgi.force_redirect configuration below +; http://php.net/doc-root +doc_root = + +; The directory under which PHP opens the script using /~username used only +; if nonempty. +; http://php.net/user-dir +user_dir = + +; Directory in which the loadable extensions (modules) reside. +; http://php.net/extension-dir +; extension_dir = "./" +; On windows: +; extension_dir = "ext" + +; Directory where the temporary files should be placed. +; Defaults to the system default (see sys_get_temp_dir) +; sys_temp_dir = "/tmp" + +; Whether or not to enable the dl() function. The dl() function does NOT work +; properly in multithreaded servers, such as IIS or Zeus, and is automatically +; disabled on them. +; http://php.net/enable-dl +enable_dl = Off + +; cgi.force_redirect is necessary to provide security running PHP as a CGI under +; most web servers. Left undefined, PHP turns this on by default. You can +; turn it off here AT YOUR OWN RISK +; **You CAN safely turn this off for IIS, in fact, you MUST.** +; http://php.net/cgi.force-redirect +;cgi.force_redirect = 1 + +; if cgi.nph is enabled it will force cgi to always sent Status: 200 with +; every request. PHP's default behavior is to disable this feature. +;cgi.nph = 1 + +; if cgi.force_redirect is turned on, and you are not running under Apache or Netscape +; (iPlanet) web servers, you MAY need to set an environment variable name that PHP +; will look for to know it is OK to continue execution. Setting this variable MAY +; cause security issues, KNOW WHAT YOU ARE DOING FIRST. +; http://php.net/cgi.redirect-status-env +;cgi.redirect_status_env = + +; cgi.fix_pathinfo provides *real* PATH_INFO/PATH_TRANSLATED support for CGI. PHP's +; previous behaviour was to set PATH_TRANSLATED to SCRIPT_FILENAME, and to not grok +; what PATH_INFO is. For more information on PATH_INFO, see the cgi specs. Setting +; this to 1 will cause PHP CGI to fix its paths to conform to the spec. A setting +; of zero causes PHP to behave as before. Default is 1. You should fix your scripts +; to use SCRIPT_FILENAME rather than PATH_TRANSLATED. +; http://php.net/cgi.fix-pathinfo + cgi.fix_pathinfo=0 + +; if cgi.discard_path is enabled, the PHP CGI binary can safely be placed outside +; of the web tree and people will not be able to circumvent .htaccess security. +; http://php.net/cgi.dicard-path +;cgi.discard_path=1 + +; FastCGI under IIS (on WINNT based OS) supports the ability to impersonate +; security tokens of the calling client. This allows IIS to define the +; security context that the request runs under. mod_fastcgi under Apache +; does not currently support this feature (03/17/2002) +; Set to 1 if running under IIS. Default is zero. +; http://php.net/fastcgi.impersonate +;fastcgi.impersonate = 1 + +; Disable logging through FastCGI connection. PHP's default behavior is to enable +; this feature. +;fastcgi.logging = 0 + +; cgi.rfc2616_headers configuration option tells PHP what type of headers to +; use when sending HTTP response code. If set to 0, PHP sends Status: header that +; is supported by Apache. When this option is set to 1, PHP will send +; RFC2616 compliant header. +; Default is zero. +; http://php.net/cgi.rfc2616-headers +;cgi.rfc2616_headers = 0 + +; cgi.check_shebang_line controls whether CGI PHP checks for line starting with #! +; (shebang) at the top of the running script. This line might be needed if the +; script support running both as stand-alone script and via PHP CGI<. PHP in CGI +; mode skips this line and ignores its content if this directive is turned on. +; http://php.net/cgi.check-shebang-line +;cgi.check_shebang_line=1 + +;;;;;;;;;;;;;;;; +; File Uploads ; +;;;;;;;;;;;;;;;; + +; Whether to allow HTTP file uploads. +; http://php.net/file-uploads +file_uploads = On + +; Temporary directory for HTTP uploaded files (will use system default if not +; specified). +; http://php.net/upload-tmp-dir +;upload_tmp_dir = + +; Maximum allowed size for uploaded files. +; http://php.net/upload-max-filesize +upload_max_filesize = 2M + +; Maximum number of files that can be uploaded via a single request +max_file_uploads = 20 + +;;;;;;;;;;;;;;;;;; +; Fopen wrappers ; +;;;;;;;;;;;;;;;;;; + +; Whether to allow the treatment of URLs (like http:// or ftp://) as files. +; http://php.net/allow-url-fopen +allow_url_fopen = On + +; Whether to allow include/require to open URLs (like http:// or ftp://) as files. +; http://php.net/allow-url-include +allow_url_include = Off + +; Define the anonymous ftp password (your email address). PHP's default setting +; for this is empty. +; http://php.net/from +;from="john@doe.com" + +; Define the User-Agent string. PHP's default setting for this is empty. +; http://php.net/user-agent +;user_agent="PHP" + +; Default timeout for socket based streams (seconds) +; http://php.net/default-socket-timeout +default_socket_timeout = 60 + +; If your scripts have to deal with files from Macintosh systems, +; or you are running on a Mac and need to deal with files from +; unix or win32 systems, setting this flag will cause PHP to +; automatically detect the EOL character in those files so that +; fgets() and file() will work regardless of the source of the file. +; http://php.net/auto-detect-line-endings +;auto_detect_line_endings = Off + +;;;;;;;;;;;;;;;;;;;;;; +; Dynamic Extensions ; +;;;;;;;;;;;;;;;;;;;;;; + +; If you wish to have an extension loaded automatically, use the following +; syntax: +; +; extension=modulename +; +; For example: +; +; extension=mysqli +; +; When the extension library to load is not located in the default extension +; directory, You may specify an absolute path to the library file: +; +; extension=/path/to/extension/mysqli.so +; +; Note : The syntax used in previous PHP versions ('extension=.so' and +; 'extension='php_.dll') is supported for legacy reasons and may be +; deprecated in a future PHP major version. So, when it is possible, please +; move to the new ('extension=) syntax. +; +; Notes for Windows environments : +; +; - ODBC support is built in, so no dll is needed for it. +; - Many DLL files are located in the extensions/ (PHP 4) or ext/ (PHP 5+) +; extension folders as well as the separate PECL DLL download (PHP 5+). +; Be sure to appropriately set the extension_dir directive. +; +;extension=bz2 +;extension=curl +;extension=fileinfo +;extension=gd2 +;extension=gettext +;extension=gmp +;extension=intl +;extension=imap +;extension=interbase +;extension=ldap +;extension=mbstring +;extension=exif ; Must be after mbstring as it depends on it +;extension=mysqli +;extension=oci8_12c ; Use with Oracle Database 12c Instant Client +;extension=openssl +;extension=pdo_firebird +;extension=pdo_mysql +;extension=pdo_oci +;extension=pdo_odbc +;extension=pdo_pgsql +;extension=pdo_sqlite +;extension=pgsql +;extension=shmop + +; The MIBS data available in the PHP distribution must be installed. +; See http://www.php.net/manual/en/snmp.installation.php +;extension=snmp + +;extension=soap +;extension=sockets +;extension=sqlite3 +;extension=tidy +;extension=xmlrpc +;extension=xsl + +;;;;;;;;;;;;;;;;;;; +; Module Settings ; +;;;;;;;;;;;;;;;;;;; + +[CLI Server] +; Whether the CLI web server uses ANSI color coding in its terminal output. +cli_server.color = On + +[Date] +; Defines the default timezone used by the date functions +; http://php.net/date.timezone +date.timezone = UTC + +; http://php.net/date.default-latitude +;date.default_latitude = 31.7667 + +; http://php.net/date.default-longitude +;date.default_longitude = 35.2333 + +; http://php.net/date.sunrise-zenith +;date.sunrise_zenith = 90.583333 + +; http://php.net/date.sunset-zenith +;date.sunset_zenith = 90.583333 + +[filter] +; http://php.net/filter.default +;filter.default = unsafe_raw + +; http://php.net/filter.default-flags +;filter.default_flags = + +[iconv] +; Use of this INI entry is deprecated, use global input_encoding instead. +; If empty, default_charset or input_encoding or iconv.input_encoding is used. +; The precedence is: default_charset < intput_encoding < iconv.input_encoding +;iconv.input_encoding = + +; Use of this INI entry is deprecated, use global internal_encoding instead. +; If empty, default_charset or internal_encoding or iconv.internal_encoding is used. +; The precedence is: default_charset < internal_encoding < iconv.internal_encoding +;iconv.internal_encoding = + +; Use of this INI entry is deprecated, use global output_encoding instead. +; If empty, default_charset or output_encoding or iconv.output_encoding is used. +; The precedence is: default_charset < output_encoding < iconv.output_encoding +; To use an output encoding conversion, iconv's output handler must be set +; otherwise output encoding conversion cannot be performed. +;iconv.output_encoding = + +[intl] +;intl.default_locale = +; This directive allows you to produce PHP errors when some error +; happens within intl functions. The value is the level of the error produced. +; Default is 0, which does not produce any errors. +;intl.error_level = E_WARNING +;intl.use_exceptions = 0 + +[sqlite3] +;sqlite3.extension_dir = + +[Pcre] +;PCRE library backtracking limit. +; http://php.net/pcre.backtrack-limit +;pcre.backtrack_limit=100000 + +;PCRE library recursion limit. +;Please note that if you set this value to a high number you may consume all +;the available process stack and eventually crash PHP (due to reaching the +;stack size limit imposed by the Operating System). +; http://php.net/pcre.recursion-limit +;pcre.recursion_limit=100000 + +;Enables or disables JIT compilation of patterns. This requires the PCRE +;library to be compiled with JIT support. +;pcre.jit=1 + +[Pdo] +; Whether to pool ODBC connections. Can be one of "strict", "relaxed" or "off" +; http://php.net/pdo-odbc.connection-pooling +;pdo_odbc.connection_pooling=strict + +;pdo_odbc.db2_instance_name + +[Pdo_mysql] +; If mysqlnd is used: Number of cache slots for the internal result set cache +; http://php.net/pdo_mysql.cache_size +pdo_mysql.cache_size = 2000 + +; Default socket name for local MySQL connects. If empty, uses the built-in +; MySQL defaults. +; http://php.net/pdo_mysql.default-socket +pdo_mysql.default_socket= + +[Phar] +; http://php.net/phar.readonly +;phar.readonly = On + +; http://php.net/phar.require-hash +;phar.require_hash = On + +;phar.cache_list = + +[mail function] +; For Win32 only. +; http://php.net/smtp +SMTP = localhost +; http://php.net/smtp-port +smtp_port = 25 + +; For Win32 only. +; http://php.net/sendmail-from +;sendmail_from = me@example.com + +; For Unix only. You may supply arguments as well (default: "sendmail -t -i"). +; http://php.net/sendmail-path +;sendmail_path = + +; Force the addition of the specified parameters to be passed as extra parameters +; to the sendmail binary. These parameters will always replace the value of +; the 5th parameter to mail(). +;mail.force_extra_parameters = + +; Add X-PHP-Originating-Script: that will include uid of the script followed by the filename +mail.add_x_header = On + +; The path to a log file that will log all mail() calls. Log entries include +; the full path of the script, line number, To address and headers. +;mail.log = +; Log mail to syslog (Event Log on Windows). +;mail.log = syslog + +[ODBC] +; http://php.net/odbc.default-db +;odbc.default_db = Not yet implemented + +; http://php.net/odbc.default-user +;odbc.default_user = Not yet implemented + +; http://php.net/odbc.default-pw +;odbc.default_pw = Not yet implemented + +; Controls the ODBC cursor model. +; Default: SQL_CURSOR_STATIC (default). +;odbc.default_cursortype + +; Allow or prevent persistent links. +; http://php.net/odbc.allow-persistent +odbc.allow_persistent = On + +; Check that a connection is still valid before reuse. +; http://php.net/odbc.check-persistent +odbc.check_persistent = On + +; Maximum number of persistent links. -1 means no limit. +; http://php.net/odbc.max-persistent +odbc.max_persistent = -1 + +; Maximum number of links (persistent + non-persistent). -1 means no limit. +; http://php.net/odbc.max-links +odbc.max_links = -1 + +; Handling of LONG fields. Returns number of bytes to variables. 0 means +; passthru. +; http://php.net/odbc.defaultlrl +odbc.defaultlrl = 4096 + +; Handling of binary data. 0 means passthru, 1 return as is, 2 convert to char. +; See the documentation on odbc_binmode and odbc_longreadlen for an explanation +; of odbc.defaultlrl and odbc.defaultbinmode +; http://php.net/odbc.defaultbinmode +odbc.defaultbinmode = 1 + +;birdstep.max_links = -1 + +[Interbase] +; Allow or prevent persistent links. +ibase.allow_persistent = 1 + +; Maximum number of persistent links. -1 means no limit. +ibase.max_persistent = -1 + +; Maximum number of links (persistent + non-persistent). -1 means no limit. +ibase.max_links = -1 + +; Default database name for ibase_connect(). +;ibase.default_db = + +; Default username for ibase_connect(). +;ibase.default_user = + +; Default password for ibase_connect(). +;ibase.default_password = + +; Default charset for ibase_connect(). +;ibase.default_charset = + +; Default timestamp format. +ibase.timestampformat = "%Y-%m-%d %H:%M:%S" + +; Default date format. +ibase.dateformat = "%Y-%m-%d" + +; Default time format. +ibase.timeformat = "%H:%M:%S" + +[MySQLi] + +; Maximum number of persistent links. -1 means no limit. +; http://php.net/mysqli.max-persistent +mysqli.max_persistent = -1 + +; Allow accessing, from PHP's perspective, local files with LOAD DATA statements +; http://php.net/mysqli.allow_local_infile +;mysqli.allow_local_infile = On + +; Allow or prevent persistent links. +; http://php.net/mysqli.allow-persistent +mysqli.allow_persistent = On + +; Maximum number of links. -1 means no limit. +; http://php.net/mysqli.max-links +mysqli.max_links = -1 + +; If mysqlnd is used: Number of cache slots for the internal result set cache +; http://php.net/mysqli.cache_size +mysqli.cache_size = 2000 + +; Default port number for mysqli_connect(). If unset, mysqli_connect() will use +; the $MYSQL_TCP_PORT or the mysql-tcp entry in /etc/services or the +; compile-time value defined MYSQL_PORT (in that order). Win32 will only look +; at MYSQL_PORT. +; http://php.net/mysqli.default-port +mysqli.default_port = 3306 + +; Default socket name for local MySQL connects. If empty, uses the built-in +; MySQL defaults. +; http://php.net/mysqli.default-socket +mysqli.default_socket = + +; Default host for mysql_connect() (doesn't apply in safe mode). +; http://php.net/mysqli.default-host +mysqli.default_host = + +; Default user for mysql_connect() (doesn't apply in safe mode). +; http://php.net/mysqli.default-user +mysqli.default_user = + +; Default password for mysqli_connect() (doesn't apply in safe mode). +; Note that this is generally a *bad* idea to store passwords in this file. +; *Any* user with PHP access can run 'echo get_cfg_var("mysqli.default_pw") +; and reveal this password! And of course, any users with read access to this +; file will be able to reveal the password as well. +; http://php.net/mysqli.default-pw +mysqli.default_pw = + +; Allow or prevent reconnect +mysqli.reconnect = Off + +[mysqlnd] +; Enable / Disable collection of general statistics by mysqlnd which can be +; used to tune and monitor MySQL operations. +; http://php.net/mysqlnd.collect_statistics +mysqlnd.collect_statistics = Off + +; Enable / Disable collection of memory usage statistics by mysqlnd which can be +; used to tune and monitor MySQL operations. +; http://php.net/mysqlnd.collect_memory_statistics +mysqlnd.collect_memory_statistics = Off + +; Records communication from all extensions using mysqlnd to the specified log +; file. +; http://php.net/mysqlnd.debug +;mysqlnd.debug = + +; Defines which queries will be logged. +; http://php.net/mysqlnd.log_mask +;mysqlnd.log_mask = 0 + +; Default size of the mysqlnd memory pool, which is used by result sets. +; http://php.net/mysqlnd.mempool_default_size +;mysqlnd.mempool_default_size = 16000 + +; Size of a pre-allocated buffer used when sending commands to MySQL in bytes. +; http://php.net/mysqlnd.net_cmd_buffer_size +;mysqlnd.net_cmd_buffer_size = 2048 + +; Size of a pre-allocated buffer used for reading data sent by the server in +; bytes. +; http://php.net/mysqlnd.net_read_buffer_size +;mysqlnd.net_read_buffer_size = 32768 + +; Timeout for network requests in seconds. +; http://php.net/mysqlnd.net_read_timeout +;mysqlnd.net_read_timeout = 31536000 + +; SHA-256 Authentication Plugin related. File with the MySQL server public RSA +; key. +; http://php.net/mysqlnd.sha256_server_public_key +;mysqlnd.sha256_server_public_key = + +[OCI8] + +; Connection: Enables privileged connections using external +; credentials (OCI_SYSOPER, OCI_SYSDBA) +; http://php.net/oci8.privileged-connect +;oci8.privileged_connect = Off + +; Connection: The maximum number of persistent OCI8 connections per +; process. Using -1 means no limit. +; http://php.net/oci8.max-persistent +;oci8.max_persistent = -1 + +; Connection: The maximum number of seconds a process is allowed to +; maintain an idle persistent connection. Using -1 means idle +; persistent connections will be maintained forever. +; http://php.net/oci8.persistent-timeout +;oci8.persistent_timeout = -1 + +; Connection: The number of seconds that must pass before issuing a +; ping during oci_pconnect() to check the connection validity. When +; set to 0, each oci_pconnect() will cause a ping. Using -1 disables +; pings completely. +; http://php.net/oci8.ping-interval +;oci8.ping_interval = 60 + +; Connection: Set this to a user chosen connection class to be used +; for all pooled server requests with Oracle 11g Database Resident +; Connection Pooling (DRCP). To use DRCP, this value should be set to +; the same string for all web servers running the same application, +; the database pool must be configured, and the connection string must +; specify to use a pooled server. +;oci8.connection_class = + +; High Availability: Using On lets PHP receive Fast Application +; Notification (FAN) events generated when a database node fails. The +; database must also be configured to post FAN events. +;oci8.events = Off + +; Tuning: This option enables statement caching, and specifies how +; many statements to cache. Using 0 disables statement caching. +; http://php.net/oci8.statement-cache-size +;oci8.statement_cache_size = 20 + +; Tuning: Enables statement prefetching and sets the default number of +; rows that will be fetched automatically after statement execution. +; http://php.net/oci8.default-prefetch +;oci8.default_prefetch = 100 + +; Compatibility. Using On means oci_close() will not close +; oci_connect() and oci_new_connect() connections. +; http://php.net/oci8.old-oci-close-semantics +;oci8.old_oci_close_semantics = Off + +[PostgreSQL] +; Allow or prevent persistent links. +; http://php.net/pgsql.allow-persistent +pgsql.allow_persistent = On + +; Detect broken persistent links always with pg_pconnect(). +; Auto reset feature requires a little overheads. +; http://php.net/pgsql.auto-reset-persistent +pgsql.auto_reset_persistent = Off + +; Maximum number of persistent links. -1 means no limit. +; http://php.net/pgsql.max-persistent +pgsql.max_persistent = -1 + +; Maximum number of links (persistent+non persistent). -1 means no limit. +; http://php.net/pgsql.max-links +pgsql.max_links = -1 + +; Ignore PostgreSQL backends Notice message or not. +; Notice message logging require a little overheads. +; http://php.net/pgsql.ignore-notice +pgsql.ignore_notice = 0 + +; Log PostgreSQL backends Notice message or not. +; Unless pgsql.ignore_notice=0, module cannot log notice message. +; http://php.net/pgsql.log-notice +pgsql.log_notice = 0 + +[bcmath] +; Number of decimal digits for all bcmath functions. +; http://php.net/bcmath.scale +bcmath.scale = 0 + +[browscap] +; http://php.net/browscap +;browscap = extra/browscap.ini + +[Session] +; Handler used to store/retrieve data. +; http://php.net/session.save-handler +session.save_handler = files + +; Argument passed to save_handler. In the case of files, this is the path +; where data files are stored. Note: Windows users have to change this +; variable in order to use PHP's session functions. +; +; The path can be defined as: +; +; session.save_path = "N;/path" +; +; where N is an integer. Instead of storing all the session files in +; /path, what this will do is use subdirectories N-levels deep, and +; store the session data in those directories. This is useful if +; your OS has problems with many files in one directory, and is +; a more efficient layout for servers that handle many sessions. +; +; NOTE 1: PHP will not create this directory structure automatically. +; You can use the script in the ext/session dir for that purpose. +; NOTE 2: See the section on garbage collection below if you choose to +; use subdirectories for session storage +; +; The file storage module creates files using mode 600 by default. +; You can change that by using +; +; session.save_path = "N;MODE;/path" +; +; where MODE is the octal representation of the mode. Note that this +; does not overwrite the process's umask. +; http://php.net/session.save-path +;session.save_path = "/var/lib/php/sessions" + +; Whether to use strict session mode. +; Strict session mode does not accept uninitialized session ID and regenerate +; session ID if browser sends uninitialized session ID. Strict mode protects +; applications from session fixation via session adoption vulnerability. It is +; disabled by default for maximum compatibility, but enabling it is encouraged. +; https://wiki.php.net/rfc/strict_sessions +session.use_strict_mode = 0 + +; Whether to use cookies. +; http://php.net/session.use-cookies +session.use_cookies = 1 + +; http://php.net/session.cookie-secure +;session.cookie_secure = + +; This option forces PHP to fetch and use a cookie for storing and maintaining +; the session id. We encourage this operation as it's very helpful in combating +; session hijacking when not specifying and managing your own session id. It is +; not the be-all and end-all of session hijacking defense, but it's a good start. +; http://php.net/session.use-only-cookies +session.use_only_cookies = 1 + +; Name of the session (used as cookie name). +; http://php.net/session.name +session.name = PHPSESSID + +; Initialize session on request startup. +; http://php.net/session.auto-start +session.auto_start = 0 + +; Lifetime in seconds of cookie or, if 0, until browser is restarted. +; http://php.net/session.cookie-lifetime +session.cookie_lifetime = 0 + +; The path for which the cookie is valid. +; http://php.net/session.cookie-path +session.cookie_path = / + +; The domain for which the cookie is valid. +; http://php.net/session.cookie-domain +session.cookie_domain = + +; Whether or not to add the httpOnly flag to the cookie, which makes it inaccessible to browser scripting languages such as JavaScript. +; http://php.net/session.cookie-httponly +session.cookie_httponly = + +; Handler used to serialize data. php is the standard serializer of PHP. +; http://php.net/session.serialize-handler +session.serialize_handler = php + +; Defines the probability that the 'garbage collection' process is started +; on every session initialization. The probability is calculated by using +; gc_probability/gc_divisor. Where session.gc_probability is the numerator +; and gc_divisor is the denominator in the equation. Setting this value to 1 +; when the session.gc_divisor value is 100 will give you approximately a 1% chance +; the gc will run on any give request. +; Default Value: 1 +; Development Value: 1 +; Production Value: 1 +; http://php.net/session.gc-probability +session.gc_probability = 0 + +; Defines the probability that the 'garbage collection' process is started on every +; session initialization. The probability is calculated by using the following equation: +; gc_probability/gc_divisor. Where session.gc_probability is the numerator and +; session.gc_divisor is the denominator in the equation. Setting this value to 1 +; when the session.gc_divisor value is 100 will give you approximately a 1% chance +; the gc will run on any give request. Increasing this value to 1000 will give you +; a 0.1% chance the gc will run on any give request. For high volume production servers, +; this is a more efficient approach. +; Default Value: 100 +; Development Value: 1000 +; Production Value: 1000 +; http://php.net/session.gc-divisor +session.gc_divisor = 1000 + +; After this number of seconds, stored data will be seen as 'garbage' and +; cleaned up by the garbage collection process. +; http://php.net/session.gc-maxlifetime +session.gc_maxlifetime = 1440 + +; NOTE: If you are using the subdirectory option for storing session files +; (see session.save_path above), then garbage collection does *not* +; happen automatically. You will need to do your own garbage +; collection through a shell script, cron entry, or some other method. +; For example, the following script would is the equivalent of +; setting session.gc_maxlifetime to 1440 (1440 seconds = 24 minutes): +; find /path/to/sessions -cmin +24 -type f | xargs rm + +; Check HTTP Referer to invalidate externally stored URLs containing ids. +; HTTP_REFERER has to contain this substring for the session to be +; considered as valid. +; http://php.net/session.referer-check +session.referer_check = + +; Set to {nocache,private,public,} to determine HTTP caching aspects +; or leave this empty to avoid sending anti-caching headers. +; http://php.net/session.cache-limiter +session.cache_limiter = nocache + +; Document expires after n minutes. +; http://php.net/session.cache-expire +session.cache_expire = 180 + +; trans sid support is disabled by default. +; Use of trans sid may risk your users' security. +; Use this option with caution. +; - User may send URL contains active session ID +; to other person via. email/irc/etc. +; - URL that contains active session ID may be stored +; in publicly accessible computer. +; - User may access your site with the same session ID +; always using URL stored in browser's history or bookmarks. +; http://php.net/session.use-trans-sid +session.use_trans_sid = 0 + +; Set session ID character length. This value could be between 22 to 256. +; Shorter length than default is supported only for compatibility reason. +; Users should use 32 or more chars. +; http://php.net/session.sid-length +; Default Value: 32 +; Development Value: 26 +; Production Value: 26 +session.sid_length = 26 + +; The URL rewriter will look for URLs in a defined set of HTML tags. +;
is special; if you include them here, the rewriter will +; add a hidden field with the info which is otherwise appended +; to URLs. tag's action attribute URL will not be modified +; unless it is specified. +; Note that all valid entries require a "=", even if no value follows. +; Default Value: "a=href,area=href,frame=src,form=" +; Development Value: "a=href,area=href,frame=src,form=" +; Production Value: "a=href,area=href,frame=src,form=" +; http://php.net/url-rewriter.tags +session.trans_sid_tags = "a=href,area=href,frame=src,form=" + +; URL rewriter does not rewrite absolute URLs by default. +; To enable rewrites for absolute pathes, target hosts must be specified +; at RUNTIME. i.e. use ini_set() +; tags is special. PHP will check action attribute's URL regardless +; of session.trans_sid_tags setting. +; If no host is defined, HTTP_HOST will be used for allowed host. +; Example value: php.net,www.php.net,wiki.php.net +; Use "," for multiple hosts. No spaces are allowed. +; Default Value: "" +; Development Value: "" +; Production Value: "" +;session.trans_sid_hosts="" + +; Define how many bits are stored in each character when converting +; the binary hash data to something readable. +; Possible values: +; 4 (4 bits: 0-9, a-f) +; 5 (5 bits: 0-9, a-v) +; 6 (6 bits: 0-9, a-z, A-Z, "-", ",") +; Default Value: 4 +; Development Value: 5 +; Production Value: 5 +; http://php.net/session.hash-bits-per-character +session.sid_bits_per_character = 5 + +; Enable upload progress tracking in $_SESSION +; Default Value: On +; Development Value: On +; Production Value: On +; http://php.net/session.upload-progress.enabled +;session.upload_progress.enabled = On + +; Cleanup the progress information as soon as all POST data has been read +; (i.e. upload completed). +; Default Value: On +; Development Value: On +; Production Value: On +; http://php.net/session.upload-progress.cleanup +;session.upload_progress.cleanup = On + +; A prefix used for the upload progress key in $_SESSION +; Default Value: "upload_progress_" +; Development Value: "upload_progress_" +; Production Value: "upload_progress_" +; http://php.net/session.upload-progress.prefix +;session.upload_progress.prefix = "upload_progress_" + +; The index name (concatenated with the prefix) in $_SESSION +; containing the upload progress information +; Default Value: "PHP_SESSION_UPLOAD_PROGRESS" +; Development Value: "PHP_SESSION_UPLOAD_PROGRESS" +; Production Value: "PHP_SESSION_UPLOAD_PROGRESS" +; http://php.net/session.upload-progress.name +;session.upload_progress.name = "PHP_SESSION_UPLOAD_PROGRESS" + +; How frequently the upload progress should be updated. +; Given either in percentages (per-file), or in bytes +; Default Value: "1%" +; Development Value: "1%" +; Production Value: "1%" +; http://php.net/session.upload-progress.freq +;session.upload_progress.freq = "1%" + +; The minimum delay between updates, in seconds +; Default Value: 1 +; Development Value: 1 +; Production Value: 1 +; http://php.net/session.upload-progress.min-freq +;session.upload_progress.min_freq = "1" + +; Only write session data when session data is changed. Enabled by default. +; http://php.net/session.lazy-write +;session.lazy_write = On + +[Assertion] +; Switch whether to compile assertions at all (to have no overhead at run-time) +; -1: Do not compile at all +; 0: Jump over assertion at run-time +; 1: Execute assertions +; Changing from or to a negative value is only possible in php.ini! (For turning assertions on and off at run-time, see assert.active, when zend.assertions = 1) +; Default Value: 1 +; Development Value: 1 +; Production Value: -1 +; http://php.net/zend.assertions +zend.assertions = -1 + +; Assert(expr); active by default. +; http://php.net/assert.active +;assert.active = On + +; Throw an AssertationException on failed assertions +; http://php.net/assert.exception +;assert.exception = On + +; Issue a PHP warning for each failed assertion. (Overridden by assert.exception if active) +; http://php.net/assert.warning +;assert.warning = On + +; Don't bail out by default. +; http://php.net/assert.bail +;assert.bail = Off + +; User-function to be called if an assertion fails. +; http://php.net/assert.callback +;assert.callback = 0 + +; Eval the expression with current error_reporting(). Set to true if you want +; error_reporting(0) around the eval(). +; http://php.net/assert.quiet-eval +;assert.quiet_eval = 0 + +[COM] +; path to a file containing GUIDs, IIDs or filenames of files with TypeLibs +; http://php.net/com.typelib-file +;com.typelib_file = + +; allow Distributed-COM calls +; http://php.net/com.allow-dcom +;com.allow_dcom = true + +; autoregister constants of a components typlib on com_load() +; http://php.net/com.autoregister-typelib +;com.autoregister_typelib = true + +; register constants casesensitive +; http://php.net/com.autoregister-casesensitive +;com.autoregister_casesensitive = false + +; show warnings on duplicate constant registrations +; http://php.net/com.autoregister-verbose +;com.autoregister_verbose = true + +; The default character set code-page to use when passing strings to and from COM objects. +; Default: system ANSI code page +;com.code_page= + +[mbstring] +; language for internal character representation. +; This affects mb_send_mail() and mbstring.detect_order. +; http://php.net/mbstring.language +;mbstring.language = Japanese + +; Use of this INI entry is deprecated, use global internal_encoding instead. +; internal/script encoding. +; Some encoding cannot work as internal encoding. (e.g. SJIS, BIG5, ISO-2022-*) +; If empty, default_charset or internal_encoding or iconv.internal_encoding is used. +; The precedence is: default_charset < internal_encoding < iconv.internal_encoding +;mbstring.internal_encoding = + +; Use of this INI entry is deprecated, use global input_encoding instead. +; http input encoding. +; mbstring.encoding_traslation = On is needed to use this setting. +; If empty, default_charset or input_encoding or mbstring.input is used. +; The precedence is: default_charset < intput_encoding < mbsting.http_input +; http://php.net/mbstring.http-input +;mbstring.http_input = + +; Use of this INI entry is deprecated, use global output_encoding instead. +; http output encoding. +; mb_output_handler must be registered as output buffer to function. +; If empty, default_charset or output_encoding or mbstring.http_output is used. +; The precedence is: default_charset < output_encoding < mbstring.http_output +; To use an output encoding conversion, mbstring's output handler must be set +; otherwise output encoding conversion cannot be performed. +; http://php.net/mbstring.http-output +;mbstring.http_output = + +; enable automatic encoding translation according to +; mbstring.internal_encoding setting. Input chars are +; converted to internal encoding by setting this to On. +; Note: Do _not_ use automatic encoding translation for +; portable libs/applications. +; http://php.net/mbstring.encoding-translation +;mbstring.encoding_translation = Off + +; automatic encoding detection order. +; "auto" detect order is changed according to mbstring.language +; http://php.net/mbstring.detect-order +;mbstring.detect_order = auto + +; substitute_character used when character cannot be converted +; one from another +; http://php.net/mbstring.substitute-character +;mbstring.substitute_character = none + +; overload(replace) single byte functions by mbstring functions. +; mail(), ereg(), etc are overloaded by mb_send_mail(), mb_ereg(), +; etc. Possible values are 0,1,2,4 or combination of them. +; For example, 7 for overload everything. +; 0: No overload +; 1: Overload mail() function +; 2: Overload str*() functions +; 4: Overload ereg*() functions +; http://php.net/mbstring.func-overload +;mbstring.func_overload = 0 + +; enable strict encoding detection. +; Default: Off +;mbstring.strict_detection = On + +; This directive specifies the regex pattern of content types for which mb_output_handler() +; is activated. +; Default: mbstring.http_output_conv_mimetype=^(text/|application/xhtml\+xml) +;mbstring.http_output_conv_mimetype= + +[gd] +; Tell the jpeg decode to ignore warnings and try to create +; a gd image. The warning will then be displayed as notices +; disabled by default +; http://php.net/gd.jpeg-ignore-warning +;gd.jpeg_ignore_warning = 1 + +[exif] +; Exif UNICODE user comments are handled as UCS-2BE/UCS-2LE and JIS as JIS. +; With mbstring support this will automatically be converted into the encoding +; given by corresponding encode setting. When empty mbstring.internal_encoding +; is used. For the decode settings you can distinguish between motorola and +; intel byte order. A decode setting cannot be empty. +; http://php.net/exif.encode-unicode +;exif.encode_unicode = ISO-8859-15 + +; http://php.net/exif.decode-unicode-motorola +;exif.decode_unicode_motorola = UCS-2BE + +; http://php.net/exif.decode-unicode-intel +;exif.decode_unicode_intel = UCS-2LE + +; http://php.net/exif.encode-jis +;exif.encode_jis = + +; http://php.net/exif.decode-jis-motorola +;exif.decode_jis_motorola = JIS + +; http://php.net/exif.decode-jis-intel +;exif.decode_jis_intel = JIS + +[Tidy] +; The path to a default tidy configuration file to use when using tidy +; http://php.net/tidy.default-config +;tidy.default_config = /usr/local/lib/php/default.tcfg + +; Should tidy clean and repair output automatically? +; WARNING: Do not use this option if you are generating non-html content +; such as dynamic images +; http://php.net/tidy.clean-output +tidy.clean_output = Off + +[soap] +; Enables or disables WSDL caching feature. +; http://php.net/soap.wsdl-cache-enabled +soap.wsdl_cache_enabled=1 + +; Sets the directory name where SOAP extension will put cache files. +; http://php.net/soap.wsdl-cache-dir +soap.wsdl_cache_dir="/tmp" + +; (time to live) Sets the number of second while cached file will be used +; instead of original one. +; http://php.net/soap.wsdl-cache-ttl +soap.wsdl_cache_ttl=86400 + +; Sets the size of the cache limit. (Max. number of WSDL files to cache) +soap.wsdl_cache_limit = 5 + +[sysvshm] +; A default size of the shared memory segment +;sysvshm.init_mem = 10000 + +[ldap] +; Sets the maximum number of open links or -1 for unlimited. +ldap.max_links = -1 + +[dba] +;dba.default_handler= + +[opcache] +; Determines if Zend OPCache is enabled +opcache.enable=1 + +; Determines if Zend OPCache is enabled for the CLI version of PHP +opcache.enable_cli=1 + +; The OPcache shared memory storage size. +opcache.memory_consumption=256 + +; The amount of memory for interned strings in Mbytes. +;opcache.interned_strings_buffer=8 + +; The maximum number of keys (scripts) in the OPcache hash table. +; Only numbers between 200 and 1000000 are allowed. +opcache.max_accelerated_files=20000 + +; The maximum percentage of "wasted" memory until a restart is scheduled. +;opcache.max_wasted_percentage=5 + +; When this directive is enabled, the OPcache appends the current working +; directory to the script key, thus eliminating possible collisions between +; files with the same name (basename). Disabling the directive improves +; performance, but may break existing applications. +;opcache.use_cwd=1 + +; When disabled, you must reset the OPcache manually or restart the +; webserver for changes to the filesystem to take effect. +opcache.validate_timestamps=0 + +; How often (in seconds) to check file timestamps for changes to the shared +; memory storage allocation. ("1" means validate once per second, but only +; once per request. "0" means always validate) +;opcache.revalidate_freq=2 + +; Enables or disables file search in include_path optimization +;opcache.revalidate_path=0 + +; If disabled, all PHPDoc comments are dropped from the code to reduce the +; size of the optimized code. +opcache.save_comments=0 + +; Allow file existence override (file_exists, etc.) performance feature. +opcache.enable_file_override=1 + +; A bitmask, where each bit enables or disables the appropriate OPcache +; passes +;opcache.optimization_level=0xffffffff + +;opcache.inherited_hack=1 +;opcache.dups_fix=0 + +; The location of the OPcache blacklist file (wildcards allowed). +; Each OPcache blacklist file is a text file that holds the names of files +; that should not be accelerated. The file format is to add each filename +; to a new line. The filename may be a full path or just a file prefix +; (i.e., /var/www/x blacklists all the files and directories in /var/www +; that start with 'x'). Line starting with a ; are ignored (comments). +;opcache.blacklist_filename= + +; Allows exclusion of large files from being cached. By default all files +; are cached. +;opcache.max_file_size=0 + +; Check the cache checksum each N requests. +; The default value of "0" means that the checks are disabled. +;opcache.consistency_checks=0 + +; How long to wait (in seconds) for a scheduled restart to begin if the cache +; is not being accessed. +;opcache.force_restart_timeout=180 + +; OPcache error_log file name. Empty string assumes "stderr". +;opcache.error_log= + +; All OPcache errors go to the Web server log. +; By default, only fatal errors (level 0) or errors (level 1) are logged. +; You can also enable warnings (level 2), info messages (level 3) or +; debug messages (level 4). +;opcache.log_verbosity_level=1 + +; Preferred Shared Memory back-end. Leave empty and let the system decide. +;opcache.preferred_memory_model= + +; Protect the shared memory from unexpected writing during script execution. +; Useful for internal debugging only. +;opcache.protect_memory=0 + +; Allows calling OPcache API functions only from PHP scripts which path is +; started from specified string. The default "" means no restriction +;opcache.restrict_api= + +; Mapping base of shared memory segments (for Windows only). All the PHP +; processes have to map shared memory into the same address space. This +; directive allows to manually fix the "Unable to reattach to base address" +; errors. +;opcache.mmap_base= + +; Enables and sets the second level cache directory. +; It should improve performance when SHM memory is full, at server restart or +; SHM reset. The default "" disables file based caching. +;opcache.file_cache= + +; Enables or disables opcode caching in shared memory. +;opcache.file_cache_only=0 + +; Enables or disables checksum validation when script loaded from file cache. +;opcache.file_cache_consistency_checks=1 + +; Implies opcache.file_cache_only=1 for a certain process that failed to +; reattach to the shared memory (for Windows only). Explicitly enabled file +; cache is required. +;opcache.file_cache_fallback=1 + +; Enables or disables copying of PHP code (text segment) into HUGE PAGES. +; This should improve performance, but requires appropriate OS configuration. +opcache.huge_code_pages=1 + +; Validate cached file permissions. +;opcache.validate_permission=0 + +; Prevent name collisions in chroot'ed environment. +;opcache.validate_root=0 + +[curl] +; A default value for the CURLOPT_CAINFO option. This is required to be an +; absolute path. +;curl.cainfo = + +[openssl] +; The location of a Certificate Authority (CA) file on the local filesystem +; to use when verifying the identity of SSL/TLS peers. Most users should +; not specify a value for this directive as PHP will attempt to use the +; OS-managed cert stores in its absence. If specified, this value may still +; be overridden on a per-stream basis via the "cafile" SSL stream context +; option. +;openssl.cafile= + +; If openssl.cafile is not specified or if the CA file is not found, the +; directory pointed to by openssl.capath is searched for a suitable +; certificate. This value must be a correctly hashed certificate directory. +; Most users should not specify a value for this directive as PHP will +; attempt to use the OS-managed cert stores in its absence. If specified, +; this value may still be overridden on a per-stream basis via the "capath" +; SSL stream context option. +;openssl.capath= + +opcache.jit_buffer_size = 128M +opcache.jit = tracing + +; Local Variables: +; tab-width: 4 +; End: \ No newline at end of file diff --git a/frameworks/PHP/laravel/deploy/laravel-s/composer.json b/frameworks/PHP/laravel/deploy/laravel-s/composer.json index fd1c676c2af..42e2a47c827 100644 --- a/frameworks/PHP/laravel/deploy/laravel-s/composer.json +++ b/frameworks/PHP/laravel/deploy/laravel-s/composer.json @@ -8,9 +8,9 @@ ], "license": "MIT", "require": { - "php": "^7.3|^8.1", - "laravel/framework": "^9", - "hhxsv5/laravel-s": "~3.7.0" + "php": "^8.0", + "laravel/framework": "^12", + "hhxsv5/laravel-s": "~3.8.5" }, "config": { "optimize-autoloader": true, @@ -27,7 +27,7 @@ "App\\": "app/" } }, - "minimum-stability": "dev", + "minimum-stability": "stable", "prefer-stable": true, "scripts": { "post-autoload-dump": [ @@ -42,5 +42,3 @@ ] } } - - diff --git a/frameworks/PHP/laravel/deploy/roadrunner/.rr.yaml b/frameworks/PHP/laravel/deploy/roadrunner/.rr.yaml index e1eecad8f04..e1b9eaa98e9 100644 --- a/frameworks/PHP/laravel/deploy/roadrunner/.rr.yaml +++ b/frameworks/PHP/laravel/deploy/roadrunner/.rr.yaml @@ -1,22 +1,35 @@ -# see https://roadrunner.dev/docs/intro-config -server: - command: "php ./vendor/bin/rr-worker start --relay-dsn unix:///usr/local/var/run/rr-rpc.sock" - relay: "unix:///usr/local/var/run/rr-rpc.sock" -logs: - mode: production - level: error +# see https://docs.roadrunner.dev/docs/general/config +# https://github.com/roadrunner-server/roadrunner/blob/master/.rr.yaml + +version: "3" + http: address: 0.0.0.0:8080 - middleware: ["headers", "static", "gzip"] pool: - #max_jobs: 64 # feel free to change this + num_workers: 0 + max_jobs: 0 supervisor: exec_ttl: 60s headers: response: Server: "RoadRunner" - static: - dir: "public" - forbid: [".php"] + middleware: ["headers"] +server: + command: "php /laravel/vendor/bin/roadrunner-worker" + #command: "php /laravel/vendor/bin/roadrunner-worker start --relay-dsn unix:///usr/local/var/run/rr-rpc.sock" + #relay: "unix:///usr/local/var/run/rr-rpc.sock" + + env: + - APP_ENV: production + - APP_BASE_PATH: "/laravel" + - LARAVEL_OCTANE: "1" + +rpc: + listen: tcp://127.0.0.1:6001 +logs: + mode: production + level: error + output: stdout + #encoding: json diff --git a/frameworks/PHP/laravel/deploy/roadrunner/composer.json b/frameworks/PHP/laravel/deploy/roadrunner/composer.json deleted file mode 100644 index c3528e5e4e3..00000000000 --- a/frameworks/PHP/laravel/deploy/roadrunner/composer.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "name": "laravel/laravel", - "type": "project", - "description": "The Laravel Framework.", - "keywords": [ - "framework", - "laravel" - ], - "license": "MIT", - "require": { - "laravel/framework": "^9", - "nyholm/psr7": "*", - "spiral/roadrunner": "^2.11", - "spiral/roadrunner-laravel": "^5.9" - }, - "config": { - "optimize-autoloader": true, - "preferred-install": "dist", - "sort-packages": true - }, - "extra": { - "laravel": { - "dont-discover": [] - } - }, - "autoload": { - "psr-4": { - "App\\": "app/" - } - }, - "minimum-stability": "dev", - "prefer-stable": true, - "scripts": { - "post-autoload-dump": [ - "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump", - "@php artisan package:discover --ansi" - ], - "post-root-package-install": [ - "@php -r \"file_exists('.env') || copy('.env.example', '.env');\"" - ], - "post-create-project-cmd": [ - "@php artisan key:generate --ansi" - ] - } -} diff --git a/frameworks/PHP/laravel/deploy/swoole/composer.json b/frameworks/PHP/laravel/deploy/swoole/composer.json deleted file mode 100644 index 8293ab06f70..00000000000 --- a/frameworks/PHP/laravel/deploy/swoole/composer.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "name": "laravel/laravel", - "type": "project", - "description": "The Laravel Framework.", - "keywords": [ - "framework", - "laravel" - ], - "license": "MIT", - "require": { - "laravel/framework": "^9", - "swooletw/laravel-swoole": "^v2.6" - }, - "config": { - "optimize-autoloader": true, - "preferred-install": "dist", - "sort-packages": true - }, - "extra": { - "laravel": { - "dont-discover": [] - } - }, - "autoload": { - "psr-4": { - "App\\": "app/" - } - }, - "minimum-stability": "dev", - "prefer-stable": true, - "scripts": { - "post-autoload-dump": [ - "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump", - "@php artisan package:discover --ansi" - ], - "post-root-package-install": [ - "@php -r \"file_exists('.env') || copy('.env.example', '.env');\"" - ], - "post-create-project-cmd": [ - "@php artisan key:generate --ansi" - ] - } -} diff --git a/frameworks/PHP/laravel/deploy/workerman/composer.json b/frameworks/PHP/laravel/deploy/workerman/composer.json deleted file mode 100644 index 343ff8fcf3c..00000000000 --- a/frameworks/PHP/laravel/deploy/workerman/composer.json +++ /dev/null @@ -1,58 +0,0 @@ -{ - "name": "laravel/laravel", - "type": "project", - "description": "The Laravel Framework.", - "keywords": [ - "framework", - "laravel" - ], - "license": "MIT", - "require": { - "php": "^8.0", - "laravel/framework": "^8.0", - "joanhey/adapterman": "^0.6" - }, - "require-dev": { - "facade/ignition": "^2.3.6", - "fzaninotto/faker": "^1.9.1", - "mockery/mockery": "^1.3.1", - "nunomaduro/collision": "^5.0", - "phpunit/phpunit": "^9.3" - }, - "config": { - "optimize-autoloader": true, - "preferred-install": "dist", - "sort-packages": true - }, - "extra": { - "laravel": { - "dont-discover": [] - } - }, - "autoload": { - "psr-4": { - "App\\": "app/" - } - }, - "autoload-dev": { - "psr-4": { - "Tests\\": "tests/" - } - }, - "minimum-stability": "dev", - "prefer-stable": true, - "scripts": { - "post-autoload-dump": [ - "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump", - "@php artisan package:discover --ansi" - ], - "post-root-package-install": [ - "@php -r \"file_exists('.env') || copy('.env.example', '.env');\"" - ], - "post-create-project-cmd": [ - "@php artisan key:generate --ansi" - ] - } -} - - diff --git a/frameworks/PHP/laravel/laravel-laravel-s.dockerfile b/frameworks/PHP/laravel/laravel-laravel-s.dockerfile index 4cce4090f3d..5cc47e90375 100644 --- a/frameworks/PHP/laravel/laravel-laravel-s.dockerfile +++ b/frameworks/PHP/laravel/laravel-laravel-s.dockerfile @@ -1,25 +1,26 @@ -FROM php:8.3-cli +FROM phpswoole/swoole:php8.4 -RUN pecl install swoole > /dev/null && \ - docker-php-ext-enable swoole -RUN docker-php-ext-install pdo_mysql pcntl opcache > /dev/null +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 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 -ADD ./ /laravel WORKDIR /laravel +COPY --link . . -RUN mkdir -p /laravel/bootstrap/cache /laravel/storage/logs /laravel/storage/framework/sessions /laravel/storage/framework/views /laravel/storage/framework/cache -RUN chmod -R 777 /laravel - -RUN apt-get update > /dev/null && \ - apt-get install -yqq git unzip > /dev/null -RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" && php composer-setup.php && php -r "unlink('composer-setup.php');" -RUN mv composer.phar /usr/local/bin/composer +RUN mkdir -p bootstrap/cache \ + storage/logs \ + storage/framework/sessions \ + storage/framework/views \ + storage/framework/cache -COPY deploy/laravel-s/composer.json ./ +COPY --link deploy/laravel-s/composer.json . RUN echo "LARAVELS_LISTEN_IP=0.0.0.0" >> .env RUN echo "LARAVELS_LISTEN_PORT=8080" >> .env @@ -30,4 +31,4 @@ RUN php artisan laravels publish EXPOSE 8080 -CMD php bin/laravels start +ENTRYPOINT [ "php", "bin/laravels", "start" ] diff --git a/frameworks/PHP/laravel/laravel-octane-frankenphp.dockerfile b/frameworks/PHP/laravel/laravel-octane-frankenphp.dockerfile new file mode 100644 index 00000000000..da9fc1c16c5 --- /dev/null +++ b/frameworks/PHP/laravel/laravel-octane-frankenphp.dockerfile @@ -0,0 +1,28 @@ +FROM dunglas/frankenphp + +RUN apt-get update -yqq && apt-get install libicu-dev unzip -y +RUN install-php-extensions \ + intl \ + pcntl \ + pdo_mysql \ + zip > /dev/null + +COPY --link . /app/ +COPY --from=composer --link /usr/bin/composer /usr/local/bin/composer + +RUN mkdir -p bootstrap/cache \ + storage/logs \ + storage/framework/sessions \ + storage/framework/views \ + storage/framework/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 php artisan optimize + +RUN frankenphp -v + +EXPOSE 8080 + +ENTRYPOINT ["php", "artisan", "octane:frankenphp", "--port=8080", "--caddyfile=/app/deploy/franken/Caddyfile"] diff --git a/frameworks/PHP/laravel/laravel-ripple.dockerfile b/frameworks/PHP/laravel/laravel-ripple.dockerfile new file mode 100644 index 00000000000..0ce2de40016 --- /dev/null +++ b/frameworks/PHP/laravel/laravel-ripple.dockerfile @@ -0,0 +1,49 @@ +FROM php:8.3-cli + +RUN apt-get update -yqq >> /dev/null +RUN apt-get install -y libevent-dev \ + libssl-dev \ + pkg-config \ + libicu-dev \ + build-essential \ + unzip >> /dev/null + +RUN docker-php-ext-install pdo_mysql \ + opcache \ + posix \ + pcntl \ + sockets >> /dev/null + +RUN pecl install event >> /dev/null + +RUN docker-php-ext-enable intl pdo_mysql opcache posix pcntl sockets +RUN docker-php-ext-enable --ini-name zz-event.ini event +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 + +COPY --from=composer --link /usr/bin/composer /usr/local/bin/composer + +# Initialize +WORKDIR /laravel +COPY --link . . + +RUN mkdir -p bootstrap/cache \ + storage/logs \ + storage/framework/sessions \ + storage/framework/views \ + storage/framework/cache + +RUN echo "RIP_HTTP_LISTEN=http://0.0.0.0:8080" >> .env +RUN echo "RIP_HTTP_WORKERS=64" >> .env +RUN echo "RIP_HTTP_RELOAD=0" >> .env + +# Configure +RUN composer install --quiet +RUN composer require cloudtay/laravel-ripple --quiet +RUN php artisan vendor:publish --tag=ripple-config +RUN php artisan optimize + +# Start +EXPOSE 8080 +ENTRYPOINT ["php","artisan","ripple:server","start"] diff --git a/frameworks/PHP/laravel/laravel-roadrunner.dockerfile b/frameworks/PHP/laravel/laravel-roadrunner.dockerfile index 8aa87522504..730df104fea 100644 --- a/frameworks/PHP/laravel/laravel-roadrunner.dockerfile +++ b/frameworks/PHP/laravel/laravel-roadrunner.dockerfile @@ -1,35 +1,36 @@ -FROM php:8.3-cli - -RUN docker-php-ext-install pdo_mysql pcntl opcache sockets > /dev/null +FROM php:8.4-cli +RUN apt-get update -yqq && \ + apt-get install -yqq libpq-dev libicu-dev > /dev/null && \ +docker-php-ext-install intl pdo_mysql pcntl opcache sockets > /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 +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 -ADD ./ /laravel WORKDIR /laravel +COPY --link . . -RUN mkdir -p /laravel/bootstrap/cache /laravel/storage/logs /laravel/storage/framework/sessions /laravel/storage/framework/views /laravel/storage/framework/cache -RUN chmod -R 777 /laravel +RUN mkdir -p bootstrap/cache \ + storage/logs \ + storage/framework/sessions \ + storage/framework/views \ + storage/framework/cache RUN apt-get update > /dev/null && \ - apt-get install -yqq git unzip > /dev/null -RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" && php composer-setup.php && php -r "unlink('composer-setup.php');" -RUN mv composer.phar /usr/local/bin/composer - -COPY deploy/roadrunner/composer.json ./ -COPY deploy/roadrunner/.rr.yaml ./ + apt-get install -yqq curl unzip > /dev/null -RUN composer install -a --no-dev --quiet -RUN php artisan optimize +RUN pecl install protobuf > /dev/null && echo "extension=protobuf.so" > /usr/local/etc/php/conf.d/protobuf.ini -# install roadrunner -COPY --from=ghcr.io/roadrunner-server/roadrunner:2.12.1 /usr/bin/rr ./rr +COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer -RUN php artisan vendor:publish --provider='Spiral\RoadRunnerLaravel\ServiceProvider' --tag=config +RUN composer require laravel/octane --update-no-dev --no-scripts --quiet +RUN php artisan octane:install --server="roadrunner" +RUN php artisan optimize +RUN export WORKERS=$((1*$(nproc))) +RUN if [ $(nproc) > 2 ]; then export WORKERS=$((1*$(nproc) -1)) ; fi; EXPOSE 8080 -# CMD bash -CMD ./rr serve -c ./.rr.yaml - +# https://artisan.page/12.x/ +#ENTRYPOINT ["php", "artisan", "octane:roadrunner", "--host=0.0.0.0", "--port=8080", "--workers=auto", "--max-requests=10000", "--rr-config=/laravel/deploy/roadrunner/.rr.yaml"] +ENTRYPOINT ["/laravel/rr", "serve", "-c", "/laravel/deploy/roadrunner/.rr.yaml"] diff --git a/frameworks/PHP/laravel/laravel-swoole.dockerfile b/frameworks/PHP/laravel/laravel-swoole.dockerfile index 77cfef19fe0..89dacff8abe 100644 --- a/frameworks/PHP/laravel/laravel-swoole.dockerfile +++ b/frameworks/PHP/laravel/laravel-swoole.dockerfile @@ -1,33 +1,24 @@ -FROM php:8.3-cli - -RUN pecl install swoole > /dev/null && \ - docker-php-ext-enable swoole -RUN docker-php-ext-install pdo_mysql pcntl opcache > /dev/null +FROM phpswoole/swoole:php8.4 +RUN apt-get update -yqq && apt-get install libicu-dev -y +RUN docker-php-ext-install intl pcntl opcache> /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 -ADD ./ /laravel WORKDIR /laravel +COPY --link . . -RUN mkdir -p /laravel/bootstrap/cache /laravel/storage/framework/sessions /laravel/storage/framework/views /laravel/storage/framework/cache -RUN chmod -R 777 /laravel - -RUN apt-get update -yqq > /dev/null && \ - apt-get install -yqq git unzip > /dev/null - -RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" && php composer-setup.php && php -r "unlink('composer-setup.php');" -RUN mv composer.phar /usr/local/bin/composer +RUN mkdir -p bootstrap/cache \ + storage/logs \ + storage/framework/sessions \ + storage/framework/views \ + storage/framework/cache -COPY deploy/swoole/composer.json ./ - -RUN echo "APP_SWOOLE=true" >> .env - -RUN composer install -a --no-dev --quiet +RUN composer require laravel/octane:2.11 --update-no-dev --no-scripts --quiet +RUN php artisan octane:install --server="swoole" RUN php artisan optimize - EXPOSE 8080 -CMD php artisan swoole:http start +ENTRYPOINT ["php", "artisan", "octane:swoole", "--host=0.0.0.0", "--port=8080", "--workers=auto", "--task-workers=auto", "--max-requests=10000"] diff --git a/frameworks/PHP/laravel/laravel-workerman.dockerfile b/frameworks/PHP/laravel/laravel-workerman.dockerfile index 016c3d0d9a7..d652fa11f84 100644 --- a/frameworks/PHP/laravel/laravel-workerman.dockerfile +++ b/frameworks/PHP/laravel/laravel-workerman.dockerfile @@ -1,31 +1,32 @@ -FROM ubuntu:22.04 +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 + apt-get update -yqq > /dev/null && apt-get upgrade -yqq > /dev/null && \ + apt-get install -yqq git unzip \ + php8.4-cli php8.4-mysql php8.4-mbstring php8.4-xml php8.4-intl php8.4-curl > /dev/null -RUN apt-get install -yqq git unzip \ - php8.3-cli php8.3-mysql php8.3-mbstring php8.3-xml php8.3-curl > /dev/null +COPY --from=composer --link /usr/bin/composer /usr/local/bin/composer -COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer +RUN apt-get install -y php-pear php8.4-dev libevent-dev > /dev/null +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 php-pear php8.3-dev libevent-dev > /dev/null -RUN pecl install event-3.0.8 > /dev/null && echo "extension=event.so" > /etc/php/8.3/cli/conf.d/event.ini - -ADD ./ /laravel WORKDIR /laravel +COPY --link . . -EXPOSE 8080 - -RUN mkdir -p /laravel/bootstrap/cache /laravel/storage/logs /laravel/storage/framework/sessions /laravel/storage/framework/views /laravel/storage/framework/cache -RUN chmod -R 777 /laravel +RUN mkdir -p bootstrap/cache \ + storage/logs \ + storage/framework/sessions \ + storage/framework/views \ + storage/framework/cache -COPY deploy/workerman/composer.json ./ -RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet +RUN composer require joanhey/adapterman --update-no-dev --no-scripts --quiet RUN php artisan optimize -COPY deploy/conf/cli-php.ini /etc/php/8.3/cli/php.ini +COPY --link deploy/conf/cli-php.ini /etc/php/8.4/cli/conf.d/20-adapterman.ini + +EXPOSE 8080 -CMD php server-man.php start +ENTRYPOINT [ "php", "server-man.php", "start" ] diff --git a/frameworks/PHP/laravel/laravel.dockerfile b/frameworks/PHP/laravel/laravel.dockerfile index c1858216a66..13ca827c6d3 100644 --- a/frameworks/PHP/laravel/laravel.dockerfile +++ b/frameworks/PHP/laravel/laravel.dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:22.04 +FROM ubuntu:24.04 ARG DEBIAN_FRONTEND=noninteractive @@ -7,19 +7,21 @@ 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 install -yqq nginx git unzip \ - php8.3-cli php8.3-fpm php8.3-mysql php8.3-mbstring php8.3-xml php8.3-dev > /dev/null + php8.4-bcmath php8.4-cli php8.4-fpm php8.4-mysql php8.4-mbstring php8.4-xml php8.4-curl php8.4-intl > /dev/null -COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer +COPY --from=composer --link /usr/bin/composer /usr/local/bin/composer -COPY deploy/conf/* /etc/php/8.3/fpm/ - -ADD ./ /laravel +COPY --link deploy/conf/* /etc/php/8.4/fpm/ WORKDIR /laravel +COPY --link . . -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.3/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.4/fpm/php-fpm.conf ; fi; -RUN mkdir -p /laravel/bootstrap/cache /laravel/storage/logs /laravel/storage/framework/sessions /laravel/storage/framework/views /laravel/storage/framework/cache -RUN chmod -R 777 /laravel +RUN mkdir -p bootstrap/cache \ + storage/logs \ + storage/framework/sessions \ + storage/framework/views \ + storage/framework/cache RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet RUN php artisan optimize @@ -27,8 +29,7 @@ RUN php artisan optimize EXPOSE 8080 # Uncomment next line for Laravel console error logging to be viewable in docker logs -# RUN echo "catch_workers_output = yes" >> /etc/php/8.3/fpm/php-fpm.conf +# RUN echo "catch_workers_output = yes" >> /etc/php/8.4/fpm/php-fpm.conf -RUN mkdir -p /run/php -CMD /usr/sbin/php-fpm8.3 --fpm-config /etc/php/8.3/fpm/php-fpm.conf && \ +CMD service php8.4-fpm start && \ nginx -c /laravel/deploy/nginx.conf diff --git a/frameworks/PHP/laravel/opcache_preload.php b/frameworks/PHP/laravel/opcache_preload.php new file mode 100644 index 00000000000..687af36e6b9 --- /dev/null +++ b/frameworks/PHP/laravel/opcache_preload.php @@ -0,0 +1,3 @@ +count = (int) shell_exec('nproc') * 4; +$http_worker->reusePort = true; $http_worker->name = 'AdapterMan-Laravel'; $http_worker->onWorkerStart = static function () { - Header::$date = gmdate('D, d M Y H:i:s').' GMT'; + Header::$date = gmdate(DATE_RFC7231); Timer::add(1, function() { - Header::$date = gmdate('D, d M Y H:i:s').' GMT'; + Header::$date = gmdate(DATE_RFC7231); }); //init(); require __DIR__.'/start.php'; diff --git a/frameworks/PHP/leaf/composer.json b/frameworks/PHP/leaf/composer.json index adc04bf753d..25dd1d1aa6e 100644 --- a/frameworks/PHP/leaf/composer.json +++ b/frameworks/PHP/leaf/composer.json @@ -1,5 +1,5 @@ { "require": { - "leafs/leaf": "^3.3" + "leafs/leaf": "^3.11" } } diff --git a/frameworks/PHP/leaf/deploy/conf/cli-php.ini b/frameworks/PHP/leaf/deploy/conf/cli-php.ini index bcccffbc63b..e03b6e352a9 100644 --- a/frameworks/PHP/leaf/deploy/conf/cli-php.ini +++ b/frameworks/PHP/leaf/deploy/conf/cli-php.ini @@ -13,4 +13,4 @@ memory_limit = 512M opcache.jit_buffer_size = 128M opcache.jit = tracing -disable_functions=header,header_remove,headers_sent,http_response_code,setcookie,session_create_id,session_id,session_name,session_save_path,session_status,session_start,session_write_close,session_regenerate_id,set_time_limit +disable_functions=header,header_remove,headers_sent,headers_list,http_response_code,setcookie,session_create_id,session_id,session_name,session_save_path,session_status,session_start,session_write_close,session_regenerate_id,session_unset,session_get_cookie_params,session_set_cookie_params,set_time_limit diff --git a/frameworks/PHP/leaf/leaf-workerman.dockerfile b/frameworks/PHP/leaf/leaf-workerman.dockerfile index 80f9248d07a..c98f11f5c84 100644 --- a/frameworks/PHP/leaf/leaf-workerman.dockerfile +++ b/frameworks/PHP/leaf/leaf-workerman.dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:22.04 +FROM ubuntu:24.04 ARG DEBIAN_FRONTEND=noninteractive @@ -7,22 +7,23 @@ 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 -yqq > /dev/null && apt-get install -yqq git \ - php8.3-cli php8.3-mysql php8.3-mbstring php8.3-xml php8.3-curl > /dev/null + php8.4-cli php8.4-mysql php8.4-mbstring php8.4-xml php8.4-curl php8.4-zip > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -RUN apt-get install -y php-pear php8.3-dev libevent-dev > /dev/null -RUN pecl install event-3.0.8 > /dev/null && echo "extension=event.so" > /etc/php/8.3/cli/conf.d/event.ini +RUN apt-get install -y libevent-dev php8.4-dev > /dev/null \ + && pecl install event-3.1.4 > /dev/null \ + && echo "extension=event.so" > /etc/php/8.4/cli/conf.d/event.ini -COPY deploy/conf/cli-php.ini /etc/php/8.3/cli/php.ini +COPY --link deploy/conf/cli-php.ini /etc/php/8.4/cli/conf.d/20-adapterman.ini -ADD ./ /leaf WORKDIR /leaf +COPY --link . . EXPOSE 8080 -RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet -RUN composer require joanhey/adapterman:^0.6 --quiet +RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet +RUN composer require joanhey/adapterman:^0.7 --quiet RUN sed -i 's|app()->run(); //| //$app->run(); //|g' index.php diff --git a/frameworks/PHP/leaf/leaf.dockerfile b/frameworks/PHP/leaf/leaf.dockerfile index 167a5af7039..1ebe23e5735 100644 --- a/frameworks/PHP/leaf/leaf.dockerfile +++ b/frameworks/PHP/leaf/leaf.dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:22.04 +FROM ubuntu:24.04 ARG DEBIAN_FRONTEND=noninteractive @@ -7,16 +7,16 @@ 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 install -yqq nginx git unzip \ - php8.3 php8.3-common php8.3-cli php8.3-fpm php8.3-mysql php8.3-xml php8.3-curl > /dev/null + php8.4-cli php8.4-fpm php8.4-mysql php8.4-xml php8.4-curl php8.4-zip > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -COPY deploy/conf/* /etc/php/8.3/fpm/ +COPY --link deploy/conf/* /etc/php/8.4/fpm/ -ADD ./ /leaf WORKDIR /leaf +COPY --link . . -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.3/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.4/fpm/php-fpm.conf ; fi; RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet @@ -24,5 +24,5 @@ RUN chmod -R 777 /leaf EXPOSE 8080 -CMD service php8.3-fpm start && \ +CMD service php8.4-fpm start && \ nginx -c /leaf/deploy/nginx.conf diff --git a/frameworks/PHP/leaf/server.php b/frameworks/PHP/leaf/server.php index c2d7355fbb7..4e931b07e33 100644 --- a/frameworks/PHP/leaf/server.php +++ b/frameworks/PHP/leaf/server.php @@ -4,12 +4,13 @@ use Adapterman\Adapterman; use Workerman\Worker; -use Workerman\Lib\Timer; +use Workerman\Timer; Adapterman::init(); $http_worker = new Worker('http://0.0.0.0:8080'); $http_worker->count = (int) shell_exec('nproc') * 4; +$http_worker->reusePort = true; $http_worker->name = 'AdapterMan-Leaf'; $http_worker->onWorkerStart = static function () { @@ -38,9 +39,9 @@ class HeaderDate public static function init(): void { - self::$date = self::NAME . gmdate('D, d M Y H:i:s').' GMT'; + self::$date = self::NAME . gmdate(DATE_RFC7231); Timer::add(1, static function() { - self::$date = self::NAME . gmdate('D, d M Y H:i:s').' GMT'; + self::$date = self::NAME . gmdate(DATE_RFC7231); }); } } \ No newline at end of file diff --git a/frameworks/PHP/lumen/.env b/frameworks/PHP/lumen/.env deleted file mode 100644 index 20669bcac2f..00000000000 --- a/frameworks/PHP/lumen/.env +++ /dev/null @@ -1,17 +0,0 @@ -APP_ENV=local -APP_DEBUG=false -APP_KEY= -APP_TIMEZONE=UTC - -LOG_CHANNEL=stack -LOG_SLACK_WEBHOOK_URL= - -DB_CONNECTION=mysql -DB_HOST=tfb-database -DB_PORT=3306 -DB_DATABASE=hello_world -DB_USERNAME=benchmarkdbuser -DB_PASSWORD=benchmarkdbpass - -CACHE_DRIVER=file -QUEUE_DRIVER=sync diff --git a/frameworks/PHP/lumen/README.md b/frameworks/PHP/lumen/README.md deleted file mode 100644 index 4c428a39691..00000000000 --- a/frameworks/PHP/lumen/README.md +++ /dev/null @@ -1,83 +0,0 @@ -# Lumen PHP Framework - -[![Build Status](https://travis-ci.org/laravel/lumen-framework.svg)](https://travis-ci.org/laravel/lumen-framework) -[![Total Downloads](https://poser.pugx.org/laravel/lumen-framework/d/total.svg)](https://packagist.org/packages/laravel/lumen-framework) -[![Latest Stable Version](https://poser.pugx.org/laravel/lumen-framework/v/stable.svg)](https://packagist.org/packages/laravel/lumen-framework) -[![Latest Unstable Version](https://poser.pugx.org/laravel/lumen-framework/v/unstable.svg)](https://packagist.org/packages/laravel/lumen-framework) -[![License](https://poser.pugx.org/laravel/lumen-framework/license.svg)](https://packagist.org/packages/laravel/lumen-framework) - -Laravel Lumen is a stunningly fast PHP micro-framework for building web applications with expressive, elegant syntax. We believe development must be an enjoyable, creative experience to be truly fulfilling. Lumen attempts to take the pain out of development by easing common tasks used in the majority of web projects, such as routing, database abstraction, queueing, and caching. - -## Official Documentation - -Documentation for the framework can be found on the [Lumen website](http://lumen.laravel.com/docs). - -## Security Vulnerabilities - -If you discover a security vulnerability within Lumen, please send an e-mail to Taylor Otwell at taylor@laravel.com. All security vulnerabilities will be promptly addressed. - -## License - -The Lumen framework is open-sourced software licensed under the [MIT license](http://opensource.org/licenses/MIT) - -# lumen-swoole Benchmarking Test - -The lumen-swoole test is a benchmark test of Lumen running on Swoole. - -Swoole is an asynchronous PHP webserver that runs as a PECL extension to PHP. - -Traditional PHP servers use php-fpm to run PHP software. On each request, php-fpm initializes a new instance of the php framework, processes the request, returns the response, and terminates the php framework. -This results in decreased performance relative to other technologies like Java or node.js based frameworks which intialize only once and then process multiple requests without terminating in between. - -Swoole provides this capability to PHP. When Swoole starts, it initializes the framework once and handles requests without terminating the framework between requests. Also, like nginx, netty, node.js, Swoole is an asynchronous event-loop based server. - -Laravel-swoole is an adapter layer between Swoole and Laravel/Lumen. It provides facades for http requests and PDO database connections. It launches Laravel worker instances for each cpu core to handle incoming requests. - -Also because Laravel was written under php-fpm environment where the framework is reset between each request, sometimes state changes are not re-initialized between requests since it isn't necessary in an environment where the framework is terminated after each request. -To handle this, Laravel-swoole creates a sandbox for each request with a copy of initial framework state so that any changes made by the request do not impact the state of other incoming requests. - -Brion Finlay 10/3/2018 - -### Test Type Implementation Source Code - -* [JSON](Relative/Path/To/Your/Source/File) -* [PLAINTEXT](Relative/Path/To/Your/Source/File) -* [DB](Relative/Path/To/Your/Source/File) -* [QUERY](Relative/Path/To/Your/Source/File) -* [UPDATE](Relative/Path/To/Your/Source/File) -* [FORTUNES](Relative/Path/To/Your/Source/File) - -## Important Libraries -The tests were run with: -* [Swoole](https://www.swoole.co.uk/) -* [laravel-swoole](https://github.com/swooletw/laravel-swoole/wiki) -* [Lumen](https://lumen.laravel.com/) - -## Test URLs -### JSON - -http://localhost:8080/json - -### PLAINTEXT - -http://localhost:8080/plaintext - -### DB - -http://localhost:8080/db - -### QUERY - -http://localhost:8080/queries/[count] - -### UPDATE - -http://localhost:8080/updates/[count] - -### FORTUNES - -http://localhost:8080/fortunes - - -# Add laravel-s Benchmarking Test -[laravel-s](https://github.com/hhxsv5/laravel-s) is an out-of-the-box adapter between Swoole and Laravel/Lumen, similar to laravel-swoole. diff --git a/frameworks/PHP/lumen/app/Console/Kernel.php b/frameworks/PHP/lumen/app/Console/Kernel.php deleted file mode 100644 index 2216b951778..00000000000 --- a/frameworks/PHP/lumen/app/Console/Kernel.php +++ /dev/null @@ -1,26 +0,0 @@ -json(['message' => 'Oops, something went wrong']); - } -} diff --git a/frameworks/PHP/lumen/app/Http/Controllers/Controller.php b/frameworks/PHP/lumen/app/Http/Controllers/Controller.php deleted file mode 100644 index 68e7aacd238..00000000000 --- a/frameworks/PHP/lumen/app/Http/Controllers/Controller.php +++ /dev/null @@ -1,84 +0,0 @@ -json(['message' => 'Hello, World!']); - } - - public function db() - { - return response()->json(World::query()->find(self::randomInt())); - } - - public function queries($queries = 1) - { - $queries = self::clamp($queries); - - $rows = []; - while ($queries--) { - $rows[] = World::query()->find(self::randomInt()); - } - - return response()->json($rows); - } - - public function fortunes() - { - $rows = Fortune::all(); - - $insert = new Fortune(); - $insert->id = 0; - $insert->message = 'Additional fortune added at request time.'; - - $rows->add($insert); - $rows = $rows->sortBy('message'); - - return view('fortunes', ['rows' => $rows]); - } - - public function updates($queries = 1) - { - $queries = self::clamp($queries); - - $rows = []; - - while ($queries--) { - $row = World::query()->find(self::randomInt()); - $row->randomNumber = self::randomInt(); - $row->save(); - - $rows[] = $row; - } - - return response()->json($rows); - } - - public function plaintext() - { - return response('Hello, World!', 200, ['Content-Type' => 'text/plain']); - } - - private static function randomInt() - { - return random_int(1, 10000); - } - - private static function clamp($value) - { - if (!is_numeric($value) || $value < 1) { - return 1; - } - if ($value > 500) { - return 500; - } - return (int)$value; - } -} diff --git a/frameworks/PHP/lumen/app/Models/Fortune.php b/frameworks/PHP/lumen/app/Models/Fortune.php deleted file mode 100644 index a3998372829..00000000000 --- a/frameworks/PHP/lumen/app/Models/Fortune.php +++ /dev/null @@ -1,11 +0,0 @@ -make( - 'Illuminate\Contracts\Console\Kernel' -); - -exit($kernel->handle(new ArgvInput, new ConsoleOutput)); diff --git a/frameworks/PHP/lumen/benchmark_config.json b/frameworks/PHP/lumen/benchmark_config.json deleted file mode 100644 index f85b97c532d..00000000000 --- a/frameworks/PHP/lumen/benchmark_config.json +++ /dev/null @@ -1,97 +0,0 @@ -{ - "framework": "lumen", - "tests": [{ - "default": { - "setup_file": "setup", - "json_url": "/json", - "db_url": "/db", - "query_url": "/queries/", - "fortune_url": "/fortunes", - "update_url": "/updates/", - "plaintext_url": "/plaintext", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "MySQL", - "framework": "lumen", - "language": "PHP", - "flavor": "PHP8.1", - "orm": "Full", - "platform": "FPM/FastCGI", - "webserver": "nginx", - "os": "Linux", - "database_os": "Linux", - "display_name": "lumen", - "notes": "", - "versus": "php" - }, - "swoole": { - "json_url": "/json", - "db_url": "/db", - "query_url": "/queries/", - "fortune_url": "/fortunes", - "update_url": "/updates/", - "plaintext_url": "/plaintext", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "MySQL", - "framework": "lumen", - "language": "PHP", - "flavor": "PHP8", - "orm": "Full", - "platform": "swoole", - "webserver": "none", - "os": "Linux", - "database_os": "Linux", - "display_name": "lumen-swoole", - "versus": "swoole" - }, - "laravel-s": { - "json_url": "/json", - "db_url": "/db", - "query_url": "/queries/", - "fortune_url": "/fortunes", - "update_url": "/updates/", - "plaintext_url": "/plaintext", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "MySQL", - "framework": "lumen", - "language": "PHP", - "flavor": "PHP8", - "orm": "Full", - "platform": "swoole", - "webserver": "none", - "os": "Linux", - "database_os": "Linux", - "display_name": "lumen-laravel-s", - "notes": "", - "versus": "swoole" - }, - "workerman": { - "json_url": "/json", - "db_url": "/db", - "query_url": "/queries/", - "fortune_url": "/fortunes", - "update_url": "/updates/", - "plaintext_url": "/plaintext", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "MySQL", - "framework": "lumen", - "language": "PHP", - "flavor": "PHP8", - "orm": "Full", - "platform": "workerman", - "webserver": "none", - "os": "Linux", - "database_os": "Linux", - "display_name": "lumen-workerman", - "notes": "", - "versus": "workerman" - } - }] -} diff --git a/frameworks/PHP/lumen/bootstrap/app.php b/frameworks/PHP/lumen/bootstrap/app.php deleted file mode 100644 index 40268a67efa..00000000000 --- a/frameworks/PHP/lumen/bootstrap/app.php +++ /dev/null @@ -1,110 +0,0 @@ -bootstrap(); - -date_default_timezone_set(env('APP_TIMEZONE', 'UTC')); - -/* - * |-------------------------------------------------------------------------- - * | Create The Application - * |-------------------------------------------------------------------------- - * | - * | Here we will load the environment and create the application instance - * | that serves as the central piece of this framework. We'll use this - * | application as an "IoC" container and router for this framework. - * | - */ - -$app = new Laravel\Lumen\Application(dirname(__DIR__)); - -// $app->withFacades(); - -$app->withEloquent(); - -/* - * |-------------------------------------------------------------------------- - * | Register Container Bindings - * |-------------------------------------------------------------------------- - * | - * | Now we will register a few bindings in the service container. We will - * | register the exception handler and the console kernel. You may add - * | your own bindings here if you like or you can make another file. - * | - */ - -$app->singleton(Illuminate\Contracts\Debug\ExceptionHandler::class, App\Exceptions\Handler::class); - -$app->singleton(Illuminate\Contracts\Console\Kernel::class, App\Console\Kernel::class); - -/* - * |-------------------------------------------------------------------------- - * | Register Config Files - * |-------------------------------------------------------------------------- - * | - * | Now we will register the "app" configuration file. If the file exists in - * | your configuration directory it will be loaded; otherwise, we'll load - * | the default version. You may register other files below as needed. - * | - */ - -if (env('APP_SWOOLE', false)) { - $app->register(\SwooleTW\Http\LumenServiceProvider::class); - $app->configure('swoole_http'); -} -if (class_exists('Hhxsv5\LaravelS\Illuminate\LaravelSServiceProvider')) { - $app->register(Hhxsv5\LaravelS\Illuminate\LaravelSServiceProvider::class); -} -$app->configure('database'); -/* - * |-------------------------------------------------------------------------- - * | Register Middleware - * |-------------------------------------------------------------------------- - * | - * | Next, we will register the middleware with the application. These can - * | be global middleware that run before and after each request into a - * | route or middleware that'll be assigned to some specific routes. - * | - */ - -// $app->middleware([ -// App\Http\Middleware\ExampleMiddleware::class -// ]); - -// $app->routeMiddleware([ -// 'auth' => App\Http\Middleware\Authenticate::class, -// ]); - -/* - * |-------------------------------------------------------------------------- - * | Register Service Providers - * |-------------------------------------------------------------------------- - * | - * | Here we will register all of the application's service providers which - * | are used to bind services into the container. Service providers are - * | totally optional, so you are not required to uncomment this line. - * | - */ - -// $app->register(App\Providers\AppServiceProvider::class); -// $app->register(App\Providers\AuthServiceProvider::class); -// $app->register(App\Providers\EventServiceProvider::class); - -/* - * |-------------------------------------------------------------------------- - * | Load The Application Routes - * |-------------------------------------------------------------------------- - * | - * | Next we will include the routes file so that they can all be added to - * | the application. This will provide all of the URLs the application - * | can respond to, as well as the controllers that may handle them. - * | - */ - -$app->router->group([ - 'namespace' => 'App\Http\Controllers' -], function ($router) { - require __DIR__ . '/../routes/web.php'; -}); - -return $app; diff --git a/frameworks/PHP/lumen/composer.json b/frameworks/PHP/lumen/composer.json deleted file mode 100644 index aaf2e3d44d1..00000000000 --- a/frameworks/PHP/lumen/composer.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "laravel/lumen", - "description": "The Laravel Lumen Framework.", - "keywords": ["framework", "laravel", "lumen"], - "license": "MIT", - "type": "project", - "require": { - "laravel/lumen-framework": "^10" - }, - "autoload": { - "psr-4": { - "App\\": "app/" - } - }, - "scripts": { - "post-root-package-install": [ - "@php -r \"file_exists('.env') || copy('.env.example', '.env');\"" - ] - }, - "minimum-stability": "dev", - "prefer-stable": true, - "config": { - "optimize-autoloader": true - } -} diff --git a/frameworks/PHP/lumen/config.toml b/frameworks/PHP/lumen/config.toml deleted file mode 100644 index f185f18f673..00000000000 --- a/frameworks/PHP/lumen/config.toml +++ /dev/null @@ -1,53 +0,0 @@ -[framework] -name = "lumen" - -[main] -urls.plaintext = "/plaintext" -urls.json = "/json" -urls.db = "/db" -urls.query = "/queries/" -urls.update = "/updates/" -urls.fortune = "/fortunes" -approach = "Realistic" -classification = "Micro" -database = "MySQL" -database_os = "Linux" -os = "Linux" -orm = "Full" -platform = "FPM/FastCGI" -webserver = "nginx" -versus = "php" - -[laravel-s] -urls.plaintext = "/plaintext" -urls.json = "/json" -urls.db = "/db" -urls.query = "/queries/" -urls.update = "/updates/" -urls.fortune = "/fortunes" -approach = "Realistic" -classification = "Micro" -database = "MySQL" -database_os = "Linux" -os = "Linux" -orm = "Full" -platform = "swoole" -webserver = "none" -versus = "swoole" - -[swoole] -urls.plaintext = "/plaintext" -urls.json = "/json" -urls.db = "/db" -urls.query = "/queries/" -urls.update = "/updates/" -urls.fortune = "/fortunes" -approach = "Realistic" -classification = "Micro" -database = "MySQL" -database_os = "Linux" -os = "Linux" -orm = "Full" -platform = "swoole" -webserver = "none" -versus = "swoole" diff --git a/frameworks/PHP/lumen/config/database.php b/frameworks/PHP/lumen/config/database.php deleted file mode 100644 index 35ceea9b388..00000000000 --- a/frameworks/PHP/lumen/config/database.php +++ /dev/null @@ -1,92 +0,0 @@ - env('DB_CONNECTION', 'mysql'), - - /* - |-------------------------------------------------------------------------- - | Database Connections - |-------------------------------------------------------------------------- - | - | Here are each of the database connections setup for your application. - | Of course, examples of configuring each database platform that is - | supported by Laravel is shown below to make development simple. - | - | - | All database work in Laravel is done through the PHP PDO facilities - | so make sure you have the driver for your particular database of - | choice installed on your machine before you begin development. - | - */ - - 'connections' => [ - - 'mysql' => [ - 'driver' => 'mysql', - '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' => '', - 'strict' => true, - 'engine' => null, - 'options'=> [ - PDO::ATTR_PERSISTENT => true, - ], - ], - ], - - /* - |-------------------------------------------------------------------------- - | Migration Repository Table - |-------------------------------------------------------------------------- - | - | This table keeps track of all the migrations that have already run for - | your application. Using this information, we can determine which of - | the migrations on disk haven't actually been run in the database. - | - */ - - 'migrations' => 'migrations', - - /* - |-------------------------------------------------------------------------- - | Redis Databases - |-------------------------------------------------------------------------- - | - | Redis is an open source, fast, and advanced key-value store that also - | provides a richer set of commands than a typical key-value systems - | such as APC or Memcached. Laravel makes it easy to dig right in. - | - */ - - 'redis' => [ - - 'client' => 'predis', - - 'default' => [ - 'host' => env('REDIS_HOST', '127.0.0.1'), - 'password' => env('REDIS_PASSWORD', null), - 'port' => env('REDIS_PORT', 6379), - 'database' => 0, - ], - - ], - -]; diff --git a/frameworks/PHP/lumen/config/swoole_http.php b/frameworks/PHP/lumen/config/swoole_http.php deleted file mode 100644 index 58b6643b7cb..00000000000 --- a/frameworks/PHP/lumen/config/swoole_http.php +++ /dev/null @@ -1,37 +0,0 @@ - [ - 'host' => env('SWOOLE_HTTP_HOST', '0.0.0.0'), - 'port' => env('SWOOLE_HTTP_PORT', '8080'), - 'options' => [ - 'pid_file' => env('SWOOLE_HTTP_PID_FILE', base_path('swoole_http.pid')), - // 'log_file' => env('SWOOLE_HTTP_LOG_FILE', base_path('storage/logs/swoole_http.log')), - 'daemonize' => env('SWOOLE_HTTP_DAEMONIZE', 0), - // 'handle_static_files' => env('SWOOLE_HTTP_STATIC', 0), - // 'public_path' => storage_path('app/public'), - // 'ob_output' => env('SWOOLE_HTTP_OB_OUTPUT', 0), - // Normally this value should be 1~4 times lager according to your cpu cores - 'reactor_num' => env('SWOOLE_HTTP_REACTOR_NUM', swoole_cpu_num() * 2), - 'worker_num' => env('SWOOLE_HTTP_WORKER_NUM', swoole_cpu_num() * 2), - 'task_worker_num' => env('SWOOLE_HTTP_TASK_WORKER_NUM', swoole_cpu_num() * 2), - // This value should be larger than `post_max_size` and `upload_max_filesize` in `php.ini`. - // This equals to 10 MB - 'package_max_length' => 10 * 1024 * 1024, - 'buffer_output_size' => 10 * 1024 * 1024, - // Max buffer size for socket connections - 'socket_buffer_size' => 128 * 1024 * 1024, - // Worker will restart after processing this number of request - 'max_request' => 3000 - ] - ], - 'providers' => [ // App\Providers\AuthServiceProvider::class, - ] -]; diff --git a/frameworks/PHP/lumen/database/factories/ModelFactory.php b/frameworks/PHP/lumen/database/factories/ModelFactory.php deleted file mode 100644 index bf9496b0eef..00000000000 --- a/frameworks/PHP/lumen/database/factories/ModelFactory.php +++ /dev/null @@ -1,19 +0,0 @@ -define(App\User::class, function (Faker\Generator $faker) { - return [ - 'name' => $faker->name, - 'email' => $faker->email, - ]; -}); diff --git a/frameworks/PHP/lumen/database/seeds/DatabaseSeeder.php b/frameworks/PHP/lumen/database/seeds/DatabaseSeeder.php deleted file mode 100644 index 23526c9d99c..00000000000 --- a/frameworks/PHP/lumen/database/seeds/DatabaseSeeder.php +++ /dev/null @@ -1,16 +0,0 @@ -call('UsersTableSeeder'); - } -} diff --git a/frameworks/PHP/lumen/deploy/conf/cli-php.ini b/frameworks/PHP/lumen/deploy/conf/cli-php.ini deleted file mode 100644 index bcccffbc63b..00000000000 --- a/frameworks/PHP/lumen/deploy/conf/cli-php.ini +++ /dev/null @@ -1,16 +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 - -mysqlnd.collect_statistics = Off - -memory_limit = 512M - -opcache.jit_buffer_size = 128M -opcache.jit = tracing - -disable_functions=header,header_remove,headers_sent,http_response_code,setcookie,session_create_id,session_id,session_name,session_save_path,session_status,session_start,session_write_close,session_regenerate_id,set_time_limit diff --git a/frameworks/PHP/lumen/deploy/conf/php-fpm.conf b/frameworks/PHP/lumen/deploy/conf/php-fpm.conf deleted file mode 100644 index 202d04b1a72..00000000000 --- a/frameworks/PHP/lumen/deploy/conf/php-fpm.conf +++ /dev/null @@ -1,551 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;; -; FPM Configuration ; -;;;;;;;;;;;;;;;;;;;;; - -; All relative paths in this configuration file are relative to PHP's install -; prefix (/usr). This prefix can be dynamically changed by using the -; '-p' argument from the command line. - -;;;;;;;;;;;;;;;;;; -; Global Options ; -;;;;;;;;;;;;;;;;;; - -[global] -; Pid file -; Note: the default prefix is /var -; Default Value: none -pid = /run/php/php-fpm.pid - -; Error log file -; If it's set to "syslog", log is sent to syslogd instead of being written -; into a local file. -; Note: the default prefix is /var -; Default Value: log/php-fpm.log -;error_log = /var/log/php-fpm.log -error_log = /dev/stderr - - -; syslog_facility is used to specify what type of program is logging the -; message. This lets syslogd specify that messages from different facilities -; will be handled differently. -; See syslog(3) for possible values (ex daemon equiv LOG_DAEMON) -; Default Value: daemon -;syslog.facility = daemon - -; syslog_ident is prepended to every message. If you have multiple FPM -; instances running on the same server, you can change the default value -; which must suit common needs. -; Default Value: php-fpm -;syslog.ident = php-fpm - -; Log level -; Possible Values: alert, error, warning, notice, debug -; Default Value: notice -;log_level = notice - -; If this number of child processes exit with SIGSEGV or SIGBUS within the time -; interval set by emergency_restart_interval then FPM will restart. A value -; of '0' means 'Off'. -; Default Value: 0 -;emergency_restart_threshold = 0 - -; Interval of time used by emergency_restart_interval to determine when -; a graceful restart will be initiated. This can be useful to work around -; accidental corruptions in an accelerator's shared memory. -; Available Units: s(econds), m(inutes), h(ours), or d(ays) -; Default Unit: seconds -; Default Value: 0 -;emergency_restart_interval = 0 - -; Time limit for child processes to wait for a reaction on signals from master. -; Available units: s(econds), m(inutes), h(ours), or d(ays) -; Default Unit: seconds -; Default Value: 0 -;process_control_timeout = 0 - -; The maximum number of processes FPM will fork. This has been designed to control -; the global number of processes when using dynamic PM within a lot of pools. -; Use it with caution. -; Note: A value of 0 indicates no limit -; Default Value: 0 -process.max = 0 - -; Specify the nice(2) priority to apply to the master process (only if set) -; The value can vary from -19 (highest priority) to 20 (lowest priority) -; Note: - It will only work if the FPM master process is launched as root -; - The pool process will inherit the master process priority -; unless specified otherwise -; Default Value: no set -; process.priority = -19 - -; Send FPM to background. Set to 'no' to keep FPM in foreground for debugging. -; Default Value: yes -;daemonize = yes - -; Set open file descriptor rlimit for the master process. -; Default Value: system defined value -rlimit_files = 100000 - -; Set max core size rlimit for the master process. -; Possible Values: 'unlimited' or an integer greater or equal to 0 -; Default Value: system defined value -rlimit_core = 'unlimited' - -; Specify the event mechanism FPM will use. The following is available: -; - select (any POSIX os) -; - poll (any POSIX os) -; - epoll (linux >= 2.5.44) -; - kqueue (FreeBSD >= 4.1, OpenBSD >= 2.9, NetBSD >= 2.0) -; - /dev/poll (Solaris >= 7) -; - port (Solaris >= 10) -; Default Value: not set (auto detection) -;events.mechanism = epoll - -; When FPM is built with systemd integration, specify the interval, -; in seconds, between health report notification to systemd. -; Set to 0 to disable. -; Available Units: s(econds), m(inutes), h(ours) -; Default Unit: seconds -; Default value: 10 -systemd_interval = 0 - -;;;;;;;;;;;;;;;;;;;; -; Pool Definitions ; -;;;;;;;;;;;;;;;;;;;; - -; Multiple pools of child processes may be started with different listening -; ports and different management options. The name of the pool will be -; used in logs and stats. There is no limitation on the number of pools which -; FPM can handle. Your system will tell you anyway :) - -; Include one or more files. If glob(3) exists, it is used to include a bunch of -; files from a glob(3) pattern. This directive can be used everywhere in the -; file. -; Relative path can also be used. They will be prefixed by: -; - the global prefix if it's been set (-p argument) -; - /usr otherwise -;include=/etc/php/7.4/fpm/pool.d/*.conf - -; Start a new pool named 'www'. -; the variable $pool can be used in any directive and will be replaced by the -; pool name ('www' here) -[www] - -; Per pool prefix -; It only applies on the following directives: -; - 'access.log' -; - 'slowlog' -; - 'listen' (unixsocket) -; - 'chroot' -; - 'chdir' -; - 'php_values' -; - 'php_admin_values' -; When not set, the global prefix (or /usr) applies instead. -; Note: This directive can also be relative to the global prefix. -; Default Value: none -;prefix = /path/to/pools/$pool - -; Unix user/group of processes -; Note: The user is mandatory. If the group is not set, the default user's group -; will be used. -user = www-data -group = www-data - -; The address on which to accept FastCGI requests. -; Valid syntaxes are: -; 'ip.add.re.ss:port' - to listen on a TCP socket to a specific IPv4 address on -; a specific port; -; '[ip:6:addr:ess]:port' - to listen on a TCP socket to a specific IPv6 address on -; a specific port; -; 'port' - to listen on a TCP socket to all addresses -; (IPv6 and IPv4-mapped) on a specific port; -; '/path/to/unix/socket' - to listen on a unix socket. -; Note: This value is mandatory. -listen = /run/php/php-fpm.sock - -; Set listen(2) backlog. -; Default Value: 511 (-1 on FreeBSD and OpenBSD) -listen.backlog = -1 - -; Set permissions for unix socket, if one is used. In Linux, read/write -; permissions must be set in order to allow connections from a web server. Many -; BSD-derived systems allow connections regardless of permissions. -; Default Values: user and group are set as the running user -; mode is set to 0660 -listen.owner = www-data -listen.group = www-data -;listen.mode = 0660 -; When POSIX Access Control Lists are supported you can set them using -; these options, value is a comma separated list of user/group names. -; When set, listen.owner and listen.group are ignored -;listen.acl_users = -;listen.acl_groups = - -; List of addresses (IPv4/IPv6) of FastCGI clients which are allowed to connect. -; Equivalent to the FCGI_WEB_SERVER_ADDRS environment variable in the original -; PHP FCGI (5.2.2+). Makes sense only with a tcp listening socket. Each address -; must be separated by a comma. If this value is left blank, connections will be -; accepted from any ip address. -; Default Value: any -;listen.allowed_clients = 127.0.0.1 - -; Specify the nice(2) priority to apply to the pool processes (only if set) -; The value can vary from -19 (highest priority) to 20 (lower priority) -; Note: - It will only work if the FPM master process is launched as root -; - The pool processes will inherit the master process priority -; unless it specified otherwise -; Default Value: no set -; process.priority = -19 - -; Set the process dumpable flag (PR_SET_DUMPABLE prctl) even if the process user -; or group is differrent than the master process user. It allows to create process -; core dump and ptrace the process for the pool user. -; Default Value: no -; process.dumpable = yes - -; Choose how the process manager will control the number of child processes. -; Possible Values: -; static - a fixed number (pm.max_children) of child processes; -; dynamic - the number of child processes are set dynamically based on the -; following directives. With this process management, there will be -; always at least 1 children. -; pm.max_children - the maximum number of children that can -; be alive at the same time. -; pm.start_servers - the number of children created on startup. -; pm.min_spare_servers - the minimum number of children in 'idle' -; state (waiting to process). If the number -; of 'idle' processes is less than this -; number then some children will be created. -; pm.max_spare_servers - the maximum number of children in 'idle' -; state (waiting to process). If the number -; of 'idle' processes is greater than this -; number then some children will be killed. -; ondemand - no children are created at startup. Children will be forked when -; new requests will connect. The following parameter are used: -; pm.max_children - the maximum number of children that -; can be alive at the same time. -; pm.process_idle_timeout - The number of seconds after which -; an idle process will be killed. -; Note: This value is mandatory. -pm = static - -; The number of child processes to be created when pm is set to 'static' and the -; maximum number of child processes when pm is set to 'dynamic' or 'ondemand'. -; This value sets the limit on the number of simultaneous requests that will be -; served. Equivalent to the ApacheMaxClients directive with mpm_prefork. -; Equivalent to the PHP_FCGI_CHILDREN environment variable in the original PHP -; CGI. The below defaults are based on a server without much resources. Don't -; forget to tweak pm.* to fit your needs. -; Note: Used when pm is set to 'static', 'dynamic' or 'ondemand' -; Note: This value is mandatory. -pm.max_children = 1024 - -; The number of child processes created on startup. -; Note: Used only when pm is set to 'dynamic' -; Default Value: min_spare_servers + (max_spare_servers - min_spare_servers) / 2 -pm.start_servers = 512 - -; The desired minimum number of idle server processes. -; Note: Used only when pm is set to 'dynamic' -; Note: Mandatory when pm is set to 'dynamic' -pm.min_spare_servers = 50 - -; The desired maximum number of idle server processes. -; Note: Used only when pm is set to 'dynamic' -; Note: Mandatory when pm is set to 'dynamic' -pm.max_spare_servers = 512 - -; The number of seconds after which an idle process will be killed. -; Note: Used only when pm is set to 'ondemand' -; Default Value: 10s -;pm.process_idle_timeout = 10s; - -; The number of requests each child process should execute before respawning. -; This can be useful to work around memory leaks in 3rd party libraries. For -; endless request processing specify '0'. Equivalent to PHP_FCGI_MAX_REQUESTS. -; Default Value: 0 -;pm.max_requests = 500 - -; The URI to view the FPM status page. If this value is not set, no URI will be -; recognized as a status page. It shows the following informations: -; pool - the name of the pool; -; process manager - static, dynamic or ondemand; -; start time - the date and time FPM has started; -; start since - number of seconds since FPM has started; -; accepted conn - the number of request accepted by the pool; -; listen queue - the number of request in the queue of pending -; connections (see backlog in listen(2)); -; max listen queue - the maximum number of requests in the queue -; of pending connections since FPM has started; -; listen queue len - the size of the socket queue of pending connections; -; idle processes - the number of idle processes; -; active processes - the number of active processes; -; total processes - the number of idle + active processes; -; max active processes - the maximum number of active processes since FPM -; has started; -; max children reached - number of times, the process limit has been reached, -; when pm tries to start more children (works only for -; pm 'dynamic' and 'ondemand'); -; Value are updated in real time. -; Example output: -; pool: www -; process manager: static -; start time: 01/Jul/2011:17:53:49 +0200 -; start since: 62636 -; accepted conn: 190460 -; listen queue: 0 -; max listen queue: 1 -; listen queue len: 42 -; idle processes: 4 -; active processes: 11 -; total processes: 15 -; max active processes: 12 -; max children reached: 0 -; -; By default the status page output is formatted as text/plain. Passing either -; 'html', 'xml' or 'json' in the query string will return the corresponding -; output syntax. Example: -; http://www.foo.bar/status -; http://www.foo.bar/status?json -; http://www.foo.bar/status?html -; http://www.foo.bar/status?xml -; -; By default the status page only outputs short status. Passing 'full' in the -; query string will also return status for each pool process. -; Example: -; http://www.foo.bar/status?full -; http://www.foo.bar/status?json&full -; http://www.foo.bar/status?html&full -; http://www.foo.bar/status?xml&full -; The Full status returns for each process: -; pid - the PID of the process; -; state - the state of the process (Idle, Running, ...); -; start time - the date and time the process has started; -; start since - the number of seconds since the process has started; -; requests - the number of requests the process has served; -; request duration - the duration in µs of the requests; -; request method - the request method (GET, POST, ...); -; request URI - the request URI with the query string; -; content length - the content length of the request (only with POST); -; user - the user (PHP_AUTH_USER) (or '-' if not set); -; script - the main script called (or '-' if not set); -; last request cpu - the %cpu the last request consumed -; it's always 0 if the process is not in Idle state -; because CPU calculation is done when the request -; processing has terminated; -; last request memory - the max amount of memory the last request consumed -; it's always 0 if the process is not in Idle state -; because memory calculation is done when the request -; processing has terminated; -; If the process is in Idle state, then informations are related to the -; last request the process has served. Otherwise informations are related to -; the current request being served. -; Example output: -; ************************ -; pid: 31330 -; state: Running -; start time: 01/Jul/2011:17:53:49 +0200 -; start since: 63087 -; requests: 12808 -; request duration: 1250261 -; request method: GET -; request URI: /test_mem.php?N=10000 -; content length: 0 -; user: - -; script: /home/fat/web/docs/php/test_mem.php -; last request cpu: 0.00 -; last request memory: 0 -; -; Note: There is a real-time FPM status monitoring sample web page available -; It's available in: /usr/share/php/7.4/fpm/status.html -; -; Note: The value must start with a leading slash (/). The value can be -; anything, but it may not be a good idea to use the .php extension or it -; may conflict with a real PHP file. -; Default Value: not set -;pm.status_path = /status - -; The ping URI to call the monitoring page of FPM. If this value is not set, no -; URI will be recognized as a ping page. This could be used to test from outside -; that FPM is alive and responding, or to -; - create a graph of FPM availability (rrd or such); -; - remove a server from a group if it is not responding (load balancing); -; - trigger alerts for the operating team (24/7). -; Note: The value must start with a leading slash (/). The value can be -; anything, but it may not be a good idea to use the .php extension or it -; may conflict with a real PHP file. -; Default Value: not set -;ping.path = /ping - -; This directive may be used to customize the response of a ping request. The -; response is formatted as text/plain with a 200 response code. -; Default Value: pong -;ping.response = pong - -; The access log file -; Default: not set -;access.log = log/$pool.access.log - -; The access log format. -; The following syntax is allowed -; %%: the '%' character -; %C: %CPU used by the request -; it can accept the following format: -; - %{user}C for user CPU only -; - %{system}C for system CPU only -; - %{total}C for user + system CPU (default) -; %d: time taken to serve the request -; it can accept the following format: -; - %{seconds}d (default) -; - %{miliseconds}d -; - %{mili}d -; - %{microseconds}d -; - %{micro}d -; %e: an environment variable (same as $_ENV or $_SERVER) -; it must be associated with embraces to specify the name of the env -; variable. Some exemples: -; - server specifics like: %{REQUEST_METHOD}e or %{SERVER_PROTOCOL}e -; - HTTP headers like: %{HTTP_HOST}e or %{HTTP_USER_AGENT}e -; %f: script filename -; %l: content-length of the request (for POST request only) -; %m: request method -; %M: peak of memory allocated by PHP -; it can accept the following format: -; - %{bytes}M (default) -; - %{kilobytes}M -; - %{kilo}M -; - %{megabytes}M -; - %{mega}M -; %n: pool name -; %o: output header -; it must be associated with embraces to specify the name of the header: -; - %{Content-Type}o -; - %{X-Powered-By}o -; - %{Transfert-Encoding}o -; - .... -; %p: PID of the child that serviced the request -; %P: PID of the parent of the child that serviced the request -; %q: the query string -; %Q: the '?' character if query string exists -; %r: the request URI (without the query string, see %q and %Q) -; %R: remote IP address -; %s: status (response code) -; %t: server time the request was received -; it can accept a strftime(3) format: -; %d/%b/%Y:%H:%M:%S %z (default) -; The strftime(3) format must be encapsuled in a %{}t tag -; e.g. for a ISO8601 formatted timestring, use: %{%Y-%m-%dT%H:%M:%S%z}t -; %T: time the log has been written (the request has finished) -; it can accept a strftime(3) format: -; %d/%b/%Y:%H:%M:%S %z (default) -; The strftime(3) format must be encapsuled in a %{}t tag -; e.g. for a ISO8601 formatted timestring, use: %{%Y-%m-%dT%H:%M:%S%z}t -; %u: remote user -; -; Default: "%R - %u %t \"%m %r\" %s" -;access.format = "%R - %u %t \"%m %r%Q%q\" %s %f %{mili}d %{kilo}M %C%%" - -; The log file for slow requests -; Default Value: not set -; Note: slowlog is mandatory if request_slowlog_timeout is set -;slowlog = log/$pool.log.slow - -; The timeout for serving a single request after which a PHP backtrace will be -; dumped to the 'slowlog' file. A value of '0s' means 'off'. -; Available units: s(econds)(default), m(inutes), h(ours), or d(ays) -; Default Value: 0 -;request_slowlog_timeout = 0 - -; Depth of slow log stack trace. -; Default Value: 20 -;request_slowlog_trace_depth = 20 - -; The timeout for serving a single request after which the worker process will -; be killed. This option should be used when the 'max_execution_time' ini option -; does not stop script execution for some reason. A value of '0' means 'off'. -; Available units: s(econds)(default), m(inutes), h(ours), or d(ays) -; Default Value: 0 -;request_terminate_timeout = 0 - -; Set open file descriptor rlimit. -; Default Value: system defined value -rlimit_files = 100000 - -; Set max core size rlimit. -; Possible Values: 'unlimited' or an integer greater or equal to 0 -; Default Value: system defined value -rlimit_core = 'unlimited' - -; Chroot to this directory at the start. This value must be defined as an -; absolute path. When this value is not set, chroot is not used. -; Note: you can prefix with '$prefix' to chroot to the pool prefix or one -; of its subdirectories. If the pool prefix is not set, the global prefix -; will be used instead. -; Note: chrooting is a great security feature and should be used whenever -; possible. However, all PHP paths will be relative to the chroot -; (error_log, sessions.save_path, ...). -; Default Value: not set -;chroot = - -; Chdir to this directory at the start. -; Note: relative path can be used. -; Default Value: current directory or / when chroot -;chdir = /var/www - -; Redirect worker stdout and stderr into main error log. If not set, stdout and -; stderr will be redirected to /dev/null according to FastCGI specs. -; Note: on highloaded environement, this can cause some delay in the page -; process time (several ms). -; Default Value: no -;catch_workers_output = yes - -; Clear environment in FPM workers -; Prevents arbitrary environment variables from reaching FPM worker processes -; by clearing the environment in workers before env vars specified in this -; pool configuration are added. -; Setting to "no" will make all environment variables available to PHP code -; via getenv(), $_ENV and $_SERVER. -; Default Value: yes -;clear_env = no - -; Limits the extensions of the main script FPM will allow to parse. This can -; prevent configuration mistakes on the web server side. You should only limit -; FPM to .php extensions to prevent malicious users to use other extensions to -; execute php code. -; Note: set an empty value to allow all extensions. -; Default Value: .php -;security.limit_extensions = .php .php3 .php4 .php5 .php7 - -; Pass environment variables like LD_LIBRARY_PATH. All $VARIABLEs are taken from -; the current environment. -; Default Value: clean env -;env[HOSTNAME] = $HOSTNAME -;env[PATH] = /usr/local/bin:/usr/bin:/bin -;env[TMP] = /tmp -;env[TMPDIR] = /tmp -;env[TEMP] = /tmp - -; Additional php.ini defines, specific to this pool of workers. These settings -; overwrite the values previously defined in the php.ini. The directives are the -; same as the PHP SAPI: -; php_value/php_flag - you can set classic ini defines which can -; be overwritten from PHP call 'ini_set'. -; php_admin_value/php_admin_flag - these directives won't be overwritten by -; PHP call 'ini_set' -; For php_*flag, valid values are on, off, 1, 0, true, false, yes or no. - -; Defining 'extension' will load the corresponding shared extension from -; extension_dir. Defining 'disable_functions' or 'disable_classes' will not -; overwrite previously defined php.ini values, but will append the new value -; instead. - -; Note: path INI options can be relative and will be expanded with the prefix -; (pool, global or /usr) - -; Default Value: nothing is defined by default except the values in php.ini and -; specified at startup with the -d argument -;php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f www@my.domain.com -;php_flag[display_errors] = off -;php_admin_value[error_log] = /var/log/fpm-php.www.log -;php_admin_flag[log_errors] = on -;php_admin_value[memory_limit] = 32M \ No newline at end of file diff --git a/frameworks/PHP/lumen/deploy/conf/php.ini b/frameworks/PHP/lumen/deploy/conf/php.ini deleted file mode 100644 index 635f242c592..00000000000 --- a/frameworks/PHP/lumen/deploy/conf/php.ini +++ /dev/null @@ -1,1926 +0,0 @@ -[PHP] - -;;;;;;;;;;;;;;;;;;; -; About php.ini ; -;;;;;;;;;;;;;;;;;;; -; PHP's initialization file, generally called php.ini, is responsible for -; configuring many of the aspects of PHP's behavior. - -; PHP attempts to find and load this configuration from a number of locations. -; The following is a summary of its search order: -; 1. SAPI module specific location. -; 2. The PHPRC environment variable. (As of PHP 5.2.0) -; 3. A number of predefined registry keys on Windows (As of PHP 5.2.0) -; 4. Current working directory (except CLI) -; 5. The web server's directory (for SAPI modules), or directory of PHP -; (otherwise in Windows) -; 6. The directory from the --with-config-file-path compile time option, or the -; Windows directory (C:\windows or C:\winnt) -; See the PHP docs for more specific information. -; http://php.net/configuration.file - -; The syntax of the file is extremely simple. Whitespace and lines -; beginning with a semicolon are silently ignored (as you probably guessed). -; Section headers (e.g. [Foo]) are also silently ignored, even though -; they might mean something in the future. - -; Directives following the section heading [PATH=/www/mysite] only -; apply to PHP files in the /www/mysite directory. Directives -; following the section heading [HOST=www.example.com] only apply to -; PHP files served from www.example.com. Directives set in these -; special sections cannot be overridden by user-defined INI files or -; at runtime. Currently, [PATH=] and [HOST=] sections only work under -; CGI/FastCGI. -; http://php.net/ini.sections - -; Directives are specified using the following syntax: -; directive = value -; Directive names are *case sensitive* - foo=bar is different from FOO=bar. -; Directives are variables used to configure PHP or PHP extensions. -; There is no name validation. If PHP can't find an expected -; directive because it is not set or is mistyped, a default value will be used. - -; The value can be a string, a number, a PHP constant (e.g. E_ALL or M_PI), one -; of the INI constants (On, Off, True, False, Yes, No and None) or an expression -; (e.g. E_ALL & ~E_NOTICE), a quoted string ("bar"), or a reference to a -; previously set variable or directive (e.g. ${foo}) - -; Expressions in the INI file are limited to bitwise operators and parentheses: -; | bitwise OR -; ^ bitwise XOR -; & bitwise AND -; ~ bitwise NOT -; ! boolean NOT - -; Boolean flags can be turned on using the values 1, On, True or Yes. -; They can be turned off using the values 0, Off, False or No. - -; An empty string can be denoted by simply not writing anything after the equal -; sign, or by using the None keyword: - -; foo = ; sets foo to an empty string -; foo = None ; sets foo to an empty string -; foo = "None" ; sets foo to the string 'None' - -; If you use constants in your value, and these constants belong to a -; dynamically loaded extension (either a PHP extension or a Zend extension), -; you may only use these constants *after* the line that loads the extension. - -;;;;;;;;;;;;;;;;;;; -; About this file ; -;;;;;;;;;;;;;;;;;;; -; PHP comes packaged with two INI files. One that is recommended to be used -; in production environments and one that is recommended to be used in -; development environments. - -; php.ini-production contains settings which hold security, performance and -; best practices at its core. But please be aware, these settings may break -; compatibility with older or less security conscience applications. We -; recommending using the production ini in production and testing environments. - -; php.ini-development is very similar to its production variant, except it is -; much more verbose when it comes to errors. We recommend using the -; development version only in development environments, as errors shown to -; application users can inadvertently leak otherwise secure information. - -; This is php.ini-production INI file. - -;;;;;;;;;;;;;;;;;;; -; Quick Reference ; -;;;;;;;;;;;;;;;;;;; -; The following are all the settings which are different in either the production -; or development versions of the INIs with respect to PHP's default behavior. -; Please see the actual settings later in the document for more details as to why -; we recommend these changes in PHP's behavior. - -; display_errors -; Default Value: On -; Development Value: On -; Production Value: Off - -; display_startup_errors -; Default Value: Off -; Development Value: On -; Production Value: Off - -; error_reporting -; Default Value: E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED -; Development Value: E_ALL -; Production Value: E_ALL & ~E_DEPRECATED & ~E_STRICT - -; html_errors -; Default Value: On -; Development Value: On -; Production value: On - -; log_errors -; Default Value: Off -; Development Value: On -; Production Value: On - -; max_input_time -; Default Value: -1 (Unlimited) -; Development Value: 60 (60 seconds) -; Production Value: 60 (60 seconds) - -; output_buffering -; Default Value: Off -; Development Value: 4096 -; Production Value: 4096 - -; register_argc_argv -; Default Value: On -; Development Value: Off -; Production Value: Off - -; request_order -; Default Value: None -; Development Value: "GP" -; Production Value: "GP" - -; session.gc_divisor -; Default Value: 100 -; Development Value: 1000 -; Production Value: 1000 - -; session.sid_bits_per_character -; Default Value: 4 -; Development Value: 5 -; Production Value: 5 - -; short_open_tag -; Default Value: On -; Development Value: Off -; Production Value: Off - -; track_errors -; Default Value: Off -; Development Value: On -; Production Value: Off - -; variables_order -; Default Value: "EGPCS" -; Development Value: "GPCS" -; Production Value: "GPCS" - -;;;;;;;;;;;;;;;;;;;; -; php.ini Options ; -;;;;;;;;;;;;;;;;;;;; -; Name for user-defined php.ini (.htaccess) files. Default is ".user.ini" -;user_ini.filename = ".user.ini" - -; To disable this feature set this option to empty value -;user_ini.filename = - -; TTL for user-defined php.ini files (time-to-live) in seconds. Default is 300 seconds (5 minutes) -;user_ini.cache_ttl = 300 - -;;;;;;;;;;;;;;;;;;;; -; Language Options ; -;;;;;;;;;;;;;;;;;;;; - -; Enable the PHP scripting language engine under Apache. -; http://php.net/engine -engine = On - -; This directive determines whether or not PHP will recognize code between -; tags as PHP source which should be processed as such. It is -; generally recommended that should be used and that this feature -; should be disabled, as enabling it may result in issues when generating XML -; documents, however this remains supported for backward compatibility reasons. -; Note that this directive does not control the would work. -; http://php.net/syntax-highlighting -;highlight.string = #DD0000 -;highlight.comment = #FF9900 -;highlight.keyword = #007700 -;highlight.default = #0000BB -;highlight.html = #000000 - -; If enabled, the request will be allowed to complete even if the user aborts -; the request. Consider enabling it if executing long requests, which may end up -; being interrupted by the user or a browser timing out. PHP's default behavior -; is to disable this feature. -; http://php.net/ignore-user-abort -;ignore_user_abort = On - -; Determines the size of the realpath cache to be used by PHP. This value should -; be increased on systems where PHP opens many files to reflect the quantity of -; the file operations performed. -; http://php.net/realpath-cache-size -realpath_cache_size = 4096k - -; Duration of time, in seconds for which to cache realpath information for a given -; file or directory. For systems with rarely changing files, consider increasing this -; value. -; http://php.net/realpath-cache-ttl -realpath_cache_ttl = 600 - -; Enables or disables the circular reference collector. -; http://php.net/zend.enable-gc -zend.enable_gc = On - -; If enabled, scripts may be written in encodings that are incompatible with -; the scanner. CP936, Big5, CP949 and Shift_JIS are the examples of such -; encodings. To use this feature, mbstring extension must be enabled. -; Default: Off -;zend.multibyte = Off - -; Allows to set the default encoding for the scripts. This value will be used -; unless "declare(encoding=...)" directive appears at the top of the script. -; Only affects if zend.multibyte is set. -; Default: "" -;zend.script_encoding = - -;;;;;;;;;;;;;;;;; -; Miscellaneous ; -;;;;;;;;;;;;;;;;; - -; Decides whether PHP may expose the fact that it is installed on the server -; (e.g. by adding its signature to the Web server header). It is no security -; threat in any way, but it makes it possible to determine whether you use PHP -; on your server or not. -; http://php.net/expose-php -expose_php = Off - -;;;;;;;;;;;;;;;;;;; -; Resource Limits ; -;;;;;;;;;;;;;;;;;;; - -; Maximum execution time of each script, in seconds -; http://php.net/max-execution-time -; Note: This directive is hardcoded to 0 for the CLI SAPI -max_execution_time = 30 - -; Maximum amount of time each script may spend parsing request data. It's a good -; idea to limit this time on productions servers in order to eliminate unexpectedly -; long running scripts. -; Note: This directive is hardcoded to -1 for the CLI SAPI -; Default Value: -1 (Unlimited) -; Development Value: 60 (60 seconds) -; Production Value: 60 (60 seconds) -; http://php.net/max-input-time -max_input_time = 60 - -; Maximum input variable nesting level -; http://php.net/max-input-nesting-level -;max_input_nesting_level = 64 - -; How many GET/POST/COOKIE input variables may be accepted -; max_input_vars = 1000 - -; Maximum amount of memory a script may consume (128MB) -; http://php.net/memory-limit -memory_limit = 128M - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; Error handling and logging ; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -; This directive informs PHP of which errors, warnings and notices you would like -; it to take action for. The recommended way of setting values for this -; directive is through the use of the error level constants and bitwise -; operators. The error level constants are below here for convenience as well as -; some common settings and their meanings. -; By default, PHP is set to take action on all errors, notices and warnings EXCEPT -; those related to E_NOTICE and E_STRICT, which together cover best practices and -; recommended coding standards in PHP. For performance reasons, this is the -; recommend error reporting setting. Your production server shouldn't be wasting -; resources complaining about best practices and coding standards. That's what -; development servers and development settings are for. -; Note: The php.ini-development file has this setting as E_ALL. This -; means it pretty much reports everything which is exactly what you want during -; development and early testing. -; -; Error Level Constants: -; E_ALL - All errors and warnings (includes E_STRICT as of PHP 5.4.0) -; E_ERROR - fatal run-time errors -; E_RECOVERABLE_ERROR - almost fatal run-time errors -; E_WARNING - run-time warnings (non-fatal errors) -; E_PARSE - compile-time parse errors -; E_NOTICE - run-time notices (these are warnings which often result -; from a bug in your code, but it's possible that it was -; intentional (e.g., using an uninitialized variable and -; relying on the fact it is automatically initialized to an -; empty string) -; E_STRICT - run-time notices, enable to have PHP suggest changes -; to your code which will ensure the best interoperability -; and forward compatibility of your code -; E_CORE_ERROR - fatal errors that occur during PHP's initial startup -; E_CORE_WARNING - warnings (non-fatal errors) that occur during PHP's -; initial startup -; E_COMPILE_ERROR - fatal compile-time errors -; E_COMPILE_WARNING - compile-time warnings (non-fatal errors) -; E_USER_ERROR - user-generated error message -; E_USER_WARNING - user-generated warning message -; E_USER_NOTICE - user-generated notice message -; E_DEPRECATED - warn about code that will not work in future versions -; of PHP -; E_USER_DEPRECATED - user-generated deprecation warnings -; -; Common Values: -; E_ALL (Show all errors, warnings and notices including coding standards.) -; E_ALL & ~E_NOTICE (Show all errors, except for notices) -; E_ALL & ~E_NOTICE & ~E_STRICT (Show all errors, except for notices and coding standards warnings.) -; E_COMPILE_ERROR|E_RECOVERABLE_ERROR|E_ERROR|E_CORE_ERROR (Show only errors) -; Default Value: E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED -; Development Value: E_ALL -; Production Value: E_ALL & ~E_DEPRECATED & ~E_STRICT -; http://php.net/error-reporting -error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT - -; This directive controls whether or not and where PHP will output errors, -; notices and warnings too. Error output is very useful during development, but -; it could be very dangerous in production environments. Depending on the code -; which is triggering the error, sensitive information could potentially leak -; out of your application such as database usernames and passwords or worse. -; For production environments, we recommend logging errors rather than -; sending them to STDOUT. -; Possible Values: -; Off = Do not display any errors -; stderr = Display errors to STDERR (affects only CGI/CLI binaries!) -; On or stdout = Display errors to STDOUT -; Default Value: On -; Development Value: On -; Production Value: Off -; http://php.net/display-errors -display_errors = Off - -; The display of errors which occur during PHP's startup sequence are handled -; separately from display_errors. PHP's default behavior is to suppress those -; errors from clients. Turning the display of startup errors on can be useful in -; debugging configuration problems. We strongly recommend you -; set this to 'off' for production servers. -; Default Value: Off -; Development Value: On -; Production Value: Off -; http://php.net/display-startup-errors -display_startup_errors = Off - -; Besides displaying errors, PHP can also log errors to locations such as a -; server-specific log, STDERR, or a location specified by the error_log -; directive found below. While errors should not be displayed on productions -; servers they should still be monitored and logging is a great way to do that. -; Default Value: Off -; Development Value: On -; Production Value: On -; http://php.net/log-errors -log_errors = On - -; Set maximum length of log_errors. In error_log information about the source is -; added. The default is 1024 and 0 allows to not apply any maximum length at all. -; http://php.net/log-errors-max-len -log_errors_max_len = 1024 - -; Do not log repeated messages. Repeated errors must occur in same file on same -; line unless ignore_repeated_source is set true. -; http://php.net/ignore-repeated-errors -ignore_repeated_errors = Off - -; Ignore source of message when ignoring repeated messages. When this setting -; is On you will not log errors with repeated messages from different files or -; source lines. -; http://php.net/ignore-repeated-source -ignore_repeated_source = Off - -; If this parameter is set to Off, then memory leaks will not be shown (on -; stdout or in the log). This has only effect in a debug compile, and if -; error reporting includes E_WARNING in the allowed list -; http://php.net/report-memleaks -report_memleaks = On - -; This setting is on by default. -;report_zend_debug = 0 - -; Store the last error/warning message in $php_errormsg (boolean). Setting this value -; to On can assist in debugging and is appropriate for development servers. It should -; however be disabled on production servers. -; This directive is DEPRECATED. -; Default Value: Off -; Development Value: Off -; Production Value: Off -; http://php.net/track-errors -;track_errors = Off - -; Turn off normal error reporting and emit XML-RPC error XML -; http://php.net/xmlrpc-errors -;xmlrpc_errors = 0 - -; An XML-RPC faultCode -;xmlrpc_error_number = 0 - -; When PHP displays or logs an error, it has the capability of formatting the -; error message as HTML for easier reading. This directive controls whether -; the error message is formatted as HTML or not. -; Note: This directive is hardcoded to Off for the CLI SAPI -; Default Value: On -; Development Value: On -; Production value: On -; http://php.net/html-errors -html_errors = On - -; If html_errors is set to On *and* docref_root is not empty, then PHP -; produces clickable error messages that direct to a page describing the error -; or function causing the error in detail. -; You can download a copy of the PHP manual from http://php.net/docs -; and change docref_root to the base URL of your local copy including the -; leading '/'. You must also specify the file extension being used including -; the dot. PHP's default behavior is to leave these settings empty, in which -; case no links to documentation are generated. -; Note: Never use this feature for production boxes. -; http://php.net/docref-root -; Examples -;docref_root = "/phpmanual/" - -; http://php.net/docref-ext -;docref_ext = .html - -; String to output before an error message. PHP's default behavior is to leave -; this setting blank. -; http://php.net/error-prepend-string -; Example: -;error_prepend_string = "" - -; String to output after an error message. PHP's default behavior is to leave -; this setting blank. -; http://php.net/error-append-string -; Example: -;error_append_string = "" - -; Log errors to specified file. PHP's default behavior is to leave this value -; empty. -; http://php.net/error-log -; Example: -;error_log = php_errors.log -; Log errors to syslog (Event Log on Windows). -;error_log = syslog - -;windows.show_crt_warning -; Default value: 0 -; Development value: 0 -; Production value: 0 - -;;;;;;;;;;;;;;;;; -; Data Handling ; -;;;;;;;;;;;;;;;;; - -; The separator used in PHP generated URLs to separate arguments. -; PHP's default setting is "&". -; http://php.net/arg-separator.output -; Example: -;arg_separator.output = "&" - -; List of separator(s) used by PHP to parse input URLs into variables. -; PHP's default setting is "&". -; NOTE: Every character in this directive is considered as separator! -; http://php.net/arg-separator.input -; Example: -;arg_separator.input = ";&" - -; This directive determines which super global arrays are registered when PHP -; starts up. G,P,C,E & S are abbreviations for the following respective super -; globals: GET, POST, COOKIE, ENV and SERVER. There is a performance penalty -; paid for the registration of these arrays and because ENV is not as commonly -; used as the others, ENV is not recommended on productions servers. You -; can still get access to the environment variables through getenv() should you -; need to. -; Default Value: "EGPCS" -; Development Value: "GPCS" -; Production Value: "GPCS"; -; http://php.net/variables-order -variables_order = "GPCS" - -; This directive determines which super global data (G,P & C) should be -; registered into the super global array REQUEST. If so, it also determines -; the order in which that data is registered. The values for this directive -; are specified in the same manner as the variables_order directive, -; EXCEPT one. Leaving this value empty will cause PHP to use the value set -; in the variables_order directive. It does not mean it will leave the super -; globals array REQUEST empty. -; Default Value: None -; Development Value: "GP" -; Production Value: "GP" -; http://php.net/request-order -request_order = "GP" - -; This directive determines whether PHP registers $argv & $argc each time it -; runs. $argv contains an array of all the arguments passed to PHP when a script -; is invoked. $argc contains an integer representing the number of arguments -; that were passed when the script was invoked. These arrays are extremely -; useful when running scripts from the command line. When this directive is -; enabled, registering these variables consumes CPU cycles and memory each time -; a script is executed. For performance reasons, this feature should be disabled -; on production servers. -; Note: This directive is hardcoded to On for the CLI SAPI -; Default Value: On -; Development Value: Off -; Production Value: Off -; http://php.net/register-argc-argv -register_argc_argv = Off - -; When enabled, the ENV, REQUEST and SERVER variables are created when they're -; first used (Just In Time) instead of when the script starts. If these -; variables are not used within a script, having this directive on will result -; in a performance gain. The PHP directive register_argc_argv must be disabled -; for this directive to have any affect. -; http://php.net/auto-globals-jit -auto_globals_jit = On - -; Whether PHP will read the POST data. -; This option is enabled by default. -; Most likely, you won't want to disable this option globally. It causes $_POST -; and $_FILES to always be empty; the only way you will be able to read the -; POST data will be through the php://input stream wrapper. This can be useful -; to proxy requests or to process the POST data in a memory efficient fashion. -; http://php.net/enable-post-data-reading -;enable_post_data_reading = Off - -; Maximum size of POST data that PHP will accept. -; Its value may be 0 to disable the limit. It is ignored if POST data reading -; is disabled through enable_post_data_reading. -; http://php.net/post-max-size -post_max_size = 8M - -; Automatically add files before PHP document. -; http://php.net/auto-prepend-file -auto_prepend_file = - -; Automatically add files after PHP document. -; http://php.net/auto-append-file -auto_append_file = - -; By default, PHP will output a media type using the Content-Type header. To -; disable this, simply set it to be empty. -; -; PHP's built-in default media type is set to text/html. -; http://php.net/default-mimetype -default_mimetype = "text/html" - -; PHP's default character set is set to UTF-8. -; http://php.net/default-charset -default_charset = "UTF-8" - -; PHP internal character encoding is set to empty. -; If empty, default_charset is used. -; http://php.net/internal-encoding -;internal_encoding = - -; PHP input character encoding is set to empty. -; If empty, default_charset is used. -; http://php.net/input-encoding -;input_encoding = - -; PHP output character encoding is set to empty. -; If empty, default_charset is used. -; See also output_buffer. -; http://php.net/output-encoding -;output_encoding = - -;;;;;;;;;;;;;;;;;;;;;;;;; -; Paths and Directories ; -;;;;;;;;;;;;;;;;;;;;;;;;; - -; UNIX: "/path1:/path2" -;include_path = ".:/usr/share/php" -; -; Windows: "\path1;\path2" -;include_path = ".;c:\php\includes" -; -; PHP's default setting for include_path is ".;/path/to/php/pear" -; http://php.net/include-path - -; The root of the PHP pages, used only if nonempty. -; if PHP was not compiled with FORCE_REDIRECT, you SHOULD set doc_root -; if you are running php as a CGI under any web server (other than IIS) -; see documentation for security issues. The alternate is to use the -; cgi.force_redirect configuration below -; http://php.net/doc-root -doc_root = - -; The directory under which PHP opens the script using /~username used only -; if nonempty. -; http://php.net/user-dir -user_dir = - -; Directory in which the loadable extensions (modules) reside. -; http://php.net/extension-dir -; extension_dir = "./" -; On windows: -; extension_dir = "ext" - -; Directory where the temporary files should be placed. -; Defaults to the system default (see sys_get_temp_dir) -; sys_temp_dir = "/tmp" - -; Whether or not to enable the dl() function. The dl() function does NOT work -; properly in multithreaded servers, such as IIS or Zeus, and is automatically -; disabled on them. -; http://php.net/enable-dl -enable_dl = Off - -; cgi.force_redirect is necessary to provide security running PHP as a CGI under -; most web servers. Left undefined, PHP turns this on by default. You can -; turn it off here AT YOUR OWN RISK -; **You CAN safely turn this off for IIS, in fact, you MUST.** -; http://php.net/cgi.force-redirect -;cgi.force_redirect = 1 - -; if cgi.nph is enabled it will force cgi to always sent Status: 200 with -; every request. PHP's default behavior is to disable this feature. -;cgi.nph = 1 - -; if cgi.force_redirect is turned on, and you are not running under Apache or Netscape -; (iPlanet) web servers, you MAY need to set an environment variable name that PHP -; will look for to know it is OK to continue execution. Setting this variable MAY -; cause security issues, KNOW WHAT YOU ARE DOING FIRST. -; http://php.net/cgi.redirect-status-env -;cgi.redirect_status_env = - -; cgi.fix_pathinfo provides *real* PATH_INFO/PATH_TRANSLATED support for CGI. PHP's -; previous behaviour was to set PATH_TRANSLATED to SCRIPT_FILENAME, and to not grok -; what PATH_INFO is. For more information on PATH_INFO, see the cgi specs. Setting -; this to 1 will cause PHP CGI to fix its paths to conform to the spec. A setting -; of zero causes PHP to behave as before. Default is 1. You should fix your scripts -; to use SCRIPT_FILENAME rather than PATH_TRANSLATED. -; http://php.net/cgi.fix-pathinfo - cgi.fix_pathinfo=0 - -; if cgi.discard_path is enabled, the PHP CGI binary can safely be placed outside -; of the web tree and people will not be able to circumvent .htaccess security. -; http://php.net/cgi.dicard-path -;cgi.discard_path=1 - -; FastCGI under IIS (on WINNT based OS) supports the ability to impersonate -; security tokens of the calling client. This allows IIS to define the -; security context that the request runs under. mod_fastcgi under Apache -; does not currently support this feature (03/17/2002) -; Set to 1 if running under IIS. Default is zero. -; http://php.net/fastcgi.impersonate -;fastcgi.impersonate = 1 - -; Disable logging through FastCGI connection. PHP's default behavior is to enable -; this feature. -;fastcgi.logging = 0 - -; cgi.rfc2616_headers configuration option tells PHP what type of headers to -; use when sending HTTP response code. If set to 0, PHP sends Status: header that -; is supported by Apache. When this option is set to 1, PHP will send -; RFC2616 compliant header. -; Default is zero. -; http://php.net/cgi.rfc2616-headers -;cgi.rfc2616_headers = 0 - -; cgi.check_shebang_line controls whether CGI PHP checks for line starting with #! -; (shebang) at the top of the running script. This line might be needed if the -; script support running both as stand-alone script and via PHP CGI<. PHP in CGI -; mode skips this line and ignores its content if this directive is turned on. -; http://php.net/cgi.check-shebang-line -;cgi.check_shebang_line=1 - -;;;;;;;;;;;;;;;; -; File Uploads ; -;;;;;;;;;;;;;;;; - -; Whether to allow HTTP file uploads. -; http://php.net/file-uploads -file_uploads = On - -; Temporary directory for HTTP uploaded files (will use system default if not -; specified). -; http://php.net/upload-tmp-dir -;upload_tmp_dir = - -; Maximum allowed size for uploaded files. -; http://php.net/upload-max-filesize -upload_max_filesize = 2M - -; Maximum number of files that can be uploaded via a single request -max_file_uploads = 20 - -;;;;;;;;;;;;;;;;;; -; Fopen wrappers ; -;;;;;;;;;;;;;;;;;; - -; Whether to allow the treatment of URLs (like http:// or ftp://) as files. -; http://php.net/allow-url-fopen -allow_url_fopen = On - -; Whether to allow include/require to open URLs (like http:// or ftp://) as files. -; http://php.net/allow-url-include -allow_url_include = Off - -; Define the anonymous ftp password (your email address). PHP's default setting -; for this is empty. -; http://php.net/from -;from="john@doe.com" - -; Define the User-Agent string. PHP's default setting for this is empty. -; http://php.net/user-agent -;user_agent="PHP" - -; Default timeout for socket based streams (seconds) -; http://php.net/default-socket-timeout -default_socket_timeout = 60 - -; If your scripts have to deal with files from Macintosh systems, -; or you are running on a Mac and need to deal with files from -; unix or win32 systems, setting this flag will cause PHP to -; automatically detect the EOL character in those files so that -; fgets() and file() will work regardless of the source of the file. -; http://php.net/auto-detect-line-endings -;auto_detect_line_endings = Off - -;;;;;;;;;;;;;;;;;;;;;; -; Dynamic Extensions ; -;;;;;;;;;;;;;;;;;;;;;; - -; If you wish to have an extension loaded automatically, use the following -; syntax: -; -; extension=modulename -; -; For example: -; -; extension=mysqli -; -; When the extension library to load is not located in the default extension -; directory, You may specify an absolute path to the library file: -; -; extension=/path/to/extension/mysqli.so -; -; Note : The syntax used in previous PHP versions ('extension=.so' and -; 'extension='php_.dll') is supported for legacy reasons and may be -; deprecated in a future PHP major version. So, when it is possible, please -; move to the new ('extension=) syntax. -; -; Notes for Windows environments : -; -; - ODBC support is built in, so no dll is needed for it. -; - Many DLL files are located in the extensions/ (PHP 4) or ext/ (PHP 5+) -; extension folders as well as the separate PECL DLL download (PHP 5+). -; Be sure to appropriately set the extension_dir directive. -; -;extension=bz2 -;extension=curl -;extension=fileinfo -;extension=gd2 -;extension=gettext -;extension=gmp -;extension=intl -;extension=imap -;extension=interbase -;extension=ldap -;extension=mbstring -;extension=exif ; Must be after mbstring as it depends on it -;extension=mysqli -;extension=oci8_12c ; Use with Oracle Database 12c Instant Client -;extension=openssl -;extension=pdo_firebird -;extension=pdo_mysql -;extension=pdo_oci -;extension=pdo_odbc -;extension=pdo_pgsql -;extension=pdo_sqlite -;extension=pgsql -;extension=shmop - -; The MIBS data available in the PHP distribution must be installed. -; See http://www.php.net/manual/en/snmp.installation.php -;extension=snmp - -;extension=soap -;extension=sockets -;extension=sqlite3 -;extension=tidy -;extension=xmlrpc -;extension=xsl - -;;;;;;;;;;;;;;;;;;; -; Module Settings ; -;;;;;;;;;;;;;;;;;;; - -[CLI Server] -; Whether the CLI web server uses ANSI color coding in its terminal output. -cli_server.color = On - -[Date] -; Defines the default timezone used by the date functions -; http://php.net/date.timezone -date.timezone = UTC - -; http://php.net/date.default-latitude -;date.default_latitude = 31.7667 - -; http://php.net/date.default-longitude -;date.default_longitude = 35.2333 - -; http://php.net/date.sunrise-zenith -;date.sunrise_zenith = 90.583333 - -; http://php.net/date.sunset-zenith -;date.sunset_zenith = 90.583333 - -[filter] -; http://php.net/filter.default -;filter.default = unsafe_raw - -; http://php.net/filter.default-flags -;filter.default_flags = - -[iconv] -; Use of this INI entry is deprecated, use global input_encoding instead. -; If empty, default_charset or input_encoding or iconv.input_encoding is used. -; The precedence is: default_charset < intput_encoding < iconv.input_encoding -;iconv.input_encoding = - -; Use of this INI entry is deprecated, use global internal_encoding instead. -; If empty, default_charset or internal_encoding or iconv.internal_encoding is used. -; The precedence is: default_charset < internal_encoding < iconv.internal_encoding -;iconv.internal_encoding = - -; Use of this INI entry is deprecated, use global output_encoding instead. -; If empty, default_charset or output_encoding or iconv.output_encoding is used. -; The precedence is: default_charset < output_encoding < iconv.output_encoding -; To use an output encoding conversion, iconv's output handler must be set -; otherwise output encoding conversion cannot be performed. -;iconv.output_encoding = - -[intl] -;intl.default_locale = -; This directive allows you to produce PHP errors when some error -; happens within intl functions. The value is the level of the error produced. -; Default is 0, which does not produce any errors. -;intl.error_level = E_WARNING -;intl.use_exceptions = 0 - -[sqlite3] -;sqlite3.extension_dir = - -[Pcre] -;PCRE library backtracking limit. -; http://php.net/pcre.backtrack-limit -;pcre.backtrack_limit=100000 - -;PCRE library recursion limit. -;Please note that if you set this value to a high number you may consume all -;the available process stack and eventually crash PHP (due to reaching the -;stack size limit imposed by the Operating System). -; http://php.net/pcre.recursion-limit -;pcre.recursion_limit=100000 - -;Enables or disables JIT compilation of patterns. This requires the PCRE -;library to be compiled with JIT support. -;pcre.jit=1 - -[Pdo] -; Whether to pool ODBC connections. Can be one of "strict", "relaxed" or "off" -; http://php.net/pdo-odbc.connection-pooling -;pdo_odbc.connection_pooling=strict - -;pdo_odbc.db2_instance_name - -[Pdo_mysql] -; If mysqlnd is used: Number of cache slots for the internal result set cache -; http://php.net/pdo_mysql.cache_size -pdo_mysql.cache_size = 2000 - -; Default socket name for local MySQL connects. If empty, uses the built-in -; MySQL defaults. -; http://php.net/pdo_mysql.default-socket -pdo_mysql.default_socket= - -[Phar] -; http://php.net/phar.readonly -;phar.readonly = On - -; http://php.net/phar.require-hash -;phar.require_hash = On - -;phar.cache_list = - -[mail function] -; For Win32 only. -; http://php.net/smtp -SMTP = localhost -; http://php.net/smtp-port -smtp_port = 25 - -; For Win32 only. -; http://php.net/sendmail-from -;sendmail_from = me@example.com - -; For Unix only. You may supply arguments as well (default: "sendmail -t -i"). -; http://php.net/sendmail-path -;sendmail_path = - -; Force the addition of the specified parameters to be passed as extra parameters -; to the sendmail binary. These parameters will always replace the value of -; the 5th parameter to mail(). -;mail.force_extra_parameters = - -; Add X-PHP-Originating-Script: that will include uid of the script followed by the filename -mail.add_x_header = On - -; The path to a log file that will log all mail() calls. Log entries include -; the full path of the script, line number, To address and headers. -;mail.log = -; Log mail to syslog (Event Log on Windows). -;mail.log = syslog - -[ODBC] -; http://php.net/odbc.default-db -;odbc.default_db = Not yet implemented - -; http://php.net/odbc.default-user -;odbc.default_user = Not yet implemented - -; http://php.net/odbc.default-pw -;odbc.default_pw = Not yet implemented - -; Controls the ODBC cursor model. -; Default: SQL_CURSOR_STATIC (default). -;odbc.default_cursortype - -; Allow or prevent persistent links. -; http://php.net/odbc.allow-persistent -odbc.allow_persistent = On - -; Check that a connection is still valid before reuse. -; http://php.net/odbc.check-persistent -odbc.check_persistent = On - -; Maximum number of persistent links. -1 means no limit. -; http://php.net/odbc.max-persistent -odbc.max_persistent = -1 - -; Maximum number of links (persistent + non-persistent). -1 means no limit. -; http://php.net/odbc.max-links -odbc.max_links = -1 - -; Handling of LONG fields. Returns number of bytes to variables. 0 means -; passthru. -; http://php.net/odbc.defaultlrl -odbc.defaultlrl = 4096 - -; Handling of binary data. 0 means passthru, 1 return as is, 2 convert to char. -; See the documentation on odbc_binmode and odbc_longreadlen for an explanation -; of odbc.defaultlrl and odbc.defaultbinmode -; http://php.net/odbc.defaultbinmode -odbc.defaultbinmode = 1 - -;birdstep.max_links = -1 - -[Interbase] -; Allow or prevent persistent links. -ibase.allow_persistent = 1 - -; Maximum number of persistent links. -1 means no limit. -ibase.max_persistent = -1 - -; Maximum number of links (persistent + non-persistent). -1 means no limit. -ibase.max_links = -1 - -; Default database name for ibase_connect(). -;ibase.default_db = - -; Default username for ibase_connect(). -;ibase.default_user = - -; Default password for ibase_connect(). -;ibase.default_password = - -; Default charset for ibase_connect(). -;ibase.default_charset = - -; Default timestamp format. -ibase.timestampformat = "%Y-%m-%d %H:%M:%S" - -; Default date format. -ibase.dateformat = "%Y-%m-%d" - -; Default time format. -ibase.timeformat = "%H:%M:%S" - -[MySQLi] - -; Maximum number of persistent links. -1 means no limit. -; http://php.net/mysqli.max-persistent -mysqli.max_persistent = -1 - -; Allow accessing, from PHP's perspective, local files with LOAD DATA statements -; http://php.net/mysqli.allow_local_infile -;mysqli.allow_local_infile = On - -; Allow or prevent persistent links. -; http://php.net/mysqli.allow-persistent -mysqli.allow_persistent = On - -; Maximum number of links. -1 means no limit. -; http://php.net/mysqli.max-links -mysqli.max_links = -1 - -; If mysqlnd is used: Number of cache slots for the internal result set cache -; http://php.net/mysqli.cache_size -mysqli.cache_size = 2000 - -; Default port number for mysqli_connect(). If unset, mysqli_connect() will use -; the $MYSQL_TCP_PORT or the mysql-tcp entry in /etc/services or the -; compile-time value defined MYSQL_PORT (in that order). Win32 will only look -; at MYSQL_PORT. -; http://php.net/mysqli.default-port -mysqli.default_port = 3306 - -; Default socket name for local MySQL connects. If empty, uses the built-in -; MySQL defaults. -; http://php.net/mysqli.default-socket -mysqli.default_socket = - -; Default host for mysql_connect() (doesn't apply in safe mode). -; http://php.net/mysqli.default-host -mysqli.default_host = - -; Default user for mysql_connect() (doesn't apply in safe mode). -; http://php.net/mysqli.default-user -mysqli.default_user = - -; Default password for mysqli_connect() (doesn't apply in safe mode). -; Note that this is generally a *bad* idea to store passwords in this file. -; *Any* user with PHP access can run 'echo get_cfg_var("mysqli.default_pw") -; and reveal this password! And of course, any users with read access to this -; file will be able to reveal the password as well. -; http://php.net/mysqli.default-pw -mysqli.default_pw = - -; Allow or prevent reconnect -mysqli.reconnect = Off - -[mysqlnd] -; Enable / Disable collection of general statistics by mysqlnd which can be -; used to tune and monitor MySQL operations. -; http://php.net/mysqlnd.collect_statistics -mysqlnd.collect_statistics = Off - -; Enable / Disable collection of memory usage statistics by mysqlnd which can be -; used to tune and monitor MySQL operations. -; http://php.net/mysqlnd.collect_memory_statistics -mysqlnd.collect_memory_statistics = Off - -; Records communication from all extensions using mysqlnd to the specified log -; file. -; http://php.net/mysqlnd.debug -;mysqlnd.debug = - -; Defines which queries will be logged. -; http://php.net/mysqlnd.log_mask -;mysqlnd.log_mask = 0 - -; Default size of the mysqlnd memory pool, which is used by result sets. -; http://php.net/mysqlnd.mempool_default_size -mysqlnd.mempool_default_size = 32768 - -; Size of a pre-allocated buffer used when sending commands to MySQL in bytes. -; http://php.net/mysqlnd.net_cmd_buffer_size -mysqlnd.net_cmd_buffer_size = 4096 - -; Size of a pre-allocated buffer used for reading data sent by the server in -; bytes. -; http://php.net/mysqlnd.net_read_buffer_size -;mysqlnd.net_read_buffer_size = 32768 - -; Timeout for network requests in seconds. -; http://php.net/mysqlnd.net_read_timeout -;mysqlnd.net_read_timeout = 31536000 - -; SHA-256 Authentication Plugin related. File with the MySQL server public RSA -; key. -; http://php.net/mysqlnd.sha256_server_public_key -;mysqlnd.sha256_server_public_key = - -[OCI8] - -; Connection: Enables privileged connections using external -; credentials (OCI_SYSOPER, OCI_SYSDBA) -; http://php.net/oci8.privileged-connect -;oci8.privileged_connect = Off - -; Connection: The maximum number of persistent OCI8 connections per -; process. Using -1 means no limit. -; http://php.net/oci8.max-persistent -;oci8.max_persistent = -1 - -; Connection: The maximum number of seconds a process is allowed to -; maintain an idle persistent connection. Using -1 means idle -; persistent connections will be maintained forever. -; http://php.net/oci8.persistent-timeout -;oci8.persistent_timeout = -1 - -; Connection: The number of seconds that must pass before issuing a -; ping during oci_pconnect() to check the connection validity. When -; set to 0, each oci_pconnect() will cause a ping. Using -1 disables -; pings completely. -; http://php.net/oci8.ping-interval -;oci8.ping_interval = 60 - -; Connection: Set this to a user chosen connection class to be used -; for all pooled server requests with Oracle 11g Database Resident -; Connection Pooling (DRCP). To use DRCP, this value should be set to -; the same string for all web servers running the same application, -; the database pool must be configured, and the connection string must -; specify to use a pooled server. -;oci8.connection_class = - -; High Availability: Using On lets PHP receive Fast Application -; Notification (FAN) events generated when a database node fails. The -; database must also be configured to post FAN events. -;oci8.events = Off - -; Tuning: This option enables statement caching, and specifies how -; many statements to cache. Using 0 disables statement caching. -; http://php.net/oci8.statement-cache-size -;oci8.statement_cache_size = 20 - -; Tuning: Enables statement prefetching and sets the default number of -; rows that will be fetched automatically after statement execution. -; http://php.net/oci8.default-prefetch -;oci8.default_prefetch = 100 - -; Compatibility. Using On means oci_close() will not close -; oci_connect() and oci_new_connect() connections. -; http://php.net/oci8.old-oci-close-semantics -;oci8.old_oci_close_semantics = Off - -[PostgreSQL] -; Allow or prevent persistent links. -; http://php.net/pgsql.allow-persistent -pgsql.allow_persistent = On - -; Detect broken persistent links always with pg_pconnect(). -; Auto reset feature requires a little overheads. -; http://php.net/pgsql.auto-reset-persistent -pgsql.auto_reset_persistent = Off - -; Maximum number of persistent links. -1 means no limit. -; http://php.net/pgsql.max-persistent -pgsql.max_persistent = -1 - -; Maximum number of links (persistent+non persistent). -1 means no limit. -; http://php.net/pgsql.max-links -pgsql.max_links = -1 - -; Ignore PostgreSQL backends Notice message or not. -; Notice message logging require a little overheads. -; http://php.net/pgsql.ignore-notice -pgsql.ignore_notice = 0 - -; Log PostgreSQL backends Notice message or not. -; Unless pgsql.ignore_notice=0, module cannot log notice message. -; http://php.net/pgsql.log-notice -pgsql.log_notice = 0 - -[bcmath] -; Number of decimal digits for all bcmath functions. -; http://php.net/bcmath.scale -bcmath.scale = 0 - -[browscap] -; http://php.net/browscap -;browscap = extra/browscap.ini - -[Session] -; Handler used to store/retrieve data. -; http://php.net/session.save-handler -session.save_handler = files - -; Argument passed to save_handler. In the case of files, this is the path -; where data files are stored. Note: Windows users have to change this -; variable in order to use PHP's session functions. -; -; The path can be defined as: -; -; session.save_path = "N;/path" -; -; where N is an integer. Instead of storing all the session files in -; /path, what this will do is use subdirectories N-levels deep, and -; store the session data in those directories. This is useful if -; your OS has problems with many files in one directory, and is -; a more efficient layout for servers that handle many sessions. -; -; NOTE 1: PHP will not create this directory structure automatically. -; You can use the script in the ext/session dir for that purpose. -; NOTE 2: See the section on garbage collection below if you choose to -; use subdirectories for session storage -; -; The file storage module creates files using mode 600 by default. -; You can change that by using -; -; session.save_path = "N;MODE;/path" -; -; where MODE is the octal representation of the mode. Note that this -; does not overwrite the process's umask. -; http://php.net/session.save-path -;session.save_path = "/var/lib/php/sessions" - -; Whether to use strict session mode. -; Strict session mode does not accept uninitialized session ID and regenerate -; session ID if browser sends uninitialized session ID. Strict mode protects -; applications from session fixation via session adoption vulnerability. It is -; disabled by default for maximum compatibility, but enabling it is encouraged. -; https://wiki.php.net/rfc/strict_sessions -session.use_strict_mode = 0 - -; Whether to use cookies. -; http://php.net/session.use-cookies -session.use_cookies = 1 - -; http://php.net/session.cookie-secure -;session.cookie_secure = - -; This option forces PHP to fetch and use a cookie for storing and maintaining -; the session id. We encourage this operation as it's very helpful in combating -; session hijacking when not specifying and managing your own session id. It is -; not the be-all and end-all of session hijacking defense, but it's a good start. -; http://php.net/session.use-only-cookies -session.use_only_cookies = 1 - -; Name of the session (used as cookie name). -; http://php.net/session.name -session.name = PHPSESSID - -; Initialize session on request startup. -; http://php.net/session.auto-start -session.auto_start = 0 - -; Lifetime in seconds of cookie or, if 0, until browser is restarted. -; http://php.net/session.cookie-lifetime -session.cookie_lifetime = 0 - -; The path for which the cookie is valid. -; http://php.net/session.cookie-path -session.cookie_path = / - -; The domain for which the cookie is valid. -; http://php.net/session.cookie-domain -session.cookie_domain = - -; Whether or not to add the httpOnly flag to the cookie, which makes it inaccessible to browser scripting languages such as JavaScript. -; http://php.net/session.cookie-httponly -session.cookie_httponly = - -; Handler used to serialize data. php is the standard serializer of PHP. -; http://php.net/session.serialize-handler -session.serialize_handler = php - -; Defines the probability that the 'garbage collection' process is started -; on every session initialization. The probability is calculated by using -; gc_probability/gc_divisor. Where session.gc_probability is the numerator -; and gc_divisor is the denominator in the equation. Setting this value to 1 -; when the session.gc_divisor value is 100 will give you approximately a 1% chance -; the gc will run on any give request. -; Default Value: 1 -; Development Value: 1 -; Production Value: 1 -; http://php.net/session.gc-probability -session.gc_probability = 0 - -; Defines the probability that the 'garbage collection' process is started on every -; session initialization. The probability is calculated by using the following equation: -; gc_probability/gc_divisor. Where session.gc_probability is the numerator and -; session.gc_divisor is the denominator in the equation. Setting this value to 1 -; when the session.gc_divisor value is 100 will give you approximately a 1% chance -; the gc will run on any give request. Increasing this value to 1000 will give you -; a 0.1% chance the gc will run on any give request. For high volume production servers, -; this is a more efficient approach. -; Default Value: 100 -; Development Value: 1000 -; Production Value: 1000 -; http://php.net/session.gc-divisor -session.gc_divisor = 1000 - -; After this number of seconds, stored data will be seen as 'garbage' and -; cleaned up by the garbage collection process. -; http://php.net/session.gc-maxlifetime -session.gc_maxlifetime = 1440 - -; NOTE: If you are using the subdirectory option for storing session files -; (see session.save_path above), then garbage collection does *not* -; happen automatically. You will need to do your own garbage -; collection through a shell script, cron entry, or some other method. -; For example, the following script would is the equivalent of -; setting session.gc_maxlifetime to 1440 (1440 seconds = 24 minutes): -; find /path/to/sessions -cmin +24 -type f | xargs rm - -; Check HTTP Referer to invalidate externally stored URLs containing ids. -; HTTP_REFERER has to contain this substring for the session to be -; considered as valid. -; http://php.net/session.referer-check -session.referer_check = - -; Set to {nocache,private,public,} to determine HTTP caching aspects -; or leave this empty to avoid sending anti-caching headers. -; http://php.net/session.cache-limiter -session.cache_limiter = nocache - -; Document expires after n minutes. -; http://php.net/session.cache-expire -session.cache_expire = 180 - -; trans sid support is disabled by default. -; Use of trans sid may risk your users' security. -; Use this option with caution. -; - User may send URL contains active session ID -; to other person via. email/irc/etc. -; - URL that contains active session ID may be stored -; in publicly accessible computer. -; - User may access your site with the same session ID -; always using URL stored in browser's history or bookmarks. -; http://php.net/session.use-trans-sid -session.use_trans_sid = 0 - -; Set session ID character length. This value could be between 22 to 256. -; Shorter length than default is supported only for compatibility reason. -; Users should use 32 or more chars. -; http://php.net/session.sid-length -; Default Value: 32 -; Development Value: 26 -; Production Value: 26 -session.sid_length = 26 - -; The URL rewriter will look for URLs in a defined set of HTML tags. -; is special; if you include them here, the rewriter will -; add a hidden field with the info which is otherwise appended -; to URLs. tag's action attribute URL will not be modified -; unless it is specified. -; Note that all valid entries require a "=", even if no value follows. -; Default Value: "a=href,area=href,frame=src,form=" -; Development Value: "a=href,area=href,frame=src,form=" -; Production Value: "a=href,area=href,frame=src,form=" -; http://php.net/url-rewriter.tags -session.trans_sid_tags = "a=href,area=href,frame=src,form=" - -; URL rewriter does not rewrite absolute URLs by default. -; To enable rewrites for absolute pathes, target hosts must be specified -; at RUNTIME. i.e. use ini_set() -; tags is special. PHP will check action attribute's URL regardless -; of session.trans_sid_tags setting. -; If no host is defined, HTTP_HOST will be used for allowed host. -; Example value: php.net,www.php.net,wiki.php.net -; Use "," for multiple hosts. No spaces are allowed. -; Default Value: "" -; Development Value: "" -; Production Value: "" -;session.trans_sid_hosts="" - -; Define how many bits are stored in each character when converting -; the binary hash data to something readable. -; Possible values: -; 4 (4 bits: 0-9, a-f) -; 5 (5 bits: 0-9, a-v) -; 6 (6 bits: 0-9, a-z, A-Z, "-", ",") -; Default Value: 4 -; Development Value: 5 -; Production Value: 5 -; http://php.net/session.hash-bits-per-character -session.sid_bits_per_character = 5 - -; Enable upload progress tracking in $_SESSION -; Default Value: On -; Development Value: On -; Production Value: On -; http://php.net/session.upload-progress.enabled -;session.upload_progress.enabled = On - -; Cleanup the progress information as soon as all POST data has been read -; (i.e. upload completed). -; Default Value: On -; Development Value: On -; Production Value: On -; http://php.net/session.upload-progress.cleanup -;session.upload_progress.cleanup = On - -; A prefix used for the upload progress key in $_SESSION -; Default Value: "upload_progress_" -; Development Value: "upload_progress_" -; Production Value: "upload_progress_" -; http://php.net/session.upload-progress.prefix -;session.upload_progress.prefix = "upload_progress_" - -; The index name (concatenated with the prefix) in $_SESSION -; containing the upload progress information -; Default Value: "PHP_SESSION_UPLOAD_PROGRESS" -; Development Value: "PHP_SESSION_UPLOAD_PROGRESS" -; Production Value: "PHP_SESSION_UPLOAD_PROGRESS" -; http://php.net/session.upload-progress.name -;session.upload_progress.name = "PHP_SESSION_UPLOAD_PROGRESS" - -; How frequently the upload progress should be updated. -; Given either in percentages (per-file), or in bytes -; Default Value: "1%" -; Development Value: "1%" -; Production Value: "1%" -; http://php.net/session.upload-progress.freq -;session.upload_progress.freq = "1%" - -; The minimum delay between updates, in seconds -; Default Value: 1 -; Development Value: 1 -; Production Value: 1 -; http://php.net/session.upload-progress.min-freq -;session.upload_progress.min_freq = "1" - -; Only write session data when session data is changed. Enabled by default. -; http://php.net/session.lazy-write -;session.lazy_write = On - -[Assertion] -; Switch whether to compile assertions at all (to have no overhead at run-time) -; -1: Do not compile at all -; 0: Jump over assertion at run-time -; 1: Execute assertions -; Changing from or to a negative value is only possible in php.ini! (For turning assertions on and off at run-time, see assert.active, when zend.assertions = 1) -; Default Value: 1 -; Development Value: 1 -; Production Value: -1 -; http://php.net/zend.assertions -zend.assertions = -1 - -; Assert(expr); active by default. -; http://php.net/assert.active -;assert.active = On - -; Throw an AssertationException on failed assertions -; http://php.net/assert.exception -;assert.exception = On - -; Issue a PHP warning for each failed assertion. (Overridden by assert.exception if active) -; http://php.net/assert.warning -;assert.warning = On - -; Don't bail out by default. -; http://php.net/assert.bail -;assert.bail = Off - -; User-function to be called if an assertion fails. -; http://php.net/assert.callback -;assert.callback = 0 - -; Eval the expression with current error_reporting(). Set to true if you want -; error_reporting(0) around the eval(). -; http://php.net/assert.quiet-eval -;assert.quiet_eval = 0 - -[COM] -; path to a file containing GUIDs, IIDs or filenames of files with TypeLibs -; http://php.net/com.typelib-file -;com.typelib_file = - -; allow Distributed-COM calls -; http://php.net/com.allow-dcom -;com.allow_dcom = true - -; autoregister constants of a components typlib on com_load() -; http://php.net/com.autoregister-typelib -;com.autoregister_typelib = true - -; register constants casesensitive -; http://php.net/com.autoregister-casesensitive -;com.autoregister_casesensitive = false - -; show warnings on duplicate constant registrations -; http://php.net/com.autoregister-verbose -;com.autoregister_verbose = true - -; The default character set code-page to use when passing strings to and from COM objects. -; Default: system ANSI code page -;com.code_page= - -[mbstring] -; language for internal character representation. -; This affects mb_send_mail() and mbstring.detect_order. -; http://php.net/mbstring.language -;mbstring.language = Japanese - -; Use of this INI entry is deprecated, use global internal_encoding instead. -; internal/script encoding. -; Some encoding cannot work as internal encoding. (e.g. SJIS, BIG5, ISO-2022-*) -; If empty, default_charset or internal_encoding or iconv.internal_encoding is used. -; The precedence is: default_charset < internal_encoding < iconv.internal_encoding -;mbstring.internal_encoding = - -; Use of this INI entry is deprecated, use global input_encoding instead. -; http input encoding. -; mbstring.encoding_traslation = On is needed to use this setting. -; If empty, default_charset or input_encoding or mbstring.input is used. -; The precedence is: default_charset < intput_encoding < mbsting.http_input -; http://php.net/mbstring.http-input -;mbstring.http_input = - -; Use of this INI entry is deprecated, use global output_encoding instead. -; http output encoding. -; mb_output_handler must be registered as output buffer to function. -; If empty, default_charset or output_encoding or mbstring.http_output is used. -; The precedence is: default_charset < output_encoding < mbstring.http_output -; To use an output encoding conversion, mbstring's output handler must be set -; otherwise output encoding conversion cannot be performed. -; http://php.net/mbstring.http-output -;mbstring.http_output = - -; enable automatic encoding translation according to -; mbstring.internal_encoding setting. Input chars are -; converted to internal encoding by setting this to On. -; Note: Do _not_ use automatic encoding translation for -; portable libs/applications. -; http://php.net/mbstring.encoding-translation -;mbstring.encoding_translation = Off - -; automatic encoding detection order. -; "auto" detect order is changed according to mbstring.language -; http://php.net/mbstring.detect-order -;mbstring.detect_order = auto - -; substitute_character used when character cannot be converted -; one from another -; http://php.net/mbstring.substitute-character -;mbstring.substitute_character = none - -; overload(replace) single byte functions by mbstring functions. -; mail(), ereg(), etc are overloaded by mb_send_mail(), mb_ereg(), -; etc. Possible values are 0,1,2,4 or combination of them. -; For example, 7 for overload everything. -; 0: No overload -; 1: Overload mail() function -; 2: Overload str*() functions -; 4: Overload ereg*() functions -; http://php.net/mbstring.func-overload -;mbstring.func_overload = 0 - -; enable strict encoding detection. -; Default: Off -;mbstring.strict_detection = On - -; This directive specifies the regex pattern of content types for which mb_output_handler() -; is activated. -; Default: mbstring.http_output_conv_mimetype=^(text/|application/xhtml\+xml) -;mbstring.http_output_conv_mimetype= - -[gd] -; Tell the jpeg decode to ignore warnings and try to create -; a gd image. The warning will then be displayed as notices -; disabled by default -; http://php.net/gd.jpeg-ignore-warning -;gd.jpeg_ignore_warning = 1 - -[exif] -; Exif UNICODE user comments are handled as UCS-2BE/UCS-2LE and JIS as JIS. -; With mbstring support this will automatically be converted into the encoding -; given by corresponding encode setting. When empty mbstring.internal_encoding -; is used. For the decode settings you can distinguish between motorola and -; intel byte order. A decode setting cannot be empty. -; http://php.net/exif.encode-unicode -;exif.encode_unicode = ISO-8859-15 - -; http://php.net/exif.decode-unicode-motorola -;exif.decode_unicode_motorola = UCS-2BE - -; http://php.net/exif.decode-unicode-intel -;exif.decode_unicode_intel = UCS-2LE - -; http://php.net/exif.encode-jis -;exif.encode_jis = - -; http://php.net/exif.decode-jis-motorola -;exif.decode_jis_motorola = JIS - -; http://php.net/exif.decode-jis-intel -;exif.decode_jis_intel = JIS - -[Tidy] -; The path to a default tidy configuration file to use when using tidy -; http://php.net/tidy.default-config -;tidy.default_config = /usr/local/lib/php/default.tcfg - -; Should tidy clean and repair output automatically? -; WARNING: Do not use this option if you are generating non-html content -; such as dynamic images -; http://php.net/tidy.clean-output -tidy.clean_output = Off - -[soap] -; Enables or disables WSDL caching feature. -; http://php.net/soap.wsdl-cache-enabled -soap.wsdl_cache_enabled=1 - -; Sets the directory name where SOAP extension will put cache files. -; http://php.net/soap.wsdl-cache-dir -soap.wsdl_cache_dir="/tmp" - -; (time to live) Sets the number of second while cached file will be used -; instead of original one. -; http://php.net/soap.wsdl-cache-ttl -soap.wsdl_cache_ttl=86400 - -; Sets the size of the cache limit. (Max. number of WSDL files to cache) -soap.wsdl_cache_limit = 5 - -[sysvshm] -; A default size of the shared memory segment -;sysvshm.init_mem = 10000 - -[ldap] -; Sets the maximum number of open links or -1 for unlimited. -ldap.max_links = -1 - -[dba] -;dba.default_handler= - -[opcache] -; Determines if Zend OPCache is enabled -opcache.enable=1 - -; Determines if Zend OPCache is enabled for the CLI version of PHP -;opcache.enable_cli=0 - -; The OPcache shared memory storage size. -opcache.memory_consumption=256 - -; The amount of memory for interned strings in Mbytes. -opcache.interned_strings_buffer=16 - -; The maximum number of keys (scripts) in the OPcache hash table. -; Only numbers between 200 and 1000000 are allowed. -opcache.max_accelerated_files=7963 - -; The maximum percentage of "wasted" memory until a restart is scheduled. -;opcache.max_wasted_percentage=5 - -; When this directive is enabled, the OPcache appends the current working -; directory to the script key, thus eliminating possible collisions between -; files with the same name (basename). Disabling the directive improves -; performance, but may break existing applications. -;opcache.use_cwd=1 - -; When disabled, you must reset the OPcache manually or restart the -; webserver for changes to the filesystem to take effect. -opcache.validate_timestamps=0 - -; How often (in seconds) to check file timestamps for changes to the shared -; memory storage allocation. ("1" means validate once per second, but only -; once per request. "0" means always validate) -;opcache.revalidate_freq=2 - -; Enables or disables file search in include_path optimization -opcache.revalidate_path=0 - -; If disabled, all PHPDoc comments are dropped from the code to reduce the -; size of the optimized code. -opcache.save_comments=0 - -; Allow file existence override (file_exists, etc.) performance feature. -opcache.enable_file_override=1 - -; A bitmask, where each bit enables or disables the appropriate OPcache -; passes -;opcache.optimization_level=0xffffffff - -;opcache.inherited_hack=1 -;opcache.dups_fix=0 - -; The location of the OPcache blacklist file (wildcards allowed). -; Each OPcache blacklist file is a text file that holds the names of files -; that should not be accelerated. The file format is to add each filename -; to a new line. The filename may be a full path or just a file prefix -; (i.e., /var/www/x blacklists all the files and directories in /var/www -; that start with 'x'). Line starting with a ; are ignored (comments). -;opcache.blacklist_filename= - -; Allows exclusion of large files from being cached. By default all files -; are cached. -;opcache.max_file_size=0 - -; Check the cache checksum each N requests. -; The default value of "0" means that the checks are disabled. -;opcache.consistency_checks=0 - -; How long to wait (in seconds) for a scheduled restart to begin if the cache -; is not being accessed. -;opcache.force_restart_timeout=180 - -; OPcache error_log file name. Empty string assumes "stderr". -;opcache.error_log= - -; All OPcache errors go to the Web server log. -; By default, only fatal errors (level 0) or errors (level 1) are logged. -; You can also enable warnings (level 2), info messages (level 3) or -; debug messages (level 4). -;opcache.log_verbosity_level=1 - -; Preferred Shared Memory back-end. Leave empty and let the system decide. -;opcache.preferred_memory_model= - -; Protect the shared memory from unexpected writing during script execution. -; Useful for internal debugging only. -;opcache.protect_memory=0 - -; Allows calling OPcache API functions only from PHP scripts which path is -; started from specified string. The default "" means no restriction -;opcache.restrict_api= - -; Mapping base of shared memory segments (for Windows only). All the PHP -; processes have to map shared memory into the same address space. This -; directive allows to manually fix the "Unable to reattach to base address" -; errors. -;opcache.mmap_base= - -; Enables and sets the second level cache directory. -; It should improve performance when SHM memory is full, at server restart or -; SHM reset. The default "" disables file based caching. -;opcache.file_cache= - -; Enables or disables opcode caching in shared memory. -;opcache.file_cache_only=0 - -; Enables or disables checksum validation when script loaded from file cache. -;opcache.file_cache_consistency_checks=1 - -; Implies opcache.file_cache_only=1 for a certain process that failed to -; reattach to the shared memory (for Windows only). Explicitly enabled file -; cache is required. -;opcache.file_cache_fallback=1 - -; Enables or disables copying of PHP code (text segment) into HUGE PAGES. -; This should improve performance, but requires appropriate OS configuration. -;opcache.huge_code_pages=1 - -; Validate cached file permissions. -;opcache.validate_permission=0 - -; Prevent name collisions in chroot'ed environment. -;opcache.validate_root=0 - -; Prevents caching files that are less than this number of seconds old. -; It protects from caching of incompletely updated files. -; In case all file updates on your site are atomic, you may increase performance by setting it to "0". -opcache.file_update_protection=0 - -opcache.fast_shutdown=1 - -opcache.preload_user=www-data - -[curl] -; A default value for the CURLOPT_CAINFO option. This is required to be an -; absolute path. -;curl.cainfo = - -[openssl] -; The location of a Certificate Authority (CA) file on the local filesystem -; to use when verifying the identity of SSL/TLS peers. Most users should -; not specify a value for this directive as PHP will attempt to use the -; OS-managed cert stores in its absence. If specified, this value may still -; be overridden on a per-stream basis via the "cafile" SSL stream context -; option. -;openssl.cafile= - -; If openssl.cafile is not specified or if the CA file is not found, the -; directory pointed to by openssl.capath is searched for a suitable -; certificate. This value must be a correctly hashed certificate directory. -; Most users should not specify a value for this directive as PHP will -; attempt to use the OS-managed cert stores in its absence. If specified, -; this value may still be overridden on a per-stream basis via the "capath" -; SSL stream context option. -;openssl.capath= - -opcache.jit_buffer_size = 128M -opcache.jit = tracing - -; Local Variables: -; tab-width: 4 -; End: diff --git a/frameworks/PHP/lumen/deploy/laravel-s/composer.json b/frameworks/PHP/lumen/deploy/laravel-s/composer.json deleted file mode 100644 index dff71f25717..00000000000 --- a/frameworks/PHP/lumen/deploy/laravel-s/composer.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "name": "laravel/lumen", - "description": "The Laravel Lumen Framework.", - "keywords": ["framework", "laravel", "lumen"], - "license": "MIT", - "type": "project", - "require": { - "laravel/lumen-framework": "^9", - "hhxsv5/laravel-s": "~3.7.0" - }, - "require-dev": { - "fzaninotto/faker": "^1.9.1", - "mockery/mockery": "^1.3.1", - "phpunit/phpunit": "^9.3" - }, - "autoload": { - "psr-4": { - "App\\": "app/" - } - }, - "autoload-dev": { - "classmap": [ - "tests/", - "database/" - ] - }, - "scripts": { - "post-root-package-install": [ - "@php -r \"file_exists('.env') || copy('.env.example', '.env');\"" - ] - }, - "minimum-stability": "dev", - "prefer-stable": true, - "config": { - "optimize-autoloader": true - } -} diff --git a/frameworks/PHP/lumen/deploy/nginx.conf b/frameworks/PHP/lumen/deploy/nginx.conf deleted file mode 100755 index a968d5cb1fe..00000000000 --- a/frameworks/PHP/lumen/deploy/nginx.conf +++ /dev/null @@ -1,64 +0,0 @@ -user www-data; -worker_processes auto; -error_log stderr error; -worker_rlimit_nofile 200000; -daemon off; - -events { - worker_connections 16384; - multi_accept off; - -} - -http { - include /etc/nginx/mime.types; - default_type application/octet-stream; - access_log off; - server_tokens off; - - sendfile on; - tcp_nopush on; - tcp_nodelay on; - keepalive_timeout 65; - keepalive_disable none; - keepalive_requests 10000; - - #the bench don't use any static file - #open_file_cache max=2000 inactive=20s; - #open_file_cache_valid 60s; - #open_file_cache_min_uses 5; - #open_file_cache_errors off; - - #FastCGI optimizations - fastcgi_buffers 256 16k; - fastcgi_buffer_size 128k; - fastcgi_connect_timeout 30s; - fastcgi_send_timeout 60s; - fastcgi_read_timeout 60s; - fastcgi_busy_buffers_size 256k; - fastcgi_temp_file_write_size 256k; - reset_timedout_connection on; - server_names_hash_bucket_size 100; - - - upstream fastcgi_backend { - server unix:/var/run/php/php-fpm.sock; - keepalive 40; - } - - server { - listen 8080; - server_name localhost; - - root /lumen/public/; - index index.php; - - location / { - fastcgi_pass fastcgi_backend; - fastcgi_keep_conn on; - fastcgi_param SCRIPT_FILENAME $document_root/index.php; - fastcgi_param PATH_INFO $uri; - include /etc/nginx/fastcgi_params; - } - } -} diff --git a/frameworks/PHP/lumen/deploy/swoole/composer.json b/frameworks/PHP/lumen/deploy/swoole/composer.json deleted file mode 100644 index 723dc0cb69d..00000000000 --- a/frameworks/PHP/lumen/deploy/swoole/composer.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "laravel/lumen", - "description": "The Laravel Lumen Framework.", - "keywords": ["framework", "laravel", "lumen"], - "license": "MIT", - "type": "project", - "require": { - "laravel/lumen-framework": "^9", - "swooletw/laravel-swoole": "^v2.12" - }, - "autoload": { - "psr-4": { - "App\\": "app/" - } - }, - "scripts": { - "post-root-package-install": [ - "@php -r \"file_exists('.env') || copy('.env.example', '.env');\"" - ] - }, - "minimum-stability": "dev", - "prefer-stable": true, - "config": { - "optimize-autoloader": true - } -} diff --git a/frameworks/PHP/lumen/deploy/swoole/install-composer.sh b/frameworks/PHP/lumen/deploy/swoole/install-composer.sh deleted file mode 100644 index f8e743d6a13..00000000000 --- a/frameworks/PHP/lumen/deploy/swoole/install-composer.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/sh - -EXPECTED_SIGNATURE="$(curl -s https://composer.github.io/installer.sig)" -php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" -ACTUAL_SIGNATURE="$(php -r "echo hash_file('SHA384', 'composer-setup.php');")" - -if [ "$EXPECTED_SIGNATURE" != "$ACTUAL_SIGNATURE" ] -then - >&2 echo 'ERROR: Invalid installer signature' - rm composer-setup.php - exit 1 -fi - -php composer-setup.php --quiet -RESULT=$? -rm composer-setup.php -exit $RESULT \ No newline at end of file diff --git a/frameworks/PHP/lumen/deploy/swoole/php.ini b/frameworks/PHP/lumen/deploy/swoole/php.ini deleted file mode 100644 index 3cf51cccca9..00000000000 --- a/frameworks/PHP/lumen/deploy/swoole/php.ini +++ /dev/null @@ -1,2 +0,0 @@ -opcache.enable_cli=1 -opcache.validate_timestamps=0 diff --git a/frameworks/PHP/lumen/lumen-laravel-s.dockerfile b/frameworks/PHP/lumen/lumen-laravel-s.dockerfile deleted file mode 100644 index a8a0aebd68a..00000000000 --- a/frameworks/PHP/lumen/lumen-laravel-s.dockerfile +++ /dev/null @@ -1,32 +0,0 @@ -FROM php:8.3-cli - -RUN pecl install swoole > /dev/null && \ - docker-php-ext-enable swoole -RUN docker-php-ext-install pdo_mysql pcntl opcache > /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 - -ADD ./ /lumen -WORKDIR /lumen - -RUN mkdir -p /lumen/bootstrap/cache /lumen/storage/logs /lumen/storage/framework/sessions /lumen/storage/framework/views /lumen/storage/framework/cache -RUN chmod -R 777 /lumen - -RUN apt-get update > /dev/null && \ - apt-get install -yqq git unzip > /dev/null -RUN php -r "copy('https://install.phpcomposer.com/installer', 'composer-setup.php');" && php composer-setup.php && php -r "unlink('composer-setup.php');" -RUN mv composer.phar /usr/local/bin/composer - -COPY deploy/laravel-s/composer.json ./ - -RUN echo "LARAVELS_LISTEN_IP=0.0.0.0" >> .env -RUN echo "LARAVELS_LISTEN_PORT=8080" >> .env - -RUN composer install -a --no-dev --quiet -RUN php artisan laravels publish - -EXPOSE 8080 - -CMD php bin/laravels start diff --git a/frameworks/PHP/lumen/lumen-swoole.dockerfile b/frameworks/PHP/lumen/lumen-swoole.dockerfile deleted file mode 100644 index 3e4c866c031..00000000000 --- a/frameworks/PHP/lumen/lumen-swoole.dockerfile +++ /dev/null @@ -1,36 +0,0 @@ -FROM php:8.3-cli - -RUN pecl install swoole > /dev/null && \ - docker-php-ext-enable swoole - -RUN docker-php-ext-install pdo_mysql > /dev/null - -ADD ./ /lumen -WORKDIR /lumen -COPY deploy/swoole/php.ini /usr/local/etc/php/ - -RUN mkdir -p /lumen/storage/framework/sessions -RUN mkdir -p /lumen/storage/framework/views -RUN mkdir -p /lumen/storage/framework/cache - -RUN chmod -R 777 /lumen - -# Install composer using the installation method documented at https://getcomposer.org/doc/faqs/how-to-install-composer-programmatically.md -# This method was chosen because composer is not part of the apt repositories that are in the default PHP 7.2 docker image -# Adding alternate apt php repos can potentially cause problems with extension compatibility between the php build from the docker image and the alternate php build -# An additional benefit of this method is that the correct version of composer will be used for the environment and version of the php system in the docker image -RUN deploy/swoole/install-composer.sh - -RUN apt-get update -yqq > /dev/null && \ - apt-get install -yqq git unzip > /dev/null - -COPY deploy/swoole/composer* ./ -RUN php composer.phar install --optimize-autoloader --classmap-authoritative --no-dev --quiet - -RUN echo "APP_SWOOLE=true" >> .env - -RUN chmod -R 777 /lumen - -EXPOSE 8080 - -CMD php artisan swoole:http start diff --git a/frameworks/PHP/lumen/lumen-workerman.dockerfile b/frameworks/PHP/lumen/lumen-workerman.dockerfile deleted file mode 100644 index bc0f416c759..00000000000 --- a/frameworks/PHP/lumen/lumen-workerman.dockerfile +++ /dev/null @@ -1,33 +0,0 @@ -FROM ubuntu:22.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 install -yqq nginx git unzip \ - php8.3-cli php8.3-mysql php8.3-mbstring php8.3-xml php8.3-dev > /dev/null - -COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer - -RUN apt-get install -y php-pear php8.3-dev libevent-dev > /dev/null -RUN pecl install event-3.0.8 > /dev/null && echo "extension=event.so" > /etc/php/8.3/cli/conf.d/event.ini - -ADD ./ /lumen -WORKDIR /lumen - -RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet -RUN composer require joanhey/adapterman:^0.6 --quiet - -RUN mkdir -p /lumen/storage -RUN mkdir -p /lumen/storage/framework/sessions -RUN mkdir -p /lumen/storage/framework/views -RUN mkdir -p /lumen/storage/framework/cache - -RUN chmod -R 777 /lumen - -EXPOSE 8080 - -CMD php -c deploy/conf/cli-php.ini \ - server-man.php start diff --git a/frameworks/PHP/lumen/lumen.dockerfile b/frameworks/PHP/lumen/lumen.dockerfile deleted file mode 100644 index 1b5f8a76e62..00000000000 --- a/frameworks/PHP/lumen/lumen.dockerfile +++ /dev/null @@ -1,33 +0,0 @@ -FROM ubuntu:22.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 install -yqq nginx git unzip \ - php8.3-cli php8.3-fpm php8.3-mysql php8.3-mbstring php8.3-xml php8.3-dev > /dev/null - -COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer - -COPY deploy/conf/* /etc/php/8.3/fpm/ - -ADD ./ /lumen -WORKDIR /lumen - -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.3/fpm/php-fpm.conf ; fi; - -RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet - -RUN mkdir -p /lumen/storage -RUN mkdir -p /lumen/storage/framework/sessions -RUN mkdir -p /lumen/storage/framework/views -RUN mkdir -p /lumen/storage/framework/cache - -RUN chmod -R 777 /lumen - -EXPOSE 8080 - -CMD service php8.3-fpm start && \ - nginx -c /lumen/deploy/nginx.conf diff --git a/frameworks/PHP/lumen/public/.htaccess b/frameworks/PHP/lumen/public/.htaccess deleted file mode 100644 index b75525bedcd..00000000000 --- a/frameworks/PHP/lumen/public/.htaccess +++ /dev/null @@ -1,21 +0,0 @@ - - - Options -MultiViews -Indexes - - - RewriteEngine On - - # Handle Authorization Header - RewriteCond %{HTTP:Authorization} . - RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] - - # Redirect Trailing Slashes If Not A Folder... - RewriteCond %{REQUEST_FILENAME} !-d - RewriteCond %{REQUEST_URI} (.+)/$ - RewriteRule ^ %1 [L,R=301] - - # Handle Front Controller... - RewriteCond %{REQUEST_FILENAME} !-d - RewriteCond %{REQUEST_FILENAME} !-f - RewriteRule ^ index.php [L] - diff --git a/frameworks/PHP/lumen/public/index.php b/frameworks/PHP/lumen/public/index.php deleted file mode 100644 index 04aa08688e0..00000000000 --- a/frameworks/PHP/lumen/public/index.php +++ /dev/null @@ -1,28 +0,0 @@ -run(); diff --git a/frameworks/PHP/lumen/routes/web.php b/frameworks/PHP/lumen/routes/web.php deleted file mode 100644 index bb6a8d1714c..00000000000 --- a/frameworks/PHP/lumen/routes/web.php +++ /dev/null @@ -1,8 +0,0 @@ -get('/json', 'Controller@json'); -$router->get('/db', 'Controller@db'); -$router->get('/queries[/{queries}]', 'Controller@queries'); -$router->get('/fortunes', 'Controller@fortunes'); -$router->get('/updates[/{queries}]', 'Controller@updates'); -$router->get('/plaintext', 'Controller@plaintext'); diff --git a/frameworks/PHP/lumen/server-man.php b/frameworks/PHP/lumen/server-man.php deleted file mode 100644 index de20d2a3e95..00000000000 --- a/frameworks/PHP/lumen/server-man.php +++ /dev/null @@ -1,45 +0,0 @@ -count = (int) shell_exec('nproc') * 4; -$http_worker->name = 'AdapterMan-Laravel'; -$http_worker->onWorkerStart = static function () { - HeaderDate::init(); - //init(); - require __DIR__.'/start.php'; -}; - -$http_worker->onMessage = static function ($connection) { - - $connection->send(run()); -}; - -Worker::runAll(); - -class HeaderDate -{ - const NAME = 'Date: '; - - /** - * Date header - * - * @var string - */ - public static $date; - - public static function init(): void - { - self::$date = self::NAME . gmdate('D, d M Y H:i:s').' GMT'; - Timer::add(1, static function() { - self::$date = self::NAME . gmdate('D, d M Y H:i:s').' GMT'; - }); - } -} diff --git a/frameworks/PHP/lumen/start.php b/frameworks/PHP/lumen/start.php deleted file mode 100644 index cc7d3075d64..00000000000 --- a/frameworks/PHP/lumen/start.php +++ /dev/null @@ -1,39 +0,0 @@ -run(); - header(HeaderDate::$date); // To pass the bench, nginx auto add it - - return ob_get_clean(); -} diff --git a/frameworks/PHP/mako/mako.dockerfile b/frameworks/PHP/mako/mako.dockerfile index 8445c793103..07010604204 100644 --- a/frameworks/PHP/mako/mako.dockerfile +++ b/frameworks/PHP/mako/mako.dockerfile @@ -7,16 +7,16 @@ 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 install -yqq nginx git unzip \ - php8.2-cli php8.2-fpm php8.2-mysql php8.2-mbstring php8.2-xml php8.2-curl > /dev/null + php8.3-cli php8.3-fpm php8.3-mysql php8.3-mbstring php8.3-xml php8.3-curl > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -COPY deploy/conf/* /etc/php/8.2/fpm/ +COPY deploy/conf/* /etc/php/8.3/fpm/ ADD ./ /mako WORKDIR /mako -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.2/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.3/fpm/php-fpm.conf ; fi; RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --ignore-platform-reqs --quiet @@ -24,5 +24,5 @@ RUN chmod -R 777 app EXPOSE 8080 -CMD service php8.2-fpm start && \ +CMD service php8.3-fpm start && \ nginx -c /mako/deploy/nginx.conf diff --git a/frameworks/PHP/mark/mark.dockerfile b/frameworks/PHP/mark/mark.dockerfile index 3b39a27ef56..7f6b8180969 100644 --- a/frameworks/PHP/mark/mark.dockerfile +++ b/frameworks/PHP/mark/mark.dockerfile @@ -1,24 +1,24 @@ -FROM ubuntu:22.04 +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 > /dev/null && \ - apt-get install -yqq php8.3-cli php8.3-pgsql php8.3-xml > /dev/null + apt-get install -yqq php8.4-cli php8.4-pgsql php8.4-xml > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -RUN apt-get install -y php-pear php8.3-dev libevent-dev git > /dev/null -RUN pecl install event-3.0.8 > /dev/null && echo "extension=event.so" > /etc/php/8.3/cli/conf.d/event.ini +RUN apt-get install -y php-pear php8.4-dev libevent-dev git > /dev/null +RUN pecl install event-3.1.3 > /dev/null && echo "extension=event.so" > /etc/php/8.4/cli/conf.d/event.ini -COPY php.ini /etc/php/8.3/cli/php.ini +COPY php.ini /etc/php/8.4/cli/php.ini ADD ./ /mark WORKDIR /mark RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet -RUN sed -i "s|opcache.jit=off|opcache.jit=tracing|g" /etc/php/8.3/cli/conf.d/10-opcache.ini +RUN sed -i "s|opcache.jit=off|opcache.jit=tracing|g" /etc/php/8.4/cli/conf.d/10-opcache.ini EXPOSE 8080 diff --git a/frameworks/PHP/mark/start.php b/frameworks/PHP/mark/start.php index b38fd3519ef..b1f96ce9ffd 100644 --- a/frameworks/PHP/mark/start.php +++ b/frameworks/PHP/mark/start.php @@ -27,12 +27,12 @@ ], \json_encode(['message' => 'Hello, World!'])); }); -$date = gmdate('D, d M Y H:i:s').' GMT'; +$date = gmdate(DATE_RFC7231); $api->onWorkerStart = static function () { Timer::add(1, function () { global $date; - $date = gmdate('D, d M Y H:i:s').' GMT'; + $date = gmdate(DATE_RFC7231); }); }; diff --git a/frameworks/PHP/mixphp/mixphp-swoole-mysql.dockerfile b/frameworks/PHP/mixphp/mixphp-swoole-mysql.dockerfile index 2001b9fde1d..ce9292f244a 100644 --- a/frameworks/PHP/mixphp/mixphp-swoole-mysql.dockerfile +++ b/frameworks/PHP/mixphp/mixphp-swoole-mysql.dockerfile @@ -1,13 +1,10 @@ -FROM php:8.3-cli +FROM phpswoole/swoole:6.0.2-php8.4 -RUN pecl install swoole > /dev/null && docker-php-ext-enable swoole +RUN docker-php-ext-install pcntl opcache bcmath > /dev/null -RUN docker-php-ext-install opcache pdo_mysql bcmath > /dev/null - -RUN apt -yqq update && apt -yqq install git unzip > /dev/null - -COPY . /mixphp -COPY php.ini /usr/local/etc/php/ +WORKDIR /mixphp +COPY --link . . +COPY --link php.ini /usr/local/etc/php/ RUN echo "opcache.enable=1" >> /usr/local/etc/php/php.ini RUN echo "opcache.enable_cli=1" >> /usr/local/etc/php/php.ini RUN echo "pcre.jit=1" >> /usr/local/etc/php/php.ini @@ -16,9 +13,6 @@ RUN echo "opcache.jit_buffer_size=256M" >> /usr/local/etc/php/php.ini RUN php -v && php -i | grep opcache -WORKDIR /mixphp - -COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer RUN composer install --no-dev --classmap-authoritative --quiet > /dev/null RUN composer dumpautoload -o @@ -27,4 +21,4 @@ RUN chmod -R 777 /mixphp/runtime/logs EXPOSE 9501 -CMD php /mixphp/bin/swoole.php start +ENTRYPOINT [ "php", "/mixphp/bin/swoole.php", "start" ] diff --git a/frameworks/PHP/mixphp/mixphp-workerman-mysql.dockerfile b/frameworks/PHP/mixphp/mixphp-workerman-mysql.dockerfile index 0861a10948d..c2a282a9611 100644 --- a/frameworks/PHP/mixphp/mixphp-workerman-mysql.dockerfile +++ b/frameworks/PHP/mixphp/mixphp-workerman-mysql.dockerfile @@ -1,16 +1,16 @@ -FROM ubuntu:22.04 +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.3-cli php8.3-mbstring php8.3-curl php8.3-xml php8.3-mysql > /dev/null +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 apt-get install -y php8.3-dev libevent-dev > /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.0.8 > /dev/null && echo "extension=event.so" > /etc/php/8.3/cli/conf.d/event.ini +RUN pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.4/cli/conf.d/event.ini -COPY php-jit.ini /etc/php/8.3/cli/php.ini +COPY php-jit.ini /etc/php/8.4/cli/php.ini ADD ./ /mixphp WORKDIR /mixphp diff --git a/frameworks/PHP/mixphp/mixphp-workerman-pgsql.dockerfile b/frameworks/PHP/mixphp/mixphp-workerman-pgsql.dockerfile index f469165bf97..85143701159 100644 --- a/frameworks/PHP/mixphp/mixphp-workerman-pgsql.dockerfile +++ b/frameworks/PHP/mixphp/mixphp-workerman-pgsql.dockerfile @@ -1,16 +1,16 @@ -FROM ubuntu:22.04 +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.3-cli php8.3-mbstring php8.3-curl php8.3-xml php8.3-pgsql > /dev/null +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 apt-get install -y php8.3-dev libevent-dev > /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.0.8 > /dev/null && echo "extension=event.so" > /etc/php/8.3/cli/conf.d/event.ini +RUN pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.4/cli/conf.d/event.ini -COPY php-jit.ini /etc/php/8.3/cli/php.ini +COPY php-jit.ini /etc/php/8.4/cli/php.ini ADD ./ /mixphp WORKDIR /mixphp diff --git a/frameworks/PHP/mixphp/mixphp.dockerfile b/frameworks/PHP/mixphp/mixphp.dockerfile index bbc64fd8705..360debab252 100644 --- a/frameworks/PHP/mixphp/mixphp.dockerfile +++ b/frameworks/PHP/mixphp/mixphp.dockerfile @@ -1,14 +1,14 @@ -FROM ubuntu:22.04 +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.3-fpm php8.3-mysql php8.3-dev > /dev/null +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 -COPY deploy/conf/* /etc/php/8.3/fpm/ +COPY deploy/conf/* /etc/php/8.4/fpm/ -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.3/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.4/fpm/php-fpm.conf ; fi; ADD ./ /mixphp WORKDIR /mixphp @@ -22,5 +22,5 @@ RUN chmod -R 777 /mixphp/runtime/logs EXPOSE 8080 -CMD service php8.3-fpm start && \ +CMD service php8.4-fpm start && \ nginx -c /mixphp/deploy/nginx.conf diff --git a/frameworks/PHP/nette/composer.json b/frameworks/PHP/nette/composer.json index 6a455dafc6b..ce416979668 100644 --- a/frameworks/PHP/nette/composer.json +++ b/frameworks/PHP/nette/composer.json @@ -6,18 +6,17 @@ "license": ["MIT", "BSD-3-Clause", "GPL-2.0", "GPL-3.0"], "require": { "php": ">= 7.2", - "nette/application": "^3.1", - "nette/bootstrap": "^3.1", - "nette/caching": "^3.1", - "nette/database": "^3.1", + "nette/application": "^3.2", + "nette/bootstrap": "^3.2", + "nette/caching": "^3.3", + "nette/database": "^3.2", "nette/di": "^3.0", - "nette/finder": "^2.5", + "nette/finder": "^3.0", "nette/forms": "^3.1", "nette/http": "^3.1", - "nette/mail": "^3.1", - "nette/robot-loader": "^3.3", + "nette/mail": "^4.0", "nette/security": "^3.1", - "nette/utils": "^3.2", + "nette/utils": "^4.0", "latte/latte": "^2.11 || ^3.0", "tracy/tracy": "^2.8" }, diff --git a/frameworks/PHP/nette/nette.dockerfile b/frameworks/PHP/nette/nette.dockerfile index fc917b9ca49..0e66d630510 100644 --- a/frameworks/PHP/nette/nette.dockerfile +++ b/frameworks/PHP/nette/nette.dockerfile @@ -1,28 +1,27 @@ -FROM ubuntu:22.04 +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 install -yqq nginx git unzip \ - php8.3-fpm php8.3-mysql php8.3-xml php8.3-mbstring php8.3-intl php8.3-dev php8.3-curl > /dev/null + php8.4-fpm php8.4-mysql php8.4-xml php8.4-mbstring php8.4-intl php8.4-dev php8.4-curl > /dev/null -COPY deploy/conf/* /etc/php/8.3/fpm/ +COPY deploy/conf/* /etc/php/8.4/fpm/ -ADD ./ /nette WORKDIR /nette - +COPY --link . . #ENV NETTE_DIR="/nette/src" COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.3/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.4/fpm/php-fpm.conf ; fi; RUN chmod -R 777 /nette EXPOSE 8080 -CMD service php8.3-fpm start && \ +CMD service php8.4-fpm start && \ nginx -c /nette/deploy/nginx.conf 2>&1 > /dev/stderr diff --git a/frameworks/PHP/openswoole/openswoole-no-async.dockerfile b/frameworks/PHP/openswoole/openswoole-no-async.dockerfile index ddfa2d2da58..73762687883 100644 --- a/frameworks/PHP/openswoole/openswoole-no-async.dockerfile +++ b/frameworks/PHP/openswoole/openswoole-no-async.dockerfile @@ -1,4 +1,4 @@ -FROM php:8.2-cli +FROM php:8.4-cli RUN apt-get update && apt-get install -y git > /dev/null diff --git a/frameworks/PHP/openswoole/openswoole-server-mysql.php b/frameworks/PHP/openswoole/openswoole-server-mysql.php index 8c921a3f184..e020600ce87 100644 --- a/frameworks/PHP/openswoole/openswoole-server-mysql.php +++ b/frameworks/PHP/openswoole/openswoole-server-mysql.php @@ -111,7 +111,7 @@ * * @return string */ -$updates_mysql = function (int $queries = 0, $pool): string { +$updates_mysql = function (int $queries, $pool): string { $db = $pool->get(); $query_count = 1; diff --git a/frameworks/PHP/openswoole/openswoole-server-postgres.php b/frameworks/PHP/openswoole/openswoole-server-postgres.php index 31a712ca9ce..107878f3343 100644 --- a/frameworks/PHP/openswoole/openswoole-server-postgres.php +++ b/frameworks/PHP/openswoole/openswoole-server-postgres.php @@ -40,7 +40,7 @@ * * @return string */ -$db_postgres = function (int $queries = 0, $pool): string { +$db_postgres = function (int $queries, $pool): string { $db = $pool->get(); // Read number of queries to run from URL parameter $query_count = 1; @@ -116,7 +116,7 @@ * * @return string */ -$updates_postgres = function (int $queries = 0, $pool): string { +$updates_postgres = function (int $queries, $pool): string { $db = $pool->get(); $query_count = 1; diff --git a/frameworks/PHP/openswoole/openswoole.dockerfile b/frameworks/PHP/openswoole/openswoole.dockerfile index 836b41c3169..d9d89845e54 100644 --- a/frameworks/PHP/openswoole/openswoole.dockerfile +++ b/frameworks/PHP/openswoole/openswoole.dockerfile @@ -1,4 +1,4 @@ -FROM php:8.2-cli +FROM php:8.4-cli RUN apt-get update && apt-get install -y git > /dev/null diff --git a/frameworks/PHP/peachpie/global.json b/frameworks/PHP/peachpie/global.json index 166cbe6e9b7..ea99fa32bb0 100644 --- a/frameworks/PHP/peachpie/global.json +++ b/frameworks/PHP/peachpie/global.json @@ -1,5 +1,5 @@ { "msbuild-sdks": { - "Peachpie.NET.Sdk": "1.0.0-preview5" + "Peachpie.NET.Sdk": "1.0.25" } } \ No newline at end of file diff --git a/frameworks/PHP/peachpie/peachpie.dockerfile b/frameworks/PHP/peachpie/peachpie.dockerfile index d8bd752611f..33a85981245 100644 --- a/frameworks/PHP/peachpie/peachpie.dockerfile +++ b/frameworks/PHP/peachpie/peachpie.dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/dotnet/sdk:7.0.100 AS build +FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build WORKDIR /app COPY . . RUN dotnet publish -c Release -o out Server diff --git a/frameworks/PHP/phalcon/benchmark_config.json b/frameworks/PHP/phalcon/benchmark_config.json index 127bce79907..810c897643b 100644 --- a/frameworks/PHP/phalcon/benchmark_config.json +++ b/frameworks/PHP/phalcon/benchmark_config.json @@ -42,8 +42,7 @@ "database_os": "Linux", "display_name": "phalcon-mongodb", "notes": "", - "versus": "php", - "tags": ["broken"] + "versus": "php" }, "micro": { "plaintext_url": "/plaintext", diff --git a/frameworks/PHP/phalcon/composer.json b/frameworks/PHP/phalcon/composer.json index f42463f3153..a1ead267232 100644 --- a/frameworks/PHP/phalcon/composer.json +++ b/frameworks/PHP/phalcon/composer.json @@ -1,6 +1,6 @@ { "require": { "mongodb/mongodb": "^1.6", - "phalcon/incubator-mongodb": "^1.0" + "phalcon/incubator-mongodb": "^2.0" } } diff --git a/frameworks/PHP/phalcon/phalcon-micro.dockerfile b/frameworks/PHP/phalcon/phalcon-micro.dockerfile index b7e77e5dc63..8d1d0efd04d 100644 --- a/frameworks/PHP/phalcon/phalcon-micro.dockerfile +++ b/frameworks/PHP/phalcon/phalcon-micro.dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:22.04 +FROM ubuntu:24.04 ARG DEBIAN_FRONTEND=noninteractive @@ -6,21 +6,21 @@ RUN apt-get update -yqq && apt-get install -yqq software-properties-common > /de 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 install -y php-pear php8.2-dev > /dev/null -RUN mkdir -p /etc/php/8.2/fpm/conf.d -RUN pecl install phalcon > /dev/null && echo "extension=phalcon.so" > /etc/php/8.2/fpm/conf.d/phalcon.ini +RUN apt-get install -y php-pear php8.4-dev > /dev/null +RUN mkdir -p /etc/php/8.4/fpm/conf.d +RUN pecl install phalcon > /dev/null && echo "extension=phalcon.so" > /etc/php/8.4/fpm/conf.d/phalcon.ini RUN apt-get install -yqq nginx git unzip \ - php8.2-cli php8.2-fpm php8.2-mysql php8.2-mbstring php8.2-xml > /dev/null + php8.4-cli php8.4-fpm php8.4-mysql php8.4-mbstring php8.4-xml > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -COPY deploy/conf/* /etc/php/8.2/fpm/ +COPY deploy/conf/* /etc/php/8.4/fpm/ ADD ./ /phalcon WORKDIR /phalcon -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.2/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.4/fpm/php-fpm.conf ; fi; RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --ignore-platform-reqs @@ -30,5 +30,5 @@ RUN chmod -R 777 app EXPOSE 8080 -CMD service php8.2-fpm start && \ +CMD service php8.4-fpm start && \ nginx -c /phalcon/deploy/nginx.conf diff --git a/frameworks/PHP/phalcon/phalcon-mongodb.dockerfile b/frameworks/PHP/phalcon/phalcon-mongodb.dockerfile index 3b176037ba1..6a2dcceeb19 100644 --- a/frameworks/PHP/phalcon/phalcon-mongodb.dockerfile +++ b/frameworks/PHP/phalcon/phalcon-mongodb.dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:22.04 +FROM ubuntu:24.04 ARG DEBIAN_FRONTEND=noninteractive @@ -6,21 +6,21 @@ RUN apt-get update -yqq && apt-get install -yqq software-properties-common > /de 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 install -y php-pear php8.2-dev > /dev/null -RUN mkdir -p /etc/php/8.2/fpm/conf.d -RUN pecl install phalcon > /dev/null && echo "extension=phalcon.so" > /etc/php/8.2/fpm/conf.d/phalcon.ini +RUN apt-get install -y php-pear php8.4-dev > /dev/null +RUN mkdir -p /etc/php/8.4/fpm/conf.d +RUN pecl install phalcon > /dev/null && echo "extension=phalcon.so" > /etc/php/8.4/fpm/conf.d/phalcon.ini RUN apt-get install -yqq nginx git unzip \ - php8.2-cli php8.2-fpm php8.2-mbstring php8.2-xml php8.2-mongodb > /dev/null + php8.4-cli php8.4-fpm php8.4-mbstring php8.4-xml php8.4-mongodb > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -COPY deploy/conf/* /etc/php/8.2/fpm/ +COPY deploy/conf/* /etc/php/8.4/fpm/ ADD ./ /phalcon WORKDIR /phalcon -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.2/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.4/fpm/php-fpm.conf ; fi; RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet --ignore-platform-reqs @@ -30,5 +30,5 @@ RUN chmod -R 777 app EXPOSE 8080 -CMD service php8.2-fpm start && \ +CMD service php8.4-fpm start && \ nginx -c /phalcon/deploy/nginx.conf diff --git a/frameworks/PHP/phalcon/phalcon.dockerfile b/frameworks/PHP/phalcon/phalcon.dockerfile index d5c07177aa3..1e872839d97 100644 --- a/frameworks/PHP/phalcon/phalcon.dockerfile +++ b/frameworks/PHP/phalcon/phalcon.dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:22.04 +FROM ubuntu:24.04 ARG DEBIAN_FRONTEND=noninteractive @@ -6,21 +6,21 @@ RUN apt-get update -yqq && apt-get install -yqq software-properties-common > /de 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 install -y php-pear php8.2-dev > /dev/null -RUN mkdir -p /etc/php/8.2/fpm/conf.d -RUN pecl install phalcon > /dev/null && echo "extension=phalcon.so" > /etc/php/8.2/fpm/conf.d/phalcon.ini +RUN apt-get install -y php-pear php8.4-dev > /dev/null +RUN mkdir -p /etc/php/8.4/fpm/conf.d +RUN pecl install phalcon > /dev/null && echo "extension=phalcon.so" > /etc/php/8.4/fpm/conf.d/phalcon.ini RUN apt-get install -yqq nginx git unzip \ - php8.2-cli php8.2-fpm php8.2-mysql php8.2-mbstring php8.2-xml > /dev/null + php8.4-cli php8.4-fpm php8.4-mysql php8.4-mbstring php8.4-xml > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -COPY deploy/conf/* /etc/php/8.2/fpm/ +COPY deploy/conf/* /etc/php/8.4/fpm/ ADD ./ /phalcon WORKDIR /phalcon -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.2/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.4/fpm/php-fpm.conf ; fi; RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --ignore-platform-reqs @@ -28,5 +28,5 @@ RUN chmod -R 777 app EXPOSE 8080 -CMD service php8.2-fpm start && \ +CMD service php8.4-fpm start && \ nginx -c /phalcon/deploy/nginx.conf diff --git a/frameworks/PHP/php-ngx/app-async.php b/frameworks/PHP/php-ngx/app-async.php index 80b78b39eb7..3d85d02aaed 100644 --- a/frameworks/PHP/php-ngx/app-async.php +++ b/frameworks/PHP/php-ngx/app-async.php @@ -1,5 +1,5 @@ /dev/null && \ RUN apt-get update -yqq > /dev/null && \ apt-get install -yqq wget git libxml2-dev systemtap-sdt-dev \ - zlib1g-dev libpcre3-dev libargon2-0-dev libsodium-dev \ - php8.2-cli php8.2-dev libphp8.2-embed php8.2-mysql > /dev/null + zlib1g-dev libpcre3-dev libargon2-dev libsodium-dev libkrb5-dev \ + php8.3-cli php8.3-dev libphp8.3-embed php8.3-mysql > /dev/null -ADD . . +ENV NGINX_VERSION 1.26.0 -ENV NGINX_VERSION 1.24.0 - -RUN git clone -b v0.0.27 --single-branch --depth 1 https://github.com/rryqszq4/ngx_php7.git > /dev/null +RUN git clone -b v0.0.29 --single-branch --depth 1 https://github.com/rryqszq4/ngx-php.git > /dev/null RUN wget -q http://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz && \ tar -zxf nginx-${NGINX_VERSION}.tar.gz && \ @@ -25,10 +23,13 @@ RUN wget -q http://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz && \ ./configure --user=www --group=www \ --prefix=/nginx \ --with-ld-opt="-Wl,-rpath,$PHP_LIB" \ - --add-module=/ngx_php7/third_party/ngx_devel_kit \ - --add-module=/ngx_php7 > /dev/null && \ + --add-module=/ngx-php/third_party/ngx_devel_kit \ + --add-module=/ngx-php > /dev/null && \ make > /dev/null && make install > /dev/null -RUN sed -i "s|opcache.jit=off|;opcache.jit=off|g" /etc/php/8.2/embed/conf.d/10-opcache.ini + +RUN sed -i "s|opcache.jit=off|;opcache.jit=off|g" /etc/php/8.3/embed/conf.d/10-opcache.ini + +COPY --link . . EXPOSE 8080 diff --git a/frameworks/PHP/php-ngx/php-ngx-mysql.dockerfile b/frameworks/PHP/php-ngx/php-ngx-mysql.dockerfile index 8a03f32516c..2eb076f20d9 100644 --- a/frameworks/PHP/php-ngx/php-ngx-mysql.dockerfile +++ b/frameworks/PHP/php-ngx/php-ngx-mysql.dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:20.04 +FROM ubuntu:24.04 ARG DEBIAN_FRONTEND=noninteractive @@ -9,13 +9,12 @@ RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null && \ RUN apt-get update -yqq > /dev/null && \ apt-get install -yqq wget git libxml2-dev systemtap-sdt-dev \ - zlib1g-dev libpcre3-dev libargon2-0-dev libsodium-dev \ - php8.2-cli php8.2-dev libphp8.2-embed php8.2-mysql > /dev/null -ADD . . + zlib1g-dev libpcre3-dev libargon2-dev libsodium-dev libkrb5-dev \ + php8.4-cli php8.4-dev libphp8.4-embed php8.4-mysql > /dev/null -ENV NGINX_VERSION 1.24.0 +ENV NGINX_VERSION 1.27.3 -RUN git clone -b v0.0.27 --single-branch --depth 1 https://github.com/rryqszq4/ngx-php.git > /dev/null +RUN git clone -b v0.0.30 --single-branch --depth 1 https://github.com/rryqszq4/ngx-php.git > /dev/null RUN wget -q http://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz && \ tar -zxf nginx-${NGINX_VERSION}.tar.gz && \ @@ -28,9 +27,13 @@ RUN wget -q http://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz && \ --add-module=/ngx-php > /dev/null && \ make > /dev/null && make install > /dev/null +RUN sed -i "s|opcache.jit=off|;opcache.jit=off|g" /etc/php/8.4/embed/conf.d/10-opcache.ini + +COPY --link . . + RUN export WORKERS=$(( 4 * $(nproc) )) && \ sed -i "s/worker_processes auto/worker_processes $WORKERS/g" /deploy/nginx.conf EXPOSE 8080 -CMD /nginx/sbin/nginx -c /deploy/nginx.conf +CMD /nginx/sbin/nginx -c /deploy/nginx.conf diff --git a/frameworks/PHP/php-ngx/php-ngx-pgsql.dockerfile b/frameworks/PHP/php-ngx/php-ngx-pgsql.dockerfile index 4b4452f3174..9d943180852 100644 --- a/frameworks/PHP/php-ngx/php-ngx-pgsql.dockerfile +++ b/frameworks/PHP/php-ngx/php-ngx-pgsql.dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:20.04 +FROM ubuntu:24.04 ARG DEBIAN_FRONTEND=noninteractive @@ -9,13 +9,12 @@ RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null && \ RUN apt-get update -yqq > /dev/null && \ apt-get install -yqq wget git libxml2-dev systemtap-sdt-dev \ - zlib1g-dev libpcre3-dev libargon2-0-dev libsodium-dev \ - php8.2-cli php8.2-dev libphp8.2-embed php8.2-pgsql > /dev/null -ADD . . + zlib1g-dev libpcre3-dev libargon2-dev libsodium-dev libkrb5-dev \ + php8.4-cli php8.4-dev libphp8.4-embed php8.4-pgsql > /dev/null -ENV NGINX_VERSION 1.24.0 +ENV NGINX_VERSION 1.27.3 -RUN git clone -b v0.0.27 --single-branch --depth 1 https://github.com/rryqszq4/ngx-php.git > /dev/null +RUN git clone -b v0.0.30 --single-branch --depth 1 https://github.com/rryqszq4/ngx-php.git > /dev/null RUN wget -q http://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz && \ tar -zxf nginx-${NGINX_VERSION}.tar.gz && \ @@ -28,11 +27,15 @@ RUN wget -q http://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz && \ --add-module=/ngx-php > /dev/null && \ make > /dev/null && make install > /dev/null +RUN sed -i "s|opcache.jit=off|;opcache.jit=off|g" /etc/php/8.4/embed/conf.d/10-opcache.ini + +COPY --link . . + RUN sed -i "s|app.php|app-pg.php|g" /deploy/nginx.conf RUN export WORKERS=$(( 4 * $(nproc) )) && \ sed -i "s|worker_processes auto|worker_processes $WORKERS|g" /deploy/nginx.conf -RUN sed -i "s|opcache.jit=off|opcache.jit=function|g" /etc/php/8.2/embed/conf.d/10-opcache.ini + EXPOSE 8080 CMD /nginx/sbin/nginx -c /deploy/nginx.conf diff --git a/frameworks/PHP/php-ngx/php-ngx.dockerfile b/frameworks/PHP/php-ngx/php-ngx.dockerfile index d20a9e08f63..3979f852433 100644 --- a/frameworks/PHP/php-ngx/php-ngx.dockerfile +++ b/frameworks/PHP/php-ngx/php-ngx.dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:20.04 +FROM ubuntu:24.04 ARG DEBIAN_FRONTEND=noninteractive @@ -9,26 +9,28 @@ RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null && \ RUN apt-get update -yqq > /dev/null && \ apt-get install -yqq wget git libxml2-dev systemtap-sdt-dev \ - zlib1g-dev libpcre3-dev libargon2-0-dev libsodium-dev \ - php8.2-cli php8.2-dev libphp8.2-embed php8.2-mysql -ADD . . + zlib1g-dev libpcre3-dev libargon2-dev libsodium-dev libkrb5-dev \ + php8.4-cli php8.4-dev libphp8.4-embed php8.4-mysql > /dev/null -ENV NGINX_VERSION 1.24.0 +ENV NGINX_VERSION 1.27.3 -RUN git clone -b v0.0.27 --single-branch --depth 1 https://github.com/rryqszq4/ngx-php.git > /dev/null +RUN git clone -b v0.0.30 --single-branch --depth 1 https://github.com/rryqszq4/ngx-php.git > /dev/null RUN wget -q http://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz && \ tar -zxf nginx-${NGINX_VERSION}.tar.gz && \ cd nginx-${NGINX_VERSION} && \ - export PHP_LIB=/usr/lib && \ + export PHP_LIB=/usr/lib && \ ./configure --user=www --group=www \ --prefix=/nginx \ --with-ld-opt="-Wl,-rpath,$PHP_LIB" \ --add-module=/ngx-php/third_party/ngx_devel_kit \ --add-module=/ngx-php > /dev/null && \ make > /dev/null && make install > /dev/null -RUN sed -i "s|opcache.jit=off|;opcache.jit=off|g" /etc/php/8.2/embed/conf.d/10-opcache.ini + +RUN sed -i "s|opcache.jit=off|;opcache.jit=off|g" /etc/php/8.4/embed/conf.d/10-opcache.ini + +COPY --link . . EXPOSE 8080 -CMD /nginx/sbin/nginx -c /deploy/nginx_default.conf +CMD /nginx/sbin/nginx -c /deploy/nginx_default.conf diff --git a/frameworks/PHP/php/apc.php b/frameworks/PHP/php/apc.php index 78e01fb4430..1ed4e7e4d1c 100644 --- a/frameworks/PHP/php/apc.php +++ b/frameworks/PHP/php/apc.php @@ -70,11 +70,11 @@ function defaults($d,$v) { } // operation constants -define('OB_HOST_STATS',1); -define('OB_SYS_CACHE',2); -define('OB_USER_CACHE',3); -define('OB_SYS_CACHE_DIR',4); -define('OB_VERSION_CHECK',9); +const OB_HOST_STATS = 1; +const OB_SYS_CACHE = 2; +const OB_USER_CACHE = 3; +const OB_SYS_CACHE_DIR = 4; +const OB_VERSION_CHECK = 9; // check validity of input variables $vardom=array( diff --git a/frameworks/PHP/php/deploy/eloquent/composer.json b/frameworks/PHP/php/deploy/eloquent/composer.json index e75de3f79ad..ebb6a48c6c9 100644 --- a/frameworks/PHP/php/deploy/eloquent/composer.json +++ b/frameworks/PHP/php/deploy/eloquent/composer.json @@ -1,7 +1,20 @@ { "require": { - "illuminate/database": "8.16.*", - "illuminate/events": "8.16.*", - "illuminate/container": "8.16.*" + "illuminate/database": "11.*", + "illuminate/events": "11.*", + "illuminate/container": "11.*" + }, + "replace": { + "symfony/polyfill-ctype": "*", + "symfony/polyfill-iconv": "*", + "symfony/polyfill-mbstring":"*", + "symfony/polyfill-php72": "*", + "symfony/polyfill-php73": "*", + "symfony/polyfill-php74": "*", + "symfony/polyfill-php80": "*", + "symfony/polyfill-php81": "*", + "symfony/polyfill-php82": "*", + "symfony/polyfill-php83": "*", + "symfony/polyfill-php84": "*" } } \ No newline at end of file diff --git a/frameworks/PHP/php/deploy/franken/Caddyfile b/frameworks/PHP/php/deploy/franken/Caddyfile index b6aa805f871..72400a7e489 100644 --- a/frameworks/PHP/php/deploy/franken/Caddyfile +++ b/frameworks/PHP/php/deploy/franken/Caddyfile @@ -11,11 +11,14 @@ :8080 route { - root * /php # FrankenPHP! + # disable static files for this benchmark + # by using php instead of php_server @phpFiles path *.php - php @phpFiles + php @phpFiles { + root /php + } respond 404 } \ No newline at end of file diff --git a/frameworks/PHP/php/deploy/nginx-unit.json b/frameworks/PHP/php/deploy/nginx-unit.json index b5bc980d07b..51fcc77c5bb 100644 --- a/frameworks/PHP/php/deploy/nginx-unit.json +++ b/frameworks/PHP/php/deploy/nginx-unit.json @@ -8,7 +8,11 @@ "applications": { "benchmark": { "type": "php", - "processes": 84, + "processes": { + "max": 224, + "spare": 168, + "idle_timeout": 20 + }, "user": "www-data", "group": "www-data", "root": "/php/", @@ -19,5 +23,10 @@ "requests": 10000000 } } + }, + "settings": { + "http": { + "server_version": false + } } } \ No newline at end of file diff --git a/frameworks/PHP/php/deploy/workerman/cli-php.ini b/frameworks/PHP/php/deploy/workerman/cli-php.ini index a6c32d06f07..9f0f3171834 100644 --- a/frameworks/PHP/php/deploy/workerman/cli-php.ini +++ b/frameworks/PHP/php/deploy/workerman/cli-php.ini @@ -13,4 +13,4 @@ memory_limit = 512M opcache.jit_buffer_size=128M opcache.jit=tracing -disable_functions=header,header_remove,headers_sent,http_response_code,setcookie,session_create_id,session_id,session_name,session_save_path,session_status,session_start,session_write_close,session_regenerate_id,set_time_limit \ No newline at end of file +disable_functions=header,header_remove,headers_sent,headers_list,http_response_code,setcookie,session_create_id,session_id,session_name,session_save_path,session_status,session_start,session_write_close,session_regenerate_id,session_unset,session_get_cookie_params,session_set_cookie_params,set_time_limit diff --git a/frameworks/PHP/php/deploy/workerman/composer.json b/frameworks/PHP/php/deploy/workerman/composer.json index 75b75e2d5ec..0cf52f71ab3 100644 --- a/frameworks/PHP/php/deploy/workerman/composer.json +++ b/frameworks/PHP/php/deploy/workerman/composer.json @@ -1,5 +1,5 @@ { "require": { - "joanhey/adapterman": "^0.6" + "joanhey/adapterman": "^0.7" } -} \ No newline at end of file +} diff --git a/frameworks/PHP/php/deploy/workerman/start.php b/frameworks/PHP/php/deploy/workerman/start.php index 0d1c04d930f..40bb89b521a 100644 --- a/frameworks/PHP/php/deploy/workerman/start.php +++ b/frameworks/PHP/php/deploy/workerman/start.php @@ -2,7 +2,7 @@ use Adapterman\Adapterman; use Workerman\Worker; -use Workerman\Lib\Timer; +use Workerman\Timer; require_once __DIR__ . '/vendor/autoload.php'; @@ -10,6 +10,7 @@ // WebServer $web = new Worker("http://0.0.0.0:8080"); $web->count = (int) shell_exec('nproc') * 4; +$web->reusePort = true; $web->name = 'workerman'; define('WEBROOT', '/php/'); diff --git a/frameworks/PHP/php/php-caddy.dockerfile b/frameworks/PHP/php/php-caddy.dockerfile index e148b16570f..3be7ccf8b61 100644 --- a/frameworks/PHP/php/php-caddy.dockerfile +++ b/frameworks/PHP/php/php-caddy.dockerfile @@ -1,30 +1,30 @@ -FROM ubuntu:22.04 +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 + apt-get update -yqq > /dev/null && apt-get upgrade -yqq RUN apt-get install -yqq git unzip curl \ - php8.3 php8.3-common php8.3-cli php8.3-fpm php8.3-mysql > /dev/null + php8.4 php8.4-common php8.4-cli php8.4-fpm php8.4-mysql > /dev/null -COPY deploy/conf/* /etc/php/8.3/fpm/ +COPY deploy/conf/* /etc/php/8.4/fpm/ # Install Caddyserver RUN apt-get install -y debian-keyring debian-archive-keyring apt-transport-https > /dev/null \ && curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg \ && curl -sf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | tee /etc/apt/sources.list.d/caddy-stable.list \ - && apt-get update > /dev/null && apt-get install caddy > /dev/null + && apt-get update > /dev/null && apt-get install caddy=2.9.1 > /dev/null ADD ./ /php WORKDIR /php -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.3/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.4/fpm/php-fpm.conf ; fi; RUN chmod -R 777 /php EXPOSE 8080 -CMD service php8.3-fpm start && \ +CMD service php8.4-fpm start && \ caddy run --config deploy/caddy/Caddyfile diff --git a/frameworks/PHP/php/php-eloquent.dockerfile b/frameworks/PHP/php/php-eloquent.dockerfile index 615f0a10072..5f9c0616938 100644 --- a/frameworks/PHP/php/php-eloquent.dockerfile +++ b/frameworks/PHP/php/php-eloquent.dockerfile @@ -1,20 +1,21 @@ -FROM ubuntu:22.04 +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 > /dev/null && \ - apt-get install -yqq nginx git unzip php8.3 php8.3-common php8.3-cli php8.3-fpm php8.3-mysql php8.3-mbstring php8.3-dev > /dev/null + apt-get install -yqq nginx git unzip \ + php8.4 php8.4-common php8.4-cli php8.4-fpm php8.4-mysql php8.4-mbstring php8.4-curl > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -COPY deploy/conf/* /etc/php/8.3/fpm/ +COPY deploy/conf/* /etc/php/8.4/fpm/ ADD ./ /php WORKDIR /php -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.3/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.4/fpm/php-fpm.conf ; fi; COPY deploy/eloquent/composer* ./ RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet @@ -23,6 +24,5 @@ RUN chmod -R 777 /php EXPOSE 8080 -CMD service php8.3-fpm start && \ +CMD service php8.4-fpm start && \ nginx -c /php/deploy/nginx7.conf -g "daemon off;" - diff --git a/frameworks/PHP/php/php-franken.dockerfile b/frameworks/PHP/php/php-franken.dockerfile index 56748c15fab..747a3722169 100644 --- a/frameworks/PHP/php/php-franken.dockerfile +++ b/frameworks/PHP/php/php-franken.dockerfile @@ -4,12 +4,13 @@ FROM dunglas/frankenphp RUN install-php-extensions \ pdo_mysql \ zip \ - opcache + opcache > /dev/null -COPY deploy/franken/Caddyfile /etc/caddy/Caddyfile +COPY --link deploy/franken/Caddyfile /etc/frankenphp/Caddyfile +COPY --link deploy/conf/php.ini /usr/local/etc/php/ -ADD . /php +COPY --link . /php # Worker mode #ENV FRANKENPHP_CONFIG="worker ./public/index.php" diff --git a/frameworks/PHP/php/php-h2o.dockerfile b/frameworks/PHP/php/php-h2o.dockerfile index 2d0c6234bcd..a722b660011 100644 --- a/frameworks/PHP/php/php-h2o.dockerfile +++ b/frameworks/PHP/php/php-h2o.dockerfile @@ -1,61 +1,66 @@ -ARG UBUNTU_VERSION=22.04 +ARG UBUNTU_VERSION=24.04 ARG H2O_PREFIX=/opt/h2o -FROM "ubuntu:${UBUNTU_VERSION}" AS compile +FROM "buildpack-deps:${UBUNTU_VERSION}" AS compile -ARG H2O_VERSION=13ba727ad12dfb2338165d2bcfb2136457e33c8a +ARG H2O_VERSION=3b9b6a53cac8bcc6a25fb28df81ad295fc5f9402 ARG DEBIAN_FRONTEND=noninteractive ARG H2O_PREFIX WORKDIR /tmp/h2o-build -RUN apt-get -yqq update && \ - apt-get -yqq install \ +RUN apt-get install \ + --no-install-recommends \ + -qqUy \ cmake \ curl \ g++ \ libbrotli-dev \ libcap-dev \ libssl-dev \ - libtool \ + liburing-dev \ libuv1-dev \ libwslay-dev \ libz-dev \ + make \ ninja-build \ pkg-config \ - systemtap-sdt-dev && \ + ruby \ + 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_AR=/usr/bin/gcc-ar \ - -DCMAKE_C_FLAGS="-flto -march=native -mtune=native" \ + -DCMAKE_C_FLAGS="-flto=auto -march=native -mtune=native" \ -DCMAKE_INSTALL_PREFIX="${H2O_PREFIX}" \ - -DCMAKE_RANLIB=/usr/bin/gcc-ranlib \ + -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}" -ARG PHP_VERSION=8.3 +ARG PHP_VERSION=8.4 ENV TZ=America/Los_Angeles ARG DEBIAN_FRONTEND=noninteractive -RUN apt-get -yqq update && \ - apt-get -yqq install \ +RUN apt-get install \ + --no-install-recommends \ + -qqUy \ apt-utils \ - software-properties-common && \ + software-properties-common > /dev/null && \ LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php && \ - apt-get -yqq update && \ - apt-get -yqq install \ + apt-get install \ + --no-install-recommends \ + -qqUy \ + liburing2 \ "php${PHP_VERSION}" \ "php${PHP_VERSION}-cli" \ "php${PHP_VERSION}-common" \ "php${PHP_VERSION}-fpm" \ - "php${PHP_VERSION}-mysql" + "php${PHP_VERSION}-mysql" > /dev/null ARG H2O_PREFIX COPY --from=compile "${H2O_PREFIX}/bin/h2o" "${H2O_PREFIX}/bin/" COPY --from=compile "${H2O_PREFIX}/share" "${H2O_PREFIX}/share/" @@ -70,5 +75,5 @@ ARG TFB_TEST_DATABASE ARG TFB_TEST_NAME CMD sed -i "s/num-threads: x/num-threads: $((2 * $(nproc)))/g" /opt/h2o/etc/h2o.conf && \ - service php8.3-fpm start && \ + service php8.4-fpm start && \ /opt/h2o/bin/h2o -c /opt/h2o/etc/h2o.conf diff --git a/frameworks/PHP/php/php-laravel-query-builder.dockerfile b/frameworks/PHP/php/php-laravel-query-builder.dockerfile index 2ca94a15881..ea2e74e1c9a 100644 --- a/frameworks/PHP/php/php-laravel-query-builder.dockerfile +++ b/frameworks/PHP/php/php-laravel-query-builder.dockerfile @@ -1,20 +1,20 @@ -FROM ubuntu:22.04 +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 > /dev/null && \ - apt-get install -yqq nginx git unzip php8.3 php8.3-common php8.3-cli php8.3-fpm php8.3-mysql php8.3-mbstring php8.3-dev > /dev/null + apt-get install -yqq nginx git unzip php8.4 php8.4-common php8.4-cli php8.4-fpm php8.4-mysql php8.4-mbstring php8.4-dev > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -COPY deploy/conf/* /etc/php/8.3/fpm/ +COPY deploy/conf/* /etc/php/8.4/fpm/ ADD ./ /php WORKDIR /php -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.3/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.4/fpm/php-fpm.conf ; fi; COPY deploy/eloquent/composer* ./ RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet @@ -23,5 +23,5 @@ RUN chmod -R 777 /php EXPOSE 8080 -CMD service php8.3-fpm start && \ +CMD service php8.4-fpm start && \ nginx -c /php/deploy/nginx7.conf -g "daemon off;" diff --git a/frameworks/PHP/php/php-pgsql-raw.dockerfile b/frameworks/PHP/php/php-pgsql-raw.dockerfile index 374656d40b9..c3d3c922718 100644 --- a/frameworks/PHP/php/php-pgsql-raw.dockerfile +++ b/frameworks/PHP/php/php-pgsql-raw.dockerfile @@ -1,13 +1,13 @@ -FROM ubuntu:22.04 +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 > /dev/null && \ - apt-get install -yqq nginx git unzip php8.3 php8.3-common php8.3-cli php8.3-fpm php8.3-pgsql > /dev/null + apt-get install -yqq nginx git unzip php8.4 php8.4-common php8.4-cli php8.4-fpm php8.4-pgsql > /dev/null -COPY deploy/conf/* /etc/php/8.3/fpm/ +COPY deploy/conf/* /etc/php/8.4/fpm/ ADD ./ /php WORKDIR /php @@ -17,11 +17,11 @@ RUN sed -i "s|PDO('mysql:|PDO('pgsql:|g" dbquery.php RUN sed -i "s|PDO('mysql:|PDO('pgsql:|g" fortune.php RUN sed -i "s|PDO('mysql:|PDO('pgsql:|g" updateraw.php -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.3/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.4/fpm/php-fpm.conf ; fi; RUN chmod -R 777 /php EXPOSE 8080 -CMD service php8.3-fpm start && \ +CMD service php8.4-fpm start && \ nginx -c /php/deploy/nginx7.conf -g "daemon off;" diff --git a/frameworks/PHP/php/php-pools.dockerfile b/frameworks/PHP/php/php-pools.dockerfile index b62917e0ec3..e217f448e88 100644 --- a/frameworks/PHP/php/php-pools.dockerfile +++ b/frameworks/PHP/php/php-pools.dockerfile @@ -1,23 +1,23 @@ -FROM ubuntu:22.04 +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 > /dev/null && \ - apt-get install -yqq nginx git unzip php8.3 php8.3-common php8.3-cli php8.3-fpm php8.3-mysql > /dev/null + apt-get install -yqq nginx git unzip php8.4 php8.4-common php8.4-cli php8.4-fpm php8.4-mysql > /dev/null -COPY deploy/conf/* /etc/php/8.3/fpm/ +COPY deploy/conf/* /etc/php/8.4/fpm/ ADD ./ /php WORKDIR /php -COPY deploy/conf/php-fpm-pools.conf /etc/php/8.3/fpm/php-fpm.conf -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 512|pm.max_children = 256|g" /etc/php/8.3/fpm/php-fpm.conf ; fi; +COPY deploy/conf/php-fpm-pools.conf /etc/php/8.4/fpm/php-fpm.conf +RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 512|pm.max_children = 256|g" /etc/php/8.4/fpm/php-fpm.conf ; fi; RUN chmod -R 777 /php EXPOSE 8080 -CMD service php8.3-fpm start && \ +CMD service php8.4-fpm start && \ nginx -c /php/deploy/nginx-pools.conf -g "daemon off;" diff --git a/frameworks/PHP/php/php-raw7-tcp.dockerfile b/frameworks/PHP/php/php-raw7-tcp.dockerfile index c8cd5eb855c..2dde7c65ee0 100644 --- a/frameworks/PHP/php/php-raw7-tcp.dockerfile +++ b/frameworks/PHP/php/php-raw7-tcp.dockerfile @@ -1,25 +1,25 @@ -FROM ubuntu:22.04 +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 > /dev/null && \ - apt-get install -yqq nginx git unzip php8.3 php8.3-common php8.3-cli php8.3-fpm php8.3-mysql > /dev/null + apt-get install -yqq nginx git unzip php8.4 php8.4-common php8.4-cli php8.4-fpm php8.4-mysql > /dev/null -COPY deploy/conf/* /etc/php/8.3/fpm/ +COPY deploy/conf/* /etc/php/8.4/fpm/ ADD ./ /php WORKDIR /php -RUN sed -i "s|listen = /run/php/php-fpm.sock|listen = 127.0.0.1:9001|g" /etc/php/8.3/fpm/php-fpm.conf +RUN sed -i "s|listen = /run/php/php-fpm.sock|listen = 127.0.0.1:9001|g" /etc/php/8.4/fpm/php-fpm.conf RUN sed -i "s|server unix:/var/run/php/php-fpm.sock;|server 127.0.0.1:9001;|g" deploy/nginx7.conf -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.3/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.4/fpm/php-fpm.conf ; fi; RUN chmod -R 777 /php EXPOSE 8080 -CMD service php8.3-fpm start && \ - nginx -c /php/deploy/nginx7.conf -g "daemon off;" \ No newline at end of file +CMD service php8.4-fpm start && \ + nginx -c /php/deploy/nginx7.conf -g "daemon off;" diff --git a/frameworks/PHP/php/php-unit.dockerfile b/frameworks/PHP/php/php-unit.dockerfile index fa37e1cb4a9..04a0539eca1 100644 --- a/frameworks/PHP/php/php-unit.dockerfile +++ b/frameworks/PHP/php/php-unit.dockerfile @@ -1,13 +1,20 @@ -FROM unit:1.30.0-php8.2 +FROM unit:php8.4 + +RUN docker-php-ext-install pdo_mysql opcache > /dev/null -ADD . /php WORKDIR /php +COPY --link . . -RUN docker-php-ext-install pdo_mysql opcache > /dev/null -RUN if [ $(nproc) = 2 ]; then sed -i "s|\"processes\": 84,|\"processes\": 64,|g" /php/deploy/nginx-unit.json ; fi; +RUN if [ $(nproc) = 2 ]; then sed -i "s|\"spare\": 168,|\"spare\": 64,|g" /php/deploy/nginx-unit.json ; fi; -EXPOSE 8080 +#RUN more /php/deploy/nginx-unit.json -COPY deploy/nginx-unit.json /docker-entrypoint.d/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/php/php-workerman.dockerfile b/frameworks/PHP/php/php-workerman.dockerfile index 6f392702778..40ce5e187af 100644 --- a/frameworks/PHP/php/php-workerman.dockerfile +++ b/frameworks/PHP/php/php-workerman.dockerfile @@ -1,26 +1,26 @@ -FROM ubuntu:22.04 +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 + apt-get update -yqq > /dev/null && apt-get upgrade -yqq RUN apt-get install -yqq git unzip \ - php8.3 php8.3-common php8.3-cli php8.3-fpm php8.3-mysql > /dev/null + php8.4 php8.4-common php8.4-cli php8.4-fpm php8.4-mysql > /dev/null -RUN apt-get install -y php-pear php8.3-dev php8.3-xml libevent-dev > /dev/null -RUN pecl install event-3.0.8 > /dev/null && echo "extension=event.so" > /etc/php/8.3/cli/conf.d/event.ini +RUN apt-get install -y php-pear php8.4-dev php8.4-xml libevent-dev > /dev/null +RUN pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.4/cli/conf.d/event.ini -COPY deploy/workerman/cli-php.ini /etc/php/8.3/cli/php.ini +COPY deploy/workerman/cli-php.ini /etc/php/8.4/cli/conf.d/20-adapterman.ini -COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer +COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer -ADD ./ /php WORKDIR /php +COPY --link . . COPY deploy/workerman/composer.json ./ -RUN composer install --optimize-autoloader --classmap-authoritative --no-dev +RUN composer install --optimize-autoloader --classmap-authoritative --no-dev COPY deploy/workerman/start.php ./ diff --git a/frameworks/PHP/php/php.dockerfile b/frameworks/PHP/php/php.dockerfile index 5ad4298427f..495e54b5631 100644 --- a/frameworks/PHP/php/php.dockerfile +++ b/frameworks/PHP/php/php.dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:22.04 +FROM ubuntu:24.04 ARG DEBIAN_FRONTEND=noninteractive @@ -6,19 +6,19 @@ RUN apt-get update -yqq && apt-get install -yqq software-properties-common > /de RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null && \ apt-get update -yqq > /dev/null && apt-get upgrade -yqq RUN apt-get install -yqq nginx git unzip \ - php8.3 php8.3-common php8.3-cli php8.3-fpm php8.3-mysql > /dev/null + php8.4 php8.4-common php8.4-cli php8.4-fpm php8.4-mysql > /dev/null -COPY deploy/conf/* /etc/php/8.3/fpm/ +COPY deploy/conf/* /etc/php/8.4/fpm/ ADD ./ /php WORKDIR /php -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.3/fpm/php-fpm.conf ; fi; -RUN sed -i "s|opcache.jit=off|;opcache.jit=off|g" /etc/php/8.3/fpm/conf.d/10-opcache.ini +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 sed -i "s|opcache.jit=off|;opcache.jit=off|g" /etc/php/8.4/fpm/conf.d/10-opcache.ini RUN chmod -R 777 /php EXPOSE 8080 -CMD service php8.3-fpm start && \ +CMD service php8.4-fpm start && \ nginx -c /php/deploy/nginx7.conf -g "daemon off;" diff --git a/frameworks/PHP/phpixie/benchmark_config.json b/frameworks/PHP/phpixie/benchmark_config.json index 4dc078d0066..4481bcdc91e 100755 --- a/frameworks/PHP/phpixie/benchmark_config.json +++ b/frameworks/PHP/phpixie/benchmark_config.json @@ -14,7 +14,7 @@ "database": "MySQL", "framework": "phpixie", "language": "PHP", - "flavor": "PHP7", + "flavor": "PHP8", "orm": "Full", "platform": "FPM/FastCGI", "webserver": "nginx", @@ -23,6 +23,29 @@ "display_name": "phpixie", "notes": "", "versus": "php" + }, + "workerman": { + "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": "phpixie", + "language": "PHP", + "flavor": "PHP8", + "orm": "Full", + "platform": "workerman", + "webserver": "none", + "os": "Linux", + "database_os": "Linux", + "display_name": "phpixie [workerman]", + "notes": "", + "versus": "php" } }] } diff --git a/frameworks/PHP/phpixie/deploy/conf/adapterman.ini b/frameworks/PHP/phpixie/deploy/conf/adapterman.ini new file mode 100644 index 00000000000..61e9f49203f --- /dev/null +++ b/frameworks/PHP/phpixie/deploy/conf/adapterman.ini @@ -0,0 +1,16 @@ +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.huge_code_pages=1 + +mysqlnd.collect_statistics = Off +memory_limit = 512M + +opcache.jit_buffer_size=128M +opcache.jit=tracing + +disable_functions=header,header_remove,headers_sent,headers_list,http_response_code,setcookie,session_create_id,session_id,session_name,session_save_path,session_status,session_start,session_write_close,session_regenerate_id,session_unset,session_get_cookie_params,session_set_cookie_params,set_time_limit \ No newline at end of file diff --git a/frameworks/PHP/phpixie/phpixie-workerman.dockerfile b/frameworks/PHP/phpixie/phpixie-workerman.dockerfile new file mode 100644 index 00000000000..fd024a84f83 --- /dev/null +++ b/frameworks/PHP/phpixie/phpixie-workerman.dockerfile @@ -0,0 +1,26 @@ +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 > /dev/null && \ + apt-get install -yqq nginx git unzip php8.0 php8.0-common php8.0-cli php8.0-mysql php8.0-xml php8.0-curl > /dev/null + +COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer + +RUN apt-get install -y php-pear php8.0-dev libevent-dev > /dev/null +RUN pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.0/cli/conf.d/event.ini + +COPY deploy/conf/adapterman.ini /etc/php/8.0/cli/conf.d/20-adapterman.ini + +WORKDIR /phpixie +COPY --link . . + +RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet +RUN composer require joanhey/adapterman:^0.6 --quiet + +RUN chmod -R 777 /phpixie + +EXPOSE 8080 +CMD php server.php start diff --git a/frameworks/PHP/phpixie/phpixie.dockerfile b/frameworks/PHP/phpixie/phpixie.dockerfile index 47369ef7dcc..152e69a4d25 100644 --- a/frameworks/PHP/phpixie/phpixie.dockerfile +++ b/frameworks/PHP/phpixie/phpixie.dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:22.04 +FROM ubuntu:24.04 ARG DEBIAN_FRONTEND=noninteractive @@ -11,8 +11,8 @@ COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer COPY deploy/conf/* /etc/php/8.0/fpm/ -ADD ./ /phpixie WORKDIR /phpixie +COPY --link . . RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.0/fpm/php-fpm.conf ; fi; diff --git a/frameworks/PHP/phpixie/server.php b/frameworks/PHP/phpixie/server.php new file mode 100644 index 00000000000..ebb29dfa817 --- /dev/null +++ b/frameworks/PHP/phpixie/server.php @@ -0,0 +1,47 @@ +count = (int) shell_exec('nproc') * 4; +$http_worker->reusePort = true; +$http_worker->name = 'AdapterMan Phpixie'; + +$http_worker->onWorkerStart = static function () { + HeaderDate::init(); + //chdir(__DIR__.'/public'); + require 'web/start.php'; +}; + +$http_worker->onMessage = static function ($connection) { + + $connection->send(run()); +}; + +Worker::runAll(); + +class HeaderDate +{ + const NAME = 'Date: '; + + /** + * Date header + * + * @var string + */ + public static $date; + + public static function init(): void + { + self::$date = self::NAME . gmdate(DATE_RFC7231); + Timer::add(1, static function() { + self::$date = self::NAME . gmdate(DATE_RFC7231); + }); + } +} \ No newline at end of file diff --git a/frameworks/PHP/phpixie/web/start.php b/frameworks/PHP/phpixie/web/start.php new file mode 100644 index 00000000000..94472f8f4ae --- /dev/null +++ b/frameworks/PHP/phpixie/web/start.php @@ -0,0 +1,19 @@ +add('', $root.'/classes/'); + +global $pixie; +$pixie = new \App\Pixie(); +$pixie->bootstrap($root); + +function run(): string +{ + global $pixie; + ob_start(); + + $pixie->handle_http_request(); + header(HeaderDate::$date); // To pass the bench, nginx auto add it + + return ob_get_clean(); +} diff --git a/frameworks/PHP/piko/.gitignore b/frameworks/PHP/piko/.gitignore new file mode 100644 index 00000000000..136e525b7af --- /dev/null +++ b/frameworks/PHP/piko/.gitignore @@ -0,0 +1 @@ +.phpactor.json diff --git a/frameworks/PHP/piko/README.md b/frameworks/PHP/piko/README.md new file mode 100755 index 00000000000..29e61d13324 --- /dev/null +++ b/frameworks/PHP/piko/README.md @@ -0,0 +1,39 @@ +# Piko Benchmarking Test + +### Test Type Implementation Source Code + +* [JSON](modules/site/controllers/DefaultController.php) +* [PLAINTEXT](modules/site/controllers/DefaultController.php) +* [DB](modules/site/controllers/DatabaseController.php) +* [QUERY](modules/site/controllers/DatabaseController.php) +* [UPDATE](modules/site/controllers/DatabaseController.php) +* [FORTUNES](modules/site/controllers/DatabaseController.php) + +## Important Libraries +The tests were run with: +* [Piko](https://piko-framework.github.io/) + +## Test URLs +### JSON + +http://localhost:8080/json + +### PLAINTEXT + +http://localhost:8080/plaintext + +### 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/PHP/piko/benchmark_config.json b/frameworks/PHP/piko/benchmark_config.json new file mode 100755 index 00000000000..2b945ad8f60 --- /dev/null +++ b/frameworks/PHP/piko/benchmark_config.json @@ -0,0 +1,54 @@ +{ + "framework": "piko", + "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": "mysql", + "framework": "Piko", + "language": "PHP", + "flavor": "None", + "orm": "Micro", + "platform": "None", + "webserver": "nginx", + "os": "Linux", + "database_os": "Linux", + "display_name": "Piko Mysql", + "notes": "", + "versus": "None" + }, + "postgres": { + "dockerfile": "piko-postgres.dockerfile", + "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": "Piko", + "language": "PHP", + "flavor": "None", + "orm": "Micro", + "platform": "None", + "webserver": "nginx", + "os": "Linux", + "database_os": "Linux", + "display_name": "Piko Postgres", + "notes": "", + "versus": "None" + } + } + ] +} diff --git a/frameworks/PHP/piko/composer.json b/frameworks/PHP/piko/composer.json new file mode 100644 index 00000000000..e1eaadc660d --- /dev/null +++ b/frameworks/PHP/piko/composer.json @@ -0,0 +1,16 @@ +{ + "name": "piko/project-benchmark", + "description": "Application to be tested on the FrameworkBenchmarks.", + "type": "project", + "license": "MIT", + "require": { + "php": ">=8.0", + "piko/framework": "^3.4", + "piko/db-record": "^2.2" + }, + "autoload": { + "psr-4": { + "app\\": "" + } + } +} diff --git a/frameworks/PHP/piko/config/app.php b/frameworks/PHP/piko/config/app.php new file mode 100644 index 00000000000..67b6f9b1d6d --- /dev/null +++ b/frameworks/PHP/piko/config/app.php @@ -0,0 +1,28 @@ + realpath(__DIR__ . '/../'), + 'defaultLayoutPath' => '@app/modules/site/layouts', + 'defaultLayout' => 'main', + 'language' => 'en', + 'components' => [ + 'Piko\View' => [], + 'Piko\Router' => [ + 'construct' => [ + [ + 'routes' => require __DIR__ . '/routes.php', + ] + ] + ], + 'PDO' => [ + 'construct' => [ + (getenv('DATABASE_DRIVER') ? getenv('DATABASE_DRIVER') : 'mysql') . ':host=tfb-database;dbname=hello_world', + 'benchmarkdbuser', + 'benchmarkdbpass' + ] + ], + ], + 'modules' => [ + 'site' => 'app\modules\site\Module' + ] +]; diff --git a/frameworks/PHP/piko/config/routes.php b/frameworks/PHP/piko/config/routes.php new file mode 100644 index 00000000000..b4fdc8d785b --- /dev/null +++ b/frameworks/PHP/piko/config/routes.php @@ -0,0 +1,17 @@ + 'site/default/plaintext', + '/json' => 'site/default/json', + '/db' => 'site/database/query', + '/queries' => 'site/database/queries', + '/fortunes' => 'site/database/fortunes', + '/updates' => 'site/database/updates', +]; diff --git a/frameworks/PHP/piko/deploy/conf/php-fpm.conf b/frameworks/PHP/piko/deploy/conf/php-fpm.conf new file mode 100644 index 00000000000..a90976aca61 --- /dev/null +++ b/frameworks/PHP/piko/deploy/conf/php-fpm.conf @@ -0,0 +1,551 @@ +;;;;;;;;;;;;;;;;;;;;; +; FPM Configuration ; +;;;;;;;;;;;;;;;;;;;;; + +; All relative paths in this configuration file are relative to PHP's install +; prefix (/usr). This prefix can be dynamically changed by using the +; '-p' argument from the command line. + +;;;;;;;;;;;;;;;;;; +; Global Options ; +;;;;;;;;;;;;;;;;;; + +[global] +; Pid file +; Note: the default prefix is /var +; Default Value: none +pid = /run/php/php-fpm.pid + +; Error log file +; If it's set to "syslog", log is sent to syslogd instead of being written +; into a local file. +; Note: the default prefix is /var +; Default Value: log/php-fpm.log +error_log = /dev/stderr + + +; syslog_facility is used to specify what type of program is logging the +; message. This lets syslogd specify that messages from different facilities +; will be handled differently. +; See syslog(3) for possible values (ex daemon equiv LOG_DAEMON) +; Default Value: daemon +;syslog.facility = daemon + +; syslog_ident is prepended to every message. If you have multiple FPM +; instances running on the same server, you can change the default value +; which must suit common needs. +; Default Value: php-fpm +;syslog.ident = php-fpm + +; Log level +; Possible Values: alert, error, warning, notice, debug +; Default Value: notice +;log_level = notice + +; If this number of child processes exit with SIGSEGV or SIGBUS within the time +; interval set by emergency_restart_interval then FPM will restart. A value +; of '0' means 'Off'. +; Default Value: 0 +;emergency_restart_threshold = 0 + +; Interval of time used by emergency_restart_interval to determine when +; a graceful restart will be initiated. This can be useful to work around +; accidental corruptions in an accelerator's shared memory. +; Available Units: s(econds), m(inutes), h(ours), or d(ays) +; Default Unit: seconds +; Default Value: 0 +;emergency_restart_interval = 0 + +; Time limit for child processes to wait for a reaction on signals from master. +; Available units: s(econds), m(inutes), h(ours), or d(ays) +; Default Unit: seconds +; Default Value: 0 +;process_control_timeout = 0 + +; The maximum number of processes FPM will fork. This has been designed to control +; the global number of processes when using dynamic PM within a lot of pools. +; Use it with caution. +; Note: A value of 0 indicates no limit +; Default Value: 0 +; process.max = 128 + +; Specify the nice(2) priority to apply to the master process (only if set) +; The value can vary from -19 (highest priority) to 20 (lowest priority) +; Note: - It will only work if the FPM master process is launched as root +; - The pool process will inherit the master process priority +; unless specified otherwise +; Default Value: no set +; process.priority = -19 + +; Send FPM to background. Set to 'no' to keep FPM in foreground for debugging. +; Default Value: yes +;daemonize = yes + +; Set open file descriptor rlimit for the master process. +; Default Value: system defined value +;rlimit_files = 1024 + +; Set max core size rlimit for the master process. +; Possible Values: 'unlimited' or an integer greater or equal to 0 +; Default Value: system defined value +;rlimit_core = 0 + +; Specify the event mechanism FPM will use. The following is available: +; - select (any POSIX os) +; - poll (any POSIX os) +; - epoll (linux >= 2.5.44) +; - kqueue (FreeBSD >= 4.1, OpenBSD >= 2.9, NetBSD >= 2.0) +; - /dev/poll (Solaris >= 7) +; - port (Solaris >= 10) +; Default Value: not set (auto detection) +;events.mechanism = epoll + +; When FPM is built with systemd integration, specify the interval, +; in seconds, between health report notification to systemd. +; Set to 0 to disable. +; Available Units: s(econds), m(inutes), h(ours) +; Default Unit: seconds +; Default value: 10 +systemd_interval = 0 + +;;;;;;;;;;;;;;;;;;;; +; Pool Definitions ; +;;;;;;;;;;;;;;;;;;;; + +; Multiple pools of child processes may be started with different listening +; ports and different management options. The name of the pool will be +; used in logs and stats. There is no limitation on the number of pools which +; FPM can handle. Your system will tell you anyway :) + +; Include one or more files. If glob(3) exists, it is used to include a bunch of +; files from a glob(3) pattern. This directive can be used everywhere in the +; file. +; Relative path can also be used. They will be prefixed by: +; - the global prefix if it's been set (-p argument) +; - /usr otherwise +;include=/etc/php/7.3/fpm/pool.d/*.conf + +; Start a new pool named 'www'. +; the variable $pool can be used in any directive and will be replaced by the +; pool name ('www' here) +[www] + +; Per pool prefix +; It only applies on the following directives: +; - 'access.log' +; - 'slowlog' +; - 'listen' (unixsocket) +; - 'chroot' +; - 'chdir' +; - 'php_values' +; - 'php_admin_values' +; When not set, the global prefix (or /usr) applies instead. +; Note: This directive can also be relative to the global prefix. +; Default Value: none +;prefix = /path/to/pools/$pool + +; Unix user/group of processes +; Note: The user is mandatory. If the group is not set, the default user's group +; will be used. +user = www-data +group = www-data + +; The address on which to accept FastCGI requests. +; Valid syntaxes are: +; 'ip.add.re.ss:port' - to listen on a TCP socket to a specific IPv4 address on +; a specific port; +; '[ip:6:addr:ess]:port' - to listen on a TCP socket to a specific IPv6 address on +; a specific port; +; 'port' - to listen on a TCP socket to all addresses +; (IPv6 and IPv4-mapped) on a specific port; +; '/path/to/unix/socket' - to listen on a unix socket. +; Note: This value is mandatory. +listen = /run/php/php-fpm.sock + +; Set listen(2) backlog. +; Default Value: 511 (-1 on FreeBSD and OpenBSD) +listen.backlog = 65535 + +; Set permissions for unix socket, if one is used. In Linux, read/write +; permissions must be set in order to allow connections from a web server. Many +; BSD-derived systems allow connections regardless of permissions. +; Default Values: user and group are set as the running user +; mode is set to 0660 +listen.owner = www-data +listen.group = www-data +;listen.mode = 0660 +; When POSIX Access Control Lists are supported you can set them using +; these options, value is a comma separated list of user/group names. +; When set, listen.owner and listen.group are ignored +;listen.acl_users = +;listen.acl_groups = + +; List of addresses (IPv4/IPv6) of FastCGI clients which are allowed to connect. +; Equivalent to the FCGI_WEB_SERVER_ADDRS environment variable in the original +; PHP FCGI (5.2.2+). Makes sense only with a tcp listening socket. Each address +; must be separated by a comma. If this value is left blank, connections will be +; accepted from any ip address. +; Default Value: any +;listen.allowed_clients = 127.0.0.1 + +; Specify the nice(2) priority to apply to the pool processes (only if set) +; The value can vary from -19 (highest priority) to 20 (lower priority) +; Note: - It will only work if the FPM master process is launched as root +; - The pool processes will inherit the master process priority +; unless it specified otherwise +; Default Value: no set +; process.priority = -19 + +; Set the process dumpable flag (PR_SET_DUMPABLE prctl) even if the process user +; or group is differrent than the master process user. It allows to create process +; core dump and ptrace the process for the pool user. +; Default Value: no +; process.dumpable = yes + +; Choose how the process manager will control the number of child processes. +; Possible Values: +; static - a fixed number (pm.max_children) of child processes; +; dynamic - the number of child processes are set dynamically based on the +; following directives. With this process management, there will be +; always at least 1 children. +; pm.max_children - the maximum number of children that can +; be alive at the same time. +; pm.start_servers - the number of children created on startup. +; pm.min_spare_servers - the minimum number of children in 'idle' +; state (waiting to process). If the number +; of 'idle' processes is less than this +; number then some children will be created. +; pm.max_spare_servers - the maximum number of children in 'idle' +; state (waiting to process). If the number +; of 'idle' processes is greater than this +; number then some children will be killed. +; ondemand - no children are created at startup. Children will be forked when +; new requests will connect. The following parameter are used: +; pm.max_children - the maximum number of children that +; can be alive at the same time. +; pm.process_idle_timeout - The number of seconds after which +; an idle process will be killed. +; Note: This value is mandatory. +pm = static + +; The number of child processes to be created when pm is set to 'static' and the +; maximum number of child processes when pm is set to 'dynamic' or 'ondemand'. +; This value sets the limit on the number of simultaneous requests that will be +; served. Equivalent to the ApacheMaxClients directive with mpm_prefork. +; Equivalent to the PHP_FCGI_CHILDREN environment variable in the original PHP +; CGI. The below defaults are based on a server without much resources. Don't +; forget to tweak pm.* to fit your needs. +; Note: Used when pm is set to 'static', 'dynamic' or 'ondemand' +; Note: This value is mandatory. +pm.max_children = 1024 + +; The number of child processes created on startup. +; Note: Used only when pm is set to 'dynamic' +; Default Value: min_spare_servers + (max_spare_servers - min_spare_servers) / 2 +pm.start_servers = 512 + +; The desired minimum number of idle server processes. +; Note: Used only when pm is set to 'dynamic' +; Note: Mandatory when pm is set to 'dynamic' +pm.min_spare_servers = 50 + +; The desired maximum number of idle server processes. +; Note: Used only when pm is set to 'dynamic' +; Note: Mandatory when pm is set to 'dynamic' +pm.max_spare_servers = 512 + +; The number of seconds after which an idle process will be killed. +; Note: Used only when pm is set to 'ondemand' +; Default Value: 10s +;pm.process_idle_timeout = 10s; + +; The number of requests each child process should execute before respawning. +; This can be useful to work around memory leaks in 3rd party libraries. For +; endless request processing specify '0'. Equivalent to PHP_FCGI_MAX_REQUESTS. +; Default Value: 0 +;pm.max_requests = 500 + +; The URI to view the FPM status page. If this value is not set, no URI will be +; recognized as a status page. It shows the following informations: +; pool - the name of the pool; +; process manager - static, dynamic or ondemand; +; start time - the date and time FPM has started; +; start since - number of seconds since FPM has started; +; accepted conn - the number of request accepted by the pool; +; listen queue - the number of request in the queue of pending +; connections (see backlog in listen(2)); +; max listen queue - the maximum number of requests in the queue +; of pending connections since FPM has started; +; listen queue len - the size of the socket queue of pending connections; +; idle processes - the number of idle processes; +; active processes - the number of active processes; +; total processes - the number of idle + active processes; +; max active processes - the maximum number of active processes since FPM +; has started; +; max children reached - number of times, the process limit has been reached, +; when pm tries to start more children (works only for +; pm 'dynamic' and 'ondemand'); +; Value are updated in real time. +; Example output: +; pool: www +; process manager: static +; start time: 01/Jul/2011:17:53:49 +0200 +; start since: 62636 +; accepted conn: 190460 +; listen queue: 0 +; max listen queue: 1 +; listen queue len: 42 +; idle processes: 4 +; active processes: 11 +; total processes: 15 +; max active processes: 12 +; max children reached: 0 +; +; By default the status page output is formatted as text/plain. Passing either +; 'html', 'xml' or 'json' in the query string will return the corresponding +; output syntax. Example: +; http://www.foo.bar/status +; http://www.foo.bar/status?json +; http://www.foo.bar/status?html +; http://www.foo.bar/status?xml +; +; By default the status page only outputs short status. Passing 'full' in the +; query string will also return status for each pool process. +; Example: +; http://www.foo.bar/status?full +; http://www.foo.bar/status?json&full +; http://www.foo.bar/status?html&full +; http://www.foo.bar/status?xml&full +; The Full status returns for each process: +; pid - the PID of the process; +; state - the state of the process (Idle, Running, ...); +; start time - the date and time the process has started; +; start since - the number of seconds since the process has started; +; requests - the number of requests the process has served; +; request duration - the duration in µs of the requests; +; request method - the request method (GET, POST, ...); +; request URI - the request URI with the query string; +; content length - the content length of the request (only with POST); +; user - the user (PHP_AUTH_USER) (or '-' if not set); +; script - the main script called (or '-' if not set); +; last request cpu - the %cpu the last request consumed +; it's always 0 if the process is not in Idle state +; because CPU calculation is done when the request +; processing has terminated; +; last request memory - the max amount of memory the last request consumed +; it's always 0 if the process is not in Idle state +; because memory calculation is done when the request +; processing has terminated; +; If the process is in Idle state, then informations are related to the +; last request the process has served. Otherwise informations are related to +; the current request being served. +; Example output: +; ************************ +; pid: 31330 +; state: Running +; start time: 01/Jul/2011:17:53:49 +0200 +; start since: 63087 +; requests: 12808 +; request duration: 1250261 +; request method: GET +; request URI: /test_mem.php?N=10000 +; content length: 0 +; user: - +; script: /home/fat/web/docs/php/test_mem.php +; last request cpu: 0.00 +; last request memory: 0 +; +; Note: There is a real-time FPM status monitoring sample web page available +; It's available in: /usr/share/php/7.3/fpm/status.html +; +; Note: The value must start with a leading slash (/). The value can be +; anything, but it may not be a good idea to use the .php extension or it +; may conflict with a real PHP file. +; Default Value: not set +;pm.status_path = /status + +; The ping URI to call the monitoring page of FPM. If this value is not set, no +; URI will be recognized as a ping page. This could be used to test from outside +; that FPM is alive and responding, or to +; - create a graph of FPM availability (rrd or such); +; - remove a server from a group if it is not responding (load balancing); +; - trigger alerts for the operating team (24/7). +; Note: The value must start with a leading slash (/). The value can be +; anything, but it may not be a good idea to use the .php extension or it +; may conflict with a real PHP file. +; Default Value: not set +;ping.path = /ping + +; This directive may be used to customize the response of a ping request. The +; response is formatted as text/plain with a 200 response code. +; Default Value: pong +;ping.response = pong + +; The access log file +; Default: not set +;access.log = log/$pool.access.log + +; The access log format. +; The following syntax is allowed +; %%: the '%' character +; %C: %CPU used by the request +; it can accept the following format: +; - %{user}C for user CPU only +; - %{system}C for system CPU only +; - %{total}C for user + system CPU (default) +; %d: time taken to serve the request +; it can accept the following format: +; - %{seconds}d (default) +; - %{miliseconds}d +; - %{mili}d +; - %{microseconds}d +; - %{micro}d +; %e: an environment variable (same as $_ENV or $_SERVER) +; it must be associated with embraces to specify the name of the env +; variable. Some exemples: +; - server specifics like: %{REQUEST_METHOD}e or %{SERVER_PROTOCOL}e +; - HTTP headers like: %{HTTP_HOST}e or %{HTTP_USER_AGENT}e +; %f: script filename +; %l: content-length of the request (for POST request only) +; %m: request method +; %M: peak of memory allocated by PHP +; it can accept the following format: +; - %{bytes}M (default) +; - %{kilobytes}M +; - %{kilo}M +; - %{megabytes}M +; - %{mega}M +; %n: pool name +; %o: output header +; it must be associated with embraces to specify the name of the header: +; - %{Content-Type}o +; - %{X-Powered-By}o +; - %{Transfert-Encoding}o +; - .... +; %p: PID of the child that serviced the request +; %P: PID of the parent of the child that serviced the request +; %q: the query string +; %Q: the '?' character if query string exists +; %r: the request URI (without the query string, see %q and %Q) +; %R: remote IP address +; %s: status (response code) +; %t: server time the request was received +; it can accept a strftime(3) format: +; %d/%b/%Y:%H:%M:%S %z (default) +; The strftime(3) format must be encapsuled in a %{}t tag +; e.g. for a ISO8601 formatted timestring, use: %{%Y-%m-%dT%H:%M:%S%z}t +; %T: time the log has been written (the request has finished) +; it can accept a strftime(3) format: +; %d/%b/%Y:%H:%M:%S %z (default) +; The strftime(3) format must be encapsuled in a %{}t tag +; e.g. for a ISO8601 formatted timestring, use: %{%Y-%m-%dT%H:%M:%S%z}t +; %u: remote user +; +; Default: "%R - %u %t \"%m %r\" %s" +;access.format = "%R - %u %t \"%m %r%Q%q\" %s %f %{mili}d %{kilo}M %C%%" + +; The log file for slow requests +; Default Value: not set +; Note: slowlog is mandatory if request_slowlog_timeout is set +;slowlog = log/$pool.log.slow + +; The timeout for serving a single request after which a PHP backtrace will be +; dumped to the 'slowlog' file. A value of '0s' means 'off'. +; Available units: s(econds)(default), m(inutes), h(ours), or d(ays) +; Default Value: 0 +;request_slowlog_timeout = 0 + +; Depth of slow log stack trace. +; Default Value: 20 +;request_slowlog_trace_depth = 20 + +; The timeout for serving a single request after which the worker process will +; be killed. This option should be used when the 'max_execution_time' ini option +; does not stop script execution for some reason. A value of '0' means 'off'. +; Available units: s(econds)(default), m(inutes), h(ours), or d(ays) +; Default Value: 0 +;request_terminate_timeout = 0 + +; Set open file descriptor rlimit. +; Default Value: system defined value +;rlimit_files = 1024 + +; Set max core size rlimit. +; Possible Values: 'unlimited' or an integer greater or equal to 0 +; Default Value: system defined value +;rlimit_core = 0 + +; Chroot to this directory at the start. This value must be defined as an +; absolute path. When this value is not set, chroot is not used. +; Note: you can prefix with '$prefix' to chroot to the pool prefix or one +; of its subdirectories. If the pool prefix is not set, the global prefix +; will be used instead. +; Note: chrooting is a great security feature and should be used whenever +; possible. However, all PHP paths will be relative to the chroot +; (error_log, sessions.save_path, ...). +; Default Value: not set +;chroot = + +; Chdir to this directory at the start. +; Note: relative path can be used. +; Default Value: current directory or / when chroot +;chdir = /var/www + +; Redirect worker stdout and stderr into main error log. If not set, stdout and +; stderr will be redirected to /dev/null according to FastCGI specs. +; Note: on highloaded environement, this can cause some delay in the page +; process time (several ms). +; Default Value: no +;catch_workers_output = yes + +; Clear environment in FPM workers +; Prevents arbitrary environment variables from reaching FPM worker processes +; by clearing the environment in workers before env vars specified in this +; pool configuration are added. +; Setting to "no" will make all environment variables available to PHP code +; via getenv(), $_ENV and $_SERVER. +; Default Value: yes +;clear_env = no + +; Limits the extensions of the main script FPM will allow to parse. This can +; prevent configuration mistakes on the web server side. You should only limit +; FPM to .php extensions to prevent malicious users to use other extensions to +; execute php code. +; Note: set an empty value to allow all extensions. +; Default Value: .php +;security.limit_extensions = .php .php3 .php4 .php5 .php7 + +; Pass environment variables like LD_LIBRARY_PATH. All $VARIABLEs are taken from +; the current environment. +; Default Value: clean env +;env[HOSTNAME] = $HOSTNAME +;env[PATH] = /usr/local/bin:/usr/bin:/bin +;env[TMP] = /tmp +;env[TMPDIR] = /tmp +;env[TEMP] = /tmp +env[DATABASE_DRIVER] = $DATABASE_DRIVER + +; Additional php.ini defines, specific to this pool of workers. These settings +; overwrite the values previously defined in the php.ini. The directives are the +; same as the PHP SAPI: +; php_value/php_flag - you can set classic ini defines which can +; be overwritten from PHP call 'ini_set'. +; php_admin_value/php_admin_flag - these directives won't be overwritten by +; PHP call 'ini_set' +; For php_*flag, valid values are on, off, 1, 0, true, false, yes or no. + +; Defining 'extension' will load the corresponding shared extension from +; extension_dir. Defining 'disable_functions' or 'disable_classes' will not +; overwrite previously defined php.ini values, but will append the new value +; instead. + +; Note: path INI options can be relative and will be expanded with the prefix +; (pool, global or /usr) + +; Default Value: nothing is defined by default except the values in php.ini and +; specified at startup with the -d argument +;php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f www@my.domain.com +;php_flag[display_errors] = off +;php_admin_value[error_log] = /var/log/fpm-php.www.log +;php_admin_flag[log_errors] = on +;php_admin_value[memory_limit] = 32M diff --git a/frameworks/PHP/piko/deploy/conf/php.ini b/frameworks/PHP/piko/deploy/conf/php.ini new file mode 100644 index 00000000000..9fa04df9edf --- /dev/null +++ b/frameworks/PHP/piko/deploy/conf/php.ini @@ -0,0 +1,1916 @@ +[PHP] + +;;;;;;;;;;;;;;;;;;; +; About php.ini ; +;;;;;;;;;;;;;;;;;;; +; PHP's initialization file, generally called php.ini, is responsible for +; configuring many of the aspects of PHP's behavior. + +; PHP attempts to find and load this configuration from a number of locations. +; The following is a summary of its search order: +; 1. SAPI module specific location. +; 2. The PHPRC environment variable. (As of PHP 5.2.0) +; 3. A number of predefined registry keys on Windows (As of PHP 5.2.0) +; 4. Current working directory (except CLI) +; 5. The web server's directory (for SAPI modules), or directory of PHP +; (otherwise in Windows) +; 6. The directory from the --with-config-file-path compile time option, or the +; Windows directory (C:\windows or C:\winnt) +; See the PHP docs for more specific information. +; http://php.net/configuration.file + +; The syntax of the file is extremely simple. Whitespace and lines +; beginning with a semicolon are silently ignored (as you probably guessed). +; Section headers (e.g. [Foo]) are also silently ignored, even though +; they might mean something in the future. + +; Directives following the section heading [PATH=/www/mysite] only +; apply to PHP files in the /www/mysite directory. Directives +; following the section heading [HOST=www.example.com] only apply to +; PHP files served from www.example.com. Directives set in these +; special sections cannot be overridden by user-defined INI files or +; at runtime. Currently, [PATH=] and [HOST=] sections only work under +; CGI/FastCGI. +; http://php.net/ini.sections + +; Directives are specified using the following syntax: +; directive = value +; Directive names are *case sensitive* - foo=bar is different from FOO=bar. +; Directives are variables used to configure PHP or PHP extensions. +; There is no name validation. If PHP can't find an expected +; directive because it is not set or is mistyped, a default value will be used. + +; The value can be a string, a number, a PHP constant (e.g. E_ALL or M_PI), one +; of the INI constants (On, Off, True, False, Yes, No and None) or an expression +; (e.g. E_ALL & ~E_NOTICE), a quoted string ("bar"), or a reference to a +; previously set variable or directive (e.g. ${foo}) + +; Expressions in the INI file are limited to bitwise operators and parentheses: +; | bitwise OR +; ^ bitwise XOR +; & bitwise AND +; ~ bitwise NOT +; ! boolean NOT + +; Boolean flags can be turned on using the values 1, On, True or Yes. +; They can be turned off using the values 0, Off, False or No. + +; An empty string can be denoted by simply not writing anything after the equal +; sign, or by using the None keyword: + +; foo = ; sets foo to an empty string +; foo = None ; sets foo to an empty string +; foo = "None" ; sets foo to the string 'None' + +; If you use constants in your value, and these constants belong to a +; dynamically loaded extension (either a PHP extension or a Zend extension), +; you may only use these constants *after* the line that loads the extension. + +;;;;;;;;;;;;;;;;;;; +; About this file ; +;;;;;;;;;;;;;;;;;;; +; PHP comes packaged with two INI files. One that is recommended to be used +; in production environments and one that is recommended to be used in +; development environments. + +; php.ini-production contains settings which hold security, performance and +; best practices at its core. But please be aware, these settings may break +; compatibility with older or less security conscience applications. We +; recommending using the production ini in production and testing environments. + +; php.ini-development is very similar to its production variant, except it is +; much more verbose when it comes to errors. We recommend using the +; development version only in development environments, as errors shown to +; application users can inadvertently leak otherwise secure information. + +; This is php.ini-production INI file. + +;;;;;;;;;;;;;;;;;;; +; Quick Reference ; +;;;;;;;;;;;;;;;;;;; +; The following are all the settings which are different in either the production +; or development versions of the INIs with respect to PHP's default behavior. +; Please see the actual settings later in the document for more details as to why +; we recommend these changes in PHP's behavior. + +; display_errors +; Default Value: On +; Development Value: On +; Production Value: Off + +; display_startup_errors +; Default Value: Off +; Development Value: On +; Production Value: Off + +; error_reporting +; Default Value: E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED +; Development Value: E_ALL +; Production Value: E_ALL & ~E_DEPRECATED & ~E_STRICT + +; html_errors +; Default Value: On +; Development Value: On +; Production value: On + +; log_errors +; Default Value: Off +; Development Value: On +; Production Value: On + +; max_input_time +; Default Value: -1 (Unlimited) +; Development Value: 60 (60 seconds) +; Production Value: 60 (60 seconds) + +; output_buffering +; Default Value: Off +; Development Value: 4096 +; Production Value: 4096 + +; register_argc_argv +; Default Value: On +; Development Value: Off +; Production Value: Off + +; request_order +; Default Value: None +; Development Value: "GP" +; Production Value: "GP" + +; session.gc_divisor +; Default Value: 100 +; Development Value: 1000 +; Production Value: 1000 + +; session.sid_bits_per_character +; Default Value: 4 +; Development Value: 5 +; Production Value: 5 + +; short_open_tag +; Default Value: On +; Development Value: Off +; Production Value: Off + +; track_errors +; Default Value: Off +; Development Value: On +; Production Value: Off + +; variables_order +; Default Value: "EGPCS" +; Development Value: "GPCS" +; Production Value: "GPCS" + +;;;;;;;;;;;;;;;;;;;; +; php.ini Options ; +;;;;;;;;;;;;;;;;;;;; +; Name for user-defined php.ini (.htaccess) files. Default is ".user.ini" +;user_ini.filename = ".user.ini" + +; To disable this feature set this option to empty value +;user_ini.filename = + +; TTL for user-defined php.ini files (time-to-live) in seconds. Default is 300 seconds (5 minutes) +;user_ini.cache_ttl = 300 + +;;;;;;;;;;;;;;;;;;;; +; Language Options ; +;;;;;;;;;;;;;;;;;;;; + +; Enable the PHP scripting language engine under Apache. +; http://php.net/engine +engine = On + +; This directive determines whether or not PHP will recognize code between +; tags as PHP source which should be processed as such. It is +; generally recommended that should be used and that this feature +; should be disabled, as enabling it may result in issues when generating XML +; documents, however this remains supported for backward compatibility reasons. +; Note that this directive does not control the would work. +; http://php.net/syntax-highlighting +;highlight.string = #DD0000 +;highlight.comment = #FF9900 +;highlight.keyword = #007700 +;highlight.default = #0000BB +;highlight.html = #000000 + +; If enabled, the request will be allowed to complete even if the user aborts +; the request. Consider enabling it if executing long requests, which may end up +; being interrupted by the user or a browser timing out. PHP's default behavior +; is to disable this feature. +; http://php.net/ignore-user-abort +;ignore_user_abort = On + +; Determines the size of the realpath cache to be used by PHP. This value should +; be increased on systems where PHP opens many files to reflect the quantity of +; the file operations performed. +; http://php.net/realpath-cache-size +realpath_cache_size = 4096k + +; Duration of time, in seconds for which to cache realpath information for a given +; file or directory. For systems with rarely changing files, consider increasing this +; value. +; http://php.net/realpath-cache-ttl +realpath_cache_ttl = 600 + +; Enables or disables the circular reference collector. +; http://php.net/zend.enable-gc +zend.enable_gc = On + +; If enabled, scripts may be written in encodings that are incompatible with +; the scanner. CP936, Big5, CP949 and Shift_JIS are the examples of such +; encodings. To use this feature, mbstring extension must be enabled. +; Default: Off +;zend.multibyte = Off + +; Allows to set the default encoding for the scripts. This value will be used +; unless "declare(encoding=...)" directive appears at the top of the script. +; Only affects if zend.multibyte is set. +; Default: "" +;zend.script_encoding = + +;;;;;;;;;;;;;;;;; +; Miscellaneous ; +;;;;;;;;;;;;;;;;; + +; Decides whether PHP may expose the fact that it is installed on the server +; (e.g. by adding its signature to the Web server header). It is no security +; threat in any way, but it makes it possible to determine whether you use PHP +; on your server or not. +; http://php.net/expose-php +expose_php = Off + +;;;;;;;;;;;;;;;;;;; +; Resource Limits ; +;;;;;;;;;;;;;;;;;;; + +; Maximum execution time of each script, in seconds +; http://php.net/max-execution-time +; Note: This directive is hardcoded to 0 for the CLI SAPI +max_execution_time = 30 + +; Maximum amount of time each script may spend parsing request data. It's a good +; idea to limit this time on productions servers in order to eliminate unexpectedly +; long running scripts. +; Note: This directive is hardcoded to -1 for the CLI SAPI +; Default Value: -1 (Unlimited) +; Development Value: 60 (60 seconds) +; Production Value: 60 (60 seconds) +; http://php.net/max-input-time +max_input_time = 60 + +; Maximum input variable nesting level +; http://php.net/max-input-nesting-level +;max_input_nesting_level = 64 + +; How many GET/POST/COOKIE input variables may be accepted +; max_input_vars = 1000 + +; Maximum amount of memory a script may consume (128MB) +; http://php.net/memory-limit +memory_limit = 128M + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Error handling and logging ; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +; This directive informs PHP of which errors, warnings and notices you would like +; it to take action for. The recommended way of setting values for this +; directive is through the use of the error level constants and bitwise +; operators. The error level constants are below here for convenience as well as +; some common settings and their meanings. +; By default, PHP is set to take action on all errors, notices and warnings EXCEPT +; those related to E_NOTICE and E_STRICT, which together cover best practices and +; recommended coding standards in PHP. For performance reasons, this is the +; recommend error reporting setting. Your production server shouldn't be wasting +; resources complaining about best practices and coding standards. That's what +; development servers and development settings are for. +; Note: The php.ini-development file has this setting as E_ALL. This +; means it pretty much reports everything which is exactly what you want during +; development and early testing. +; +; Error Level Constants: +; E_ALL - All errors and warnings (includes E_STRICT as of PHP 5.4.0) +; E_ERROR - fatal run-time errors +; E_RECOVERABLE_ERROR - almost fatal run-time errors +; E_WARNING - run-time warnings (non-fatal errors) +; E_PARSE - compile-time parse errors +; E_NOTICE - run-time notices (these are warnings which often result +; from a bug in your code, but it's possible that it was +; intentional (e.g., using an uninitialized variable and +; relying on the fact it is automatically initialized to an +; empty string) +; E_STRICT - run-time notices, enable to have PHP suggest changes +; to your code which will ensure the best interoperability +; and forward compatibility of your code +; E_CORE_ERROR - fatal errors that occur during PHP's initial startup +; E_CORE_WARNING - warnings (non-fatal errors) that occur during PHP's +; initial startup +; E_COMPILE_ERROR - fatal compile-time errors +; E_COMPILE_WARNING - compile-time warnings (non-fatal errors) +; E_USER_ERROR - user-generated error message +; E_USER_WARNING - user-generated warning message +; E_USER_NOTICE - user-generated notice message +; E_DEPRECATED - warn about code that will not work in future versions +; of PHP +; E_USER_DEPRECATED - user-generated deprecation warnings +; +; Common Values: +; E_ALL (Show all errors, warnings and notices including coding standards.) +; E_ALL & ~E_NOTICE (Show all errors, except for notices) +; E_ALL & ~E_NOTICE & ~E_STRICT (Show all errors, except for notices and coding standards warnings.) +; E_COMPILE_ERROR|E_RECOVERABLE_ERROR|E_ERROR|E_CORE_ERROR (Show only errors) +; Default Value: E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED +; Development Value: E_ALL +; Production Value: E_ALL & ~E_DEPRECATED & ~E_STRICT +; http://php.net/error-reporting +error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT + +; This directive controls whether or not and where PHP will output errors, +; notices and warnings too. Error output is very useful during development, but +; it could be very dangerous in production environments. Depending on the code +; which is triggering the error, sensitive information could potentially leak +; out of your application such as database usernames and passwords or worse. +; For production environments, we recommend logging errors rather than +; sending them to STDOUT. +; Possible Values: +; Off = Do not display any errors +; stderr = Display errors to STDERR (affects only CGI/CLI binaries!) +; On or stdout = Display errors to STDOUT +; Default Value: On +; Development Value: On +; Production Value: Off +; http://php.net/display-errors +display_errors = Off + +; The display of errors which occur during PHP's startup sequence are handled +; separately from display_errors. PHP's default behavior is to suppress those +; errors from clients. Turning the display of startup errors on can be useful in +; debugging configuration problems. We strongly recommend you +; set this to 'off' for production servers. +; Default Value: Off +; Development Value: On +; Production Value: Off +; http://php.net/display-startup-errors +display_startup_errors = Off + +; Besides displaying errors, PHP can also log errors to locations such as a +; server-specific log, STDERR, or a location specified by the error_log +; directive found below. While errors should not be displayed on productions +; servers they should still be monitored and logging is a great way to do that. +; Default Value: Off +; Development Value: On +; Production Value: On +; http://php.net/log-errors +log_errors = On + +; Set maximum length of log_errors. In error_log information about the source is +; added. The default is 1024 and 0 allows to not apply any maximum length at all. +; http://php.net/log-errors-max-len +log_errors_max_len = 1024 + +; Do not log repeated messages. Repeated errors must occur in same file on same +; line unless ignore_repeated_source is set true. +; http://php.net/ignore-repeated-errors +ignore_repeated_errors = Off + +; Ignore source of message when ignoring repeated messages. When this setting +; is On you will not log errors with repeated messages from different files or +; source lines. +; http://php.net/ignore-repeated-source +ignore_repeated_source = Off + +; If this parameter is set to Off, then memory leaks will not be shown (on +; stdout or in the log). This has only effect in a debug compile, and if +; error reporting includes E_WARNING in the allowed list +; http://php.net/report-memleaks +report_memleaks = On + +; This setting is on by default. +;report_zend_debug = 0 + +; Store the last error/warning message in $php_errormsg (boolean). Setting this value +; to On can assist in debugging and is appropriate for development servers. It should +; however be disabled on production servers. +; This directive is DEPRECATED. +; Default Value: Off +; Development Value: Off +; Production Value: Off +; http://php.net/track-errors +;track_errors = Off + +; Turn off normal error reporting and emit XML-RPC error XML +; http://php.net/xmlrpc-errors +;xmlrpc_errors = 0 + +; An XML-RPC faultCode +;xmlrpc_error_number = 0 + +; When PHP displays or logs an error, it has the capability of formatting the +; error message as HTML for easier reading. This directive controls whether +; the error message is formatted as HTML or not. +; Note: This directive is hardcoded to Off for the CLI SAPI +; Default Value: On +; Development Value: On +; Production value: On +; http://php.net/html-errors +html_errors = On + +; If html_errors is set to On *and* docref_root is not empty, then PHP +; produces clickable error messages that direct to a page describing the error +; or function causing the error in detail. +; You can download a copy of the PHP manual from http://php.net/docs +; and change docref_root to the base URL of your local copy including the +; leading '/'. You must also specify the file extension being used including +; the dot. PHP's default behavior is to leave these settings empty, in which +; case no links to documentation are generated. +; Note: Never use this feature for production boxes. +; http://php.net/docref-root +; Examples +;docref_root = "/phpmanual/" + +; http://php.net/docref-ext +;docref_ext = .html + +; String to output before an error message. PHP's default behavior is to leave +; this setting blank. +; http://php.net/error-prepend-string +; Example: +;error_prepend_string = "" + +; String to output after an error message. PHP's default behavior is to leave +; this setting blank. +; http://php.net/error-append-string +; Example: +;error_append_string = "" + +; Log errors to specified file. PHP's default behavior is to leave this value +; empty. +; http://php.net/error-log +; Example: +;error_log = php_errors.log +; Log errors to syslog (Event Log on Windows). +;error_log = syslog + +;windows.show_crt_warning +; Default value: 0 +; Development value: 0 +; Production value: 0 + +;;;;;;;;;;;;;;;;; +; Data Handling ; +;;;;;;;;;;;;;;;;; + +; The separator used in PHP generated URLs to separate arguments. +; PHP's default setting is "&". +; http://php.net/arg-separator.output +; Example: +;arg_separator.output = "&" + +; List of separator(s) used by PHP to parse input URLs into variables. +; PHP's default setting is "&". +; NOTE: Every character in this directive is considered as separator! +; http://php.net/arg-separator.input +; Example: +;arg_separator.input = ";&" + +; This directive determines which super global arrays are registered when PHP +; starts up. G,P,C,E & S are abbreviations for the following respective super +; globals: GET, POST, COOKIE, ENV and SERVER. There is a performance penalty +; paid for the registration of these arrays and because ENV is not as commonly +; used as the others, ENV is not recommended on productions servers. You +; can still get access to the environment variables through getenv() should you +; need to. +; Default Value: "EGPCS" +; Development Value: "GPCS" +; Production Value: "GPCS"; +; http://php.net/variables-order +variables_order = "GPCS" + +; This directive determines which super global data (G,P & C) should be +; registered into the super global array REQUEST. If so, it also determines +; the order in which that data is registered. The values for this directive +; are specified in the same manner as the variables_order directive, +; EXCEPT one. Leaving this value empty will cause PHP to use the value set +; in the variables_order directive. It does not mean it will leave the super +; globals array REQUEST empty. +; Default Value: None +; Development Value: "GP" +; Production Value: "GP" +; http://php.net/request-order +request_order = "GP" + +; This directive determines whether PHP registers $argv & $argc each time it +; runs. $argv contains an array of all the arguments passed to PHP when a script +; is invoked. $argc contains an integer representing the number of arguments +; that were passed when the script was invoked. These arrays are extremely +; useful when running scripts from the command line. When this directive is +; enabled, registering these variables consumes CPU cycles and memory each time +; a script is executed. For performance reasons, this feature should be disabled +; on production servers. +; Note: This directive is hardcoded to On for the CLI SAPI +; Default Value: On +; Development Value: Off +; Production Value: Off +; http://php.net/register-argc-argv +register_argc_argv = Off + +; When enabled, the ENV, REQUEST and SERVER variables are created when they're +; first used (Just In Time) instead of when the script starts. If these +; variables are not used within a script, having this directive on will result +; in a performance gain. The PHP directive register_argc_argv must be disabled +; for this directive to have any affect. +; http://php.net/auto-globals-jit +auto_globals_jit = On + +; Whether PHP will read the POST data. +; This option is enabled by default. +; Most likely, you won't want to disable this option globally. It causes $_POST +; and $_FILES to always be empty; the only way you will be able to read the +; POST data will be through the php://input stream wrapper. This can be useful +; to proxy requests or to process the POST data in a memory efficient fashion. +; http://php.net/enable-post-data-reading +;enable_post_data_reading = Off + +; Maximum size of POST data that PHP will accept. +; Its value may be 0 to disable the limit. It is ignored if POST data reading +; is disabled through enable_post_data_reading. +; http://php.net/post-max-size +post_max_size = 8M + +; Automatically add files before PHP document. +; http://php.net/auto-prepend-file +auto_prepend_file = + +; Automatically add files after PHP document. +; http://php.net/auto-append-file +auto_append_file = + +; By default, PHP will output a media type using the Content-Type header. To +; disable this, simply set it to be empty. +; +; PHP's built-in default media type is set to text/html. +; http://php.net/default-mimetype +default_mimetype = "text/html" + +; PHP's default character set is set to UTF-8. +; http://php.net/default-charset +default_charset = "UTF-8" + +; PHP internal character encoding is set to empty. +; If empty, default_charset is used. +; http://php.net/internal-encoding +;internal_encoding = + +; PHP input character encoding is set to empty. +; If empty, default_charset is used. +; http://php.net/input-encoding +;input_encoding = + +; PHP output character encoding is set to empty. +; If empty, default_charset is used. +; See also output_buffer. +; http://php.net/output-encoding +;output_encoding = + +;;;;;;;;;;;;;;;;;;;;;;;;; +; Paths and Directories ; +;;;;;;;;;;;;;;;;;;;;;;;;; + +; UNIX: "/path1:/path2" +;include_path = ".:/usr/share/php" +; +; Windows: "\path1;\path2" +;include_path = ".;c:\php\includes" +; +; PHP's default setting for include_path is ".;/path/to/php/pear" +; http://php.net/include-path + +; The root of the PHP pages, used only if nonempty. +; if PHP was not compiled with FORCE_REDIRECT, you SHOULD set doc_root +; if you are running php as a CGI under any web server (other than IIS) +; see documentation for security issues. The alternate is to use the +; cgi.force_redirect configuration below +; http://php.net/doc-root +doc_root = + +; The directory under which PHP opens the script using /~username used only +; if nonempty. +; http://php.net/user-dir +user_dir = + +; Directory in which the loadable extensions (modules) reside. +; http://php.net/extension-dir +; extension_dir = "./" +; On windows: +; extension_dir = "ext" + +; Directory where the temporary files should be placed. +; Defaults to the system default (see sys_get_temp_dir) +; sys_temp_dir = "/tmp" + +; Whether or not to enable the dl() function. The dl() function does NOT work +; properly in multithreaded servers, such as IIS or Zeus, and is automatically +; disabled on them. +; http://php.net/enable-dl +enable_dl = Off + +; cgi.force_redirect is necessary to provide security running PHP as a CGI under +; most web servers. Left undefined, PHP turns this on by default. You can +; turn it off here AT YOUR OWN RISK +; **You CAN safely turn this off for IIS, in fact, you MUST.** +; http://php.net/cgi.force-redirect +;cgi.force_redirect = 1 + +; if cgi.nph is enabled it will force cgi to always sent Status: 200 with +; every request. PHP's default behavior is to disable this feature. +;cgi.nph = 1 + +; if cgi.force_redirect is turned on, and you are not running under Apache or Netscape +; (iPlanet) web servers, you MAY need to set an environment variable name that PHP +; will look for to know it is OK to continue execution. Setting this variable MAY +; cause security issues, KNOW WHAT YOU ARE DOING FIRST. +; http://php.net/cgi.redirect-status-env +;cgi.redirect_status_env = + +; cgi.fix_pathinfo provides *real* PATH_INFO/PATH_TRANSLATED support for CGI. PHP's +; previous behaviour was to set PATH_TRANSLATED to SCRIPT_FILENAME, and to not grok +; what PATH_INFO is. For more information on PATH_INFO, see the cgi specs. Setting +; this to 1 will cause PHP CGI to fix its paths to conform to the spec. A setting +; of zero causes PHP to behave as before. Default is 1. You should fix your scripts +; to use SCRIPT_FILENAME rather than PATH_TRANSLATED. +; http://php.net/cgi.fix-pathinfo + cgi.fix_pathinfo=0 + +; if cgi.discard_path is enabled, the PHP CGI binary can safely be placed outside +; of the web tree and people will not be able to circumvent .htaccess security. +; http://php.net/cgi.dicard-path +;cgi.discard_path=1 + +; FastCGI under IIS (on WINNT based OS) supports the ability to impersonate +; security tokens of the calling client. This allows IIS to define the +; security context that the request runs under. mod_fastcgi under Apache +; does not currently support this feature (03/17/2002) +; Set to 1 if running under IIS. Default is zero. +; http://php.net/fastcgi.impersonate +;fastcgi.impersonate = 1 + +; Disable logging through FastCGI connection. PHP's default behavior is to enable +; this feature. +;fastcgi.logging = 0 + +; cgi.rfc2616_headers configuration option tells PHP what type of headers to +; use when sending HTTP response code. If set to 0, PHP sends Status: header that +; is supported by Apache. When this option is set to 1, PHP will send +; RFC2616 compliant header. +; Default is zero. +; http://php.net/cgi.rfc2616-headers +;cgi.rfc2616_headers = 0 + +; cgi.check_shebang_line controls whether CGI PHP checks for line starting with #! +; (shebang) at the top of the running script. This line might be needed if the +; script support running both as stand-alone script and via PHP CGI<. PHP in CGI +; mode skips this line and ignores its content if this directive is turned on. +; http://php.net/cgi.check-shebang-line +;cgi.check_shebang_line=1 + +;;;;;;;;;;;;;;;; +; File Uploads ; +;;;;;;;;;;;;;;;; + +; Whether to allow HTTP file uploads. +; http://php.net/file-uploads +file_uploads = On + +; Temporary directory for HTTP uploaded files (will use system default if not +; specified). +; http://php.net/upload-tmp-dir +;upload_tmp_dir = + +; Maximum allowed size for uploaded files. +; http://php.net/upload-max-filesize +upload_max_filesize = 2M + +; Maximum number of files that can be uploaded via a single request +max_file_uploads = 20 + +;;;;;;;;;;;;;;;;;; +; Fopen wrappers ; +;;;;;;;;;;;;;;;;;; + +; Whether to allow the treatment of URLs (like http:// or ftp://) as files. +; http://php.net/allow-url-fopen +allow_url_fopen = On + +; Whether to allow include/require to open URLs (like http:// or ftp://) as files. +; http://php.net/allow-url-include +allow_url_include = Off + +; Define the anonymous ftp password (your email address). PHP's default setting +; for this is empty. +; http://php.net/from +;from="john@doe.com" + +; Define the User-Agent string. PHP's default setting for this is empty. +; http://php.net/user-agent +;user_agent="PHP" + +; Default timeout for socket based streams (seconds) +; http://php.net/default-socket-timeout +default_socket_timeout = 60 + +; If your scripts have to deal with files from Macintosh systems, +; or you are running on a Mac and need to deal with files from +; unix or win32 systems, setting this flag will cause PHP to +; automatically detect the EOL character in those files so that +; fgets() and file() will work regardless of the source of the file. +; http://php.net/auto-detect-line-endings +;auto_detect_line_endings = Off + +;;;;;;;;;;;;;;;;;;;;;; +; Dynamic Extensions ; +;;;;;;;;;;;;;;;;;;;;;; + +; If you wish to have an extension loaded automatically, use the following +; syntax: +; +; extension=modulename +; +; For example: +; +; extension=mysqli +; +; When the extension library to load is not located in the default extension +; directory, You may specify an absolute path to the library file: +; +; extension=/path/to/extension/mysqli.so +; +; Note : The syntax used in previous PHP versions ('extension=.so' and +; 'extension='php_.dll') is supported for legacy reasons and may be +; deprecated in a future PHP major version. So, when it is possible, please +; move to the new ('extension=) syntax. +; +; Notes for Windows environments : +; +; - ODBC support is built in, so no dll is needed for it. +; - Many DLL files are located in the extensions/ (PHP 4) or ext/ (PHP 5+) +; extension folders as well as the separate PECL DLL download (PHP 5+). +; Be sure to appropriately set the extension_dir directive. +; +;extension=bz2 +;extension=curl +;extension=fileinfo +;extension=gd2 +;extension=gettext +;extension=gmp +;extension=intl +;extension=imap +;extension=interbase +;extension=ldap +;extension=mbstring +;extension=exif ; Must be after mbstring as it depends on it +;extension=mysqli +;extension=oci8_12c ; Use with Oracle Database 12c Instant Client +;extension=openssl +;extension=pdo_firebird +;extension=pdo_mysql +;extension=pdo_oci +;extension=pdo_odbc +;extension=pdo_pgsql +;extension=pdo_sqlite +;extension=pgsql +;extension=shmop + +; The MIBS data available in the PHP distribution must be installed. +; See http://www.php.net/manual/en/snmp.installation.php +;extension=snmp + +;extension=soap +;extension=sockets +;extension=sqlite3 +;extension=tidy +;extension=xmlrpc +;extension=xsl + +;;;;;;;;;;;;;;;;;;; +; Module Settings ; +;;;;;;;;;;;;;;;;;;; + +[CLI Server] +; Whether the CLI web server uses ANSI color coding in its terminal output. +cli_server.color = On + +[Date] +; Defines the default timezone used by the date functions +; http://php.net/date.timezone +date.timezone = UTC + +; http://php.net/date.default-latitude +;date.default_latitude = 31.7667 + +; http://php.net/date.default-longitude +;date.default_longitude = 35.2333 + +; http://php.net/date.sunrise-zenith +;date.sunrise_zenith = 90.583333 + +; http://php.net/date.sunset-zenith +;date.sunset_zenith = 90.583333 + +[filter] +; http://php.net/filter.default +;filter.default = unsafe_raw + +; http://php.net/filter.default-flags +;filter.default_flags = + +[iconv] +; Use of this INI entry is deprecated, use global input_encoding instead. +; If empty, default_charset or input_encoding or iconv.input_encoding is used. +; The precedence is: default_charset < intput_encoding < iconv.input_encoding +;iconv.input_encoding = + +; Use of this INI entry is deprecated, use global internal_encoding instead. +; If empty, default_charset or internal_encoding or iconv.internal_encoding is used. +; The precedence is: default_charset < internal_encoding < iconv.internal_encoding +;iconv.internal_encoding = + +; Use of this INI entry is deprecated, use global output_encoding instead. +; If empty, default_charset or output_encoding or iconv.output_encoding is used. +; The precedence is: default_charset < output_encoding < iconv.output_encoding +; To use an output encoding conversion, iconv's output handler must be set +; otherwise output encoding conversion cannot be performed. +;iconv.output_encoding = + +[intl] +;intl.default_locale = +; This directive allows you to produce PHP errors when some error +; happens within intl functions. The value is the level of the error produced. +; Default is 0, which does not produce any errors. +;intl.error_level = E_WARNING +;intl.use_exceptions = 0 + +[sqlite3] +;sqlite3.extension_dir = + +[Pcre] +;PCRE library backtracking limit. +; http://php.net/pcre.backtrack-limit +;pcre.backtrack_limit=100000 + +;PCRE library recursion limit. +;Please note that if you set this value to a high number you may consume all +;the available process stack and eventually crash PHP (due to reaching the +;stack size limit imposed by the Operating System). +; http://php.net/pcre.recursion-limit +;pcre.recursion_limit=100000 + +;Enables or disables JIT compilation of patterns. This requires the PCRE +;library to be compiled with JIT support. +;pcre.jit=1 + +[Pdo] +; Whether to pool ODBC connections. Can be one of "strict", "relaxed" or "off" +; http://php.net/pdo-odbc.connection-pooling +;pdo_odbc.connection_pooling=strict + +;pdo_odbc.db2_instance_name + +[Pdo_mysql] +; If mysqlnd is used: Number of cache slots for the internal result set cache +; http://php.net/pdo_mysql.cache_size +pdo_mysql.cache_size = 2000 + +; Default socket name for local MySQL connects. If empty, uses the built-in +; MySQL defaults. +; http://php.net/pdo_mysql.default-socket +pdo_mysql.default_socket= + +[Phar] +; http://php.net/phar.readonly +;phar.readonly = On + +; http://php.net/phar.require-hash +;phar.require_hash = On + +;phar.cache_list = + +[mail function] +; For Win32 only. +; http://php.net/smtp +SMTP = localhost +; http://php.net/smtp-port +smtp_port = 25 + +; For Win32 only. +; http://php.net/sendmail-from +;sendmail_from = me@example.com + +; For Unix only. You may supply arguments as well (default: "sendmail -t -i"). +; http://php.net/sendmail-path +;sendmail_path = + +; Force the addition of the specified parameters to be passed as extra parameters +; to the sendmail binary. These parameters will always replace the value of +; the 5th parameter to mail(). +;mail.force_extra_parameters = + +; Add X-PHP-Originating-Script: that will include uid of the script followed by the filename +mail.add_x_header = On + +; The path to a log file that will log all mail() calls. Log entries include +; the full path of the script, line number, To address and headers. +;mail.log = +; Log mail to syslog (Event Log on Windows). +;mail.log = syslog + +[ODBC] +; http://php.net/odbc.default-db +;odbc.default_db = Not yet implemented + +; http://php.net/odbc.default-user +;odbc.default_user = Not yet implemented + +; http://php.net/odbc.default-pw +;odbc.default_pw = Not yet implemented + +; Controls the ODBC cursor model. +; Default: SQL_CURSOR_STATIC (default). +;odbc.default_cursortype + +; Allow or prevent persistent links. +; http://php.net/odbc.allow-persistent +odbc.allow_persistent = On + +; Check that a connection is still valid before reuse. +; http://php.net/odbc.check-persistent +odbc.check_persistent = On + +; Maximum number of persistent links. -1 means no limit. +; http://php.net/odbc.max-persistent +odbc.max_persistent = -1 + +; Maximum number of links (persistent + non-persistent). -1 means no limit. +; http://php.net/odbc.max-links +odbc.max_links = -1 + +; Handling of LONG fields. Returns number of bytes to variables. 0 means +; passthru. +; http://php.net/odbc.defaultlrl +odbc.defaultlrl = 4096 + +; Handling of binary data. 0 means passthru, 1 return as is, 2 convert to char. +; See the documentation on odbc_binmode and odbc_longreadlen for an explanation +; of odbc.defaultlrl and odbc.defaultbinmode +; http://php.net/odbc.defaultbinmode +odbc.defaultbinmode = 1 + +;birdstep.max_links = -1 + +[Interbase] +; Allow or prevent persistent links. +ibase.allow_persistent = 1 + +; Maximum number of persistent links. -1 means no limit. +ibase.max_persistent = -1 + +; Maximum number of links (persistent + non-persistent). -1 means no limit. +ibase.max_links = -1 + +; Default database name for ibase_connect(). +;ibase.default_db = + +; Default username for ibase_connect(). +;ibase.default_user = + +; Default password for ibase_connect(). +;ibase.default_password = + +; Default charset for ibase_connect(). +;ibase.default_charset = + +; Default timestamp format. +ibase.timestampformat = "%Y-%m-%d %H:%M:%S" + +; Default date format. +ibase.dateformat = "%Y-%m-%d" + +; Default time format. +ibase.timeformat = "%H:%M:%S" + +[MySQLi] + +; Maximum number of persistent links. -1 means no limit. +; http://php.net/mysqli.max-persistent +mysqli.max_persistent = -1 + +; Allow accessing, from PHP's perspective, local files with LOAD DATA statements +; http://php.net/mysqli.allow_local_infile +;mysqli.allow_local_infile = On + +; Allow or prevent persistent links. +; http://php.net/mysqli.allow-persistent +mysqli.allow_persistent = On + +; Maximum number of links. -1 means no limit. +; http://php.net/mysqli.max-links +mysqli.max_links = -1 + +; If mysqlnd is used: Number of cache slots for the internal result set cache +; http://php.net/mysqli.cache_size +mysqli.cache_size = 2000 + +; Default port number for mysqli_connect(). If unset, mysqli_connect() will use +; the $MYSQL_TCP_PORT or the mysql-tcp entry in /etc/services or the +; compile-time value defined MYSQL_PORT (in that order). Win32 will only look +; at MYSQL_PORT. +; http://php.net/mysqli.default-port +mysqli.default_port = 3306 + +; Default socket name for local MySQL connects. If empty, uses the built-in +; MySQL defaults. +; http://php.net/mysqli.default-socket +mysqli.default_socket = + +; Default host for mysql_connect() (doesn't apply in safe mode). +; http://php.net/mysqli.default-host +mysqli.default_host = + +; Default user for mysql_connect() (doesn't apply in safe mode). +; http://php.net/mysqli.default-user +mysqli.default_user = + +; Default password for mysqli_connect() (doesn't apply in safe mode). +; Note that this is generally a *bad* idea to store passwords in this file. +; *Any* user with PHP access can run 'echo get_cfg_var("mysqli.default_pw") +; and reveal this password! And of course, any users with read access to this +; file will be able to reveal the password as well. +; http://php.net/mysqli.default-pw +mysqli.default_pw = + +; Allow or prevent reconnect +mysqli.reconnect = Off + +[mysqlnd] +; Enable / Disable collection of general statistics by mysqlnd which can be +; used to tune and monitor MySQL operations. +; http://php.net/mysqlnd.collect_statistics +mysqlnd.collect_statistics = Off + +; Enable / Disable collection of memory usage statistics by mysqlnd which can be +; used to tune and monitor MySQL operations. +; http://php.net/mysqlnd.collect_memory_statistics +mysqlnd.collect_memory_statistics = Off + +; Records communication from all extensions using mysqlnd to the specified log +; file. +; http://php.net/mysqlnd.debug +;mysqlnd.debug = + +; Defines which queries will be logged. +; http://php.net/mysqlnd.log_mask +;mysqlnd.log_mask = 0 + +; Default size of the mysqlnd memory pool, which is used by result sets. +; http://php.net/mysqlnd.mempool_default_size +;mysqlnd.mempool_default_size = 16000 + +; Size of a pre-allocated buffer used when sending commands to MySQL in bytes. +; http://php.net/mysqlnd.net_cmd_buffer_size +;mysqlnd.net_cmd_buffer_size = 2048 + +; Size of a pre-allocated buffer used for reading data sent by the server in +; bytes. +; http://php.net/mysqlnd.net_read_buffer_size +;mysqlnd.net_read_buffer_size = 32768 + +; Timeout for network requests in seconds. +; http://php.net/mysqlnd.net_read_timeout +;mysqlnd.net_read_timeout = 31536000 + +; SHA-256 Authentication Plugin related. File with the MySQL server public RSA +; key. +; http://php.net/mysqlnd.sha256_server_public_key +;mysqlnd.sha256_server_public_key = + +[OCI8] + +; Connection: Enables privileged connections using external +; credentials (OCI_SYSOPER, OCI_SYSDBA) +; http://php.net/oci8.privileged-connect +;oci8.privileged_connect = Off + +; Connection: The maximum number of persistent OCI8 connections per +; process. Using -1 means no limit. +; http://php.net/oci8.max-persistent +;oci8.max_persistent = -1 + +; Connection: The maximum number of seconds a process is allowed to +; maintain an idle persistent connection. Using -1 means idle +; persistent connections will be maintained forever. +; http://php.net/oci8.persistent-timeout +;oci8.persistent_timeout = -1 + +; Connection: The number of seconds that must pass before issuing a +; ping during oci_pconnect() to check the connection validity. When +; set to 0, each oci_pconnect() will cause a ping. Using -1 disables +; pings completely. +; http://php.net/oci8.ping-interval +;oci8.ping_interval = 60 + +; Connection: Set this to a user chosen connection class to be used +; for all pooled server requests with Oracle 11g Database Resident +; Connection Pooling (DRCP). To use DRCP, this value should be set to +; the same string for all web servers running the same application, +; the database pool must be configured, and the connection string must +; specify to use a pooled server. +;oci8.connection_class = + +; High Availability: Using On lets PHP receive Fast Application +; Notification (FAN) events generated when a database node fails. The +; database must also be configured to post FAN events. +;oci8.events = Off + +; Tuning: This option enables statement caching, and specifies how +; many statements to cache. Using 0 disables statement caching. +; http://php.net/oci8.statement-cache-size +;oci8.statement_cache_size = 20 + +; Tuning: Enables statement prefetching and sets the default number of +; rows that will be fetched automatically after statement execution. +; http://php.net/oci8.default-prefetch +;oci8.default_prefetch = 100 + +; Compatibility. Using On means oci_close() will not close +; oci_connect() and oci_new_connect() connections. +; http://php.net/oci8.old-oci-close-semantics +;oci8.old_oci_close_semantics = Off + +[PostgreSQL] +; Allow or prevent persistent links. +; http://php.net/pgsql.allow-persistent +pgsql.allow_persistent = On + +; Detect broken persistent links always with pg_pconnect(). +; Auto reset feature requires a little overheads. +; http://php.net/pgsql.auto-reset-persistent +pgsql.auto_reset_persistent = Off + +; Maximum number of persistent links. -1 means no limit. +; http://php.net/pgsql.max-persistent +pgsql.max_persistent = -1 + +; Maximum number of links (persistent+non persistent). -1 means no limit. +; http://php.net/pgsql.max-links +pgsql.max_links = -1 + +; Ignore PostgreSQL backends Notice message or not. +; Notice message logging require a little overheads. +; http://php.net/pgsql.ignore-notice +pgsql.ignore_notice = 0 + +; Log PostgreSQL backends Notice message or not. +; Unless pgsql.ignore_notice=0, module cannot log notice message. +; http://php.net/pgsql.log-notice +pgsql.log_notice = 0 + +[bcmath] +; Number of decimal digits for all bcmath functions. +; http://php.net/bcmath.scale +bcmath.scale = 0 + +[browscap] +; http://php.net/browscap +;browscap = extra/browscap.ini + +[Session] +; Handler used to store/retrieve data. +; http://php.net/session.save-handler +session.save_handler = files + +; Argument passed to save_handler. In the case of files, this is the path +; where data files are stored. Note: Windows users have to change this +; variable in order to use PHP's session functions. +; +; The path can be defined as: +; +; session.save_path = "N;/path" +; +; where N is an integer. Instead of storing all the session files in +; /path, what this will do is use subdirectories N-levels deep, and +; store the session data in those directories. This is useful if +; your OS has problems with many files in one directory, and is +; a more efficient layout for servers that handle many sessions. +; +; NOTE 1: PHP will not create this directory structure automatically. +; You can use the script in the ext/session dir for that purpose. +; NOTE 2: See the section on garbage collection below if you choose to +; use subdirectories for session storage +; +; The file storage module creates files using mode 600 by default. +; You can change that by using +; +; session.save_path = "N;MODE;/path" +; +; where MODE is the octal representation of the mode. Note that this +; does not overwrite the process's umask. +; http://php.net/session.save-path +;session.save_path = "/var/lib/php/sessions" + +; Whether to use strict session mode. +; Strict session mode does not accept uninitialized session ID and regenerate +; session ID if browser sends uninitialized session ID. Strict mode protects +; applications from session fixation via session adoption vulnerability. It is +; disabled by default for maximum compatibility, but enabling it is encouraged. +; https://wiki.php.net/rfc/strict_sessions +session.use_strict_mode = 0 + +; Whether to use cookies. +; http://php.net/session.use-cookies +session.use_cookies = 1 + +; http://php.net/session.cookie-secure +;session.cookie_secure = + +; This option forces PHP to fetch and use a cookie for storing and maintaining +; the session id. We encourage this operation as it's very helpful in combating +; session hijacking when not specifying and managing your own session id. It is +; not the be-all and end-all of session hijacking defense, but it's a good start. +; http://php.net/session.use-only-cookies +session.use_only_cookies = 1 + +; Name of the session (used as cookie name). +; http://php.net/session.name +session.name = PHPSESSID + +; Initialize session on request startup. +; http://php.net/session.auto-start +session.auto_start = 0 + +; Lifetime in seconds of cookie or, if 0, until browser is restarted. +; http://php.net/session.cookie-lifetime +session.cookie_lifetime = 0 + +; The path for which the cookie is valid. +; http://php.net/session.cookie-path +session.cookie_path = / + +; The domain for which the cookie is valid. +; http://php.net/session.cookie-domain +session.cookie_domain = + +; Whether or not to add the httpOnly flag to the cookie, which makes it inaccessible to browser scripting languages such as JavaScript. +; http://php.net/session.cookie-httponly +session.cookie_httponly = + +; Handler used to serialize data. php is the standard serializer of PHP. +; http://php.net/session.serialize-handler +session.serialize_handler = php + +; Defines the probability that the 'garbage collection' process is started +; on every session initialization. The probability is calculated by using +; gc_probability/gc_divisor. Where session.gc_probability is the numerator +; and gc_divisor is the denominator in the equation. Setting this value to 1 +; when the session.gc_divisor value is 100 will give you approximately a 1% chance +; the gc will run on any give request. +; Default Value: 1 +; Development Value: 1 +; Production Value: 1 +; http://php.net/session.gc-probability +session.gc_probability = 0 + +; Defines the probability that the 'garbage collection' process is started on every +; session initialization. The probability is calculated by using the following equation: +; gc_probability/gc_divisor. Where session.gc_probability is the numerator and +; session.gc_divisor is the denominator in the equation. Setting this value to 1 +; when the session.gc_divisor value is 100 will give you approximately a 1% chance +; the gc will run on any give request. Increasing this value to 1000 will give you +; a 0.1% chance the gc will run on any give request. For high volume production servers, +; this is a more efficient approach. +; Default Value: 100 +; Development Value: 1000 +; Production Value: 1000 +; http://php.net/session.gc-divisor +session.gc_divisor = 1000 + +; After this number of seconds, stored data will be seen as 'garbage' and +; cleaned up by the garbage collection process. +; http://php.net/session.gc-maxlifetime +session.gc_maxlifetime = 1440 + +; NOTE: If you are using the subdirectory option for storing session files +; (see session.save_path above), then garbage collection does *not* +; happen automatically. You will need to do your own garbage +; collection through a shell script, cron entry, or some other method. +; For example, the following script would is the equivalent of +; setting session.gc_maxlifetime to 1440 (1440 seconds = 24 minutes): +; find /path/to/sessions -cmin +24 -type f | xargs rm + +; Check HTTP Referer to invalidate externally stored URLs containing ids. +; HTTP_REFERER has to contain this substring for the session to be +; considered as valid. +; http://php.net/session.referer-check +session.referer_check = + +; Set to {nocache,private,public,} to determine HTTP caching aspects +; or leave this empty to avoid sending anti-caching headers. +; http://php.net/session.cache-limiter +session.cache_limiter = nocache + +; Document expires after n minutes. +; http://php.net/session.cache-expire +session.cache_expire = 180 + +; trans sid support is disabled by default. +; Use of trans sid may risk your users' security. +; Use this option with caution. +; - User may send URL contains active session ID +; to other person via. email/irc/etc. +; - URL that contains active session ID may be stored +; in publicly accessible computer. +; - User may access your site with the same session ID +; always using URL stored in browser's history or bookmarks. +; http://php.net/session.use-trans-sid +session.use_trans_sid = 0 + +; Set session ID character length. This value could be between 22 to 256. +; Shorter length than default is supported only for compatibility reason. +; Users should use 32 or more chars. +; http://php.net/session.sid-length +; Default Value: 32 +; Development Value: 26 +; Production Value: 26 +session.sid_length = 26 + +; The URL rewriter will look for URLs in a defined set of HTML tags. +; is special; if you include them here, the rewriter will +; add a hidden field with the info which is otherwise appended +; to URLs. tag's action attribute URL will not be modified +; unless it is specified. +; Note that all valid entries require a "=", even if no value follows. +; Default Value: "a=href,area=href,frame=src,form=" +; Development Value: "a=href,area=href,frame=src,form=" +; Production Value: "a=href,area=href,frame=src,form=" +; http://php.net/url-rewriter.tags +session.trans_sid_tags = "a=href,area=href,frame=src,form=" + +; URL rewriter does not rewrite absolute URLs by default. +; To enable rewrites for absolute pathes, target hosts must be specified +; at RUNTIME. i.e. use ini_set() +; tags is special. PHP will check action attribute's URL regardless +; of session.trans_sid_tags setting. +; If no host is defined, HTTP_HOST will be used for allowed host. +; Example value: php.net,www.php.net,wiki.php.net +; Use "," for multiple hosts. No spaces are allowed. +; Default Value: "" +; Development Value: "" +; Production Value: "" +;session.trans_sid_hosts="" + +; Define how many bits are stored in each character when converting +; the binary hash data to something readable. +; Possible values: +; 4 (4 bits: 0-9, a-f) +; 5 (5 bits: 0-9, a-v) +; 6 (6 bits: 0-9, a-z, A-Z, "-", ",") +; Default Value: 4 +; Development Value: 5 +; Production Value: 5 +; http://php.net/session.hash-bits-per-character +session.sid_bits_per_character = 5 + +; Enable upload progress tracking in $_SESSION +; Default Value: On +; Development Value: On +; Production Value: On +; http://php.net/session.upload-progress.enabled +;session.upload_progress.enabled = On + +; Cleanup the progress information as soon as all POST data has been read +; (i.e. upload completed). +; Default Value: On +; Development Value: On +; Production Value: On +; http://php.net/session.upload-progress.cleanup +;session.upload_progress.cleanup = On + +; A prefix used for the upload progress key in $_SESSION +; Default Value: "upload_progress_" +; Development Value: "upload_progress_" +; Production Value: "upload_progress_" +; http://php.net/session.upload-progress.prefix +;session.upload_progress.prefix = "upload_progress_" + +; The index name (concatenated with the prefix) in $_SESSION +; containing the upload progress information +; Default Value: "PHP_SESSION_UPLOAD_PROGRESS" +; Development Value: "PHP_SESSION_UPLOAD_PROGRESS" +; Production Value: "PHP_SESSION_UPLOAD_PROGRESS" +; http://php.net/session.upload-progress.name +;session.upload_progress.name = "PHP_SESSION_UPLOAD_PROGRESS" + +; How frequently the upload progress should be updated. +; Given either in percentages (per-file), or in bytes +; Default Value: "1%" +; Development Value: "1%" +; Production Value: "1%" +; http://php.net/session.upload-progress.freq +;session.upload_progress.freq = "1%" + +; The minimum delay between updates, in seconds +; Default Value: 1 +; Development Value: 1 +; Production Value: 1 +; http://php.net/session.upload-progress.min-freq +;session.upload_progress.min_freq = "1" + +; Only write session data when session data is changed. Enabled by default. +; http://php.net/session.lazy-write +;session.lazy_write = On + +[Assertion] +; Switch whether to compile assertions at all (to have no overhead at run-time) +; -1: Do not compile at all +; 0: Jump over assertion at run-time +; 1: Execute assertions +; Changing from or to a negative value is only possible in php.ini! (For turning assertions on and off at run-time, see assert.active, when zend.assertions = 1) +; Default Value: 1 +; Development Value: 1 +; Production Value: -1 +; http://php.net/zend.assertions +zend.assertions = -1 + +; Assert(expr); active by default. +; http://php.net/assert.active +;assert.active = On + +; Throw an AssertationException on failed assertions +; http://php.net/assert.exception +;assert.exception = On + +; Issue a PHP warning for each failed assertion. (Overridden by assert.exception if active) +; http://php.net/assert.warning +;assert.warning = On + +; Don't bail out by default. +; http://php.net/assert.bail +;assert.bail = Off + +; User-function to be called if an assertion fails. +; http://php.net/assert.callback +;assert.callback = 0 + +; Eval the expression with current error_reporting(). Set to true if you want +; error_reporting(0) around the eval(). +; http://php.net/assert.quiet-eval +;assert.quiet_eval = 0 + +[COM] +; path to a file containing GUIDs, IIDs or filenames of files with TypeLibs +; http://php.net/com.typelib-file +;com.typelib_file = + +; allow Distributed-COM calls +; http://php.net/com.allow-dcom +;com.allow_dcom = true + +; autoregister constants of a components typlib on com_load() +; http://php.net/com.autoregister-typelib +;com.autoregister_typelib = true + +; register constants casesensitive +; http://php.net/com.autoregister-casesensitive +;com.autoregister_casesensitive = false + +; show warnings on duplicate constant registrations +; http://php.net/com.autoregister-verbose +;com.autoregister_verbose = true + +; The default character set code-page to use when passing strings to and from COM objects. +; Default: system ANSI code page +;com.code_page= + +[mbstring] +; language for internal character representation. +; This affects mb_send_mail() and mbstring.detect_order. +; http://php.net/mbstring.language +;mbstring.language = Japanese + +; Use of this INI entry is deprecated, use global internal_encoding instead. +; internal/script encoding. +; Some encoding cannot work as internal encoding. (e.g. SJIS, BIG5, ISO-2022-*) +; If empty, default_charset or internal_encoding or iconv.internal_encoding is used. +; The precedence is: default_charset < internal_encoding < iconv.internal_encoding +;mbstring.internal_encoding = + +; Use of this INI entry is deprecated, use global input_encoding instead. +; http input encoding. +; mbstring.encoding_traslation = On is needed to use this setting. +; If empty, default_charset or input_encoding or mbstring.input is used. +; The precedence is: default_charset < intput_encoding < mbsting.http_input +; http://php.net/mbstring.http-input +;mbstring.http_input = + +; Use of this INI entry is deprecated, use global output_encoding instead. +; http output encoding. +; mb_output_handler must be registered as output buffer to function. +; If empty, default_charset or output_encoding or mbstring.http_output is used. +; The precedence is: default_charset < output_encoding < mbstring.http_output +; To use an output encoding conversion, mbstring's output handler must be set +; otherwise output encoding conversion cannot be performed. +; http://php.net/mbstring.http-output +;mbstring.http_output = + +; enable automatic encoding translation according to +; mbstring.internal_encoding setting. Input chars are +; converted to internal encoding by setting this to On. +; Note: Do _not_ use automatic encoding translation for +; portable libs/applications. +; http://php.net/mbstring.encoding-translation +;mbstring.encoding_translation = Off + +; automatic encoding detection order. +; "auto" detect order is changed according to mbstring.language +; http://php.net/mbstring.detect-order +;mbstring.detect_order = auto + +; substitute_character used when character cannot be converted +; one from another +; http://php.net/mbstring.substitute-character +;mbstring.substitute_character = none + +; overload(replace) single byte functions by mbstring functions. +; mail(), ereg(), etc are overloaded by mb_send_mail(), mb_ereg(), +; etc. Possible values are 0,1,2,4 or combination of them. +; For example, 7 for overload everything. +; 0: No overload +; 1: Overload mail() function +; 2: Overload str*() functions +; 4: Overload ereg*() functions +; http://php.net/mbstring.func-overload +;mbstring.func_overload = 0 + +; enable strict encoding detection. +; Default: Off +;mbstring.strict_detection = On + +; This directive specifies the regex pattern of content types for which mb_output_handler() +; is activated. +; Default: mbstring.http_output_conv_mimetype=^(text/|application/xhtml\+xml) +;mbstring.http_output_conv_mimetype= + +[gd] +; Tell the jpeg decode to ignore warnings and try to create +; a gd image. The warning will then be displayed as notices +; disabled by default +; http://php.net/gd.jpeg-ignore-warning +;gd.jpeg_ignore_warning = 1 + +[exif] +; Exif UNICODE user comments are handled as UCS-2BE/UCS-2LE and JIS as JIS. +; With mbstring support this will automatically be converted into the encoding +; given by corresponding encode setting. When empty mbstring.internal_encoding +; is used. For the decode settings you can distinguish between motorola and +; intel byte order. A decode setting cannot be empty. +; http://php.net/exif.encode-unicode +;exif.encode_unicode = ISO-8859-15 + +; http://php.net/exif.decode-unicode-motorola +;exif.decode_unicode_motorola = UCS-2BE + +; http://php.net/exif.decode-unicode-intel +;exif.decode_unicode_intel = UCS-2LE + +; http://php.net/exif.encode-jis +;exif.encode_jis = + +; http://php.net/exif.decode-jis-motorola +;exif.decode_jis_motorola = JIS + +; http://php.net/exif.decode-jis-intel +;exif.decode_jis_intel = JIS + +[Tidy] +; The path to a default tidy configuration file to use when using tidy +; http://php.net/tidy.default-config +;tidy.default_config = /usr/local/lib/php/default.tcfg + +; Should tidy clean and repair output automatically? +; WARNING: Do not use this option if you are generating non-html content +; such as dynamic images +; http://php.net/tidy.clean-output +tidy.clean_output = Off + +[soap] +; Enables or disables WSDL caching feature. +; http://php.net/soap.wsdl-cache-enabled +soap.wsdl_cache_enabled=1 + +; Sets the directory name where SOAP extension will put cache files. +; http://php.net/soap.wsdl-cache-dir +soap.wsdl_cache_dir="/tmp" + +; (time to live) Sets the number of second while cached file will be used +; instead of original one. +; http://php.net/soap.wsdl-cache-ttl +soap.wsdl_cache_ttl=86400 + +; Sets the size of the cache limit. (Max. number of WSDL files to cache) +soap.wsdl_cache_limit = 5 + +[sysvshm] +; A default size of the shared memory segment +;sysvshm.init_mem = 10000 + +[ldap] +; Sets the maximum number of open links or -1 for unlimited. +ldap.max_links = -1 + +[dba] +;dba.default_handler= + +[opcache] +; Determines if Zend OPCache is enabled +opcache.enable=1 + +opcache.jit_buffer_size = 128M + +; Determines if Zend OPCache is enabled for the CLI version of PHP +;opcache.enable_cli=0 + +; The OPcache shared memory storage size. +;opcache.memory_consumption=128 + +; The amount of memory for interned strings in Mbytes. +;opcache.interned_strings_buffer=8 + +; The maximum number of keys (scripts) in the OPcache hash table. +; Only numbers between 200 and 1000000 are allowed. +;opcache.max_accelerated_files=10000 + +; The maximum percentage of "wasted" memory until a restart is scheduled. +;opcache.max_wasted_percentage=5 + +; When this directive is enabled, the OPcache appends the current working +; directory to the script key, thus eliminating possible collisions between +; files with the same name (basename). Disabling the directive improves +; performance, but may break existing applications. +;opcache.use_cwd=1 + +; When disabled, you must reset the OPcache manually or restart the +; webserver for changes to the filesystem to take effect. +opcache.validate_timestamps=0 + +; How often (in seconds) to check file timestamps for changes to the shared +; memory storage allocation. ("1" means validate once per second, but only +; once per request. "0" means always validate) +;opcache.revalidate_freq=2 + +; Enables or disables file search in include_path optimization +;opcache.revalidate_path=0 + +; If disabled, all PHPDoc comments are dropped from the code to reduce the +; size of the optimized code. +opcache.save_comments=0 + +; Allow file existence override (file_exists, etc.) performance feature. +opcache.enable_file_override=1 + +; A bitmask, where each bit enables or disables the appropriate OPcache +; passes +;opcache.optimization_level=0xffffffff + +;opcache.inherited_hack=1 +;opcache.dups_fix=0 + +; The location of the OPcache blacklist file (wildcards allowed). +; Each OPcache blacklist file is a text file that holds the names of files +; that should not be accelerated. The file format is to add each filename +; to a new line. The filename may be a full path or just a file prefix +; (i.e., /var/www/x blacklists all the files and directories in /var/www +; that start with 'x'). Line starting with a ; are ignored (comments). +;opcache.blacklist_filename= + +; Allows exclusion of large files from being cached. By default all files +; are cached. +;opcache.max_file_size=0 + +; Check the cache checksum each N requests. +; The default value of "0" means that the checks are disabled. +;opcache.consistency_checks=0 + +; How long to wait (in seconds) for a scheduled restart to begin if the cache +; is not being accessed. +;opcache.force_restart_timeout=180 + +; OPcache error_log file name. Empty string assumes "stderr". +;opcache.error_log= + +; All OPcache errors go to the Web server log. +; By default, only fatal errors (level 0) or errors (level 1) are logged. +; You can also enable warnings (level 2), info messages (level 3) or +; debug messages (level 4). +;opcache.log_verbosity_level=1 + +; Preferred Shared Memory back-end. Leave empty and let the system decide. +;opcache.preferred_memory_model= + +; Protect the shared memory from unexpected writing during script execution. +; Useful for internal debugging only. +;opcache.protect_memory=0 + +; Allows calling OPcache API functions only from PHP scripts which path is +; started from specified string. The default "" means no restriction +;opcache.restrict_api= + +; Mapping base of shared memory segments (for Windows only). All the PHP +; processes have to map shared memory into the same address space. This +; directive allows to manually fix the "Unable to reattach to base address" +; errors. +;opcache.mmap_base= + +; Enables and sets the second level cache directory. +; It should improve performance when SHM memory is full, at server restart or +; SHM reset. The default "" disables file based caching. +;opcache.file_cache= + +; Enables or disables opcode caching in shared memory. +;opcache.file_cache_only=0 + +; Enables or disables checksum validation when script loaded from file cache. +;opcache.file_cache_consistency_checks=1 + +; Implies opcache.file_cache_only=1 for a certain process that failed to +; reattach to the shared memory (for Windows only). Explicitly enabled file +; cache is required. +;opcache.file_cache_fallback=1 + +; Enables or disables copying of PHP code (text segment) into HUGE PAGES. +; This should improve performance, but requires appropriate OS configuration. +opcache.huge_code_pages=1 + +; Validate cached file permissions. +;opcache.validate_permission=0 + +; Prevent name collisions in chroot'ed environment. +;opcache.validate_root=0 + +[curl] +; A default value for the CURLOPT_CAINFO option. This is required to be an +; absolute path. +;curl.cainfo = + +[openssl] +; The location of a Certificate Authority (CA) file on the local filesystem +; to use when verifying the identity of SSL/TLS peers. Most users should +; not specify a value for this directive as PHP will attempt to use the +; OS-managed cert stores in its absence. If specified, this value may still +; be overridden on a per-stream basis via the "cafile" SSL stream context +; option. +;openssl.cafile= + +; If openssl.cafile is not specified or if the CA file is not found, the +; directory pointed to by openssl.capath is searched for a suitable +; certificate. This value must be a correctly hashed certificate directory. +; Most users should not specify a value for this directive as PHP will +; attempt to use the OS-managed cert stores in its absence. If specified, +; this value may still be overridden on a per-stream basis via the "capath" +; SSL stream context option. +;openssl.capath= + +; Local Variables: +; tab-width: 4 +; End: diff --git a/frameworks/PHP/piko/deploy/nginx.conf b/frameworks/PHP/piko/deploy/nginx.conf new file mode 100644 index 00000000000..9914073e1c9 --- /dev/null +++ b/frameworks/PHP/piko/deploy/nginx.conf @@ -0,0 +1,64 @@ +user www-data; +worker_processes auto; +daemon off; +events { + worker_connections 16384; + multi_accept off; + +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + access_log off; + server_tokens off; + + sendfile on; + tcp_nopush on; + tcp_nodelay on; + keepalive_timeout 65; + keepalive_disable none; + keepalive_requests 10000; + + #the bench don't use any static file + #open_file_cache max=2000 inactive=20s; + #open_file_cache_valid 60s; + #open_file_cache_min_uses 5; + #open_file_cache_errors off; + + #FastCGI optimizations + fastcgi_buffers 256 16k; + fastcgi_buffer_size 128k; + fastcgi_connect_timeout 30s; + fastcgi_send_timeout 60s; + fastcgi_read_timeout 60s; + fastcgi_busy_buffers_size 256k; + fastcgi_temp_file_write_size 256k; + reset_timedout_connection on; + server_names_hash_bucket_size 100; + + + upstream fastcgi_backend { + server unix:/var/run/php/php-fpm.sock; + keepalive 40; + } + + server { + listen 8080; + server_name tfb-server; + + root /piko/www; + index index.php; + + location / { + try_files $uri $uri/ /index.php$is_args$args; + } + + location /index.php { + fastcgi_pass fastcgi_backend; + fastcgi_keep_conn on; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + include /etc/nginx/fastcgi_params; + } + } +} diff --git a/frameworks/PHP/piko/modules/site/Module.php b/frameworks/PHP/piko/modules/site/Module.php new file mode 100644 index 00000000000..a583457066c --- /dev/null +++ b/frameworks/PHP/piko/modules/site/Module.php @@ -0,0 +1,6 @@ +db); + $id = mt_rand(1, 10000); + $world->load($id); + + return $this->jsonResponse($world->toArray()); + } + + /** + * Return as Json response a set of random records form the World table + * + * @param string $queries The number of queries requested to fetch records + * + * @return ResponseInterface + */ + public function queriesAction(string $queries = ''): ResponseInterface + { + // Bound and sanitize $queries parameter + $queries = is_numeric($queries) ? (int) $queries : 1; + + if ($queries < 1) { + $queries = 1; + } elseif ($queries > 500) { + $queries = 500; + } + + $rows = []; + $world = new World($this->db); + + while ($queries) { + $id = mt_rand(1, 10000); + $rows[] = $world->load($id)->toArray(); + $queries--; + } + + return $this->jsonResponse($rows); + } + + /** + * Retrieves, sorts, and renders the list of fortunes. + * + * Fetches all fortunes from the database, adds an additional fortune at request time, + * sorts the list of fortunes by message text, and renders the result using the "fortunes" view. + * + * @return string The rendered Fortune page + */ + public function fortunesAction(): string + { + $st = $this->db->prepare('SELECT * FROM fortune'); + $st->execute(); + $rows = $st->fetchAll(PDO::FETCH_CLASS, Fortune::class, [$this->db]); + + // Add a new record without saving it in the db + $fortune = new Fortune($this->db); + $fortune->message = 'Additional fortune added at request time.'; + $rows[] = $fortune; + + // Sort messages + usort($rows, function($a, $b) { + return strcmp($a->message, $b->message); + }); + + return $this->render('fortunes', [ + 'fortunes' => $rows + ]); + } + + /** + * Updates a set of random records in the World table and returns them as a Json response. + * + * Fetches the specified number of World records, + * assigns each a new randomNumber, saves, and returns the modified records. + * + * @param string $queries The number of records to update and return + * + * @return ResponseInterface + */ + public function updatesAction(string $queries = ''): ResponseInterface + { + // Bound and sanitize $queries parameter + $queries = is_numeric($queries) ? (int) $queries : 1; + + if ($queries < 1) { + $queries = 1; + } elseif ($queries > 500) { + $queries = 500; + } + + $rows = []; + $world = new World($this->db); + + while ($queries) { + $id = mt_rand(1, 10000); + $world = $world->load($id); + $world->randomnumber = mt_rand(1, 10000); + $world->save(); + $rows[] = $world->toArray(); + $queries--; + } + + return $this->jsonResponse($rows); + } +} diff --git a/frameworks/PHP/piko/modules/site/controllers/DefaultController.php b/frameworks/PHP/piko/modules/site/controllers/DefaultController.php new file mode 100644 index 00000000000..4b9cfd9a51d --- /dev/null +++ b/frameworks/PHP/piko/modules/site/controllers/DefaultController.php @@ -0,0 +1,30 @@ +createStream('Hello, World!'); + + return $this->response->withHeader('Content-Type', 'text/plain; charset=UTF-8')->withBody($body); + } + + /** + * Return a json response with a Hello, World! message + * + * @return ResponseInterface + */ + public function jsonAction(): ResponseInterface + { + return $this->jsonResponse(['message' => 'Hello, World!']); + } +} diff --git a/frameworks/PHP/piko/modules/site/layouts/main.php b/frameworks/PHP/piko/modules/site/layouts/main.php new file mode 100644 index 00000000000..2fc30f17bbd --- /dev/null +++ b/frameworks/PHP/piko/modules/site/layouts/main.php @@ -0,0 +1,17 @@ + + + + + + <?= $this->escape($this->title) ?> + head() ?> + + + + + diff --git a/frameworks/PHP/piko/modules/site/models/Fortune.php b/frameworks/PHP/piko/modules/site/models/Fortune.php new file mode 100644 index 00000000000..ca85714ad10 --- /dev/null +++ b/frameworks/PHP/piko/modules/site/models/Fortune.php @@ -0,0 +1,18 @@ + $fortunes + */ + + $this->title = 'Fortunes'; +?> + + + + + + +
idmessage
id ?>escape((string) $fortune->message) ?>
diff --git a/frameworks/PHP/piko/piko-postgres.dockerfile b/frameworks/PHP/piko/piko-postgres.dockerfile new file mode 100644 index 00000000000..6f9b970d864 --- /dev/null +++ b/frameworks/PHP/piko/piko-postgres.dockerfile @@ -0,0 +1,28 @@ +FROM ubuntu:24.04 + +ENV DATABASE_DRIVER pgsql + +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 install -yqq nginx git unzip php8.4-fpm php8.4-pgsql > /dev/null + +COPY deploy/conf/* /etc/php/8.4/fpm/ + +WORKDIR /piko +COPY --link . . + +COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer + +RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet + +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 chmod -R 777 /piko + +EXPOSE 8080 + +CMD set -e; \ + /usr/sbin/nginx -c /piko/deploy/nginx.conf 2>&1 > /dev/stderr & \ + exec /usr/sbin/php-fpm8.4 --nodaemonize --fpm-config /etc/php/8.4/fpm/php-fpm.conf diff --git a/frameworks/PHP/piko/piko.dockerfile b/frameworks/PHP/piko/piko.dockerfile new file mode 100644 index 00000000000..e525d2b64d7 --- /dev/null +++ b/frameworks/PHP/piko/piko.dockerfile @@ -0,0 +1,25 @@ +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 install -yqq nginx git unzip php8.4-fpm php8.4-mysql > /dev/null + +COPY deploy/conf/* /etc/php/8.4/fpm/ + +WORKDIR /piko +COPY --link . . + +COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer + +RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet + +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 chmod -R 777 /piko + +EXPOSE 8080 + +CMD service php8.4-fpm start && \ + nginx -c /piko/deploy/nginx.conf 2>&1 > /dev/stderr diff --git a/frameworks/PHP/piko/www/index.php b/frameworks/PHP/piko/www/index.php new file mode 100644 index 00000000000..4aac7d862ef --- /dev/null +++ b/frameworks/PHP/piko/www/index.php @@ -0,0 +1,8 @@ +run(); diff --git a/frameworks/PHP/reactphp/.dockerignore b/frameworks/PHP/reactphp/.dockerignore new file mode 100644 index 00000000000..265ee153b77 --- /dev/null +++ b/frameworks/PHP/reactphp/.dockerignore @@ -0,0 +1,5 @@ +vendor +composer.lock +*.dockerfile +.dockerignore +.gitignore diff --git a/frameworks/PHP/reactphp/.gitignore b/frameworks/PHP/reactphp/.gitignore new file mode 100644 index 00000000000..987e2a253ca --- /dev/null +++ b/frameworks/PHP/reactphp/.gitignore @@ -0,0 +1,2 @@ +composer.lock +vendor diff --git a/frameworks/PHP/reactphp/app.php b/frameworks/PHP/reactphp/app.php index 7c4e230e10f..bea0c65038d 100644 --- a/frameworks/PHP/reactphp/app.php +++ b/frameworks/PHP/reactphp/app.php @@ -1,134 +1,150 @@ PDO::FETCH_ASSOC, - PDO::ATTR_EMULATE_PREPARES => false - ] - ); - $world = $pdo->prepare('SELECT id,randomNumber FROM World WHERE id=?'); - $update = $pdo->prepare('UPDATE World SET randomNumber=? WHERE id=?'); - $fortune = $pdo->prepare('SELECT id,message FROM Fortune'); - $fortune->setFetchMode(PDO::FETCH_KEY_PAIR); -} +use function React\Promise\all; +use function React\Promise\resolve; -function router(Request $request) +/** @return Closure(Request):ResponseInterface */ +function requestHandler(): Closure { - return match($request->getUri()->getPath()) { - '/plaintext' => text(), - '/json' => json(), - '/db' => db(), - '/fortunes' => fortune(), - '/query' => query($request), - '/update' => updateraw($request), - // '/info' => info(), - default => new Response(404, [], 'Error 404'), + $connection = establishDbConnection('benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world?idle=0.5'); + + $world = static function (int $id) use ($connection): PromiseInterface { + return $connection->query('SELECT id,randomNumber FROM World WHERE id=?', [$id]); }; -} -function text() -{ - return new Response(200, [ - 'Content-Type' => 'text/plain' - ], 'Hello, World!'); -} + $fortune = static function () use ($connection): PromiseInterface { + return $connection->query('SELECT id,message FROM Fortune'); + }; -function json() -{ - return new Response(200, [ - 'Content-Type' => 'application/json' - ], json_encode(['message' => 'Hello, World!'])); + $update = static function (int $id, int $randomNumber) use ($connection): PromiseInterface { + return $connection->query('UPDATE World SET randomNumber=? WHERE id=?', [$randomNumber, $id]); + }; + + return static function (Request $request) use ($world, $fortune, $update): ResponseInterface | PromiseInterface { + return resolve((match($request->getUri()->getPath()) { + '/plaintext' => Response::plaintext('Hello, World!'), + '/json' => Response::json(['message' => 'Hello, World!']), + '/db' => db($world), + '/fortunes' => fortune($fortune), + '/query' => query(queryCount($request), $world), + '/update' => updateraw(queryCount($request), $world, $update), + // '/info' => info(), + default => new Response(404, [], 'Error 404'), + }))->catch( + static fn (Throwable $error): PromiseInterface => resolve(Response::plaintext($error->getMessage())->withStatus(500)), + ); + }; } -function db() -{ - global $world; +function establishDbConnection( + #[SensitiveParameter] + string $uri, +): DbConnection { + $connection = (new DbFactory())->createLazyConnection($uri); + + $interrupt = $connection->quit(...); - $world->execute([mt_rand(1, 10000)]); + $connection->on('close', static function () use (&$interrupt) { + Loop::removeSignal(SIGINT, $interrupt); + Loop::removeSignal(SIGTERM, $interrupt); + }); - return new Response(200, [ - 'Content-Type' => 'application/json' - ], json_encode($world->fetch())); + Loop::addSignal(SIGINT, $interrupt); + Loop::addSignal(SIGTERM, $interrupt); + + return $connection; } -function query($request) +/** @param Closure(int):PromiseInterface $world */ +function db(Closure $world): PromiseInterface { - global $world; + $id = mt_rand(1, 10000); + + return $world($id)->then( + static fn (QueryResult $result): ResponseInterface => Response::json($result->resultRows[0]), + ); +} - $query_count = 1; - $q = (int) $request->getQueryParams()['q']; - if ($q > 1) { - $query_count = min($q, 500); - } +function queryCount(Request $request): int +{ + $count = (int) ($request->getQueryParams()['q'] ?? 1); - while ($query_count--) { - $world->execute([mt_rand(1, 10000)]); - $arr[] = $world->fetch(); + if ($count > 1) { + return min($count, 500); } - return new Response(200, [ - 'Content-Type' => 'application/json' - ], json_encode($arr)); + return 1; } -function updateraw($request) +/** @param Closure(int):PromiseInterface $world */ +function query(int $queryCount, Closure $world): PromiseInterface { - global $world, $update; + $processQueries = static function (int $count) use ($world): iterable { + while ($count--) { + $id = mt_rand(1, 10000); - $query_count = 1; - $q = (int) $request->getQueryParams()['q']; - if ($q > 1) { - $query_count = min($q, 500); - } + yield $world($id)->then(static fn (QueryResult $result): array => $result->resultRows[0]); + } + }; - while ($query_count--) { - $id = mt_rand(1, 10000); - $world->execute([$id]); - $item = $world->fetch(); - $update->execute( - [$item['randomNumber'] = mt_rand(1, 10000), $id] - ); + return all($processQueries($queryCount)) + ->then(static fn (array $result): ResponseInterface => Response::json($result)); +} - $arr[] = $item; - } +/** + * @param Closure(int):PromiseInterface $world + * @param Closure(int, int):PromiseInterface $update + */ +function updateraw(int $queryCount, Closure $world, Closure $update): PromiseInterface +{ + $processQueries = static function (int $count) use ($world, $update): iterable { + while ($count--) { + $id = mt_rand(1, 10000); + + yield $world($id)->then( + static function (QueryResult $result) use ($update): PromiseInterface { + $updated = $result->resultRows[0]; + $updated['randomNumber'] = mt_rand(1, 10000); + + return $update($updated['id'], $updated['randomNumber']) + ->then(static fn (): array => $updated); + } + ); + } + }; - // $pdo->beginTransaction(); - // foreach($arr as $world) { - // $update->execute([$world['randomNumber'], $world['id']]); - // } - // $pdo->commit(); - return new Response(200, [ - 'Content-Type' => 'application/json' - ], json_encode($arr)); + return all($processQueries($queryCount)) + ->then(static fn (array $result): ResponseInterface => Response::json($result)); } -function fortune() +function fortune(Closure $fortune): PromiseInterface { - global $fortune; + $formatResult = static function (array $rows): string { + $rows[] = ['id' => 0, 'message' => 'Additional fortune added at request time.']; + usort($rows, static fn (array $one, array $other) => $one['message'] <=> $other['message']); - $fortune->execute(); + $html = ''; - $arr = $fortune->fetchAll(); - $arr[0] = 'Additional fortune added at request time.'; - asort($arr); + foreach ($rows as $row) { + $message = htmlspecialchars($row['message'], ENT_QUOTES, 'UTF-8'); - $html = ''; - foreach ($arr as $id => $message) { - $message = htmlspecialchars($message, ENT_QUOTES, 'UTF-8'); - $html .= "$id$message"; - } + $html .= "{$row['id']}{$message}"; + } + + return "Fortunes$html
idmessage
"; + }; - return new Response(200, [ - 'Content-Type' => 'text/html; charset=UTF-8', - ], "Fortunes$html
idmessage
" + return $fortune()->then( + static fn (QueryResult $result): ResponseInterface => Response::html($formatResult($result->resultRows)), ); } @@ -138,4 +154,4 @@ function fortune() phpinfo(); return new Response(200, ['Content-Type' => 'text/plain'], ob_get_clean()); } - */ \ No newline at end of file + */ diff --git a/frameworks/PHP/reactphp/benchmark_config.json b/frameworks/PHP/reactphp/benchmark_config.json index 8da2a6e62f9..e53c029d748 100644 --- a/frameworks/PHP/reactphp/benchmark_config.json +++ b/frameworks/PHP/reactphp/benchmark_config.json @@ -1,12 +1,9 @@ { "framework": "reactphp", + "maintainers": ["WyriHaximus"], "tests": [{ "default": { "json_url": "/json", - "db_url": "/db", - "query_url": "/query?q=", - "fortune_url": "/fortunes", - "update_url": "/update?q=", "plaintext_url": "/plaintext", "port": 8080, "approach": "Realistic", @@ -20,9 +17,28 @@ "webserver": "None", "os": "Linux", "database_os": "Linux", - "display_name": "reactphp", + "display_name": "reactphp [libevent]", "notes": "", "versus": "php" + }, + "libuv": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Platform", + "framework": "reactphp", + "language": "PHP", + "flavor": "PHP8", + "database": "MySQL", + "orm": "Raw", + "platform": "reactphp", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "reactphp [libuv]", + "notes": "", + "versus": "reactphp" } }] } diff --git a/frameworks/PHP/reactphp/composer.json b/frameworks/PHP/reactphp/composer.json index fdea490c2d2..c03159aaa54 100644 --- a/frameworks/PHP/reactphp/composer.json +++ b/frameworks/PHP/reactphp/composer.json @@ -1,9 +1,10 @@ { "require": { - "php": ">=5.3.0", + "php": ">=8.3.0", "psr/http-message": "^1.0", - "react/event-loop": "^1.2", - "react/http": "^1.6", - "react/socket": "^1.11" + "react/event-loop": "^1.5", + "react/http": "^1.9", + "react/socket": "^1.14", + "react/mysql": "^0.6" } } diff --git a/frameworks/PHP/reactphp/reactphp-libuv.dockerfile b/frameworks/PHP/reactphp/reactphp-libuv.dockerfile new file mode 100644 index 00000000000..48126b5c59c --- /dev/null +++ b/frameworks/PHP/reactphp/reactphp-libuv.dockerfile @@ -0,0 +1,35 @@ +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 +RUN apt-get update -yqq > /dev/null && \ + apt-get install -yqq git unzip wget curl build-essential \ + php8.4-cli php8.4-mbstring php8.4-dev php8.4-xml > /dev/null + +# An extension is required! +# We deal with concurrencies over 1k, which stream_select doesn't support. +# libuv +RUN apt-get install -yqq libuv1-dev > /dev/null \ + && pecl install uv-beta > /dev/null \ + && echo "extension=uv.so" > /etc/php/8.4/cli/conf.d/uv.ini + +# libevent +# RUN apt-get install -y libevent-dev > /dev/null \ +# && pecl install event-3.1.4 > /dev/null \ +# && echo "extension=event.so" > /etc/php/8.4/cli/conf.d/event.ini + +COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer + +COPY --link deploy/conf/* /etc/php/8.4/cli/conf.d/ + +WORKDIR /reactphp +COPY --link . . + +RUN composer install --prefer-dist --optimize-autoloader --no-dev --quiet + +EXPOSE 8080 + +ENTRYPOINT ["/usr/bin/php"] +CMD ["server.php"] diff --git a/frameworks/PHP/reactphp/reactphp.dockerfile b/frameworks/PHP/reactphp/reactphp.dockerfile index eb5a070ba1c..0ecb546a1c3 100644 --- a/frameworks/PHP/reactphp/reactphp.dockerfile +++ b/frameworks/PHP/reactphp/reactphp.dockerfile @@ -1,30 +1,35 @@ -FROM ubuntu:22.04 +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 LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null RUN apt-get update -yqq > /dev/null && \ apt-get install -yqq git unzip wget curl build-essential \ - php8.2-cli php8.2-mbstring php8.2-dev php8.2-xml php8.2-curl php8.2-mysql > /dev/null + php8.4-cli php8.4-mbstring php8.4-dev php8.4-xml > /dev/null # An extension is required! # We deal with concurrencies over 1k, which stream_select doesn't support. -RUN wget http://pear.php.net/go-pear.phar --quiet && php go-pear.phar -#RUN apt-get install -y libuv1-dev > /dev/null -RUN apt-get install -y libevent-dev > /dev/null -#RUN pecl install uv-0.2.4 > /dev/null && echo "extension=uv.so" > /etc/php/8.2/cli/conf.d/uv.ini -RUN pecl install event-3.0.8 > /dev/null && echo "extension=event.so" > /etc/php/8.2/cli/conf.d/event.ini +# libuv +# RUN apt-get install -yqq libuv1-dev > /dev/null \ +# && pecl install uv-beta > /dev/null \ +# && echo "extension=uv.so" > /etc/php/8.4/cli/conf.d/uv.ini -ADD ./ /reactphp -WORKDIR /reactphp - -COPY deploy/conf/* /etc/php/8.2/cli/conf.d/ +# libevent +RUN apt-get install -y libevent-dev > /dev/null \ + && pecl install event-3.1.4 > /dev/null \ + && echo "extension=event.so" > /etc/php/8.4/cli/conf.d/event.ini COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer +COPY --link deploy/conf/* /etc/php/8.4/cli/conf.d/ + +WORKDIR /reactphp +COPY --link . . + RUN composer install --prefer-dist --optimize-autoloader --no-dev --quiet EXPOSE 8080 -CMD php server.php +ENTRYPOINT ["/usr/bin/php"] +CMD ["server.php"] diff --git a/frameworks/PHP/reactphp/server.php b/frameworks/PHP/reactphp/server.php index 107ee1b78bd..278208b6291 100644 --- a/frameworks/PHP/reactphp/server.php +++ b/frameworks/PHP/reactphp/server.php @@ -1,20 +1,30 @@ on('error', function (\Throwable $error) { + echo $error->getMessage(), PHP_EOL; }); - -$socket = new React\Socket\Server('0.0.0.0:8080', $loop); +$socket = new SocketServer('0.0.0.0:8080'); $server->listen($socket); echo "React Server running at http://0.0.0.0:8080\n"; -echo "EventLoop: ", $loop::class, "\n"; +echo "EventLoop: ", Loop::get()::class, "\n"; + +$interrupt = static function () use ($server, $socket, &$interrupt): void { + echo 'Interrupting server', PHP_EOL; + + $socket->close(); + + Loop::removeSignal(SIGINT, $interrupt); + Loop::removeSignal(SIGTERM, $interrupt); +}; -$loop->run(); +Loop::addSignal(SIGINT, $interrupt); +Loop::addSignal(SIGTERM, $interrupt); diff --git a/frameworks/PHP/ripple/README.md b/frameworks/PHP/ripple/README.md new file mode 100644 index 00000000000..ce4d89d0bc2 --- /dev/null +++ b/frameworks/PHP/ripple/README.md @@ -0,0 +1,75 @@ +

+Logo +

+

+Build Status +Download statistics +Stable version +License +

+

+Ripple is a modern, high-performance native PHP coroutine engine designed to solve PHP's challenges in high concurrency, complex network communication and data operations. +The engine uses an innovative architecture and efficient programming model to provide powerful and flexible backend support for modern web and web applications. +By using ripple, you will experience the advantages of managing tasks from a global view of the system and efficiently handling network traffic and data.

+ +## Install + +````bash +composer require cloudtay/ripple +```` + +## Latest documentation + +You can visit `ripple`’s [documentation](https://ripple.cloudtay.com/) to start reading + +We recommend that you start with [Manual Installation](https://ripple.cloudtay.com/docs/install/professional) to better +understand the workflow of ripple + +If you want to quickly deploy and use `ripple` services, you can directly +visit [Quick Deployment](https://ripple.cloudtay.com/docs/install/server) + +## Appendix + +### Applicable component library + +> We allow users to choose applicable component libraries by themselves. All components can be used as described in the +> document without additional configuration. + +**🚀 [Guzzle](https://docs.guzzlephp.org/en/stable/)** +PHP is the most widely used HTTP client + +**🔥 [AmPHP](https://amphp.org/)** +Provides rich PHP asynchronous components for users to encapsulate by themselves + +**🚀 [Driver](https://github.com/cloudtay/ripple-driver)** +The official high-performance driver library provides seamless access to your traditional applications. + +**🚀 [Webman-coroutine](https://github.com/workbunny/webman-coroutine)** +The workbunny team's integrated webman coroutine extension provides coroutine support for Webman. + +**🟢[ripple](https://github.com/cloudtay/ripple)** +Provides standard coroutine architecture and tools for rapid development or packaging of traditional applications + +### Event Library Guide + +| Extension Types | Recommended Use | Compatibility | Description | +|:---------------:|:---------------:|:-------------:|:--------------------------------------------------------------------------------------------------------------------:| +| `libev` | 🏅️ | 🟢️ | `Ev` is a more efficient event extension that performs consistently in various systems and is recommended to be used | +| `Native` | ️ | 🟢 | Support the use of PHP's built-in select mechanism | +| `event` | | 🌗 | The event characteristics under different systems are not uniform, and their use is not recommended | + +## Special thanks + + + jetbrains + + +[Jetbrains](https://www.jetbrains.com/?from=ripple) provides free development tools for this project + +### Contact information + +`Email` jingnigg@gmail.com + +`WeChat` jingnigg + +--- diff --git a/frameworks/PHP/ripple/benchmark_config.json b/frameworks/PHP/ripple/benchmark_config.json new file mode 100644 index 00000000000..4c625c29bbe --- /dev/null +++ b/frameworks/PHP/ripple/benchmark_config.json @@ -0,0 +1,29 @@ +{ + "framework": "ripple", + "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": "ripple", + "language": "PHP", + "flavor": "PHP8.3", + "orm": "Raw", + "platform": "ripple", + "os": "Linux", + "database_os": "Linux", + "display_name": "ripple", + "notes": "", + "versus": "php" + } + } + ] +} diff --git a/frameworks/PHP/ripple/composer.json b/frameworks/PHP/ripple/composer.json new file mode 100644 index 00000000000..350f9763c06 --- /dev/null +++ b/frameworks/PHP/ripple/composer.json @@ -0,0 +1,8 @@ +{ + "require": { + "ext-pdo": "*", + "cloudtay/ripple": "^2.0" + }, + "minimum-stability": "beta", + "prefer-stable": true +} diff --git a/frameworks/PHP/ripple/fortunes.php b/frameworks/PHP/ripple/fortunes.php new file mode 100644 index 00000000000..32f765eabb6 --- /dev/null +++ b/frameworks/PHP/ripple/fortunes.php @@ -0,0 +1,18 @@ + + +Fortunes + + + + + + + + + + + + +
idmessage
+ + diff --git a/frameworks/PHP/ripple/ripple.dockerfile b/frameworks/PHP/ripple/ripple.dockerfile new file mode 100644 index 00000000000..138d91d0918 --- /dev/null +++ b/frameworks/PHP/ripple/ripple.dockerfile @@ -0,0 +1,33 @@ +FROM php:8.3-cli + +RUN apt-get update -yqq >> /dev/null +RUN apt-get install -y libevent-dev \ + libffi-dev \ + libssl-dev \ + pkg-config \ + build-essential \ + unzip >> /dev/null + +RUN docker-php-ext-install pdo_mysql \ + ffi \ + opcache \ + posix \ + pcntl \ + sockets >> /dev/null + +RUN pecl install ev >> /dev/null + +RUN docker-php-ext-enable posix pcntl sockets ev + +COPY --from=composer --link /usr/bin/composer /usr/local/bin/composer + +# Initialize +WORKDIR /ripple +COPY --link . . + +# Configure +RUN composer install + +# Start +EXPOSE 8080 +ENTRYPOINT ["php","server.php"] diff --git a/frameworks/PHP/ripple/server.php b/frameworks/PHP/ripple/server.php new file mode 100644 index 00000000000..400e9fd574b --- /dev/null +++ b/frameworks/PHP/ripple/server.php @@ -0,0 +1,299 @@ +format('D, d M Y H:i:s T'); + } + + /** + * @return int + */ + public static function randomInt(): int + { + try { + return \random_int(1, 10000); + } catch (Throwable $e) { + return \mt_rand(1, 10000); + } + } + + /** + * @param mixed $value + * @return int + */ + public static function clamp(mixed $value): int + { + if (!\is_numeric($value) || $value < 1) { + return 1; + } + if ($value > 500) { + return 500; + } + return \intval($value); + } + + /** + * @param array $rows + * @return string + */ + public static function renderFortunes(array $rows): string + { + if (self::$fortunesRenderer === null) { + $code = \file_get_contents(__DIR__ . '/fortunes.php'); + if ($code === false) { + return ''; + } + + $renderer = static function (array $scope) use ($code): string { + foreach ($scope as $key => $value) { + $$key = $value; + } + \ob_start(); + + eval('?>' . $code); + return (string) \ob_get_clean(); + }; + + self::$fortunesRenderer = $renderer; + } + + /** @var callable $renderer */ + $renderer = self::$fortunesRenderer; + return $renderer(['rows' => $rows]); + } +} + +$manager = new Manager(); +$worker = new class () extends Worker { + /** + * @var Server + */ + private Server $server; + + /** + * @var Channel + */ + private Channel $STM_queryWorldWhereID; + + /** + * @var Channel + */ + private Channel $STM_updateWorldRandomNumber; + + /** + * @var Channel + */ + private Channel $STM_queryFortune; + + /** + * @return void + */ + public function register(): void + { + $this->count = 32; + $context = \stream_context_create([ + 'socket' => [ + 'so_reuseport' => 1, + 'so_reuseaddr' => 1 + ] + ]); + $this->server = Http::server('http://0.0.0.0:8080', $context); + } + + /** + * @return void + */ + public function boot(): void + { + Setup::dateRefresh(); + go(static function () { + while (1) { + \Co\sleep(1); + Setup::dateRefresh(); + } + }); + + $this->STM_queryWorldWhereID = new Channel(10); + $this->STM_updateWorldRandomNumber = new Channel(10); + $this->STM_queryFortune = new Channel(10); + + for ($i = 0; $i < 10; $i++) { + $client = new Client( + 'mysql:host=tfb-database;port=3306;dbname=hello_world', + 'benchmarkdbuser', + 'benchmarkdbpass', + ); + + $this->STM_queryWorldWhereID->send($client->prepare('SELECT id, randomNumber FROM World WHERE id = ?')); + $this->STM_updateWorldRandomNumber->send($client->prepare('UPDATE World SET randomNumber = ? WHERE id = ?')); + $this->STM_queryFortune->send($client->prepare('SELECT * FROM `Fortune`')); + } + + $this->server->onRequest = fn (Request $request) => $this->onRequest($request); + $this->server->listen(); + } + + /** + * @param Request $request + * @return void + */ + public function onRequest(Request $request): void + { + switch ($request->SERVER['REQUEST_URI']) { + case '/json': + { + $request->respondJson( + ['message' => 'Hello, World!'], + ['Date' => Setup::$dateFormatted] + ); + break; + } + + case '/db': + { + $statement = $this->STM_queryWorldWhereID->receive(); + $statement->execute([Setup::randomInt()]); + $request->respondJson($statement->fetch(AbstractResultSet::ASSOC_ARRAY), ['Date' => Setup::$dateFormatted]); + $this->STM_queryWorldWhereID->send($statement); + break; + } + + case '/queries': + { + $queries = Setup::clamp($request->GET['queries'] ?? 1); + $results = []; + + $waitGroup = new WaitGroup(); + $waitGroup->add($queries); + + while ($queries--) { + go(function () use (&$results, $waitGroup) { + $statement = $this->STM_queryWorldWhereID->receive(); + + $statement->execute([Setup::randomInt()]); + $results[] = $statement->fetch(AbstractResultSet::ASSOC_ARRAY); + + $this->STM_queryWorldWhereID->send($statement); + $waitGroup->done(); + }); + } + + $waitGroup->wait(); + + $request->respondJson($results, ['Date' => Setup::$dateFormatted]); + break; + } + + case '/fortunes': + { + $statement = $this->STM_queryFortune->receive(); + $statement->execute(); + $rows = $statement->fetchAll(AbstractResultSet::ASSOC_ARRAY); + $this->STM_queryFortune->send($statement); + + $rows[] = ['id' => 0, 'message' => 'Additional fortune added at request time.']; + \usort($rows, function ($a, $b) { + return $a['message'] <=> $b['message']; + }); + + $request->respondHtml( + Setup::renderFortunes($rows), + [ + 'Date' => Setup::$dateFormatted, + 'Content-Type' => 'text/html; charset=UTF-8' + ] + ); + break; + } + + case '/updates': + { + $queries = Setup::clamp($request->GET['queries'] ?? 1); + $results = []; + + $waitGroup = new WaitGroup(); + $waitGroup->add($queries); + + while ($queries--) { + go(function () use (&$results, $waitGroup) { + $statement = $this->STM_queryWorldWhereID->receive(); + $update = $this->STM_updateWorldRandomNumber->receive(); + + $statement->execute([Setup::randomInt()]); + $row = $statement->fetch(AbstractResultSet::ASSOC_ARRAY); + $row['randomNumber'] = Setup::randomInt(); + $results[] = $row; + $update->execute([$row['randomNumber'], $row['id']]); + + $this->STM_queryWorldWhereID->send($statement); + $this->STM_updateWorldRandomNumber->send($update); + + $waitGroup->done(); + }); + } + + $waitGroup->wait(); + $request->respondJson($results, ['Date' => Setup::$dateFormatted]); + + break; + } + + case '/plaintext': + { + $request->respond( + 'Hello, World!', + [ + 'Content-Type' => 'text/plain; charset=utf-8', + 'Date' => Setup::$dateFormatted + ] + ); + break; + } + + default: + { + $request->respond('Not Found', [], 404); + } + } + } +}; + +$manager->add($worker); +$manager->run(); +wait(); diff --git a/frameworks/PHP/simps/simps-micro.dockerfile b/frameworks/PHP/simps/simps-micro.dockerfile index baa74e103e1..4e5b9ffd075 100644 --- a/frameworks/PHP/simps/simps-micro.dockerfile +++ b/frameworks/PHP/simps/simps-micro.dockerfile @@ -1,22 +1,15 @@ -FROM php:8.3-cli +FROM phpswoole/swoole:5.1.3-php8.3 -RUN pecl install swoole > /dev/null && \ - docker-php-ext-enable swoole - -RUN docker-php-ext-install opcache pdo_mysql > /dev/null - -RUN apt -yqq update > /dev/null && \ - apt -yqq install git unzip > /dev/null +RUN docker-php-ext-install pcntl opcache curl > /dev/null WORKDIR /simps -COPY . /simps -COPY php.ini /usr/local/etc/php/ +COPY --link . . +COPY --link php.ini /usr/local/etc/php/ -RUN curl -sSL https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer RUN composer install --no-dev --classmap-authoritative --quiet > /dev/null RUN composer dumpautoload -o EXPOSE 8080 -CMD php sbin/simps.php http:start +ENTRYPOINT [ "php", "sbin/simps.php", "http:start" ] diff --git a/frameworks/PHP/simps/simps.dockerfile b/frameworks/PHP/simps/simps.dockerfile index baa74e103e1..4e5b9ffd075 100644 --- a/frameworks/PHP/simps/simps.dockerfile +++ b/frameworks/PHP/simps/simps.dockerfile @@ -1,22 +1,15 @@ -FROM php:8.3-cli +FROM phpswoole/swoole:5.1.3-php8.3 -RUN pecl install swoole > /dev/null && \ - docker-php-ext-enable swoole - -RUN docker-php-ext-install opcache pdo_mysql > /dev/null - -RUN apt -yqq update > /dev/null && \ - apt -yqq install git unzip > /dev/null +RUN docker-php-ext-install pcntl opcache curl > /dev/null WORKDIR /simps -COPY . /simps -COPY php.ini /usr/local/etc/php/ +COPY --link . . +COPY --link php.ini /usr/local/etc/php/ -RUN curl -sSL https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer RUN composer install --no-dev --classmap-authoritative --quiet > /dev/null RUN composer dumpautoload -o EXPOSE 8080 -CMD php sbin/simps.php http:start +ENTRYPOINT [ "php", "sbin/simps.php", "http:start" ] diff --git a/frameworks/PHP/slim/composer.json b/frameworks/PHP/slim/composer.json index 78202c96223..2969d6f9fbd 100644 --- a/frameworks/PHP/slim/composer.json +++ b/frameworks/PHP/slim/composer.json @@ -4,7 +4,7 @@ "slim/php-view": "3.2.0", "slim/psr7": "1.*", "slim/http": "1.*", - "php-di/php-di": "^6.4" + "php-di/php-di": "^7" }, "autoload": { "psr-4": { diff --git a/frameworks/PHP/slim/deploy/conf/cli-php.ini b/frameworks/PHP/slim/deploy/conf/cli-php.ini index bcccffbc63b..e03b6e352a9 100644 --- a/frameworks/PHP/slim/deploy/conf/cli-php.ini +++ b/frameworks/PHP/slim/deploy/conf/cli-php.ini @@ -13,4 +13,4 @@ memory_limit = 512M opcache.jit_buffer_size = 128M opcache.jit = tracing -disable_functions=header,header_remove,headers_sent,http_response_code,setcookie,session_create_id,session_id,session_name,session_save_path,session_status,session_start,session_write_close,session_regenerate_id,set_time_limit +disable_functions=header,header_remove,headers_sent,headers_list,http_response_code,setcookie,session_create_id,session_id,session_name,session_save_path,session_status,session_start,session_write_close,session_regenerate_id,session_unset,session_get_cookie_params,session_set_cookie_params,set_time_limit diff --git a/frameworks/PHP/slim/server.php b/frameworks/PHP/slim/server.php index 35f6c3fe62a..7eafd061037 100644 --- a/frameworks/PHP/slim/server.php +++ b/frameworks/PHP/slim/server.php @@ -4,12 +4,13 @@ use Adapterman\Adapterman; use Workerman\Worker; -use Workerman\Lib\Timer; +use Workerman\Timer; Adapterman::init(); $http_worker = new Worker('http://0.0.0.0:8080'); $http_worker->count = (int) shell_exec('nproc') * 4; +$http_worker->reusePort = true; $http_worker->name = 'AdapterMan-Slim'; $http_worker->onWorkerStart = static function () { @@ -38,9 +39,9 @@ class HeaderDate public static function init(): void { - self::$date = self::NAME . gmdate('D, d M Y H:i:s').' GMT'; + self::$date = self::NAME . gmdate(DATE_RFC7231); Timer::add(1, static function() { - self::$date = self::NAME . gmdate('D, d M Y H:i:s').' GMT'; + self::$date = self::NAME . gmdate(DATE_RFC7231); }); } } \ No newline at end of file diff --git a/frameworks/PHP/slim/slim-workerman-pgsql.dockerfile b/frameworks/PHP/slim/slim-workerman-pgsql.dockerfile index 4a40505c701..8a06648dd86 100644 --- a/frameworks/PHP/slim/slim-workerman-pgsql.dockerfile +++ b/frameworks/PHP/slim/slim-workerman-pgsql.dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:22.04 +FROM ubuntu:24.04 ARG DEBIAN_FRONTEND=noninteractive @@ -8,22 +8,22 @@ RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null && \ RUN apt-get upgrade -yqq > /dev/null RUN apt-get install -yqq git \ - php8.3-cli php8.3-pgsql php8.3-mbstring php8.3-xml php8.3-curl > /dev/null + php8.4-cli php8.4-pgsql php8.4-mbstring php8.4-xml php8.4-curl > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -RUN apt-get install -y php-pear php8.3-dev libevent-dev > /dev/null -RUN pecl install event-3.0.8 > /dev/null && echo "extension=event.so" > /etc/php/8.3/cli/conf.d/event.ini +RUN apt-get install -y php-pear php8.4-dev libevent-dev > /dev/null +RUN pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.4/cli/conf.d/event.ini -COPY deploy/conf/cli-php.ini /etc/php/8.3/cli/php.ini +COPY deploy/conf/cli-php.ini /etc/php/8.4/cli/conf.d/20-adapterman.ini -ADD ./ /slim WORKDIR /slim +COPY --link . . EXPOSE 8080 RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet -RUN composer require joanhey/adapterman:^0.6 --quiet +RUN composer require joanhey/adapterman:^0.7 --quiet RUN sed -i 's|/index.php|/start.php|g' server.php diff --git a/frameworks/PHP/slim/slim-workerman.dockerfile b/frameworks/PHP/slim/slim-workerman.dockerfile index fefb80f8106..a8c535bb05c 100644 --- a/frameworks/PHP/slim/slim-workerman.dockerfile +++ b/frameworks/PHP/slim/slim-workerman.dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:22.04 +FROM ubuntu:24.04 ARG DEBIAN_FRONTEND=noninteractive @@ -7,22 +7,22 @@ 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 -yqq > /dev/null && apt-get install -yqq git \ - php8.3-cli php8.3-mysql php8.3-mbstring php8.3-xml php8.3-curl > /dev/null + php8.4-cli php8.4-mysql php8.4-mbstring php8.4-xml php8.4-curl > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -RUN apt-get install -y php-pear php8.3-dev libevent-dev > /dev/null -RUN pecl install event-3.0.8 > /dev/null && echo "extension=event.so" > /etc/php/8.3/cli/conf.d/event.ini +RUN apt-get install -y php-pear php8.4-dev libevent-dev > /dev/null +RUN pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.4/cli/conf.d/event.ini -COPY deploy/conf/cli-php.ini /etc/php/8.3/cli/php.ini +COPY deploy/conf/cli-php.ini /etc/php/8.4/cli/conf.d/20-adapterman.ini -ADD ./ /slim WORKDIR /slim +COPY --link . . EXPOSE 8080 RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet -RUN composer require joanhey/adapterman:^0.6 --quiet +RUN composer require joanhey/adapterman:^0.7 --quiet RUN sed -i 's|$app->run(); //| //$app->run(); //|g' index.php diff --git a/frameworks/PHP/slim/slim.dockerfile b/frameworks/PHP/slim/slim.dockerfile index 90c81c6deb6..c81bf1e051f 100644 --- a/frameworks/PHP/slim/slim.dockerfile +++ b/frameworks/PHP/slim/slim.dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:22.04 +FROM ubuntu:24.04 ARG DEBIAN_FRONTEND=noninteractive @@ -7,16 +7,16 @@ 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 install -yqq nginx git unzip \ - php8.3 php8.3-common php8.3-cli php8.3-fpm php8.3-mysql php8.3-xml php8.3-curl > /dev/null + php8.4 php8.4-common php8.4-cli php8.4-fpm php8.4-mysql php8.4-xml php8.4-curl > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -COPY deploy/conf/* /etc/php/8.3/fpm/ +COPY deploy/conf/* /etc/php/8.4/fpm/ -ADD ./ /slim WORKDIR /slim +COPY --link . . -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.3/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.4/fpm/php-fpm.conf ; fi; RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet @@ -24,5 +24,5 @@ RUN chmod -R 777 /slim EXPOSE 8080 -CMD service php8.3-fpm start && \ +CMD service php8.4-fpm start && \ nginx -c /slim/deploy/nginx.conf diff --git a/frameworks/PHP/spiral/.env b/frameworks/PHP/spiral/.env index 99b475a0bef..c515771e507 100644 --- a/frameworks/PHP/spiral/.env +++ b/frameworks/PHP/spiral/.env @@ -1,4 +1,5 @@ # Debug mode disabled view cache and enabled higher verbosity. +APP_ENV=prod DEBUG=false DB_DSN=mysql:host=tfb-database:3306;charset=utf8;dbname=hello_world;user=benchmarkdbuser;password=benchmarkdbpass diff --git a/frameworks/PHP/spiral/.rr.yaml b/frameworks/PHP/spiral/.rr.yaml index 392e5df92b4..f4b6753ca6f 100644 --- a/frameworks/PHP/spiral/.rr.yaml +++ b/frameworks/PHP/spiral/.rr.yaml @@ -4,6 +4,8 @@ rpc: listen: tcp://127.0.0.1:6001 server: + on_init: + command: "php app.php cycle" command: "php app.php" relay: pipes diff --git a/frameworks/PHP/spiral/app.php b/frameworks/PHP/spiral/app.php index 0aa75e9826e..0f747f19b01 100644 --- a/frameworks/PHP/spiral/app.php +++ b/frameworks/PHP/spiral/app.php @@ -3,16 +3,25 @@ declare(strict_types=1); use App\App; +use Spiral\Core\Container; +use Spiral\Core\Options; \mb_internal_encoding('UTF-8'); -\error_reporting(E_ALL | E_STRICT ^ E_DEPRECATED); +\error_reporting(E_ALL ^ E_DEPRECATED); \ini_set('display_errors', 'stderr'); // Register Composer's auto loader. require __DIR__ . '/vendor/autoload.php'; // Initialize shared container, bindings, directories and etc. -$app = App::create(directories: ['root' => __DIR__])->run(); +$options = new Options(); +$options->validateArguments = false; +$options->allowSingletonsRebinding = true; +$container = new Container(options: $options); +$app = App::create( + directories: ['root' => __DIR__], + container: $container, +)->run(); if ($app === null) { exit(255); diff --git a/frameworks/PHP/spiral/app/config/cycle.php b/frameworks/PHP/spiral/app/config/cycle.php new file mode 100644 index 00000000000..773081decb6 --- /dev/null +++ b/frameworks/PHP/spiral/app/config/cycle.php @@ -0,0 +1,52 @@ + [ + /** + * true (Default) - Schema will be stored in a cache after compilation. + * It won't be changed after entity modification. Use `php app.php cycle` to update schema. + * + * false - Schema won't be stored in a cache after compilation. + * It will be automatically changed after entity modification. (Development mode) + */ + 'cache' => true, + + /** + * The CycleORM provides the ability to manage default settings for + * every schema with not defined segments + */ + 'defaults' => [ + SchemaInterface::MAPPER => \Cycle\ORM\Mapper\Mapper::class, + SchemaInterface::REPOSITORY => \Cycle\ORM\Select\Repository::class, + SchemaInterface::SCOPE => null, + SchemaInterface::TYPECAST_HANDLER => [ + \Cycle\ORM\Parser\Typecast::class + ], + ], + + 'collections' => [ + 'default' => 'array', + 'factories' => [ + 'array' => new \Cycle\ORM\Collection\ArrayCollectionFactory(), + // 'doctrine' => new \Cycle\ORM\Collection\DoctrineCollectionFactory(), + // 'illuminate' => new \Cycle\ORM\Collection\IlluminateCollectionFactory(), + ], + ], + + /** + * Schema generators (Optional) + * null (default) - Will be used schema generators defined in bootloaders + */ + 'generators' => null, + ], + + /** + * Prepare all internal ORM services (mappers, repositories, typecasters...) + */ + 'warmup' => \env('RR_MODE') !== null, +]; diff --git a/frameworks/PHP/spiral/app/src/App.php b/frameworks/PHP/spiral/app/src/App.php index b40bd257aa5..ffd8ebdf8ab 100644 --- a/frameworks/PHP/spiral/app/src/App.php +++ b/frameworks/PHP/spiral/app/src/App.php @@ -31,14 +31,7 @@ class App extends Kernel */ protected const LOAD = [ // Core Services - Bootloader\DebugBootloader::class, Bootloader\SnapshotsBootloader::class, - - // Security and validation - Bootloader\Security\EncrypterBootloader::class, - Bootloader\Security\FiltersBootloader::class, - Bootloader\Security\GuardBootloader::class, - RoadRunnerBridge\HttpBootloader::class, // HTTP extensions @@ -59,8 +52,6 @@ class App extends Kernel // Template engine Stempler\StemplerBootloader::class, - Scaffolder\ScaffolderBootloader::class, - // Framework commands Bootloader\CommandBootloader::class, RoadRunnerBridge\CommandBootloader::class, diff --git a/frameworks/PHP/spiral/composer.json b/frameworks/PHP/spiral/composer.json index 815b273af96..6246e74b539 100644 --- a/frameworks/PHP/spiral/composer.json +++ b/frameworks/PHP/spiral/composer.json @@ -16,14 +16,6 @@ "spiral/roadrunner-bridge": "^3.0", "spiral/roadrunner-cli": "^2.4" }, - "scripts": { - "post-create-project-cmd": [ - "php -r \"copy('.env.sample', '.env');\"", - "php app.php encrypt:key -m .env", - "php app.php configure -vv", - "rr get-binary --quiet" - ] - }, "autoload": { "psr-4": { "App\\": "app/src/" diff --git a/frameworks/PHP/spiral/php/install-composer.sh b/frameworks/PHP/spiral/php/install-composer.sh deleted file mode 100644 index f8e743d6a13..00000000000 --- a/frameworks/PHP/spiral/php/install-composer.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/sh - -EXPECTED_SIGNATURE="$(curl -s https://composer.github.io/installer.sig)" -php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" -ACTUAL_SIGNATURE="$(php -r "echo hash_file('SHA384', 'composer-setup.php');")" - -if [ "$EXPECTED_SIGNATURE" != "$ACTUAL_SIGNATURE" ] -then - >&2 echo 'ERROR: Invalid installer signature' - rm composer-setup.php - exit 1 -fi - -php composer-setup.php --quiet -RESULT=$? -rm composer-setup.php -exit $RESULT \ No newline at end of file diff --git a/frameworks/PHP/spiral/php/php.ini b/frameworks/PHP/spiral/php/php.ini index 11fcf3af36e..6270be627e7 100644 --- a/frameworks/PHP/spiral/php/php.ini +++ b/frameworks/PHP/spiral/php/php.ini @@ -1909,6 +1909,11 @@ opcache.huge_code_pages=1 ; SSL stream context option. ;openssl.capath= + + +opcache.jit_buffer_size=128M +opcache.jit=tracing + ; Local Variables: ; tab-width: 4 ; End: \ No newline at end of file diff --git a/frameworks/PHP/spiral/spiral.dockerfile b/frameworks/PHP/spiral/spiral.dockerfile index 3b8656690de..22f390d0e49 100644 --- a/frameworks/PHP/spiral/spiral.dockerfile +++ b/frameworks/PHP/spiral/spiral.dockerfile @@ -1,25 +1,28 @@ -FROM php:8.2.0-cli +FROM php:8.4-cli -RUN docker-php-ext-install pdo_mysql > /dev/null +RUN apt-get update -yqq > /dev/null && apt-get install -yqq git unzip > /dev/null +COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer + +RUN docker-php-ext-install \ + opcache \ + pdo_mysql \ + sockets > /dev/null -# Workaround solution for installing ext-sockets for PHP 8.0 -# See https://github.com/docker-library/php/issues/1245 -RUN CFLAGS="$CFLAGS -D_GNU_SOURCE" docker-php-ext-install sockets > /dev/null +# RoadRunner >= 2024.x.x requires protobuf extensions to be installed +ARG PROTOBUF_VERSION="4.30.1" +RUN pecl channel-update pecl.php.net +RUN MAKEFLAGS="-j $(nproc)" pecl install protobuf-${PROTOBUF_VERSION} > /dev/null -ADD ./ /spiral WORKDIR /spiral +COPY --link . . # composer and opcache settings -COPY php/* /usr/local/etc/php/ -RUN chmod +x /usr/local/etc/php/install-composer.sh && /usr/local/etc/php/install-composer.sh - -# install dependencies -RUN apt-get update -yqq > /dev/null && apt-get install -yqq git unzip > /dev/null -RUN php composer.phar install --optimize-autoloader --classmap-authoritative --no-dev +COPY --link php/php.ini /usr/local/etc/php/ +RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet # pre-configure RUN ./vendor/bin/rr get-binary > /dev/null 2>&1 -RUN php app.php configure > /dev/null 2>&1 +RUN php app.php configure EXPOSE 8080 diff --git a/frameworks/PHP/sw-fw-less/.env b/frameworks/PHP/sw-fw-less/.env deleted file mode 100644 index a1f35255fd2..00000000000 --- a/frameworks/PHP/sw-fw-less/.env +++ /dev/null @@ -1,8 +0,0 @@ -## MySQL -MYSQL_DSN="mysql:dbname=hello_world;host=tfb-database;port=3306" -MYSQL_USERNAME=benchmarkdbuser -MYSQL_PASSWD=benchmarkdbpass -MYSQL_POOL_SIZE=10 -MYSQL_SWITCH=1 -MYSQL_POOL_CHANGE_EVENT=0 -MYSQL_REPORT_POOL_CHANGE=0 \ No newline at end of file diff --git a/frameworks/PHP/sw-fw-less/.gitignore b/frameworks/PHP/sw-fw-less/.gitignore deleted file mode 100644 index 588e36cc131..00000000000 --- a/frameworks/PHP/sw-fw-less/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -/vendor/ -/.idea -/.idea/ -/runtime -/runtime/ -/composer.lock \ No newline at end of file diff --git a/frameworks/PHP/sw-fw-less/README.md b/frameworks/PHP/sw-fw-less/README.md deleted file mode 100644 index 949cce2368e..00000000000 --- a/frameworks/PHP/sw-fw-less/README.md +++ /dev/null @@ -1,51 +0,0 @@ -# [Sw-Fw-Less](https://github.com/luoxiaojun1992/sw-fw-less) Benchmarking Test - -This is the [Sw-Fw-Less](https://github.com/luoxiaojun1992/sw-fw-less) portion of a [benchmarking test suite](../) comparing a variety of web development platforms. - -### JSON Encoding Test - -* [JSON test source](app/services/TestService.php) - -### Plaintext Test - -* [Plaintext test source](app/services/TestService.php) - -### Data-Store/Database Mapping Test - -* [DB test controller](app/services/TestService.php) -* [DB test model](app/models/World.php) - -### Fortunes Test -* [Fortunes test controller](app/services/TestService.php) -* [Fortunes test model](app/models/Fortune.php) - - -## Infrastructure Software Versions -The tests were run with: -* [PHP 7.4](https://www.php.net/) -* [Swoole v4.5.6](https://www.swoole.com/) - -## Test URLs -### JSON Encoding Test - -http://localhost:9501/json - -### Plaintext Test - -http://localhost:9501/plaintext - -### Data-Store/Database Mapping Test - -http://localhost:9501/db - -### Variable Query Test - -http://localhost:9501/queries/2 - -### Data Updates Test - -http://localhost:9501/updates/2 - -### Fortunes Test - -http://localhost:9501/fortunes diff --git a/frameworks/PHP/sw-fw-less/app/models/Fortune.php b/frameworks/PHP/sw-fw-less/app/models/Fortune.php deleted file mode 100644 index 50d37a727b5..00000000000 --- a/frameworks/PHP/sw-fw-less/app/models/Fortune.php +++ /dev/null @@ -1,10 +0,0 @@ - 'Hello, World!']; - } - - public function db() - { - $world = World::select()->cols(['*'])->where('`id` = :id') - ->bindValue(':id', random_int(1, 10000)) - ->first(); - - return $world ? $world->toArray() : []; - } - - public function queries($queries = 1) - { - $queries = $this->clamp($queries); - - $rows = []; - while ($queries--) { - $row = World::select()->cols(['*'])->where('`id` = :id') - ->bindValue(':id', random_int(1, 10000)) - ->first(); - $rows[] = $row ? $row->toArray() : []; - } - - return $rows; - } - - public function fortunes() - { - $rows = Fortune::select()->cols(['*'])->get(); - - $insert = new Fortune(); - $insert->id = 0; - $insert->message = 'Additional fortune added at request time.'; - - $rows[] = $insert; - - usort($rows, function ($left, $right) { - return strcmp($left->message, $right->message); - }); - - return Response::output($this->renderFortunes($rows), 200, ['Content-Type' => 'text/html;charset=utf-8']); - } - - private function renderFortunes($fortunes) - { - $html = << - -Fortunes - - - - - %s -
idmessage
- - -EOF; - - $fortuneRows = ''; - foreach ($fortunes as $fortune) { - $fortuneRows .= ' ' . htmlspecialchars($fortune->id) . - '' . htmlspecialchars($fortune->message) . '' . PHP_EOL; - } - - return sprintf($html, $fortuneRows); - } - - public function updates($queries = 1) - { - $queries = $this->clamp($queries); - - $rows = []; - - while ($queries--) { - $row = World::select()->cols(['*'])->where('`id` = :id') - ->bindValue(':id', random_int(1, 10000)) - ->first(); - if ($row) { - $row->randomNumber = random_int(1, 10000); - $row->save(); - - $rows[] = $row->toArray(); - } else { - $rows[] = []; - } - } - - return $rows; - } - - public function plaintext() - { - return Response::output('Hello, World!', 200, ['Content-Type' => 'text/plain']); - } - - private function clamp($value): int - { - if (! is_numeric($value) || $value < 1) { - return 1; - } - if ($value > 500) { - return 500; - } - return (int)$value; - } -} diff --git a/frameworks/PHP/sw-fw-less/benchmark_config.json b/frameworks/PHP/sw-fw-less/benchmark_config.json deleted file mode 100755 index 5274a2a7268..00000000000 --- a/frameworks/PHP/sw-fw-less/benchmark_config.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "framework": "sw-fw-less", - "tests": [ - { - "default": { - "json_url": "/json", - "db_url": "/db", - "query_url": "/queries/", - "fortune_url": "/fortunes", - "update_url": "/updates/", - "plaintext_url": "/plaintext", - "port": 9501, - "approach": "Realistic", - "classification": "Micro", - "database": "MySQL", - "framework": "Sw-Fw-Less", - "language": "PHP", - "flavor": "None", - "orm": "Full", - "platform": "swoole", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "Sw-Fw-Less", - "notes": "", - "versus": "swoole", - "tags": ["broken"] - } - } - ] -} diff --git a/frameworks/PHP/sw-fw-less/composer.json b/frameworks/PHP/sw-fw-less/composer.json deleted file mode 100644 index 90e38601f9a..00000000000 --- a/frameworks/PHP/sw-fw-less/composer.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "name": "luoxiaojun/sw-fw-less-app", - "description": "Swoole Http Server App", - "type": "project", - "keywords": [ - "swoole", - "framework", - "coroutine", - "php", - "app" - ], - "require": { - "php": ">=7.1", - "ext-json": "*", - "ext-pdo": "*", - "ext-swoole": ">=4.4.0", - "luoxiaojun/sw-fw-less": "dev-master" - }, - "suggest": { - "ext-redis": "*" - }, - "license": "apache-2.0", - "authors": [ - { - "name": "luoxiaojun", - "email": "luoxiaojun1992@sina.cn" - } - ], - "autoload": { - "psr-4": {"App\\": "app/"} - }, - "scripts": { - "post-root-package-install": [ - "@php -r \"file_exists('.env') || copy('.env.example', '.env');\"" - ] - }, - "config": { - "sort-packages": true, - "optimize-autoloader": true, - "preferred-install": "dist" - }, - "minimum-stability": "dev", - "prefer-stable": true -} diff --git a/frameworks/PHP/sw-fw-less/config.toml b/frameworks/PHP/sw-fw-less/config.toml deleted file mode 100644 index 4c03bee7d3d..00000000000 --- a/frameworks/PHP/sw-fw-less/config.toml +++ /dev/null @@ -1,19 +0,0 @@ -[framework] -name = "sw-fw-less" - -[main] -urls.plaintext = "/plaintext" -urls.json = "/json" -urls.db = "/db" -urls.query = "/queries/" -urls.update = "/updates/" -urls.fortune = "/fortunes" -approach = "Realistic" -classification = "Micro" -database = "MySQL" -database_os = "Linux" -os = "Linux" -orm = "Full" -platform = "swoole" -webserver = "None" -versus = "swoole" diff --git a/frameworks/PHP/sw-fw-less/config/app.php b/frameworks/PHP/sw-fw-less/config/app.php deleted file mode 100644 index 9c497c3b7af..00000000000 --- a/frameworks/PHP/sw-fw-less/config/app.php +++ /dev/null @@ -1,88 +0,0 @@ - [ - 'origin' => env('CORS_ORIGIN', ''), - 'switch' => envInt('CORS_SWITCH', 0), - ], - - //Timezone - 'timezone' => env('TIMEZONE', null), - - //Monitor - 'monitor' => [ - 'switch' => envInt('MONITOR_SWITCH', 0), - ], - - //Throttle - 'throttle' => [ - 'metric' => function(\SwFwLess\components\http\Request $request){ - return $request->getRoute(); - }, - 'period' => envInt('THROTTLE_PERIOD', 60), - 'throttle' => envInt('THROTTLE_THROTTLE', 10000), - ], - - //RedLock - 'red_lock' => [ - 'connection' => env('RED_LOCK_CONNECTION', 'red_lock'), - ], - - //RateLimit - 'rate_limit' => [ - 'connection' => env('RATE_LIMIT_CONNECTION', 'rate_limit'), - ], - - //Cache - 'cache' => [ - 'connection' => env('CACHE_CONNECTION', 'cache'), //redis connection - 'update_lock_ttl' => envInt('CACHE_UPDATE_LOCK_TTL', 10), - ], - - //Hot Reload - 'hot_reload' => [ - 'switch' => envInt('HOT_RELOAD_SWITCH', 0), - 'watch_dirs' => [ - __DIR__ . '/', - __DIR__ . '/../app/', - __DIR__ . '/../vendor/', - __DIR__ . '/../', - ], - 'excluded_dirs' => [], - 'watch_suffixes' => ['.php', '.env'], - 'driver' => env('HOT_RELOAD_DRIVER', \Kwf\FileWatcher\Watcher::class), //HuangYi\Watcher\Watcher::class is another choice - ], - - //Error handler - 'error_handler' => [ - 'err_formatter' => function (\Throwable $e) { - return nl2br($e->getMessage() . PHP_EOL . $e->getTraceAsString()); - }, - ], - - //Ip Restriction - 'ip_restriction' => [ - 'ips' => env('IP_RESTRICTION_IPS'), - 'api_prefix' => env('IP_RESTRICTION_API_PREFIX'), - ], - - //Scheduler - 'scheduler' => [ -// [ -// 'schedule' => '* * * * *', -// 'jobs' => function () { -// echo 'Every minute', PHP_EOL; -// }, -// ], -// [ -// 'schedule' => '*/2 * * * *', -// 'jobs' => function () { -// echo 'Every two minutes', PHP_EOL; -// }, -// ], - ], - - //You can turn off the switch to improve the performance - 'route_di_switch' => envBool('ROUTE_DI_SWITCH', false), -]; diff --git a/frameworks/PHP/sw-fw-less/config/coroutine.php b/frameworks/PHP/sw-fw-less/config/coroutine.php deleted file mode 100644 index ca102cdcbcc..00000000000 --- a/frameworks/PHP/sw-fw-less/config/coroutine.php +++ /dev/null @@ -1,6 +0,0 @@ - envInt('COROUTINE_PREEMPTIVE_SCHEDULER', 0), - 'hook_flags' => SWOOLE_HOOK_ALL, -]; diff --git a/frameworks/PHP/sw-fw-less/config/events.php b/frameworks/PHP/sw-fw-less/config/events.php deleted file mode 100644 index c81f2ce7605..00000000000 --- a/frameworks/PHP/sw-fw-less/config/events.php +++ /dev/null @@ -1,40 +0,0 @@ - [ - function (\Cake\Event\Event $event) { - $count = $event->getData('count'); - - if (\SwFwLess\components\Config::get('redis.report_pool_change')) { - \SwFwLess\components\swoole\counter\Counter::incr('monitor:pool:redis', $count); - } - }, - ], - \SwFwLess\components\mysql\MysqlPool::EVENT_MYSQL_POOL_CHANGE => [ - function (\Cake\Event\Event $event) { - $count = $event->getData('count'); - - if (\SwFwLess\components\Config::get('mysql.report_pool_change')) { - \SwFwLess\components\swoole\counter\Counter::incr('monitor:pool:mysql', $count); - } - }, - ], - \SwFwLess\components\amqp\ConnectionPool::EVENT_AMQP_POOL_CHANGE => [ - function (\Cake\Event\Event $event) { - $count = $event->getData('count'); - - if (\SwFwLess\components\Config::get('amqp.report_pool_change')) { - \SwFwLess\components\swoole\counter\Counter::incr('monitor:pool:amqp', $count); - } - }, - ], - \SwFwLess\components\hbase\HbasePool::EVENT_HBASE_POOL_CHANGE => [ - function (\Cake\Event\Event $event) { - $count = $event->getData('count'); - - if (\SwFwLess\components\Config::get('hbase.report_pool_change')) { - \SwFwLess\components\swoole\counter\Counter::incr('monitor:pool:hbase', $count); - } - }, - ], -]; diff --git a/frameworks/PHP/sw-fw-less/config/log.php b/frameworks/PHP/sw-fw-less/config/log.php deleted file mode 100644 index 3e3a8b8f500..00000000000 --- a/frameworks/PHP/sw-fw-less/config/log.php +++ /dev/null @@ -1,11 +0,0 @@ - env('LOG_PATH', __DIR__ . '/../runtime/logs/app-{date}.log'), - 'level' => envInt('LOG_LEVEL', \Monolog\Logger::DEBUG), - 'pool_size' => envInt('LOG_POOL_SIZE', 100), - 'buffer_max_size' => envInt('LOG_BUFFER_MAX_SIZE', 10), - 'name' => env('LOG_NAME', 'sw-fw-less'), - 'reserve_days' => envInt('LOG_RESERVE_DAYS', 3), - 'switch' => envInt('LOG_SWITCH', 0), -]; diff --git a/frameworks/PHP/sw-fw-less/config/middleware.php b/frameworks/PHP/sw-fw-less/config/middleware.php deleted file mode 100644 index bc4dc44ae4c..00000000000 --- a/frameworks/PHP/sw-fw-less/config/middleware.php +++ /dev/null @@ -1,18 +0,0 @@ - [ -// \SwFwLess\components\zipkin\Middleware::class, -// \SwFwLess\components\chaos\Middleware::class, -// \SwFwLess\middlewares\Cors::class, -// \SwFwLess\components\auth\Middleware::class, -// \SwFwLess\middlewares\IpRestriction::class, - ], - 'routeMiddleware' => [ -// \SwFwLess\components\ratelimit\Middleware::class, - ], - 'aliases' => [ - 'cors' => \SwFwLess\middlewares\Cors::class, - 'auth' => \SwFwLess\components\auth\Middleware::class, - ], -]; diff --git a/frameworks/PHP/sw-fw-less/config/mysql.php b/frameworks/PHP/sw-fw-less/config/mysql.php deleted file mode 100644 index 33d4d727ea8..00000000000 --- a/frameworks/PHP/sw-fw-less/config/mysql.php +++ /dev/null @@ -1,23 +0,0 @@ - env('MYSQL_DEFAULT', 'default'), - 'connections' => [ - env('MYSQL_DEFAULT', 'default') => [ - 'dsn' => env('MYSQL_DSN', 'mysql:dbname=sw_test;host=127.0.0.1'), - 'username' => env('MYSQL_USERNAME', 'root'), - 'passwd' => env('MYSQL_PASSWD', null), - 'options' => [ - \PDO::ATTR_CASE => \PDO::CASE_NATURAL, - \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION, - \PDO::ATTR_ORACLE_NULLS => \PDO::NULL_NATURAL, - \PDO::ATTR_STRINGIFY_FETCHES => false, - \PDO::ATTR_EMULATE_PREPARES => false, - ], - 'pool_size' => envInt('MYSQL_POOL_SIZE', 5), - ], - ], - 'switch' => envInt('MYSQL_SWITCH', 0), - 'pool_change_event' => envInt('MYSQL_POOL_CHANGE_EVENT', 0), - 'report_pool_change' => envInt('MYSQL_REPORT_POOL_CHANGE', 0), -]; diff --git a/frameworks/PHP/sw-fw-less/config/providers.php b/frameworks/PHP/sw-fw-less/config/providers.php deleted file mode 100644 index 8e885a94ac4..00000000000 --- a/frameworks/PHP/sw-fw-less/config/providers.php +++ /dev/null @@ -1,30 +0,0 @@ - [ - ['GET', '/json', [TestService::class, 'json']], - ['GET', '/db', [TestService::class, 'db']], - ['GET', '/queries/[{queries}]', [TestService::class, 'queries']], - ['GET', '/fortunes', [TestService::class, 'fortunes']], - ['GET', '/updates/[{queries}]', [TestService::class, 'updates']], - ['GET', '/plaintext', [TestService::class, 'plaintext']], - ], - 'group' => [], -]; diff --git a/frameworks/PHP/sw-fw-less/config/server.php b/frameworks/PHP/sw-fw-less/config/server.php deleted file mode 100644 index c90bd44d5fc..00000000000 --- a/frameworks/PHP/sw-fw-less/config/server.php +++ /dev/null @@ -1,23 +0,0 @@ - env('SERVER_HOST', '0.0.0.0'), - 'port' => envInt('SERVER_PORT', 9501), - 'worker_num' => envInt('SERVER_WORKER_NUM', swoole_cpu_num() * 2), - 'daemonize' => envBool('SERVER_DAEMONIZE', false), - 'backlog' => envInt('SERVER_BACKLOG', 128), - 'max_request' => envInt('SERVER_MAX_REQUEST', 0), - 'dispatch_mode' => envInt('SERVER_DISPATCH_MODE', 2), - 'open_http2_protocol' => envBool('SERVER_OPEN_HTTP2', false), - 'task_worker_num' => envInt('SERVER_TASK_WORKER_NUM', 0), - 'task_enable_coroutine' => envBool('SERVER_TASK_ENABLE_COROUTINE', false), - 'open_tcp_nodelay' => envBool('SERVER_OPEN_TCP_NODELAY', true), - 'max_coroutine' => envInt('SERVER_MAX_COROUTINE', 1000000), - 'socket_buffer_size' => envInt('SERVER_SOCKET_BUFFER_SIZE', 2 * 1024 * 1024), -]; - -if (!empty($pidFile = env('SERVER_PID_FILE'))) { - $serverConfig['pid_file'] = $pidFile; -} - -return $serverConfig; diff --git a/frameworks/PHP/sw-fw-less/start.php b/frameworks/PHP/sw-fw-less/start.php deleted file mode 100644 index b5b58592280..00000000000 --- a/frameworks/PHP/sw-fw-less/start.php +++ /dev/null @@ -1,12 +0,0 @@ -run(); diff --git a/frameworks/PHP/sw-fw-less/sw-fw-less.dockerfile b/frameworks/PHP/sw-fw-less/sw-fw-less.dockerfile deleted file mode 100644 index 6cd83a9597f..00000000000 --- a/frameworks/PHP/sw-fw-less/sw-fw-less.dockerfile +++ /dev/null @@ -1,33 +0,0 @@ -FROM php:7.4 - -RUN pecl install swoole > /dev/null && \ - docker-php-ext-enable swoole - -RUN docker-php-ext-install pdo_mysql > /dev/null - -RUN apt -yqq update > /dev/null && \ - apt -yqq install git unzip > /dev/null - -# Composer -RUN curl -sS https://getcomposer.org/installer | php \ - && mv composer.phar /usr/local/bin/composer \ - && composer self-update --clean-backups - -# Bcmath extension required by amqp composer package -RUN docker-php-ext-install bcmath > /dev/null - -# Sockets extension -RUN docker-php-ext-install sockets > /dev/null - -ADD . /var/www/sw-fw-less - -WORKDIR /var/www/sw-fw-less - -RUN composer install --no-dev --quiet > /dev/null \ - && composer dump-autoload -o - -EXPOSE 9501 - -ENTRYPOINT ["php", "/var/www/sw-fw-less/start.php"] - -LABEL luoxiaojun1992 \ No newline at end of file diff --git a/frameworks/PHP/swoole/10-opcache.ini b/frameworks/PHP/swoole/10-opcache.ini new file mode 100644 index 00000000000..bc77a43761e --- /dev/null +++ b/frameworks/PHP/swoole/10-opcache.ini @@ -0,0 +1,10 @@ +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/database.php b/frameworks/PHP/swoole/database.php index 6a7cdb3c1ea..a0c15234921 100644 --- a/frameworks/PHP/swoole/database.php +++ b/frameworks/PHP/swoole/database.php @@ -15,20 +15,20 @@ class Operation public static function db(PDOStatement|PDOStatementProxy $db): string { $db->execute([mt_rand(1, 10000)]); - return json_encode($db->fetch(PDO::FETCH_ASSOC), JSON_NUMERIC_CHECK); + return json_encode($db->fetch(PDO::FETCH_ASSOC)); } public static function fortunes(PDOStatement|PDOStatementProxy $fortune): string { $fortune->execute(); - $results = $fortune->fetchAll(PDO::FETCH_KEY_PAIR); + $results = $fortune->fetchAll(PDO::FETCH_KEY_PAIR); $results[0] = 'Additional fortune added at request time.'; asort($results); $html = ''; foreach ($results as $id => $message) { $message = htmlspecialchars($message, ENT_QUOTES, 'UTF-8'); - $html .= "$id$message"; + $html .= "$id$message"; } return "Fortunes$html
idmessage
"; @@ -36,47 +36,47 @@ public static function fortunes(PDOStatement|PDOStatementProxy $fortune): string public static function query(PDOStatement|PDOStatementProxy $query, int $queries): string { - $query_count = 1; - if ($queries > 1) { - $query_count = min($queries, 500); - } - $results = []; - while ($query_count--) { + while ($queries--) { $query->execute([mt_rand(1, 10000)]); $results[] = $query->fetch(PDO::FETCH_ASSOC); } - return json_encode($results, JSON_NUMERIC_CHECK); + return json_encode($results); } - public static function updates(PDOStatement|PDOStatementProxy $random, PDOStatement|PDOStatementProxy $update, int $queries): string + public static function updates(PDOStatement|PDOStatementProxy $random, PDOStatement|PDOStatementProxy $update, int $queries, string $driver): string { - $query_count = 1; - if ($queries > 1) { - $query_count = min($queries, 500); - } + $results = $keys = $values = []; + while ($queries--) { + $random->execute([mt_rand(1, 10000)]); + $item = $random->fetch(PDO::FETCH_ASSOC); + $item['randomNumber'] = mt_rand(1, 10000); + $results[] = $item; - $results = []; - while ($query_count--) { - $id = mt_rand(1, 10000); - $random->execute([$id]); - $item = $random->fetch(PDO::FETCH_ASSOC); - $update->execute([$item['randomNumber'] = mt_rand(1, 10000), $id]); - - $results[] = $item; + if ($driver == 'pgsql') { + $values[] = $keys[] = $item['id']; + $values[] = $item['randomNumber']; + } else { + $update->execute([$item['randomNumber'], $item['id']]); + } } - return json_encode($results, JSON_NUMERIC_CHECK); + if ($driver == 'pgsql') { + $update->execute([...$values, ...$keys]); + } + return json_encode($results); } } class Connection { + private static PDO $pdo; + private static string $driver; + private static array $updates = []; private static PDOStatement $db; private static PDOStatement $fortune; private static PDOStatement $random; - private static PDOStatement $update; private static PDOStatement $query; public static function init(string $driver): void @@ -87,15 +87,16 @@ public static function init(string $driver): void "benchmarkdbpass", [ PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, - PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, - PDO::ATTR_EMULATE_PREPARES => false + PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, + PDO::ATTR_EMULATE_PREPARES => false ] ); - self::$db = self::$random = self::$query = $pdo->prepare(Operation::WORLD_SELECT_SQL); + self::$db = self::$random = self::$query = $pdo->prepare(Operation::WORLD_SELECT_SQL); self::$fortune = $pdo->prepare(Operation::FORTUNE_SQL); - self::$update = $pdo->prepare(Operation::WORLD_UPDATE_SQL); + self::$pdo = $pdo; + self::$driver = $driver; } public static function db(): string @@ -115,13 +116,20 @@ public static function query(int $queries): string public static function updates(int $queries): string { - return Operation::updates(self::$random, self::$update, $queries); + if (!isset(self::$updates[$queries])) { + self::$updates[$queries] = self::$driver == 'pgsql' + ? self::$pdo->prepare('UPDATE World SET randomNumber = CASE id'.\str_repeat(' WHEN ?::INTEGER THEN ?::INTEGER ', $queries).'END WHERE id IN ('.\str_repeat('?::INTEGER,', $queries - 1).'?::INTEGER)') + : self::$pdo->prepare(Operation::WORLD_UPDATE_SQL); + } + + return Operation::updates(self::$random, self::$updates[$queries], $queries, self::$driver); } } class Connections { private static PDOPool $pool; + private static string $driver; public static function init(string $driver): void { @@ -133,22 +141,22 @@ public static function init(string $driver): void ->withUsername('benchmarkdbuser') ->withPassword('benchmarkdbpass'); - self::$pool = new PDOPool($config, intval(1024 / swoole_cpu_num())); + self::$pool = new PDOPool($config, intval(1400 / swoole_cpu_num())); + self::$driver = $driver; } public static function db(): string { - $pdo = self::get(); - $result = Operation::db($pdo->prepare(Operation::WORLD_SELECT_SQL)); + $pdo = self::get(); + $result = Operation::db(self::getStatement($pdo, 'select')); self::put($pdo); - return $result; } public static function fortunes(): string { - $pdo = self::get(); - $result = Operation::fortunes($pdo->prepare(Operation::FORTUNE_SQL)); + $pdo = self::get(); + $result = Operation::fortunes(self::getStatement($pdo, 'fortunes')); self::put($pdo); return $result; @@ -156,8 +164,8 @@ public static function fortunes(): string public static function query(int $queries): string { - $pdo = self::get(); - $result = Operation::query($pdo->prepare(Operation::WORLD_SELECT_SQL), $queries); + $pdo = self::get(); + $result = Operation::query(self::getStatement($pdo, 'select'), $queries); self::put($pdo); return $result; @@ -165,8 +173,8 @@ public static function query(int $queries): string public static function updates(int $queries): string { - $pdo = self::get(); - $result = Operation::updates($pdo->prepare(Operation::WORLD_SELECT_SQL), $pdo->prepare(Operation::WORLD_UPDATE_SQL), $queries); + $pdo = self::get(); + $result = Operation::updates(self::getStatement($pdo, 'select'), self::getStatement($pdo, 'update', $queries), $queries, self::$driver); self::put($pdo); return $result; @@ -181,4 +189,17 @@ private static function put(PDO|PDOProxy $db): void { self::$pool->put($db); } + + private static function getStatement(PDO|PDOProxy $pdo, string $type, int $queries = 0): PDOStatement|PDOStatementProxy + { + if ('select' == $type) { + return $pdo->prepare(Operation::WORLD_SELECT_SQL); + } elseif ('fortunes' == $type) { + return $pdo->prepare(Operation::FORTUNE_SQL); + } else { + return self::$driver == 'pgsql' + ? $pdo->prepare('UPDATE World SET randomNumber = CASE id'.\str_repeat(' WHEN ?::INTEGER THEN ?::INTEGER ', $queries).'END WHERE id IN ('.\str_repeat('?::INTEGER,', $queries - 1).'?::INTEGER)') + : $pdo->prepare(Operation::WORLD_UPDATE_SQL); + } + } } diff --git a/frameworks/PHP/swoole/php.ini b/frameworks/PHP/swoole/php.ini deleted file mode 100644 index 99a548fe57e..00000000000 --- a/frameworks/PHP/swoole/php.ini +++ /dev/null @@ -1,9 +0,0 @@ -opcache.enable=1 -opcache.enable_cli=1 -opcache.validate_timestamps=0 -opcache.enable_file_override=1 -opcache.huge_code_pages=1 -memory_limit=1024M - -opcache.jit_buffer_size=128M -opcache.jit=tracing diff --git a/frameworks/PHP/swoole/swoole-async-mysql.dockerfile b/frameworks/PHP/swoole/swoole-async-mysql.dockerfile index 9b9daf07c43..632481846ba 100644 --- a/frameworks/PHP/swoole/swoole-async-mysql.dockerfile +++ b/frameworks/PHP/swoole/swoole-async-mysql.dockerfile @@ -1,7 +1,7 @@ -FROM ubuntu:22.04 +FROM ubuntu:24.04 -ENV SWOOLE_VERSION 5.1.1 ENV ENABLE_COROUTINE 1 +ENV CPU_MULTIPLES 1 ENV DATABASE_DRIVER mysql ARG DEBIAN_FRONTEND=noninteractive @@ -10,22 +10,18 @@ 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 php8.3-cli php8.3-pdo-mysql php8.3-dev -y > /dev/null \ - && cd /tmp && curl -sSL "https://github.com/swoole/swoole-src/archive/v${SWOOLE_VERSION}.tar.gz" | tar xzf - \ - && cd /tmp/swoole-src-${SWOOLE_VERSION} \ - && phpize > /dev/null \ - && ./configure > /dev/null \ - && make -j8 > /dev/null \ - && make install > /dev/null \ - && echo "extension=swoole.so" > /etc/php/8.3/cli/conf.d/50-swoole.ini + && 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 WORKDIR /swoole ADD ./swoole-server.php /swoole -ADD ./php.ini /swoole ADD ./database.php /swoole -RUN cat /swoole/php.ini >> /etc/php/8.3/cli/php.ini +COPY 10-opcache.ini /etc/php/8.4/cli/conf.d/10-opcache.ini EXPOSE 8080 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 d75390c922e..ed6bdd36f5d 100644 --- a/frameworks/PHP/swoole/swoole-async-postgres.dockerfile +++ b/frameworks/PHP/swoole/swoole-async-postgres.dockerfile @@ -1,7 +1,7 @@ -FROM ubuntu:22.04 +FROM ubuntu:24.04 -ENV SWOOLE_VERSION 5.1.1 ENV ENABLE_COROUTINE 1 +ENV CPU_MULTIPLES 1 ENV DATABASE_DRIVER pgsql ARG DEBIAN_FRONTEND=noninteractive @@ -10,22 +10,18 @@ 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 php8.3-cli php8.3-pdo-pgsql php8.3-dev libpq-dev -y > /dev/null \ - && cd /tmp && curl -sSL "https://github.com/swoole/swoole-src/archive/v${SWOOLE_VERSION}.tar.gz" | tar xzf - \ - && cd /tmp/swoole-src-${SWOOLE_VERSION} \ - && phpize > /dev/null \ - && ./configure --enable-swoole-pgsql > /dev/null \ - && make -j8 > /dev/null \ - && make install > /dev/null \ - && echo "extension=swoole.so" > /etc/php/8.3/cli/conf.d/50-swoole.ini + && 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 WORKDIR /swoole ADD ./swoole-server.php /swoole -ADD ./php.ini /swoole ADD ./database.php /swoole -RUN cat /swoole/php.ini >> /etc/php/8.3/cli/php.ini +COPY 10-opcache.ini /etc/php/8.4/cli/conf.d/10-opcache.ini EXPOSE 8080 CMD php /swoole/swoole-server.php diff --git a/frameworks/PHP/swoole/swoole-server.php b/frameworks/PHP/swoole/swoole-server.php index 8de85f5c0a1..38a4152476f 100644 --- a/frameworks/PHP/swoole/swoole-server.php +++ b/frameworks/PHP/swoole/swoole-server.php @@ -8,22 +8,21 @@ $enableCoroutine = getenv('ENABLE_COROUTINE') == 1; $connection = $enableCoroutine ? Connections::class : Connection::class; -$server = new Server('0.0.0.0', 8080); $setting = [ - 'worker_num' => swoole_cpu_num() * 4, + 'worker_num' => swoole_cpu_num() * ((int) getenv('CPU_MULTIPLES')), 'log_file' => '/dev/null', 'enable_coroutine' => $enableCoroutine, - 'enable_reuse_port' => true + 'enable_reuse_port' => true, + 'http_compression' => false ]; if ($enableCoroutine) { $setting['hook_flags'] = SWOOLE_HOOK_ALL; - $setting['worker_num'] = swoole_cpu_num(); } +$server = new Server('0.0.0.0', 8080); $server->set($setting); - $server->on('workerStart', function () use ($connection) { $connection::init(getenv('DATABASE_DRIVER')); }); @@ -48,16 +47,18 @@ $res->end($connection::fortunes()); break; case '/query': + $queries = isset($req->get['queries']) ? (int) $req->get['queries'] : -1; + $query_count = $queries > 1 ? min($queries, 500) : 1; + $res->header['Content-Type'] = 'application/json'; - $res->end($connection::query( - isset($req->get['queries']) ? (int) $req->get['queries'] : -1 - )); + $res->end($connection::query($query_count)); break; case '/updates': + $queries = isset($req->get['queries']) ? (int) $req->get['queries'] : -1; + $query_count = $queries > 1 ? min($queries, 500) : 1; + $res->header['Content-Type'] = 'application/json'; - $res->end($connection::updates( - isset($req->get['queries']) ? (int) $req->get['queries'] : -1 - )); + $res->end($connection::updates($query_count)); break; default: diff --git a/frameworks/PHP/swoole/swoole-sync-mysql.dockerfile b/frameworks/PHP/swoole/swoole-sync-mysql.dockerfile index 4893a1aad1a..fa92ac2d197 100644 --- a/frameworks/PHP/swoole/swoole-sync-mysql.dockerfile +++ b/frameworks/PHP/swoole/swoole-sync-mysql.dockerfile @@ -1,7 +1,7 @@ -FROM ubuntu:22.04 +FROM ubuntu:24.04 -ENV SWOOLE_VERSION 5.1.1 ENV ENABLE_COROUTINE 0 +ENV CPU_MULTIPLES 1 ENV DATABASE_DRIVER mysql ARG DEBIAN_FRONTEND=noninteractive @@ -10,22 +10,18 @@ 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 php8.3-cli php8.3-pdo-mysql php8.3-dev -y > /dev/null \ - && cd /tmp && curl -sSL "https://github.com/swoole/swoole-src/archive/v${SWOOLE_VERSION}.tar.gz" | tar xzf - \ - && cd /tmp/swoole-src-${SWOOLE_VERSION} \ - && phpize > /dev/null \ - && ./configure > /dev/null \ - && make -j8 > /dev/null \ - && make install > /dev/null \ - && echo "extension=swoole.so" > /etc/php/8.3/cli/conf.d/50-swoole.ini + && 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 WORKDIR /swoole ADD ./swoole-server.php /swoole -ADD ./php.ini /swoole ADD ./database.php /swoole -RUN cat /swoole/php.ini >> /etc/php/8.3/cli/php.ini +COPY 10-opcache.ini /etc/php/8.4/cli/conf.d/10-opcache.ini EXPOSE 8080 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 9559267ce6c..f27393f8ddd 100644 --- a/frameworks/PHP/swoole/swoole-sync-postgres.dockerfile +++ b/frameworks/PHP/swoole/swoole-sync-postgres.dockerfile @@ -1,7 +1,7 @@ -FROM ubuntu:22.04 +FROM ubuntu:24.04 -ENV SWOOLE_VERSION 5.1.1 ENV ENABLE_COROUTINE 0 +ENV CPU_MULTIPLES 4 ENV DATABASE_DRIVER pgsql ARG DEBIAN_FRONTEND=noninteractive @@ -10,22 +10,18 @@ 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 php8.3-cli php8.3-pdo-pgsql php8.3-dev libpq-dev -y > /dev/null \ - && cd /tmp && curl -sSL "https://github.com/swoole/swoole-src/archive/v${SWOOLE_VERSION}.tar.gz" | tar xzf - \ - && cd /tmp/swoole-src-${SWOOLE_VERSION} \ - && phpize > /dev/null \ - && ./configure > /dev/null \ - && make -j2 > /dev/null \ - && make install > /dev/null \ - && echo "extension=swoole.so" > /etc/php/8.3/cli/conf.d/50-swoole.ini + && 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 WORKDIR /swoole ADD ./swoole-server.php /swoole -ADD ./php.ini /swoole ADD ./database.php /swoole -RUN cat /swoole/php.ini >> /etc/php/8.3/cli/php.ini +COPY 10-opcache.ini /etc/php/8.4/cli/conf.d/10-opcache.ini EXPOSE 8080 CMD php /swoole/swoole-server.php diff --git a/frameworks/PHP/symfony/.rr.yaml b/frameworks/PHP/symfony/.rr.yaml new file mode 100644 index 00000000000..88aeb945668 --- /dev/null +++ b/frameworks/PHP/symfony/.rr.yaml @@ -0,0 +1,25 @@ +version: "3" +#https://github.com/roadrunner-server/roadrunner/blob/master/.rr.yaml + +server: + command: "php /symfony/public/runtime.php" + env: + - APP_RUNTIME: Runtime\RoadRunnerSymfonyNyholm\Runtime + +http: + address: "0.0.0.0:8080" + + middleware: ["headers"] + headers: + response: + Server: "RoadRunner" + #pool: + #num_workers: 0 + #max_jobs: 500 + +logs: + mode: production + level: error +#rpc: +# listen: tcp://127.0.0.1:6001 + diff --git a/frameworks/PHP/symfony/benchmark_config.json b/frameworks/PHP/symfony/benchmark_config.json index 2c202dbfdf1..5d37f665589 100644 --- a/frameworks/PHP/symfony/benchmark_config.json +++ b/frameworks/PHP/symfony/benchmark_config.json @@ -63,7 +63,7 @@ "webserver": "nginx", "os": "Linux", "database_os": "Linux", - "display_name": "symfony-raw", + "display_name": "symfony [raw orm]", "notes": "", "versus": "php", "tags": [] @@ -87,7 +87,7 @@ "webserver": "none", "os": "Linux", "database_os": "Linux", - "display_name": "symfony-swoole", + "display_name": "symfony [swoole]", "notes": "", "versus": "swoole", "tags": [] @@ -111,7 +111,55 @@ "webserver": "None", "os": "Linux", "database_os": "Linux", - "display_name": "symfony-workerman", + "display_name": "symfony [workerman]", + "notes": "", + "versus": "php", + "tags": [] + }, + "roadrunner": { + "plaintext_url": "/plaintext", + "json_url": "/json", + "db_url": "/db", + "update_url": "/updates?queries=", + "query_url": "/queries?queries=", + "fortune_url": "/fortunes", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "database": "Postgres", + "framework": "symfony", + "language": "PHP", + "flavor": "PHP8", + "orm": "Full", + "platform": "roadrunner", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "symfony [roadrunner]", + "notes": "", + "versus": "php", + "tags": [] + }, + "react": { + "plaintext_url": "/plaintext", + "json_url": "/json", + "db_url": "/db", + "update_url": "/updates?queries=", + "query_url": "/queries?queries=", + "fortune_url": "/fortunes", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "database": "Postgres", + "framework": "symfony", + "language": "PHP", + "flavor": "PHP8", + "orm": "Full", + "platform": "reactphp", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "symfony [react]", "notes": "", "versus": "php", "tags": [] @@ -135,7 +183,7 @@ "webserver": "caddy", "os": "Linux", "database_os": "Linux", - "display_name": "symfony-frankenphp", + "display_name": "symfony [frankenphp]", "notes": "Use php 8.2", "versus": "php", "tags": [] diff --git a/frameworks/PHP/symfony/composer.json b/frameworks/PHP/symfony/composer.json index 074ee8b8e1a..9061d99d608 100644 --- a/frameworks/PHP/symfony/composer.json +++ b/frameworks/PHP/symfony/composer.json @@ -2,18 +2,18 @@ "type": "project", "license": "proprietary", "require": { - "php": ">=8.1", + "php": ">=8.2", "ext-ctype": "*", "ext-iconv": "*", "ext-mbstring": "*", - "symfony/console": "^6", - "symfony/dotenv": "^6", + "symfony/console": "^7", + "symfony/dotenv": "^7", "symfony/flex": "^2", - "symfony/framework-bundle": "^6", + "symfony/framework-bundle": "^7", "symfony/orm-pack": "^2", - "symfony/twig-bundle": "^6", - "symfony/yaml": "^6.0", - "joanhey/adapterman": "^0.5" + "symfony/twig-bundle": "^7", + "symfony/yaml": "^7", + "joanhey/adapterman": "^0.7" }, "minimum-stability": "dev", "prefer-stable": true, @@ -41,11 +41,15 @@ "replace": { "symfony/polyfill-ctype": "*", "symfony/polyfill-iconv": "*", + "symfony/polyfill-mbstring":"*", "symfony/polyfill-php72": "*", "symfony/polyfill-php73": "*", "symfony/polyfill-php74": "*", "symfony/polyfill-php80": "*", - "symfony/polyfill-php81": "*" + "symfony/polyfill-php81": "*", + "symfony/polyfill-php82": "*", + "symfony/polyfill-php83": "*", + "symfony/polyfill-php84": "*" }, "scripts": { "auto-scripts": { @@ -65,7 +69,7 @@ "extra": { "symfony": { "allow-contrib": false, - "require": "^6", + "require": "^7", "docker": true } } diff --git a/frameworks/PHP/symfony/config/routes/annotations.yaml b/frameworks/PHP/symfony/config/routes/annotations.yaml deleted file mode 100644 index e92efc59693..00000000000 --- a/frameworks/PHP/symfony/config/routes/annotations.yaml +++ /dev/null @@ -1,7 +0,0 @@ -controllers: - resource: ../../src/Controller/ - type: annotation - -kernel: - resource: ../../src/Kernel.php - type: annotation diff --git a/frameworks/PHP/symfony/config/routes/attributes.yaml b/frameworks/PHP/symfony/config/routes/attributes.yaml new file mode 100644 index 00000000000..296cf15dacc --- /dev/null +++ b/frameworks/PHP/symfony/config/routes/attributes.yaml @@ -0,0 +1,9 @@ +controllers: + resource: + path: ../../src/Controller/ + namespace: App\Controller + type: attribute + +kernel: + resource: App\Kernel + type: attribute \ No newline at end of file diff --git a/frameworks/PHP/symfony/deploy/Caddyfile b/frameworks/PHP/symfony/deploy/Caddyfile index 56f20d882a2..6faa66909af 100644 --- a/frameworks/PHP/symfony/deploy/Caddyfile +++ b/frameworks/PHP/symfony/deploy/Caddyfile @@ -3,7 +3,7 @@ {$CADDY_DEBUG} frankenphp { - #worker /path/to/your/worker.php + #worker /path/to/your/runtime.php {$FRANKENPHP_CONFIG} } } @@ -11,18 +11,13 @@ :8080 route { - root * /symfony/public - # If the requested file does not exist, try index files - @indexFiles file { - try_files {path} {path}/worker.php worker.php - split_path .php + # FrankenPHP! + # disable static files for this benchmark + # by using php instead of php_server + rewrite runtime.php + php { + root /symfony/public } - rewrite @indexFiles {http.matchers.file.relative} - - # FrankenPHP! - @phpFiles path *.php - php @phpFiles - respond 404 } diff --git a/frameworks/PHP/symfony/deploy/conf/cli-php.ini b/frameworks/PHP/symfony/deploy/conf/cli-php.ini index d3dfaa8270a..e03b6e352a9 100644 --- a/frameworks/PHP/symfony/deploy/conf/cli-php.ini +++ b/frameworks/PHP/symfony/deploy/conf/cli-php.ini @@ -13,4 +13,4 @@ memory_limit = 512M opcache.jit_buffer_size = 128M opcache.jit = tracing -disable_functions=header,header_remove,http_response_code,setcookie,session_create_id,session_id,session_name,session_save_path,session_status,session_start,session_write_close,session_regenerate_id,set_time_limit +disable_functions=header,header_remove,headers_sent,headers_list,http_response_code,setcookie,session_create_id,session_id,session_name,session_save_path,session_status,session_start,session_write_close,session_regenerate_id,session_unset,session_get_cookie_params,session_set_cookie_params,set_time_limit diff --git a/frameworks/PHP/symfony/deploy/conf/php.ini b/frameworks/PHP/symfony/deploy/conf/php.ini index 0e87f1d8855..e0f3a8a6e41 100644 --- a/frameworks/PHP/symfony/deploy/conf/php.ini +++ b/frameworks/PHP/symfony/deploy/conf/php.ini @@ -1767,7 +1767,7 @@ ldap.max_links = -1 opcache.enable=1 ; Determines if Zend OPCache is enabled for the CLI version of PHP -;opcache.enable_cli=0 +opcache.enable_cli=1 ; The OPcache shared memory storage size. opcache.memory_consumption=256 diff --git a/frameworks/PHP/symfony/deploy/swoole/php.ini b/frameworks/PHP/symfony/deploy/swoole/php.ini index 5a77f55e2ad..54182323396 100644 --- a/frameworks/PHP/symfony/deploy/swoole/php.ini +++ b/frameworks/PHP/symfony/deploy/swoole/php.ini @@ -17,3 +17,6 @@ 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/public/runtime.php b/frameworks/PHP/symfony/public/runtime.php new file mode 100644 index 00000000000..c99b79378ef --- /dev/null +++ b/frameworks/PHP/symfony/public/runtime.php @@ -0,0 +1,9 @@ +count = (int) shell_exec('nproc') * 4; +$http_worker->reusePort = true; $http_worker->name = 'AdapterMan-Symfony'; $http_worker->onWorkerStart = static function () { - Header::$date = gmdate('D, d M Y H:i:s').' GMT'; + Header::$date = gmdate(DATE_RFC7231); Timer::add(1, function() { - Header::$date = gmdate('D, d M Y H:i:s').' GMT'; + Header::$date = gmdate(DATE_RFC7231); }); //init(); require __DIR__.'/start.php'; diff --git a/frameworks/PHP/symfony/symfony-franken.dockerfile b/frameworks/PHP/symfony/symfony-franken.dockerfile index 3bf0b7e3fd9..a985294ab58 100644 --- a/frameworks/PHP/symfony/symfony-franken.dockerfile +++ b/frameworks/PHP/symfony/symfony-franken.dockerfile @@ -1,31 +1,25 @@ -FROM dunglas/frankenphp +FROM dunglas/frankenphp:php8.4 # add additional extensions here: RUN install-php-extensions \ + opcache \ pdo_pgsql \ - intl \ - opcache + zip > /dev/null -RUN apt-get update -yqq > /dev/null && apt-get upgrade -yqq > /dev/null && \ - apt-get install unzip > /dev/null +COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer -COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer +COPY --link deploy/Caddyfile /etc/frankenphp/Caddyfile +COPY --link deploy/conf/php.ini /usr/local/etc/php/ -EXPOSE 8080 - -COPY deploy/Caddyfile /etc/caddy/Caddyfile - -ADD . /symfony WORKDIR /symfony +COPY --link . . -RUN mkdir -m 777 -p /symfony/var/cache/{dev,prod} /symfony/var/log - -ENV COMPOSER_ALLOW_SUPERUSER=1 -RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet --no-scripts +ENV FRANKENPHP_CONFIG="worker /symfony/public/runtime.php" +ENV APP_RUNTIME="Runtime\FrankenPhpSymfony\Runtime" +#ENV CADDY_DEBUG=debug +RUN composer require runtime/frankenphp-symfony --update-no-dev --no-scripts --quiet RUN cp deploy/postgresql/.env . && composer dump-env prod && bin/console cache:clear -RUN composer require runtime/frankenphp-symfony -ENV FRANKENPHP_CONFIG="worker ./public/worker.php" -ENV APP_RUNTIME=Runtime\\FrankenPhpSymfony\\Runtime +EXPOSE 8080 -#ENV CADDY_DEBUG=debug +RUN frankenphp -v diff --git a/frameworks/PHP/symfony/symfony-mysql.dockerfile b/frameworks/PHP/symfony/symfony-mysql.dockerfile index c6361bcacd8..a09d877ade2 100644 --- a/frameworks/PHP/symfony/symfony-mysql.dockerfile +++ b/frameworks/PHP/symfony/symfony-mysql.dockerfile @@ -1,5 +1,4 @@ -FROM composer/composer:2-bin AS composer -FROM ubuntu:22.04 +FROM ubuntu:24.04 ARG DEBIAN_FRONTEND=noninteractive @@ -8,32 +7,27 @@ 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 install -yqq nginx git unzip curl \ - php8.3-cli php8.3-fpm php8.3-mysql \ - php8.3-mbstring php8.3-xml php8.3-curl php8.3-dev > /dev/null + php8.4-cli php8.4-fpm php8.4-mysql \ + php8.4-mbstring php8.4-xml php8.4-curl > /dev/null -COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer +COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer -COPY deploy/conf/* /etc/php/8.3/fpm/ - -ADD . /symfony +COPY --link deploy/conf/* /etc/php/8.4/fpm/ WORKDIR /symfony +COPY --link . . -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.3/fpm/php-fpm.conf ; fi; - -RUN mkdir -m 777 -p /symfony/var/cache/{dev,prod} /symfony/var/log +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; -ENV COMPOSER_ALLOW_SUPERUSER=1 -RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet --no-scripts +RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --no-scripts --quiet RUN cp deploy/mysql/.env . && composer dump-env prod && bin/console cache:clear -RUN echo "opcache.preload=/symfony/var/cache/prod/App_KernelProdContainer.preload.php" >> /etc/php/8.3/fpm/php.ini - +RUN echo "opcache.preload=/symfony/var/cache/prod/App_KernelProdContainer.preload.php" >> /etc/php/8.4/fpm/php.ini EXPOSE 8080 # Uncomment next line for Laravel console error logging to be viewable in docker logs -# RUN echo "catch_workers_output = yes" >> /etc/php/8.3/fpm/php-fpm.conf +# RUN echo "catch_workers_output = yes" >> /etc/php/8.4/fpm/php-fpm.conf RUN mkdir -p /run/php -CMD service php8.3-fpm start && \ +CMD service php8.4-fpm start && \ nginx -c /symfony/deploy/nginx.conf \ No newline at end of file diff --git a/frameworks/PHP/symfony/symfony-raw.dockerfile b/frameworks/PHP/symfony/symfony-raw.dockerfile index 2957d6246c2..a2622d5a397 100644 --- a/frameworks/PHP/symfony/symfony-raw.dockerfile +++ b/frameworks/PHP/symfony/symfony-raw.dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:22.04 +FROM ubuntu:24.04 ARG DEBIAN_FRONTEND=noninteractive @@ -7,31 +7,27 @@ 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 install -yqq nginx git unzip curl \ - php8.3-cli php8.3-fpm php8.3-pgsql \ - php8.3-mbstring php8.3-xml php8.3-curl > /dev/null + php8.4-cli php8.4-fpm php8.4-pgsql \ + php8.4-mbstring php8.4-xml php8.4-curl > /dev/null -COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer +COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer -COPY deploy/conf/* /etc/php/8.3/fpm/ - -ADD . /symfony +COPY --link deploy/conf/* /etc/php/8.4/fpm/ WORKDIR /symfony +COPY --link . . -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.3/fpm/php-fpm.conf ; fi; - -RUN mkdir -m 777 -p /symfony/var/cache/{dev,prod} /symfony/var/log +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; -ENV COMPOSER_ALLOW_SUPERUSER=1 -RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet --no-scripts +RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --no-scripts --quiet RUN cp deploy/postgresql/.env . && composer dump-env prod && bin/console cache:clear -RUN echo "opcache.preload=/symfony/var/cache/prod/App_KernelProdContainer.preload.php" >> /etc/php/8.3/fpm/php.ini +RUN echo "opcache.preload=/symfony/var/cache/prod/App_KernelProdContainer.preload.php" >> /etc/php/8.4/fpm/php.ini EXPOSE 8080 # Uncomment next line for Laravel console error logging to be viewable in docker logs -# RUN echo "catch_workers_output = yes" >> /etc/php/8.3/fpm/php-fpm.conf +# RUN echo "catch_workers_output = yes" >> /etc/php/8.4/fpm/php-fpm.conf RUN mkdir -p /run/php -CMD service php8.3-fpm start && \ +CMD service php8.4-fpm start && \ nginx -c /symfony/deploy/nginx.conf diff --git a/frameworks/PHP/symfony/symfony-react.dockerfile b/frameworks/PHP/symfony/symfony-react.dockerfile new file mode 100644 index 00000000000..e2a47c08f73 --- /dev/null +++ b/frameworks/PHP/symfony/symfony-react.dockerfile @@ -0,0 +1,38 @@ +FROM php:8.4-cli + +RUN apt-get update -yqq && \ + apt-get install -yqq libpq-dev libicu-dev git > /dev/null && \ + docker-php-ext-install pdo_pgsql opcache intl pcntl > /dev/null + +COPY --link deploy/swoole/php.ini /usr/local/etc/php/ +WORKDIR /symfony +COPY --link . . + +# We deal with concurrencies over 1k, which stream_select doesn't support. +# libuv +RUN apt-get install -yqq libuv1-dev > /dev/null \ + && pecl install uv-beta > /dev/null +RUN docker-php-ext-enable uv + +# libevent +# RUN apt-get install -y libevent-dev > /dev/null \ +# && pecl install event-3.1.4 > /dev/null +# RUN docker-php-ext-enable event + + +COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer + +#ENV APP_DEBUG 1 +ENV APP_ENV prod + +#ENV APP_RUNTIME "Runtime\React\Runtime" +#RUN composer require runtime/react --update-no-dev --no-scripts --quiet + +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 +RUN cp deploy/postgresql/.env . && composer dump-env prod && bin/console cache:clear + +EXPOSE 8080 + +ENTRYPOINT [ "php", "/symfony/public/runtime.php" ] diff --git a/frameworks/PHP/symfony/symfony-roadrunner.dockerfile b/frameworks/PHP/symfony/symfony-roadrunner.dockerfile new file mode 100644 index 00000000000..a388570c60f --- /dev/null +++ b/frameworks/PHP/symfony/symfony-roadrunner.dockerfile @@ -0,0 +1,26 @@ +FROM php:8.4-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 + +RUN install-php-extensions \ + intl \ + opcache \ + pdo_pgsql \ + sockets \ + zip > /dev/null + +COPY --link deploy/conf/php.ini /usr/local/etc/php/ +WORKDIR /symfony +COPY --link . . + +RUN pecl install protobuf > /dev/null && echo "extension=protobuf.so" > /usr/local/etc/php/conf.d/protobuf.ini + +ENV APP_RUNTIME="Runtime\RoadRunnerSymfonyNyholm\Runtime" +RUN composer require runtime/roadrunner-symfony-nyholm --update-no-dev --no-scripts --quiet +RUN cp deploy/postgresql/.env . && composer dump-env prod && bin/console cache:clear + +EXPOSE 8080 + +ENTRYPOINT ["rr", "serve"] diff --git a/frameworks/PHP/symfony/symfony-swoole.dockerfile b/frameworks/PHP/symfony/symfony-swoole.dockerfile index b23c0e67b02..c9d32159b13 100644 --- a/frameworks/PHP/symfony/symfony-swoole.dockerfile +++ b/frameworks/PHP/symfony/symfony-swoole.dockerfile @@ -1,34 +1,21 @@ -FROM php:8.3-cli - -RUN pecl install swoole > /dev/null && \ - docker-php-ext-enable swoole - -RUN pecl install apcu > /dev/null && \ - docker-php-ext-enable apcu +FROM phpswoole/swoole:php8.4 RUN apt-get update -yqq && \ - apt-get install -yqq libpq-dev libicu-dev git unzip > /dev/null && \ + apt-get install -yqq libpq-dev libicu-dev > /dev/null && \ docker-php-ext-install pdo_pgsql opcache intl > /dev/null -COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer - -COPY deploy/swoole/php.ini /usr/local/etc/php/ +RUN pecl install apcu > /dev/null && \ + docker-php-ext-enable apcu -ADD . /symfony +COPY --link deploy/swoole/php.ini /usr/local/etc/php/ WORKDIR /symfony -RUN mkdir -m 777 -p /symfony/var/cache/{dev,prod} /symfony/var/log -#RUN mkdir -m 777 -p /symfony/var/cache/swoole /symfony/var/log -RUN COMPOSER_ALLOW_SUPERUSER=1 composer install --no-dev --no-scripts --quiet -RUN cp deploy/postgresql/.env . && composer dump-env prod && bin/console cache:clear - -ENV APP_RUNTIME=Runtime\\Swoole\\Runtime -RUN composer require runtime/swoole - -RUN COMPOSER_ALLOW_SUPERUSER=1 composer dump-autoload --no-dev --classmap-authoritative -RUN COMPOSER_ALLOW_SUPERUSER=1 composer dump-env prod +COPY --link . . #ENV APP_DEBUG=1 +ENV APP_RUNTIME="Runtime\Swoole\Runtime" +RUN composer require runtime/swoole --update-no-dev --no-scripts --quiet +RUN cp deploy/postgresql/.env . && composer dump-env prod && bin/console cache:clear EXPOSE 8080 -CMD php /symfony/public/swoole.php +ENTRYPOINT [ "php", "/symfony/public/swoole.php" ] diff --git a/frameworks/PHP/symfony/symfony-workerman.dockerfile b/frameworks/PHP/symfony/symfony-workerman.dockerfile index b306f90710d..480b734100a 100644 --- a/frameworks/PHP/symfony/symfony-workerman.dockerfile +++ b/frameworks/PHP/symfony/symfony-workerman.dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:22.04 +FROM ubuntu:24.04 ARG DEBIAN_FRONTEND=noninteractive @@ -6,25 +6,22 @@ RUN apt-get update -yqq && apt-get install -yqq software-properties-common > /de 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 install -yqq git unzip \ - php8.3-cli php8.3-pgsql php8.3-mbstring php8.3-xml php8.3-curl > /dev/null +RUN apt-get install -yqq unzip \ + php8.4-cli php8.4-pgsql php8.4-mbstring php8.4-xml php8.4-curl > /dev/null -COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer +COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer -RUN apt-get install -y php-pear php8.3-dev libevent-dev > /dev/null -RUN pecl install event-3.0.8 > /dev/null && echo "extension=event.so" > /etc/php/8.3/cli/conf.d/event.ini +RUN apt-get install -y php-pear php8.4-dev libevent-dev > /dev/null && \ + pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.4/cli/conf.d/event.ini -EXPOSE 8080 - -ADD . /symfony WORKDIR /symfony +COPY --link . . -RUN mkdir -m 777 -p /symfony/var/cache/{dev,prod} /symfony/var/log - -ENV COMPOSER_ALLOW_SUPERUSER=1 -RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet --no-scripts +RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --no-scripts --quiet RUN cp deploy/postgresql/.env . && composer dump-env prod && bin/console cache:clear -COPY deploy/conf/cli-php.ini /etc/php/8.3/cli/php.ini +COPY --link deploy/conf/cli-php.ini /etc/php/8.4/cli/conf.d/20-adapterman.ini + +EXPOSE 8080 -CMD php server.php start +ENTRYPOINT [ "php", "server.php", "start" ] diff --git a/frameworks/PHP/symfony/symfony.dockerfile b/frameworks/PHP/symfony/symfony.dockerfile index 392f19e91b6..1d2fd84193f 100644 --- a/frameworks/PHP/symfony/symfony.dockerfile +++ b/frameworks/PHP/symfony/symfony.dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:22.04 +FROM ubuntu:24.04 ARG DEBIAN_FRONTEND=noninteractive @@ -7,31 +7,28 @@ 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 install -yqq nginx git unzip curl \ - php8.3-cli php8.3-fpm php8.3-pgsql \ - php8.3-mbstring php8.3-xml php8.3-curl php8.3-dev > /dev/null + php8.4-bcmath php8.4-cli php8.4-fpm php8.4-pgsql \ + php8.4-mbstring php8.4-xml php8.4-curl php8.4-intl > /dev/null -COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer +COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer -COPY deploy/conf/* /etc/php/8.3/fpm/ +COPY --link deploy/conf/* /etc/php/8.4/fpm/ -ADD . /symfony WORKDIR /symfony +COPY --link . . -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.3/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.4/fpm/php-fpm.conf ; fi; -RUN mkdir -m 777 -p /symfony/var/cache/{dev,prod} /symfony/var/log - -ENV COMPOSER_ALLOW_SUPERUSER=1 -RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet --no-scripts +RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --no-scripts --quiet RUN cp deploy/postgresql/.env . && composer dump-env prod && bin/console cache:clear -RUN echo "opcache.preload=/symfony/var/cache/prod/App_KernelProdContainer.preload.php" >> /etc/php/8.3/fpm/php.ini +RUN echo "opcache.preload=/symfony/var/cache/prod/App_KernelProdContainer.preload.php" >> /etc/php/8.4/fpm/php.ini EXPOSE 8080 # Uncomment next line for Laravel console error logging to be viewable in docker logs -# RUN echo "catch_workers_output = yes" >> /etc/php/8.3/fpm/php-fpm.conf +# RUN echo "catch_workers_output = yes" >> /etc/php/8.4/fpm/php-fpm.conf RUN mkdir -p /run/php -CMD service php8.3-fpm start && \ +CMD service php8.4-fpm start && \ nginx -c /symfony/deploy/nginx.conf \ No newline at end of file diff --git a/frameworks/PHP/ubiquity/app/models/CachedWorld.php b/frameworks/PHP/ubiquity/app/models/CachedWorld.php index e438b1b513c..d23623bc8f9 100644 --- a/frameworks/PHP/ubiquity/app/models/CachedWorld.php +++ b/frameworks/PHP/ubiquity/app/models/CachedWorld.php @@ -4,6 +4,7 @@ /** * @table("World") */ +#[\AllowDynamicProperties] class CachedWorld extends World{ } diff --git a/frameworks/PHP/ubiquity/app/models/Fortune.php b/frameworks/PHP/ubiquity/app/models/Fortune.php index 1877df14b1a..b5d244820a5 100644 --- a/frameworks/PHP/ubiquity/app/models/Fortune.php +++ b/frameworks/PHP/ubiquity/app/models/Fortune.php @@ -1,6 +1,7 @@ /dev/null RUN apt-get update -yqq > /dev/null && \ apt-get install -yqq wget git unzip libxml2-dev cmake make systemtap-sdt-dev \ - zlib1g-dev libpcre3-dev libargon2-0-dev libsodium-dev \ - php8.0-cli php8.0-dev php8.0-mbstring libphp8.0-embed nginx > /dev/null + zlib1g-dev libpcre3-dev libargon2-dev libsodium-dev \ + php8.3-cli php8.3-dev php8.3-mbstring libphp8.3-embed nginx > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -ADD ./ ./ +COPY ./ ./ -ENV NGINX_VERSION=1.21.0 +ENV NGINX_VERSION=1.27.3 -RUN git clone -b v0.0.25 --single-branch --depth 1 https://github.com/rryqszq4/ngx_php7.git > /dev/null +RUN git clone -b v0.0.28 --single-branch --depth 1 https://github.com/rryqszq4/ngx_php7.git > /dev/null RUN wget -q http://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz && \ tar -zxf nginx-${NGINX_VERSION}.tar.gz && \ diff --git a/frameworks/PHP/ubiquity/ubiquity-ngx-raw.dockerfile b/frameworks/PHP/ubiquity/ubiquity-ngx-raw.dockerfile index d30d00b6a4b..582c7f402fd 100644 --- a/frameworks/PHP/ubiquity/ubiquity-ngx-raw.dockerfile +++ b/frameworks/PHP/ubiquity/ubiquity-ngx-raw.dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:20.04 +FROM ubuntu:24.04 ARG DEBIAN_FRONTEND=noninteractive @@ -8,16 +8,16 @@ RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null RUN apt-get update -yqq > /dev/null && \ apt-get install -yqq wget git unzip libxml2-dev cmake make systemtap-sdt-dev \ - zlib1g-dev libpcre3-dev libargon2-0-dev libsodium-dev \ - php8.0-cli php8.0-dev libphp8.0-embed php8.0-pgsql nginx > /dev/null + zlib1g-dev libpcre3-dev libargon2-dev libsodium-dev \ + php8.3-cli php8.3-dev libphp8.3-embed php8.3-pgsql nginx > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -ADD ./ ./ +COPY ./ ./ -ENV NGINX_VERSION=1.21.0 +ENV NGINX_VERSION=1.27.3 -RUN git clone -b v0.0.25 --single-branch --depth 1 https://github.com/rryqszq4/ngx_php7.git > /dev/null +RUN git clone -b v0.0.28 --single-branch --depth 1 https://github.com/rryqszq4/ngx_php7.git > /dev/null RUN wget -q http://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz && \ tar -zxf nginx-${NGINX_VERSION}.tar.gz && \ diff --git a/frameworks/PHP/ubiquity/ubiquity-ngx.dockerfile b/frameworks/PHP/ubiquity/ubiquity-ngx.dockerfile index 1b92f2d745d..58cf9c98fe9 100644 --- a/frameworks/PHP/ubiquity/ubiquity-ngx.dockerfile +++ b/frameworks/PHP/ubiquity/ubiquity-ngx.dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:20.04 +FROM ubuntu:24.04 ARG DEBIAN_FRONTEND=noninteractive @@ -8,16 +8,16 @@ RUN LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null RUN apt-get update -yqq > /dev/null && \ apt-get install -yqq wget git unzip libxml2-dev cmake make systemtap-sdt-dev \ - zlib1g-dev libpcre3-dev libargon2-0-dev libsodium-dev \ - php8.0-cli php8.0-dev libphp8.0-embed php8.0-pgsql nginx > /dev/null + zlib1g-dev libpcre3-dev libargon2-dev libsodium-dev \ + php8.3-cli php8.3-dev libphp8.3-embed php8.3-pgsql nginx > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -ADD ./ ./ +COPY ./ ./ -ENV NGINX_VERSION=1.21.0 +ENV NGINX_VERSION=1.27.3 -RUN git clone -b v0.0.25 --single-branch --depth 1 https://github.com/rryqszq4/ngx_php7.git > /dev/null +RUN git clone -b v0.0.28 --single-branch --depth 1 https://github.com/rryqszq4/ngx_php7.git > /dev/null RUN wget -q http://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz && \ tar -zxf nginx-${NGINX_VERSION}.tar.gz && \ diff --git a/frameworks/PHP/ubiquity/ubiquity-roadrunner-mysql.dockerfile b/frameworks/PHP/ubiquity/ubiquity-roadrunner-mysql.dockerfile index fdd3263c306..0abc0ab08ca 100644 --- a/frameworks/PHP/ubiquity/ubiquity-roadrunner-mysql.dockerfile +++ b/frameworks/PHP/ubiquity/ubiquity-roadrunner-mysql.dockerfile @@ -5,13 +5,13 @@ 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 > /dev/null && \ - apt-get install -yqq php8.0 php8.0-common php8.0-cgi php-curl php8.0-mysql > /dev/null + apt-get install -yqq php8.3 php8.3-common php8.3-cgi php-curl php8.3-mysql > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer RUN apt-get install -y php-pear php-dev > /dev/null -COPY deploy/conf/php-async.ini /etc/php/8.0/cgi/php.ini +COPY deploy/conf/php-async.ini /etc/php/8.3/cgi/php.ini ADD ./ /ubiquity WORKDIR /ubiquity @@ -33,8 +33,8 @@ RUN chmod 755 /bin/envwrapper.sh RUN chmod 777 -R /ubiquity/.ubiquity/* -#RUN echo "opcache.preload=/ubiquity/app/config/preloader.script.php" >> /etc/php/8.0/cgi/php.ini -RUN echo "opcache.jit_buffer_size=128M\nopcache.jit=tracing\n" >> /etc/php/8.0/cgi/php.ini +#RUN echo "opcache.preload=/ubiquity/app/config/preloader.script.php" >> /etc/php/8.3/cgi/php.ini +RUN echo "opcache.jit_buffer_size=128M\nopcache.jit=tracing\n" >> /etc/php/8.3/cgi/php.ini COPY deploy/conf/roadrunner/mysql/rrServices.php app/config/rrServices.php diff --git a/frameworks/PHP/ubiquity/ubiquity-roadrunner.dockerfile b/frameworks/PHP/ubiquity/ubiquity-roadrunner.dockerfile index 80dee9c051d..a8532d8d779 100644 --- a/frameworks/PHP/ubiquity/ubiquity-roadrunner.dockerfile +++ b/frameworks/PHP/ubiquity/ubiquity-roadrunner.dockerfile @@ -5,14 +5,14 @@ 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 > /dev/null && \ - apt-get install -yqq php8.0 php8.0-common php8.0-cgi php8.0-pgsql php-curl > /dev/null + apt-get install -yqq php8.3 php8.3-common php8.3-cgi php8.3-pgsql php-curl > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer RUN apt-get install -y php-pear php-dev > /dev/null -COPY deploy/conf/php-async.ini /etc/php/8.0/cgi/php.ini +COPY deploy/conf/php-async.ini /etc/php/8.3/cgi/php.ini ADD ./ /ubiquity WORKDIR /ubiquity @@ -34,8 +34,8 @@ RUN chmod 755 /bin/envwrapper.sh RUN chmod 777 -R /ubiquity/.ubiquity/* -#RUN echo "opcache.preload=/ubiquity/app/config/preloader.script.php" >> /etc/php/8.0/cgi/php.ini -RUN echo "opcache.jit_buffer_size=128M\nopcache.jit=function\n" >> /etc/php/8.0/cgi/php.ini +#RUN echo "opcache.preload=/ubiquity/app/config/preloader.script.php" >> /etc/php/8.3/cgi/php.ini +RUN echo "opcache.jit_buffer_size=128M\nopcache.jit=function\n" >> /etc/php/8.3/cgi/php.ini COPY deploy/conf/roadrunner/pgsql/rrServices.php app/config/rrServices.php diff --git a/frameworks/PHP/ubiquity/ubiquity-swoole-mysql.dockerfile b/frameworks/PHP/ubiquity/ubiquity-swoole-mysql.dockerfile index 5e4fd4122bd..94bb6c98809 100644 --- a/frameworks/PHP/ubiquity/ubiquity-swoole-mysql.dockerfile +++ b/frameworks/PHP/ubiquity/ubiquity-swoole-mysql.dockerfile @@ -1,29 +1,17 @@ -FROM php:8.0 +FROM phpswoole/swoole:php8.4 -RUN apt-get update > /dev/null - -RUN pecl install swoole > /dev/null && \ - docker-php-ext-enable swoole - -RUN docker-php-ext-install pdo_mysql opcache pcntl > /dev/null +RUN docker-php-ext-install pcntl opcache > /dev/null COPY deploy/conf/php-async.ini /usr/local/etc/php/php.ini -ADD ./ /ubiquity WORKDIR /ubiquity +COPY --link . . RUN chmod -R 777 /ubiquity -RUN ["chmod", "+x", "deploy/run/install-composer.sh"] - -RUN deploy/run/install-composer.sh - -RUN apt-get update -yqq > /dev/null && \ - apt-get install -yqq git unzip > /dev/null - -RUN php composer.phar require phpmv/ubiquity-devtools:dev-master phpmv/ubiquity-swoole:dev-master --quiet +RUN composer require phpmv/ubiquity-devtools:dev-master phpmv/ubiquity-swoole:dev-master --quiet -RUN php composer.phar install --optimize-autoloader --classmap-authoritative --no-dev --quiet +RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet RUN chmod 777 -R /ubiquity/.ubiquity/* @@ -36,4 +24,4 @@ COPY deploy/conf/swoole/mysql/swooleServices.php app/config/swooleServices.php EXPOSE 8080 -CMD /ubiquity/vendor/bin/Ubiquity serve -t=swoole -p=8080 -h=0.0.0.0 +ENTRYPOINT [ "/ubiquity/vendor/bin/Ubiquity", "serve", "-t=swoole", "-p=8080", "-h=0.0.0.0" ] diff --git a/frameworks/PHP/ubiquity/ubiquity-swoole.dockerfile b/frameworks/PHP/ubiquity/ubiquity-swoole.dockerfile index 0439f54c5e5..4f37f5f954f 100644 --- a/frameworks/PHP/ubiquity/ubiquity-swoole.dockerfile +++ b/frameworks/PHP/ubiquity/ubiquity-swoole.dockerfile @@ -1,9 +1,4 @@ -FROM php:8.0 - -RUN apt-get update > /dev/null - -RUN pecl install swoole > /dev/null && \ - docker-php-ext-enable swoole +FROM phpswoole/swoole:php8.4 RUN apt-get install -y libpq-dev \ && docker-php-ext-configure pgsql -with-pgsql=/usr/local/pgsql \ @@ -11,21 +6,14 @@ RUN apt-get install -y libpq-dev \ COPY deploy/conf/php-async.ini /usr/local/etc/php/php.ini -ADD ./ /ubiquity WORKDIR /ubiquity +COPY --link . . RUN chmod -R 777 /ubiquity -RUN ["chmod", "+x", "deploy/run/install-composer.sh"] - -RUN deploy/run/install-composer.sh - -RUN apt-get update -yqq > /dev/null && \ - apt-get install -yqq git unzip > /dev/null - -RUN php composer.phar require phpmv/ubiquity-devtools:dev-master phpmv/ubiquity-swoole:dev-master --quiet +RUN composer require phpmv/ubiquity-devtools:dev-master phpmv/ubiquity-swoole:dev-master --quiet -RUN php composer.phar install --optimize-autoloader --classmap-authoritative --no-dev --quiet +RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet RUN chmod 777 -R /ubiquity/.ubiquity/* @@ -38,4 +26,4 @@ COPY deploy/conf/swoole/pgsql/swooleServices.php app/config/swooleServices.php EXPOSE 8080 -CMD /ubiquity/vendor/bin/Ubiquity serve -t=swoole -p=8080 -h=0.0.0.0 +ENTRYPOINT [ "/ubiquity/vendor/bin/Ubiquity", "serve", "-t=swoole", "-p=8080", "-h=0.0.0.0" ] diff --git a/frameworks/PHP/ubiquity/ubiquity-workerman-mongo.dockerfile b/frameworks/PHP/ubiquity/ubiquity-workerman-mongo.dockerfile index 437cc2fdc26..a1408d288be 100644 --- a/frameworks/PHP/ubiquity/ubiquity-workerman-mongo.dockerfile +++ b/frameworks/PHP/ubiquity/ubiquity-workerman-mongo.dockerfile @@ -1,18 +1,18 @@ -FROM ubuntu:20.04 +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 LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/php > /dev/null RUN apt-get update -yqq > /dev/null && \ - apt-get install -yqq git php8.1-cli php8.1-mongodb php8.1-xml php8.1-mbstring > /dev/null + apt-get install -yqq git php8.4-cli php8.4-mongodb php8.4-xml php8.4-mbstring > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -RUN apt-get install -y php-pear php8.1-dev libevent-dev > /dev/null -RUN pecl install event-3.0.8 > /dev/null && echo "extension=event.so" > /etc/php/8.1/cli/conf.d/event.ini +RUN apt-get install -y php-pear php8.4-dev libevent-dev > /dev/null +RUN pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.4/cli/conf.d/event.ini -COPY deploy/conf/php-async.ini /etc/php/8.1/cli/php.ini +COPY deploy/conf/php-async.ini /etc/php/8.4/cli/php.ini ADD ./ /ubiquity @@ -31,8 +31,8 @@ RUN chmod 777 -R /ubiquity/.ubiquity/* COPY deploy/conf/workerman/mongo/workerServices.php app/config/workerServices.php -RUN echo "opcache.preload=/ubiquity/app/config/preloader.script.php" >> /etc/php/8.1/cli/php.ini -RUN echo "opcache.jit_buffer_size=128M\nopcache.jit=tracing\n" >> /etc/php/8.1/cli/php.ini +RUN echo "opcache.preload=/ubiquity/app/config/preloader.script.php" >> /etc/php/8.4/cli/php.ini +RUN echo "opcache.jit_buffer_size=128M\nopcache.jit=tracing\n" >> /etc/php/8.4/cli/php.ini EXPOSE 8080 diff --git a/frameworks/PHP/ubiquity/ubiquity-workerman-mysql.dockerfile b/frameworks/PHP/ubiquity/ubiquity-workerman-mysql.dockerfile index 47d2262ea91..a797a6a6da3 100644 --- a/frameworks/PHP/ubiquity/ubiquity-workerman-mysql.dockerfile +++ b/frameworks/PHP/ubiquity/ubiquity-workerman-mysql.dockerfile @@ -1,18 +1,18 @@ -FROM ubuntu:20.04 +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 > /dev/null && \ - apt-get install -yqq git php8.1-cli php8.1-mysql php8.1-xml php8.1-mbstring > /dev/null + apt-get install -yqq git php8.4-cli php8.4-mysql php8.4-xml php8.4-mbstring > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -RUN apt-get install -y php-pear php8.1-dev libevent-dev > /dev/null -RUN pecl install event-3.0.8 > /dev/null && echo "extension=event.so" > /etc/php/8.1/cli/conf.d/event.ini +RUN apt-get install -y php-pear php8.4-dev libevent-dev > /dev/null +RUN pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.4/cli/conf.d/event.ini -COPY deploy/conf/php-async.ini /etc/php/8.1/cli/php.ini +COPY deploy/conf/php-async.ini /etc/php/8.4/cli/php.ini ADD ./ /ubiquity WORKDIR /ubiquity @@ -30,8 +30,8 @@ RUN chmod 777 -R /ubiquity/.ubiquity/* COPY deploy/conf/workerman/mysql/workerServices.php app/config/workerServices.php -RUN echo "opcache.preload=/ubiquity/app/config/preloader.script.php" >> /etc/php/8.1/cli/php.ini -RUN echo "opcache.jit_buffer_size=128M\nopcache.jit=tracing\n" >> /etc/php/8.1/cli/php.ini +RUN echo "opcache.preload=/ubiquity/app/config/preloader.script.php" >> /etc/php/8.4/cli/php.ini +RUN echo "opcache.jit_buffer_size=128M\nopcache.jit=tracing\n" >> /etc/php/8.4/cli/php.ini EXPOSE 8080 diff --git a/frameworks/PHP/ubiquity/ubiquity-workerman-raw.dockerfile b/frameworks/PHP/ubiquity/ubiquity-workerman-raw.dockerfile index f095ab239f8..ead124fa0b1 100644 --- a/frameworks/PHP/ubiquity/ubiquity-workerman-raw.dockerfile +++ b/frameworks/PHP/ubiquity/ubiquity-workerman-raw.dockerfile @@ -1,18 +1,18 @@ -FROM ubuntu:20.04 +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 > /dev/null && \ - apt-get install -yqq git php8.1-cli php8.1-pgsql php8.1-xml php8.1-mbstring > /dev/null + apt-get install -yqq git php8.4-cli php8.4-pgsql php8.4-xml php8.4-mbstring > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -RUN apt-get install -y php-pear php8.1-dev libevent-dev > /dev/null -RUN pecl install event-3.0.8 > /dev/null && echo "extension=event.so" > /etc/php/8.1/cli/conf.d/event.ini +RUN apt-get install -y php-pear php8.4-dev libevent-dev > /dev/null +RUN pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.4/cli/conf.d/event.ini -COPY deploy/conf/php-async.ini /etc/php/8.1/cli/php.ini +COPY deploy/conf/php-async.ini /etc/php/8.4/cli/php.ini ADD ./ /ubiquity WORKDIR /ubiquity @@ -30,8 +30,8 @@ RUN chmod 777 -R /ubiquity/.ubiquity/* COPY deploy/conf/workerman/pgsql/raw/workerServices.php app/config/workerServices.php -RUN echo "opcache.preload=/ubiquity/app/config/preloader.script.php\n" >> /etc/php/8.1/cli/php.ini -RUN echo "opcache.jit_buffer_size=128M\nopcache.jit=tracing\n" >> /etc/php/8.1/cli/php.ini +RUN echo "opcache.preload=/ubiquity/app/config/preloader.script.php\n" >> /etc/php/8.4/cli/php.ini +RUN echo "opcache.jit_buffer_size=128M\nopcache.jit=tracing\n" >> /etc/php/8.4/cli/php.ini EXPOSE 8080 diff --git a/frameworks/PHP/ubiquity/ubiquity-workerman.dockerfile b/frameworks/PHP/ubiquity/ubiquity-workerman.dockerfile index 5242c94ffbc..379edd9cdd8 100644 --- a/frameworks/PHP/ubiquity/ubiquity-workerman.dockerfile +++ b/frameworks/PHP/ubiquity/ubiquity-workerman.dockerfile @@ -1,18 +1,18 @@ -FROM ubuntu:20.04 +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 > /dev/null && \ - apt-get install -yqq git php8.1-cli php8.1-pgsql php8.1-xml php8.1-mbstring > /dev/null + apt-get install -yqq git php8.4-cli php8.4-pgsql php8.4-xml php8.4-mbstring > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -RUN apt-get install -y php-pear php8.1-dev libevent-dev > /dev/null -RUN pecl install event-3.0.8 > /dev/null && echo "extension=event.so" > /etc/php/8.1/cli/conf.d/event.ini +RUN apt-get install -y php-pear php8.4-dev libevent-dev > /dev/null +RUN pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.4/cli/conf.d/event.ini -COPY deploy/conf/php-async.ini /etc/php/8.1/cli/php.ini +COPY deploy/conf/php-async.ini /etc/php/8.4/cli/php.ini ADD ./ /ubiquity WORKDIR /ubiquity @@ -30,8 +30,8 @@ RUN chmod 777 -R /ubiquity/.ubiquity/* COPY deploy/conf/workerman/pgsql/workerServices.php app/config/workerServices.php -RUN echo "opcache.preload=/ubiquity/app/config/preloader.script.php\n" >> /etc/php/8.1/cli/php.ini -RUN echo "opcache.jit_buffer_size=128M\nopcache.jit=function\n" >> /etc/php/8.1/cli/php.ini +RUN echo "opcache.preload=/ubiquity/app/config/preloader.script.php\n" >> /etc/php/8.4/cli/php.ini +RUN echo "opcache.jit_buffer_size=128M\nopcache.jit=function\n" >> /etc/php/8.4/cli/php.ini EXPOSE 8080 diff --git a/frameworks/PHP/ubiquity/ubiquity.dockerfile b/frameworks/PHP/ubiquity/ubiquity.dockerfile index 7417ec1c802..f757732149c 100644 --- a/frameworks/PHP/ubiquity/ubiquity.dockerfile +++ b/frameworks/PHP/ubiquity/ubiquity.dockerfile @@ -1,20 +1,20 @@ -FROM ubuntu:20.04 +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 > /dev/null && \ - apt-get install -yqq nginx git unzip php8.1 php8.1-common php8.1-cli php8.1-fpm php8.1-mysql php8.1-dev > /dev/null + apt-get install -yqq nginx git unzip php8.4 php8.4-common php8.4-cli php8.4-fpm php8.4-mysql php8.4-dev > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -COPY deploy/conf/* /etc/php/8.1/fpm/ +COPY deploy/conf/* /etc/php/8.4/fpm/ ADD ./ /ubiquity WORKDIR /ubiquity -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.1/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.4/fpm/php-fpm.conf ; fi; RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet @@ -22,9 +22,9 @@ RUN chmod 777 -R /ubiquity/app/cache/* COPY deploy/conf/ubiquity-config.php app/config/config.php -RUN echo "opcache.preload=/ubiquity/app/config/preloader.script.php" >> /etc/php/8.1/fpm/php.ini +RUN echo "opcache.preload=/ubiquity/app/config/preloader.script.php" >> /etc/php/8.4/fpm/php.ini EXPOSE 8080 -CMD service php8.1-fpm start && \ +CMD service php8.4-fpm start && \ nginx -c /ubiquity/deploy/nginx.conf -g "daemon off;" diff --git a/frameworks/PHP/webman/app/controller/Index.php b/frameworks/PHP/webman/app/controller/Index.php index 947e85a0d0b..5d40b24b0ed 100644 --- a/frameworks/PHP/webman/app/controller/Index.php +++ b/frameworks/PHP/webman/app/controller/Index.php @@ -5,11 +5,14 @@ use support\bootstrap\Date; use support\bootstrap\db\Raw as Db; use support\Response; -use PDO; +use function json_encode; +use function max; +use function min; +use function mt_rand; class Index { - public function plaintext($request) + public function plaintext() { return new Response(200, [ 'Content-Type' => 'text/plain', @@ -18,7 +21,7 @@ public function plaintext($request) } - public function json($request) + public function json() { return new Response(200, [ 'Content-Type' => 'application/json', @@ -26,10 +29,10 @@ public function json($request) ], json_encode(['message' => 'Hello, World!'])); } - public function db($request) + public function db() { $statement = Db::$random; - $statement->execute([\mt_rand(1, 10000)]); + $statement->execute([mt_rand(1, 10000)]); return new Response(200, [ 'Content-Type' => 'application/json', @@ -37,7 +40,7 @@ public function db($request) ], json_encode($statement->fetch())); } - public function fortunes($request) + public function fortunes() { $fortune = Db::$fortune; @@ -59,18 +62,15 @@ public function fortunes($request) ); } - public function queries($request, $q = 1) + public function queries(Request $request, $q = 1) { $statement = Db::$random; - $query_count = 1; - if ((int) $q > 1) { - $query_count = \min($q, 500); - } + $query_count = min(max((int) $q, 1), 500); $arr = []; while ($query_count--) { - $statement->execute([\mt_rand(1, 10000)]); + $statement->execute([mt_rand(1, 10000)]); $arr[] = $statement->fetch(); } @@ -80,31 +80,33 @@ public function queries($request, $q = 1) ], json_encode($arr)); } - public function updates($request, $q = 1) + public function updates(Request $request, $q = 1) { - $random = Db::$random; + static $updates = []; - $query_count = 1; - if ((int) $q > 1) { - $query_count = \min($q, 500); + $random = Db::$random; + $pdo = Db::$pdo; + $count = min(max((int) $q, 1), 500); + + $worlds = $keys = $values = []; + for ($i = 0; $i < $count; ++ $i) { + $values[] = $keys[] = $id = mt_rand(1, 10000); + $random->execute([$id]); + $row = $random->fetch(); + $values[] = $row['randomNumber'] = mt_rand(1, 10000); + $worlds[] = $row; } - - $worlds = []; - - while ($query_count--) { - $random->execute([\mt_rand(1, 10000)]); - $world = $random->fetch(); - $world['randomNumber'] = \mt_rand(1, 10000); - - $worlds[] = $world; + if (!isset($updates[$count])) { + $sql = 'UPDATE World SET randomNumber = CASE id' . str_repeat(' WHEN ?::INTEGER THEN ?::INTEGER ', $count) . 'END WHERE id IN (' . str_repeat('?::INTEGER,', $count - 1) . '?::INTEGER)'; + $updates[$count] = $pdo->prepare($sql); } - - Db::update($worlds); + $updates[$count]->execute([...$values, ...$keys]); return new Response(200, [ 'Content-Type' => 'application/json', 'Date' => Date::$date - ], \json_encode($worlds)); + ], json_encode($worlds)); + } diff --git a/frameworks/PHP/webman/benchmark_config.json b/frameworks/PHP/webman/benchmark_config.json index 864deacb0bf..5c2a7f4d4bf 100644 --- a/frameworks/PHP/webman/benchmark_config.json +++ b/frameworks/PHP/webman/benchmark_config.json @@ -2,8 +2,27 @@ "framework": "webman", "tests": [{ "default": { + "dockerfile": "webman.dockerfile", "json_url": "/json", "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "Postgres", + "framework": "webman", + "language": "PHP", + "flavor": "PHP7", + "orm": "Raw", + "platform": "workerman", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "webman", + "notes": "", + "versus": "workerman" + }, + "pgsql": { + "dockerfile": "webman-pgsql.dockerfile", "db_url": "/db", "query_url": "/queries/", "update_url": "/updates/", @@ -20,7 +39,7 @@ "webserver": "None", "os": "Linux", "database_os": "Linux", - "display_name": "webman", + "display_name": "webman-pgsql", "notes": "", "versus": "workerman" } diff --git a/frameworks/PHP/webman/composer.json b/frameworks/PHP/webman/composer.json index 73af23714b2..317e6598381 100644 --- a/frameworks/PHP/webman/composer.json +++ b/frameworks/PHP/webman/composer.json @@ -25,9 +25,10 @@ }, "require": { "php": ">=7.2", - "workerman/webman-framework": "^1.0", + "workerman/webman-framework": "dev-master", "monolog/monolog": "^2.0", - "vlucas/phpdotenv": ">=4.1,<6.0" + "vlucas/phpdotenv": ">=4.1,<6.0", + "workerman/workerman": "dev-master" }, "suggest": { "ext-event": "For better performance. " @@ -51,5 +52,6 @@ "pre-package-uninstall": [ "support\\Plugin::uninstall" ] - } -} + }, + "minimum-stability": "dev" +} \ No newline at end of file diff --git a/frameworks/PHP/webman/config.toml b/frameworks/PHP/webman/config.toml index b4cfc7e64d6..3aa7a920672 100644 --- a/frameworks/PHP/webman/config.toml +++ b/frameworks/PHP/webman/config.toml @@ -17,3 +17,21 @@ orm = "Raw" platform = "workerman" webserver = "None" versus = "workerman" + + +[pgsql] +urls.plaintext = "/plaintext" +urls.json = "/json" +urls.db = "/db" +urls.query = "/queries/" +urls.update = "/updates/" +urls.fortune = "/fortunes" +approach = "Realistic" +classification = "Micro" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "workerman" +webserver = "None" +versus = "workerman" \ No newline at end of file diff --git a/frameworks/PHP/webman/config/server.php b/frameworks/PHP/webman/config/server.php index 39f256488ef..a9e2686c8dc 100644 --- a/frameworks/PHP/webman/config/server.php +++ b/frameworks/PHP/webman/config/server.php @@ -17,9 +17,10 @@ 'transport' => 'tcp', 'context' => [], 'name' => 'webman', - 'count' => cpu_count() * 4, + 'count' => cpu_count() * ( getenv('TEST_TYPE') === 'default' ? 1 : 4 ), 'user' => '', 'group' => '', + 'reuse_port' => true, 'pid_file' => runtime_path() . '/webman.pid', 'status_file' => runtime_path() . '/webman.status', 'stdout_file' => runtime_path() . '/logs/stdout.log', diff --git a/frameworks/PHP/webman/php.ini b/frameworks/PHP/webman/php.ini index f0c616f9fb2..f4817cc9e3a 100644 --- a/frameworks/PHP/webman/php.ini +++ b/frameworks/PHP/webman/php.ini @@ -1,13 +1,11 @@ +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 - mysqlnd.collect_statistics = Off - memory_limit = 512M - opcache.jit_buffer_size=128M -opcache.jit=tracing +opcache.jit=tracing \ No newline at end of file diff --git a/frameworks/PHP/webman/support/bootstrap/Date.php b/frameworks/PHP/webman/support/bootstrap/Date.php index c4ac4f2bc57..0101c5ad44f 100644 --- a/frameworks/PHP/webman/support/bootstrap/Date.php +++ b/frameworks/PHP/webman/support/bootstrap/Date.php @@ -30,9 +30,9 @@ class Date implements Bootstrap { */ public static function start($worker) { - self::$date = gmdate('D, d M Y H:i:s').' GMT'; + self::$date = gmdate(DATE_RFC7231); Timer::add(1, function() { - self::$date = gmdate('D, d M Y H:i:s').' GMT'; + self::$date = gmdate(DATE_RFC7231); }); } diff --git a/frameworks/PHP/webman/support/bootstrap/db/Raw.php b/frameworks/PHP/webman/support/bootstrap/db/Raw.php index d27d846bb3c..5c4389c2347 100644 --- a/frameworks/PHP/webman/support/bootstrap/db/Raw.php +++ b/frameworks/PHP/webman/support/bootstrap/db/Raw.php @@ -31,11 +31,6 @@ class Raw implements Bootstrap public static PDOStatement $random; - /** - * @var PDOStatement[] - */ - public static array $update; - /** * @param Worker $worker * @@ -53,32 +48,4 @@ public static function start($worker) self::$pdo = $pdo; } - /** - * Postgres bulk update - * - * @param array $worlds - * @return void - */ - public static function update(array $worlds) - { - $rows = count($worlds); - - if (!isset(self::$update[$rows])) { - $sql = 'UPDATE world SET randomNumber = CASE id' - . str_repeat(' WHEN ?::INTEGER THEN ?::INTEGER ', $rows) - . 'END WHERE id IN (' - . str_repeat('?::INTEGER,', $rows - 1) . '?::INTEGER)'; - - self::$update[$rows] = self::$pdo->prepare($sql); - } - - $val = []; - $keys = []; - foreach ($worlds as $world) { - $val[] = $keys[] = $world['id']; - $val[] = $world['randomNumber']; - } - - self::$update[$rows]->execute([...$val, ...$keys]); - } } diff --git a/frameworks/PHP/webman/webman-pgsql.dockerfile b/frameworks/PHP/webman/webman-pgsql.dockerfile new file mode 100644 index 00000000000..2fe12ba3529 --- /dev/null +++ b/frameworks/PHP/webman/webman-pgsql.dockerfile @@ -0,0 +1,26 @@ +FROM ubuntu:24.04 + +ENV TEST_TYPE pgsql + +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 install -yqq php8.4-cli php8.4-pgsql php8.4-xml > /dev/null + +COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer + +RUN apt-get update -yqq && apt-get install -y php-pear php8.4-dev libevent-dev git > /dev/null +RUN pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.4/cli/conf.d/30-event.ini + +WORKDIR /webman +COPY --link . . + +RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet +COPY php.ini /etc/php/8.4/cli/conf.d/10-opcache.ini + +EXPOSE 8080 + +CMD php /webman/start.php start \ No newline at end of file diff --git a/frameworks/PHP/webman/webman.dockerfile b/frameworks/PHP/webman/webman.dockerfile index 512b164d99c..6020fed75ed 100644 --- a/frameworks/PHP/webman/webman.dockerfile +++ b/frameworks/PHP/webman/webman.dockerfile @@ -1,4 +1,6 @@ -FROM ubuntu:22.04 +FROM ubuntu:24.04 + +ENV TEST_TYPE default ARG DEBIAN_FRONTEND=noninteractive @@ -6,20 +8,19 @@ RUN apt-get update -yqq && apt-get install -yqq software-properties-common > /de 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 install -yqq php8.3-cli php8.3-pgsql php8.3-xml > /dev/null +RUN apt-get install -yqq php8.4-cli php8.4-pgsql php8.4-xml > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -RUN apt-get update -yqq && apt-get install -y php-pear php8.3-dev libevent-dev git > /dev/null -RUN pecl install event-3.0.8 > /dev/null && echo "extension=event.so" > /etc/php/8.3/cli/conf.d/event.ini - -COPY php.ini /etc/php/8.3/cli/php.ini +RUN apt-get update -yqq && apt-get install -y php-pear php8.4-dev libevent-dev git > /dev/null +RUN pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.4/cli/conf.d/30-event.ini -ADD ./ /webman WORKDIR /webman +COPY --link . . RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet +COPY php.ini /etc/php/8.4/cli/conf.d/10-opcache.ini EXPOSE 8080 -CMD php /webman/start.php start +CMD php /webman/start.php start \ No newline at end of file diff --git a/frameworks/PHP/wolff/app/controllers/Home.php b/frameworks/PHP/wolff/app/controllers/Home.php index 949e1cf71d1..1ba61adf674 100644 --- a/frameworks/PHP/wolff/app/controllers/Home.php +++ b/frameworks/PHP/wolff/app/controllers/Home.php @@ -25,15 +25,10 @@ public function json(Request $req, Response $res) public function db(Request $req, Response $res) { - $random_id = mt_rand(1, 10000); - /** @var \Wolff\Core\DB */ - $db = Container::get('db'); - $row = $db->select('World', 'id = ?', $random_id)[0]; + $row = Container::get('db')->select('World', 'id = ?', mt_rand(1, 10000))[0]; + $res->setHeader('Content-Type', 'application/json'); - $res->writeJson([ - 'id' => $row['id'], - 'randomNumber' => $row['randomNumber'] - ]); + $res->writeJson($row); } public function queries(Request $req, Response $res) @@ -50,13 +45,7 @@ public function queries(Request $req, Response $res) $worlds = []; for ($i = 0; $i < $queries; ++$i) { - $random_id = mt_rand(1, 10000); - $row = $db->select('World', 'id = ?', $random_id)[0]; - $world = [ - 'id' => $row['id'], - 'randomNumber' => $row['randomNumber'] - ]; - $worlds[] = $world; + $worlds[] = $db->select('World', 'id = ?', mt_rand(1, 10000))[0]; } $res->setHeader('Content-Type', 'application/json'); $res->writeJson($worlds); @@ -80,11 +69,10 @@ public function update(Request $req, Response $res) $random_update_id = mt_rand(1, 10000); $row = $db->select('World', 'id = ?', $random_id)[0]; $db->query('UPDATE World SET randomNumber = ? WHERE id = ?', $random_update_id, $row['id']); - $world = [ - 'id' => $row['id'], - 'randomNumber' => $random_update_id - ]; - $worlds[] = $world; + $worlds[] = [ + 'id' => $row['id'], + 'randomNumber' => $random_update_id + ]; } $res->setHeader('Content-Type', 'application/json'); $res->writeJson($worlds); @@ -93,14 +81,11 @@ public function update(Request $req, Response $res) public function fortunes(Request $req, Response $res) { - /** @var \Wolff\Core\DB */ - $db = Container::get('db'); - - $fortunes = $db->select('Fortune'); + $fortunes = Container::get('db')->select('Fortune'); $fortunes[] = [ 'id' => 0, 'message' => 'Additional fortune added at request time.' ]; - usort($fortunes, function ($left, $right) { - return $left['message'] <=> $right['message']; - }); + usort($fortunes, fn($left, $right) => $left['message'] <=> $right['message'] ); + + $res->setHeader('Content-Type', 'text/html; charset=utf-8'); View::render('fortunes', [ 'fortunes' => $fortunes, ]); diff --git a/frameworks/PHP/wolff/benchmark_config.json b/frameworks/PHP/wolff/benchmark_config.json index 9752e40967e..f5fae37d32e 100755 --- a/frameworks/PHP/wolff/benchmark_config.json +++ b/frameworks/PHP/wolff/benchmark_config.json @@ -5,10 +5,10 @@ "default": { "json_url": "/json", "plaintext_url": "/plaintext", - "db_url": "/db", - "query_url": "/queries?queries=", - "update_url": "/update?queries=", - "fortune_url": "/fortunes", + "db_url": "/db", + "query_url": "/queries?queries=", + "update_url": "/update?queries=", + "fortune_url": "/fortunes", "port": 8080, "approach": "Realistic", "classification": "Fullstack", @@ -24,6 +24,29 @@ "display_name": "Wolff", "notes": "", "versus": "php" + }, + "workerman": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "db_url": "/db", + "query_url": "/queries?queries=", + "update_url": "/update?queries=", + "fortune_url": "/fortunes", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "database": "mysql", + "framework": "Wolff", + "language": "PHP", + "flavor": "PHP8", + "orm": "raw", + "platform": "workerman", + "webserver": "none", + "os": "Linux", + "database_os": "Linux", + "display_name": "Wolff [workerman]", + "notes": "", + "versus": "php" } } ] diff --git a/frameworks/PHP/wolff/composer.json b/frameworks/PHP/wolff/composer.json index 1b43803812c..9c3ade8f03f 100644 --- a/frameworks/PHP/wolff/composer.json +++ b/frameworks/PHP/wolff/composer.json @@ -22,10 +22,7 @@ ], "require": { "php": ">=7.1.0", - "usbac/wolff-framework": "~4.0" - }, - "require-dev": { - "phpunit/phpunit": "8.*" + "usbac/wolff-framework": "~4.1" }, "autoload": { "psr-4": { diff --git a/frameworks/PHP/wolff/deploy/conf/adapterman-php.ini b/frameworks/PHP/wolff/deploy/conf/adapterman-php.ini new file mode 100644 index 00000000000..9f0f3171834 --- /dev/null +++ b/frameworks/PHP/wolff/deploy/conf/adapterman-php.ini @@ -0,0 +1,16 @@ +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.huge_code_pages=1 + +mysqlnd.collect_statistics = Off +memory_limit = 512M + +opcache.jit_buffer_size=128M +opcache.jit=tracing + +disable_functions=header,header_remove,headers_sent,headers_list,http_response_code,setcookie,session_create_id,session_id,session_name,session_save_path,session_status,session_start,session_write_close,session_regenerate_id,session_unset,session_get_cookie_params,session_set_cookie_params,set_time_limit diff --git a/frameworks/PHP/wolff/public/start.php b/frameworks/PHP/wolff/public/start.php new file mode 100644 index 00000000000..6000846e077 --- /dev/null +++ b/frameworks/PHP/wolff/public/start.php @@ -0,0 +1,32 @@ +start(); + header(HeaderDate::$date); // To pass the bench, nginx auto add it + + return ob_get_clean(); +} diff --git a/frameworks/PHP/wolff/server.php b/frameworks/PHP/wolff/server.php new file mode 100644 index 00000000000..507f3df619f --- /dev/null +++ b/frameworks/PHP/wolff/server.php @@ -0,0 +1,47 @@ +count = (int) shell_exec('nproc') * 4; +$http_worker->reusePort = true; +$http_worker->name = 'AdapterMan Wolff'; + +$http_worker->onWorkerStart = static function () { + HeaderDate::init(); + chdir(__DIR__.'/public'); + require 'start.php'; +}; + +$http_worker->onMessage = static function ($connection) { + + $connection->send(run()); +}; + +Worker::runAll(); + +class HeaderDate +{ + const NAME = 'Date: '; + + /** + * Date header + * + * @var string + */ + public static $date; + + public static function init(): void + { + self::$date = self::NAME . gmdate(DATE_RFC7231); + Timer::add(1, static function() { + self::$date = self::NAME . gmdate(DATE_RFC7231); + }); + } +} \ No newline at end of file diff --git a/frameworks/PHP/wolff/system/web.php b/frameworks/PHP/wolff/system/web.php index 4c94a4a4607..5797eff92f3 100644 --- a/frameworks/PHP/wolff/system/web.php +++ b/frameworks/PHP/wolff/system/web.php @@ -14,6 +14,5 @@ Route::get('/update', [ Controller\Home::class, 'update' ]); Route::get('/fortunes', [ Controller\Home::class, 'fortunes' ]); -Container::singleton('db', function() { - return new \Wolff\Core\DB; -}); + +Container::singleton('db', fn() => new \Wolff\Core\DB ); diff --git a/frameworks/PHP/wolff/wolff-workerman.dockerfile b/frameworks/PHP/wolff/wolff-workerman.dockerfile new file mode 100644 index 00000000000..920de95b389 --- /dev/null +++ b/frameworks/PHP/wolff/wolff-workerman.dockerfile @@ -0,0 +1,30 @@ +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 -yqq > /dev/null && apt-get install -yqq git \ + php8.4-cli php8.4-mysql php8.4-mbstring php8.4-xml php8.4-curl > /dev/null + +COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer + +RUN apt-get install -y php-pear php8.4-dev libevent-dev > /dev/null +RUN pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.4/cli/conf.d/event.ini + +COPY deploy/conf/adapterman-php.ini /etc/php/8.4/cli/conf.d/20-adapterman.ini + +WORKDIR /wolff/bench +COPY --link . . + +EXPOSE 8080 + +RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet +RUN composer require joanhey/adapterman:^0.7 --quiet + +RUN chmod -R 777 /wolff + +CMD php server.php start + diff --git a/frameworks/PHP/wolff/wolff.dockerfile b/frameworks/PHP/wolff/wolff.dockerfile index 1d94b5bc668..d3dfc84bfad 100644 --- a/frameworks/PHP/wolff/wolff.dockerfile +++ b/frameworks/PHP/wolff/wolff.dockerfile @@ -1,26 +1,26 @@ -FROM ubuntu:22.04 +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 install -yqq nginx git unzip \ - php8.3-fpm php8.3-mysql php8.3-xml php8.3-mbstring php8.3-intl php8.3-dev php8.3-curl > /dev/null + php8.4-fpm php8.4-mysql php8.4-xml php8.4-mbstring php8.4-intl php8.4-dev php8.4-curl > /dev/null -COPY deploy/conf/* /etc/php/8.3/fpm/ +COPY deploy/conf/* /etc/php/8.4/fpm/ -ADD ./ /wolff WORKDIR /wolff +COPY --link . . COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.3/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.4/fpm/php-fpm.conf ; fi; RUN chmod -R 777 /wolff EXPOSE 8080 -CMD service php8.3-fpm start && \ +CMD service php8.4-fpm start && \ nginx -c /wolff/deploy/nginx.conf 2>&1 > /dev/stderr diff --git a/frameworks/PHP/workerman/Date.php b/frameworks/PHP/workerman/Date.php new file mode 100644 index 00000000000..d3df8c47523 --- /dev/null +++ b/frameworks/PHP/workerman/Date.php @@ -0,0 +1,15 @@ +date = gmdate(DATE_RFC7231); + Timer::add(1, function() { + $this->date = gmdate(DATE_RFC7231); + }); + } +} \ No newline at end of file diff --git a/frameworks/PHP/workerman/Mysql.php b/frameworks/PHP/workerman/Mysql.php new file mode 100644 index 00000000000..968ffcfef80 --- /dev/null +++ b/frameworks/PHP/workerman/Mysql.php @@ -0,0 +1,77 @@ +pdo = new PDO( + 'mysql:host=tfb-database;dbname=hello_world', + 'benchmarkdbuser', + 'benchmarkdbpass', + [ + PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, + PDO::ATTR_EMULATE_PREPARES => false + ] + ); + $this->world = $this->pdo->prepare('SELECT id,randomNumber FROM World WHERE id=?'); + $this->fortune = $this->pdo->prepare('SELECT id,message FROM Fortune'); + $this->update = $this->pdo->prepare('UPDATE World SET randomNumber=? WHERE id=?'); + } + + function db(): array + { + $this->world->execute([mt_rand(1, 10000)]); + return $this->world->fetch(); + } + + function query($request): array + { + $count = min(max((int) $request->get('q'), 1), 500); + $arr = []; + $world = $this->world; + while ($count--) { + $world->execute([mt_rand(1, 10000)]); + $arr[] = $world->fetch(); + } + return $arr; + } + + function update($request): array + { + $count = min(max((int) $request->get('q'), 1), 500); + $arr = []; + $world = $this->world; + $update = $this->update; + while ($count--) { + $id = mt_rand(1, 10000); + $world->execute([$id]); + $item = $world->fetch(); + $update->execute( + [$item['randomNumber'] = mt_rand(1, 10000), $id] + ); + $arr[] = $item; + } + return $arr; + } + + function fortune(): string + { + $this->fortune->execute(); + $arr = $this->fortune->fetchAll(PDO::FETCH_KEY_PAIR); + $arr[0] = 'Additional fortune added at request time.'; + asort($arr); + $html = ''; + foreach ($arr as $id => $message) { + $message = htmlspecialchars($message, ENT_QUOTES, 'UTF-8'); + $html .= "$id$message"; + } + return "Fortunes$html
idmessage
"; + } + +} \ No newline at end of file diff --git a/frameworks/PHP/workerman/MysqlSwoole.php b/frameworks/PHP/workerman/MysqlSwoole.php new file mode 100644 index 00000000000..d294afae62d --- /dev/null +++ b/frameworks/PHP/workerman/MysqlSwoole.php @@ -0,0 +1,83 @@ +withDriver('mysql') + ->withHost('tfb-database') + ->withPort(3306) + ->withDbName('hello_world') + ->withUsername('benchmarkdbuser') + ->withPassword('benchmarkdbpass'); + $this->pool = new PDOPool($config, $size); + } + + function db(): array + { + $pdo = $this->pool->get(); + $stmt = $pdo->prepare('SELECT id,randomNumber FROM World WHERE id=?'); + $stmt->execute([mt_rand(1, 10000)]); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + $this->pool->put($pdo); + return $result; + } + + function query($request): array + { + $count = min(max((int) $request->get('q'), 1), 500); + $pdo = $this->pool->get(); + $stmt = $pdo->prepare('SELECT id,randomNumber FROM World WHERE id=?'); + $arr = []; + while ($count--) { + $stmt->execute([mt_rand(1, 10000)]); + $arr[] = $stmt->fetch(PDO::FETCH_ASSOC); + } + $this->pool->put($pdo); + return $arr; + } + + function update($request): array + { + $count = min(max((int) $request->get('q'), 1), 500); + $arr = []; + $pdo = $this->pool->get(); + $world = $pdo->prepare('SELECT id,randomNumber FROM World WHERE id=?'); + $update = $pdo->prepare('UPDATE World SET randomNumber=? WHERE id=?'); + while ($count--) { + $id = mt_rand(1, 10000); + $world->execute([$id]); + $item = $world->fetch(PDO::FETCH_ASSOC); + $update->execute( + [$item['randomNumber'] = mt_rand(1, 10000), $id] + ); + $arr[] = $item; + } + $this->pool->put($pdo); + return $arr; + } + + function fortune(): string + { + $pdo = $this->pool->get(); + $stmt = $pdo->prepare('SELECT id,message FROM Fortune'); + $stmt->execute(); + $arr = $stmt->fetchAll(PDO::FETCH_KEY_PAIR); + $this->pool->put($pdo); + $arr[0] = 'Additional fortune added at request time.'; + asort($arr); + $html = ''; + foreach ($arr as $id => $message) { + $message = htmlspecialchars($message, ENT_QUOTES, 'UTF-8'); + $html .= "$id$message"; + } + return "Fortunes$html
idmessage
"; + } + +} \ No newline at end of file diff --git a/frameworks/PHP/workerman/MysqlSwow.php b/frameworks/PHP/workerman/MysqlSwow.php new file mode 100644 index 00000000000..81cb8534c2a --- /dev/null +++ b/frameworks/PHP/workerman/MysqlSwow.php @@ -0,0 +1,12 @@ +pool = new Pool("mysql:host=tfb-database;dbname=hello_world", 'benchmarkdbuser', 'benchmarkdbpass', $size); + } + +} \ No newline at end of file diff --git a/frameworks/PHP/workerman/Pgsql.php b/frameworks/PHP/workerman/Pgsql.php new file mode 100644 index 00000000000..637497eb03e --- /dev/null +++ b/frameworks/PHP/workerman/Pgsql.php @@ -0,0 +1,50 @@ +pdo = new PDO( + 'pgsql:host=tfb-database;dbname=hello_world', + 'benchmarkdbuser', + 'benchmarkdbpass', + [ + PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, + PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, + PDO::ATTR_EMULATE_PREPARES => false + ] + ); + $this->world = $this->random = $this->pdo->prepare('SELECT id,randomNumber FROM World WHERE id=?'); + $this->fortune = $this->pdo->prepare('SELECT id,message FROM Fortune'); + $this->update = $this->pdo->prepare('UPDATE World SET randomNumber=? WHERE id=?'); + } + + function update($request): array + { + $queries = $request->get('q'); + $worlds = $keys = $values = []; + $count = min(max((int) $queries, 1), 500); + $random = $this->random; + for ($i = 0; $i < $count; ++ $i) { + $values[] = $keys[] = $id = mt_rand(1, 10000); + $random->execute([$id]); + $row = $random->fetch(); + $values[] = $row['randomNumber'] = mt_rand(1, 10000); + $worlds[] = $row; + } + if (!isset($this->updates[$count])) { + $sql = 'UPDATE World SET randomNumber = CASE id' . str_repeat(' WHEN ?::INTEGER THEN ?::INTEGER ', $count) . 'END WHERE id IN (' . str_repeat('?::INTEGER,', $count - 1) . '?::INTEGER)'; + $this->updates[$count] = $this->pdo->prepare($sql); + } + $this->updates[$count]->execute([...$values, ...$keys]); + return $worlds; + } + +} \ No newline at end of file diff --git a/frameworks/PHP/workerman/PgsqlSwoole.php b/frameworks/PHP/workerman/PgsqlSwoole.php new file mode 100644 index 00000000000..0a8b99dfc18 --- /dev/null +++ b/frameworks/PHP/workerman/PgsqlSwoole.php @@ -0,0 +1,57 @@ +withDriver('pgsql') + ->withHost('tfb-database') + ->withPort(5432) + ->withDbName('hello_world') + ->withUsername('benchmarkdbuser') + ->withPassword('benchmarkdbpass'); + + $this->pool = new PDOPool($config, $size); + } + + + function update($request): array + { + $count = min(max((int) $request->get('q'), 1), 500); + $worlds = []; + $pdo = $this->pool->get(); + $random = $pdo->prepare('SELECT id,randomNumber FROM World WHERE id=?'); + while ($count--) { + $random->execute([mt_rand(1, 10000)]); + $world = $random->fetch(PDO::FETCH_ASSOC); + $world['randomNumber'] = mt_rand(1, 10000); + $worlds[] = $world; + } + $rows = count($worlds); + + $sql = 'UPDATE world SET randomNumber = CASE id' + . str_repeat(' WHEN ?::INTEGER THEN ?::INTEGER ', $rows) + . 'END WHERE id IN (' + . str_repeat('?::INTEGER,', $rows - 1) . '?::INTEGER)'; + + $update = $pdo->prepare($sql); + + $val = []; + $keys = []; + foreach ($worlds as $world) { + $val[] = $keys[] = $world['id']; + $val[] = $world['randomNumber']; + } + + $update->execute([...$val, ...$keys]); + $this->pool->put($pdo); + return $worlds; + } + +} \ No newline at end of file diff --git a/frameworks/PHP/workerman/PgsqlSwow.php b/frameworks/PHP/workerman/PgsqlSwow.php new file mode 100644 index 00000000000..c2a2d3cc4aa --- /dev/null +++ b/frameworks/PHP/workerman/PgsqlSwow.php @@ -0,0 +1,12 @@ +pool = new Pool("pgsql:host=tfb-database;dbname=hello_world", 'benchmarkdbuser', 'benchmarkdbpass', $size); + } + +} \ No newline at end of file diff --git a/frameworks/PHP/workerman/Pool.php b/frameworks/PHP/workerman/Pool.php new file mode 100644 index 00000000000..522ad7afed2 --- /dev/null +++ b/frameworks/PHP/workerman/Pool.php @@ -0,0 +1,29 @@ +push(new PDO($dsn, $username, $password,[ + PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC + ])); + } + } + + public function get(): PDO + { + return static::$channel->pop(); + } + + public function put(PDO $pdo) + { + return static::$channel->push($pdo); + } +} \ No newline at end of file diff --git a/frameworks/PHP/workerman/app-pg.php b/frameworks/PHP/workerman/app-pg.php deleted file mode 100644 index 471c71b2186..00000000000 --- a/frameworks/PHP/workerman/app-pg.php +++ /dev/null @@ -1,118 +0,0 @@ -path()) { - '/plaintext' => text(), - '/json' => json(), - '/db' => db(), - '/fortunes' => fortune(), - '/query' => query($request), - '/update' => updateraw($request), - // '/info' => info(), - default => new Response(404, [], 'Error 404'), - }; -} - -function text() -{ - return new Response(200, [ - 'Content-Type' => 'text/plain', - 'Date' => Header::$date - ], 'Hello, World!'); -} - -function json() -{ - return new Response(200, [ - 'Content-Type' => 'application/json', - 'Date' => Header::$date - ], json_encode(['message' => 'Hello, World!'])); -} - -function db() -{ - DbRaw::$random->execute([mt_rand(1, 10000)]); - - return new Response(200, [ - 'Content-Type' => 'application/json', - 'Date' => Header::$date - ], json_encode(DbRaw::$random->fetch())); -} - -function query($request) -{ - $query_count = 1; - $q = (int) $request->get('q'); - if ($q > 1) { - $query_count = min($q, 500); - } - - while ($query_count--) { - DbRaw::$random->execute([mt_rand(1, 10000)]); - $arr[] = DbRaw::$random->fetch(); - } - - return new Response(200, [ - 'Content-Type' => 'application/json', - 'Date' => Header::$date - ], json_encode($arr)); -} - -function updateraw($request) -{ - $query_count = 1; - $q = (int) $request->get('q'); - if ($q > 1) { - $query_count = min($q, 500); - } - - while ($query_count--) { - - DbRaw::$random->execute([mt_rand(1, 10000)]); - $row = DbRaw::$random->fetch(); - $row['randomNumber'] = mt_rand(1, 10000); - - $worlds[] = $row; - } - - DbRaw::update($worlds); - - return new Response(200, [ - 'Content-Type' => 'application/json', - 'Date' => Header::$date - ], json_encode($worlds)); -} - -function fortune() -{ - DbRaw::$fortune->execute(); - - $arr = DbRaw::$fortune->fetchAll(PDO::FETCH_KEY_PAIR); - $arr[0] = 'Additional fortune added at request time.'; - asort($arr); - - $html = ''; - foreach ($arr as $id => $message) { - $message = htmlspecialchars($message, ENT_QUOTES, 'UTF-8'); - $html .= "$id$message"; - } - - return new Response(200, [ - 'Date' => Header::$date - ], "Fortunes$html
idmessage
" - ); -} - -/* function info() -{ - ob_start(); - phpinfo(); - return new Response(200, ['Content-Type' => 'text/plain'], ob_get_clean()); -} - */ diff --git a/frameworks/PHP/workerman/app.php b/frameworks/PHP/workerman/app.php deleted file mode 100644 index ad6b7997efc..00000000000 --- a/frameworks/PHP/workerman/app.php +++ /dev/null @@ -1,145 +0,0 @@ - PDO::FETCH_ASSOC, - PDO::ATTR_EMULATE_PREPARES => false - ] - ); - $world = $pdo->prepare('SELECT id,randomNumber FROM World WHERE id=?'); - $fortune = $pdo->prepare('SELECT id,message FROM Fortune'); - $update = $pdo->prepare('UPDATE World SET randomNumber=? WHERE id=?'); -} - -function router(Request $request) -{ - return match($request->path()) { - '/plaintext' => text(), - '/json' => json(), - '/db' => db(), - '/fortunes' => fortune(), - '/query' => query($request), - '/update' => updateraw($request), - // '/info' => info(), - default => new Response(404, [], 'Error 404'), - }; -} - -function text() -{ - return new Response(200, [ - 'Content-Type' => 'text/plain', - 'Date' => Header::$date - ], 'Hello, World!'); -} - -function json() -{ - return new Response(200, [ - 'Content-Type' => 'application/json', - 'Date' => Header::$date - ], json_encode(['message' => 'Hello, World!'])); -} - -function db() -{ - global $world; - - $world->execute([mt_rand(1, 10000)]); - - return new Response(200, [ - 'Content-Type' => 'application/json', - 'Date' => Header::$date - ], json_encode($world->fetch())); -} - -function query($request) -{ - global $world; - - $query_count = 1; - $q = (int) $request->get('q'); - if ($q > 1) { - $query_count = min($q, 500); - } - - while ($query_count--) { - $world->execute([mt_rand(1, 10000)]); - $arr[] = $world->fetch(); - } - - return new Response(200, [ - 'Content-Type' => 'application/json', - 'Date' => Header::$date - ], json_encode($arr)); -} - -function updateraw($request) -{ - global $world, $update; - - $query_count = 1; - $q = (int) $request->get('q'); - if ($q > 1) { - $query_count = min($q, 500); - } - - while ($query_count--) { - $id = mt_rand(1, 10000); - $world->execute([$id]); - $item = $world->fetch(); - $update->execute( - [$item['randomNumber'] = mt_rand(1, 10000), $id] - ); - - $arr[] = $item; - } - - // $pdo->beginTransaction(); - // foreach($arr as $world) { - // $update->execute([$world['randomNumber'], $world['id']]); - // } - // $pdo->commit(); - return new Response(200, [ - 'Content-Type' => 'application/json', - 'Date' => Header::$date - ], json_encode($arr)); -} - -function fortune() -{ - global $fortune; - - $fortune->execute(); - - $arr = $fortune->fetchAll(PDO::FETCH_KEY_PAIR); - $arr[0] = 'Additional fortune added at request time.'; - asort($arr); - - $html = ''; - foreach ($arr as $id => $message) { - $message = htmlspecialchars($message, ENT_QUOTES, 'UTF-8'); - $html .= "$id$message"; - } - - return new Response(200, [ - 'Date' => Header::$date - ], "Fortunes$html
idmessage
" - ); -} - -/* function info() -{ - ob_start(); - phpinfo(); - return new Response(200, ['Content-Type' => 'text/plain'], ob_get_clean()); -} - */ \ No newline at end of file diff --git a/frameworks/PHP/workerman/benchmark_config.json b/frameworks/PHP/workerman/benchmark_config.json index 68ce09ced79..0d4b57bad54 100644 --- a/frameworks/PHP/workerman/benchmark_config.json +++ b/frameworks/PHP/workerman/benchmark_config.json @@ -2,8 +2,49 @@ "framework": "workerman", "tests": [{ "default": { + "dockerfile": "workerman-jit.dockerfile", "json_url": "/json", "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Platform", + "database": "MySQL", + "framework": "workerman", + "language": "PHP", + "flavor": "PHP8", + "orm": "Raw", + "platform": "workerman", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "workerman [jit]", + "notes": "", + "versus": "php" + }, + "pgsql": { + "dockerfile": "workerman-pgsql-jit.dockerfile", + "db_url": "/db", + "query_url": "/query?q=", + "update_url": "/update?q=", + "fortune_url": "/fortunes", + "port": 8080, + "approach": "Realistic", + "classification": "Platform", + "database": "Postgres", + "framework": "workerman", + "language": "PHP", + "flavor": "PHP8", + "orm": "Raw", + "platform": "workerman", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "workerman [jit, pgsql]", + "notes": "", + "versus": "php" + }, + "mysql": { + "dockerfile": "workerman-mysql-jit.dockerfile", "db_url": "/db", "query_url": "/query?q=", "update_url": "/update?q=", @@ -20,11 +61,32 @@ "webserver": "None", "os": "Linux", "database_os": "Linux", + "display_name": "workerman [jit, mysql]", + "notes": "", + "versus": "php" + }, + "without-jit": { + "dockerfile": "workerman.dockerfile", + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Platform", + "database": "MySQL", + "framework": "workerman", + "language": "PHP", + "flavor": "PHP8", + "orm": "Raw", + "platform": "workerman", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", "display_name": "workerman", "notes": "", "versus": "php" }, - "pgsql": { + "pgsql-without-jit": { + "dockerfile": "workerman-pgsql.dockerfile", "db_url": "/db", "query_url": "/query?q=", "update_url": "/update?q=", @@ -41,12 +103,15 @@ "webserver": "None", "os": "Linux", "database_os": "Linux", - "display_name": "workerman-postgres", + "display_name": "workerman [pgsql]", "notes": "", "versus": "php" }, - "async": { + "mysql-swow": { + "dockerfile": "workerman-mysql-swow-jit.dockerfile", "db_url": "/db", + "query_url": "/query?q=", + "update_url": "/update?q=", "fortune_url": "/fortunes", "port": 8080, "approach": "Realistic", @@ -54,22 +119,18 @@ "database": "MySQL", "framework": "workerman", "language": "PHP", - "flavor": "PHP7", + "flavor": "PHP8", "orm": "Raw", "platform": "workerman", "webserver": "None", "os": "Linux", "database_os": "Linux", - "display_name": "workerman-async-db", + "display_name": "workerman [jit, mysql, swow, async]", "notes": "", - "versus": "php", - "tags": [ - "broken" - ] + "versus": "php" }, - "php8-jit": { - "json_url": "/json", - "plaintext_url": "/plaintext", + "mysql-swoole": { + "dockerfile": "workerman-mysql-swoole-jit.dockerfile", "db_url": "/db", "query_url": "/query?q=", "update_url": "/update?q=", @@ -77,7 +138,7 @@ "port": 8080, "approach": "Realistic", "classification": "Platform", - "database": "Postgres", + "database": "MySQL", "framework": "workerman", "language": "PHP", "flavor": "PHP8", @@ -86,8 +147,8 @@ "webserver": "None", "os": "Linux", "database_os": "Linux", - "display_name": "workerman-php8-jit", - "notes": "php8 jit", + "display_name": "workerman [jit, mysql, swoole, async]", + "notes": "", "versus": "php" } }] diff --git a/frameworks/PHP/workerman/composer.json b/frameworks/PHP/workerman/composer.json index 7e6c8b1f088..d0c8ca7e678 100644 --- a/frameworks/PHP/workerman/composer.json +++ b/frameworks/PHP/workerman/composer.json @@ -1,5 +1,10 @@ { "require": { "workerman/workerman": "dev-master" + }, + "autoload": { + "psr-4": { + "": "./" + } } } diff --git a/frameworks/PHP/workerman/config.toml b/frameworks/PHP/workerman/config.toml index 2f3bbffd22c..791e9502688 100644 --- a/frameworks/PHP/workerman/config.toml +++ b/frameworks/PHP/workerman/config.toml @@ -33,7 +33,7 @@ platform = "workerman" webserver = "None" versus = "php" -[php8-jit] +[mysql] urls.plaintext = "/plaintext" urls.json = "/json" urls.db = "/db" @@ -50,8 +50,12 @@ platform = "workerman" webserver = "None" versus = "php" -[async] +[without-jit] +urls.plaintext = "/plaintext" +urls.json = "/json" urls.db = "/db" +urls.query = "/query?q=" +urls.update = "/update?q=" urls.fortune = "/fortunes" approach = "Realistic" classification = "Platform" @@ -62,3 +66,80 @@ orm = "Raw" platform = "workerman" webserver = "None" versus = "php" + +[pgsql-without-jit] +urls.plaintext = "/plaintext" +urls.json = "/json" +urls.db = "/db" +urls.query = "/query?q=" +urls.update = "/update?q=" +urls.fortune = "/fortunes" +approach = "Realistic" +classification = "Platform" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "workerman" +webserver = "None" +versus = "php" + +[pgsql-swow] +urls.db = "/db" +urls.query = "/query?q=" +urls.update = "/update?q=" +urls.fortune = "/fortunes" +approach = "Realistic" +classification = "Platform" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "workerman" +webserver = "None" +versus = "php" + +[mysql-swow] +urls.db = "/db" +urls.query = "/query?q=" +urls.update = "/update?q=" +urls.fortune = "/fortunes" +approach = "Realistic" +classification = "Platform" +database = "MySQL" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "workerman" +webserver = "None" +versus = "php" + +[pgsql-swoole] +urls.db = "/db" +urls.query = "/query?q=" +urls.update = "/update?q=" +urls.fortune = "/fortunes" +approach = "Realistic" +classification = "Platform" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "workerman" +webserver = "None" +versus = "php" + +[mysql-swoole] +urls.db = "/db" +urls.query = "/query?q=" +urls.update = "/update?q=" +urls.fortune = "/fortunes" +approach = "Realistic" +classification = "Platform" +database = "MySQL" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "workerman" +webserver = "None" +versus = "php" \ No newline at end of file diff --git a/frameworks/PHP/workerman/dbraw.php b/frameworks/PHP/workerman/dbraw.php deleted file mode 100644 index 2a7c8d355c1..00000000000 --- a/frameworks/PHP/workerman/dbraw.php +++ /dev/null @@ -1,88 +0,0 @@ - PDO::FETCH_ASSOC, - PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, - PDO::ATTR_EMULATE_PREPARES => false - ] - ); - - self::$fortune = $pdo->prepare('SELECT id,message FROM Fortune'); - self::$random = $pdo->prepare('SELECT id,randomNumber FROM World WHERE id = ?'); - self::$instance = $pdo; - } - - /** - * Postgres bulk update - * - * @param array $worlds - * @return void - */ - public static function update(array $worlds) - { - $rows = count($worlds); - - if (!isset(self::$update[$rows])) { - $sql = 'UPDATE world SET randomNumber = CASE id' - . str_repeat(' WHEN ?::INTEGER THEN ?::INTEGER ', $rows) - . 'END WHERE id IN (' - . str_repeat('?::INTEGER,', $rows - 1) . '?::INTEGER)'; - - self::$update[$rows] = self::$instance->prepare($sql); - } - - $val = []; - $keys = []; - foreach ($worlds as $world) { - $val[] = $keys[] = $world['id']; - $val[] = $world['randomNumber']; - } - - self::$update[$rows]->execute([...$val, ...$keys]); - } - - /** - * Alternative bulk update in Postgres - * - * @param array $worlds - * @return void - */ - public static function update2(array $worlds) - { - $rows = count($worlds); - - if (!isset(self::$update[$rows])) { - $sql = 'UPDATE world SET randomNumber = temp.randomNumber FROM (VALUES ' - . implode(', ', array_fill(0, $rows, '(?::INTEGER, ?::INTEGER)')) . - ' ORDER BY 1) AS temp(id, randomNumber) WHERE temp.id = world.id'; - - self::$update[$rows] = self::$instance->prepare($sql); - } - - $val = []; - foreach ($worlds as $world) { - $val[] = $world['id']; - $val[] = $world['randomNumber']; - //$update->bindParam(++$i, $world['id'], PDO::PARAM_INT); - } - - self::$update[$rows]->execute($val); - } -} diff --git a/frameworks/PHP/workerman/php-jit.ini b/frameworks/PHP/workerman/php-jit.ini index f0c616f9fb2..f4817cc9e3a 100644 --- a/frameworks/PHP/workerman/php-jit.ini +++ b/frameworks/PHP/workerman/php-jit.ini @@ -1,13 +1,11 @@ +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 - mysqlnd.collect_statistics = Off - memory_limit = 512M - opcache.jit_buffer_size=128M -opcache.jit=tracing +opcache.jit=tracing \ No newline at end of file diff --git a/frameworks/PHP/workerman/php.ini b/frameworks/PHP/workerman/php.ini index e12bbd2fb0c..f6be852042e 100644 --- a/frameworks/PHP/workerman/php.ini +++ b/frameworks/PHP/workerman/php.ini @@ -7,4 +7,4 @@ opcache.huge_code_pages=1 mysqlnd.collect_statistics = Off -memory_limit = 512M +memory_limit = 512M \ No newline at end of file diff --git a/frameworks/PHP/workerman/server-async.php b/frameworks/PHP/workerman/server-async.php deleted file mode 100644 index ce468df5cd6..00000000000 --- a/frameworks/PHP/workerman/server-async.php +++ /dev/null @@ -1,80 +0,0 @@ -count = (int) shell_exec('nproc') * 2; -$http_worker->onWorkerStart = static function() { - global $mysql; - - $loop = Worker::getEventLoop(); - - $mysql = new React\MySQL\Connection($loop, [ - 'host' => 'tfb-database', - 'dbname' => 'hello_world', - 'user' => 'benchmarkdbuser', - 'passwd' => 'benchmarkdbpass' - ]); - - $mysql->on('error', function($e){ - echo $e; - }); - - $mysql->connect(function ($e) {}); -}; - -$http_worker->onMessage = static function ($connection, $request) { - - global $mysql; - - switch ($request->path()) { - case '/db': - $mysql->query('SELECT id,randomNumber FROM World WHERE id='.mt_rand(1, 10000), - static function ($command) use ($connection) { - $connection->send(new Response(200, ['Content-Type' => 'application/json', 'Date' => gmdate('D, d M Y H:i:s').' GMT'], json_encode($command->resultRows, JSON_NUMERIC_CHECK))); - } - ); - return; - - case '/fortunes': - // By default use 'Content-Type: text/html; charset=utf-8'; - $mysql->query('SELECT id,message FROM Fortune', - static function ($command) use ($connection) { - $arr = $command->resultRows; - foreach ($arr as $row) { - $fortune[$row['id']] = htmlspecialchars($row['message'], ENT_QUOTES, 'UTF-8'); - } - $fortune[0] = 'Additional fortune added at request time.'; - asort($fortune); - - $html = 'Fortunes'; - foreach ($fortune as $id => $message) { - $html .= ""; - } - - $connection->send(new Response(200, ['Date' => gmdate('D, d M Y H:i:s').' GMT'], $html.'
idmessage
$id$message
')); - - } - ); - return; - - //case '/update': - // Http::header('Content-Type: application/json'); - // return $connection->send(update()); - - //case '/info': - // Http::header('Content-Type: text/plain'); - // ob_start(); - // phpinfo(); - // return $connection->send(ob_get_clean()); - - default: - $connection->send(new Response(200, [], 'Error 404')); - - } -}; - -Worker::runAll(); diff --git a/frameworks/PHP/workerman/server.php b/frameworks/PHP/workerman/server.php index 2822b170ff0..8f845329bf2 100644 --- a/frameworks/PHP/workerman/server.php +++ b/frameworks/PHP/workerman/server.php @@ -1,29 +1,83 @@ count = (int) shell_exec('nproc') * 4; -$http_worker->onWorkerStart = function () { - Header::$date = gmdate('D, d M Y H:i:s').' GMT'; - Timer::add(1, function() { - Header::$date = gmdate('D, d M Y H:i:s').' GMT'; - }); - init(); +$test_type = getenv('TEST_TYPE') ?: 'default'; +$process = getenv('PROCESS_MULTIPLIER') ?: 1; +$pool_size = getenv('POOL_SIZE') ?: 2; +$process_count = (int) shell_exec('nproc') * $process; +$event_loop = getenv('EVENT_LOOP'); + +$db = $date = null; +$http_worker = new Worker('http://0.0.0.0:8080'); +$http_worker->reusePort = true; +$http_worker->count = $process_count; +$http_worker->onWorkerStart = static function () use ($test_type, $pool_size, &$db, &$date) { + $db = match ($test_type) { + 'pgsql' => new Pgsql(), + 'mysql' => new Mysql(), + 'pgsql-swow' => new PgsqlSwow($pool_size), + 'mysql-swow' => new MysqlSwow($pool_size), + 'pgsql-swoole' => new PgsqlSwoole($pool_size), + 'mysql-swoole' => new MysqlSwoole($pool_size), + 'default' => new Mysql(), + }; + $date = new Date(); }; -$http_worker->onMessage = static function ($connection, $request) { +Worker::$eventLoopClass = "Workerman\\Events\\$event_loop"; +if ($event_loop === 'Swoole') { + Coroutine::set(['hook_flags' => SWOOLE_HOOK_ALL]); +} - $connection->send(router($request)); - +$http_worker->onMessage = static function ($connection, $request) use (&$db, &$date) { + switch ($request->path()) { + case '/plaintext': + $connection->headers = [ + 'Content-Type' => 'text/plain', + 'Date' => $date->date + ]; + return $connection->send('Hello, World!'); + case '/json': + $connection->headers = [ + 'Content-Type' => 'application/json', + 'Date' => $date->date + ]; + return $connection->send(json_encode(['message' => 'Hello, World!'])); + case '/db': + $connection->headers = [ + 'Content-Type' => 'application/json', + 'Date' => $date->date + ]; + return $connection->send(json_encode($db->db())); + case '/fortunes': + $connection->headers = [ + 'Date' => $date->date + ]; + return $connection->send($db->fortune()); + case '/query': + $connection->headers = [ + 'Content-Type' => 'application/json', + 'Date' => $date->date + ]; + return $connection->send(json_encode($db->query($request))); + case '/update': + $connection->headers = [ + 'Content-Type' => 'application/json', + 'Date' => $date->date + ]; + return $connection->send(json_encode($db->update($request))); + } + return $connection->send(new Response(404, [ + 'Content-Type' => 'text/plain', + 'Date' => $date->date + ], '404 Not Found')); }; Worker::runAll(); - - -class Header { - public static $date = null; -} diff --git a/frameworks/PHP/workerman/workerman-async.dockerfile b/frameworks/PHP/workerman/workerman-async.dockerfile deleted file mode 100644 index ceef86cbc42..00000000000 --- a/frameworks/PHP/workerman/workerman-async.dockerfile +++ /dev/null @@ -1,26 +0,0 @@ -FROM ubuntu:22.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 install -yqq php7.4-cli php7.4-mysql > /dev/null - -COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer - -RUN apt-get install -y php-pear php7.4-dev libevent-dev git > /dev/null -RUN pecl install event > /dev/null && echo "extension=event.so" > /etc/php/7.4/cli/conf.d/event.ini - -COPY php.ini /etc/php/7.4/cli/php.ini - -ADD ./ /workerman -WORKDIR /workerman - -RUN composer require react/mysql "^0.3.3" --quiet -RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet - -EXPOSE 8080 - -CMD php /workerman/server-async.php start diff --git a/frameworks/PHP/workerman/workerman-jit.dockerfile b/frameworks/PHP/workerman/workerman-jit.dockerfile new file mode 100644 index 00000000000..47ae11800d2 --- /dev/null +++ b/frameworks/PHP/workerman/workerman-jit.dockerfile @@ -0,0 +1,28 @@ +FROM ubuntu:24.04 + +ENV TEST_TYPE default +ENV PROCESS_MULTIPLIER 1 +ENV EVENT_LOOP Select + +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 install -yqq php8.4-cli php8.4-mysql php8.4-xml > /dev/null + +COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer + +RUN apt-get install -y php-pear php8.4-dev libevent-dev git > /dev/null && \ + pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.4/cli/conf.d/30-event.ini + +WORKDIR /workerman +COPY --link . . + +RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet +COPY php-jit.ini /etc/php/8.4/cli/conf.d/10-opcache.ini + +EXPOSE 8080 + +CMD php /workerman/server.php start diff --git a/frameworks/PHP/workerman/workerman-mysql-jit.dockerfile b/frameworks/PHP/workerman/workerman-mysql-jit.dockerfile new file mode 100644 index 00000000000..8992f918a0d --- /dev/null +++ b/frameworks/PHP/workerman/workerman-mysql-jit.dockerfile @@ -0,0 +1,28 @@ +FROM ubuntu:24.04 + +ENV TEST_TYPE mysql +ENV PROCESS_MULTIPLIER 4 +ENV EVENT_LOOP Event + +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 install -yqq php8.4-cli php8.4-mysql php8.4-xml > /dev/null + +COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer + +RUN apt-get install -y php-pear php8.4-dev libevent-dev git > /dev/null && \ + pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.4/cli/conf.d/30-event.ini + +WORKDIR /workerman +COPY --link . . + +RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet +COPY php-jit.ini /etc/php/8.4/cli/conf.d/10-opcache.ini + +EXPOSE 8080 + +CMD php /workerman/server.php start diff --git a/frameworks/PHP/workerman/workerman-mysql-swoole-jit.dockerfile b/frameworks/PHP/workerman/workerman-mysql-swoole-jit.dockerfile new file mode 100644 index 00000000000..54440a5a047 --- /dev/null +++ b/frameworks/PHP/workerman/workerman-mysql-swoole-jit.dockerfile @@ -0,0 +1,35 @@ +FROM ubuntu:24.04 + +ENV TEST_TYPE mysql-swoole +ENV SWOOLE_VERSION 5.1.5 +ENV PROCESS_MULTIPLIER 1 +ENV POOL_SIZE 4 +ENV EVENT_LOOP Swoole + +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 libbrotli-dev php8.3-cli php8.3-pdo-mysql php8.3-dev php8.3-mbstring git -y > /dev/null \ + && cd /tmp && curl -sSL "https://github.com/swoole/swoole-src/archive/v${SWOOLE_VERSION}.tar.gz" | tar xzf - \ + && cd /tmp/swoole-src-${SWOOLE_VERSION} \ + && phpize > /dev/null \ + && ./configure > /dev/null \ + && make -j "$(nproc)" > /dev/null \ + && make install > /dev/null \ + && echo "extension=swoole.so" > /etc/php/8.3/cli/conf.d/50-swoole.ini \ + && echo "memory_limit=1024M" >> /etc/php/8.3/cli/php.ini + +COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer + +WORKDIR /workerman +COPY --link . . + +RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet +COPY php-jit.ini /etc/php/8.3/cli/conf.d/10-opcache.ini + +EXPOSE 8080 + +CMD php /workerman/server.php start diff --git a/frameworks/PHP/workerman/workerman-mysql-swow-jit.dockerfile b/frameworks/PHP/workerman/workerman-mysql-swow-jit.dockerfile new file mode 100644 index 00000000000..ffab87c078d --- /dev/null +++ b/frameworks/PHP/workerman/workerman-mysql-swow-jit.dockerfile @@ -0,0 +1,34 @@ +FROM ubuntu:24.04 + +ENV TEST_TYPE mysql-swow +ENV PROCESS_MULTIPLIER 1 +ENV POOL_SIZE 4 +ENV EVENT_LOOP Swow + +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 install -yqq php8.3-cli php8.3-mysql php8.3-xml > /dev/null + +COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer + +RUN apt-get install -y php-pear php8.3-dev git > /dev/null + + +WORKDIR /workerman +COPY --link . . + + +RUN composer require swow/swow > /dev/null +RUN ./vendor/bin/swow-builder --install > /dev/null +RUN echo extension=swow.so > /etc/php/8.3/cli/conf.d/20-swow.ini +RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet +COPY php-jit.ini /etc/php/8.3/cli/conf.d/10-opcache.ini + +EXPOSE 8080 + + +CMD php /workerman/server.php start diff --git a/frameworks/PHP/workerman/workerman-pgsql-jit.dockerfile b/frameworks/PHP/workerman/workerman-pgsql-jit.dockerfile new file mode 100644 index 00000000000..f1e84f54011 --- /dev/null +++ b/frameworks/PHP/workerman/workerman-pgsql-jit.dockerfile @@ -0,0 +1,28 @@ +FROM ubuntu:24.04 + +ENV TEST_TYPE pgsql +ENV PROCESS_MULTIPLIER 4 +ENV EVENT_LOOP Event + +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 install -yqq php8.4-cli php8.4-pgsql php8.4-xml > /dev/null + +COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer + +RUN apt-get install -y php-pear php8.4-dev libevent-dev git > /dev/null && \ + pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.4/cli/conf.d/30-event.ini + +WORKDIR /workerman +COPY --link . . + +RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet +COPY php-jit.ini /etc/php/8.4/cli/conf.d/10-opcache.ini + +EXPOSE 8080 + +CMD php /workerman/server.php start diff --git a/frameworks/PHP/workerman/workerman-pgsql-swoole-jit.dockerfile b/frameworks/PHP/workerman/workerman-pgsql-swoole-jit.dockerfile new file mode 100644 index 00000000000..09a6026a853 --- /dev/null +++ b/frameworks/PHP/workerman/workerman-pgsql-swoole-jit.dockerfile @@ -0,0 +1,35 @@ +FROM ubuntu:24.04 + +ENV TEST_TYPE pgsql-swoole +ENV SWOOLE_VERSION 5.1.5 +ENV PROCESS_MULTIPLIER 2 +ENV POOL_SIZE 16 +ENV EVENT_LOOP Swoole + +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 libbrotli-dev php8.3-cli php8.3-pdo-pgsql php8.3-dev libpq-dev php8.3-mbstring git -y > /dev/null \ + && cd /tmp && curl -sSL "https://github.com/swoole/swoole-src/archive/v${SWOOLE_VERSION}.tar.gz" | tar xzf - \ + && cd /tmp/swoole-src-${SWOOLE_VERSION} \ + && phpize > /dev/null \ + && ./configure --enable-swoole-pgsql > /dev/null \ + && make -j "$(nproc)" > /dev/null \ + && make install > /dev/null \ + && echo "extension=swoole.so" > /etc/php/8.3/cli/conf.d/50-swoole.ini \ + && echo "memory_limit=1024M" >> /etc/php/8.3/cli/php.ini + +COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer + +WORKDIR /workerman +COPY --link . . + +RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet +COPY php-jit.ini /etc/php/8.3/cli/conf.d/10-opcache.ini + +EXPOSE 8080 + +CMD php /workerman/server.php start diff --git a/frameworks/PHP/workerman/workerman-pgsql-swow-jit.dockerfile b/frameworks/PHP/workerman/workerman-pgsql-swow-jit.dockerfile new file mode 100644 index 00000000000..72557d22306 --- /dev/null +++ b/frameworks/PHP/workerman/workerman-pgsql-swow-jit.dockerfile @@ -0,0 +1,34 @@ +FROM ubuntu:24.04 + +ENV TEST_TYPE pgsql-swow +ENV PROCESS_MULTIPLIER 2 +ENV POOL_SIZE 16 +ENV EVENT_LOOP Swow + +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 install -yqq php8.3-cli php8.3-pgsql php8.3-xml > /dev/null + +COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer + +RUN apt-get install -y php-pear php8.3-dev git > /dev/null + + +WORKDIR /workerman +COPY --link . . + + +RUN composer require swow/swow > /dev/null +RUN ./vendor/bin/swow-builder --install > /dev/null +RUN echo extension=swow.so > /etc/php/8.3/cli/conf.d/20-swow.ini +RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet +COPY php-jit.ini /etc/php/8.3/cli/conf.d/10-opcache.ini + +EXPOSE 8080 + + +CMD php /workerman/server.php start diff --git a/frameworks/PHP/workerman/workerman-pgsql.dockerfile b/frameworks/PHP/workerman/workerman-pgsql.dockerfile index 5e799c4b578..f8209fb7d00 100644 --- a/frameworks/PHP/workerman/workerman-pgsql.dockerfile +++ b/frameworks/PHP/workerman/workerman-pgsql.dockerfile @@ -1,26 +1,27 @@ -FROM ubuntu:22.04 +FROM ubuntu:24.04 + +ENV TEST_TYPE pgsql +ENV PROCESS_MULTIPLIER 4 +ENV EVENT_LOOP Event + 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 install -yqq php8.3-cli php8.3-pgsql php8.3-xml > /dev/null +RUN apt-get install -yqq php8.4-cli php8.4-pgsql php8.4-xml > /dev/null -COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer +COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer -RUN apt-get install -y php-pear php8.3-dev libevent-dev git > /dev/null -RUN pecl install event-3.0.8 > /dev/null && echo "extension=event.so" > /etc/php/8.3/cli/conf.d/event.ini +RUN apt-get install -y php-pear php8.4-dev libevent-dev git > /dev/null && \ + pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.4/cli/conf.d/30-event.ini -COPY php.ini /etc/php/8.3/cli/php.ini - -ADD ./ /workerman WORKDIR /workerman - -RUN sed -i "s|'/app.php|'/app-pg.php|g" server.php -RUN sed -i "s|init()|DbRaw::init()|g" server.php +COPY --link . . RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet +COPY php.ini /etc/php/8.4/cli/php.ini EXPOSE 8080 diff --git a/frameworks/PHP/workerman/workerman-php8-jit.dockerfile b/frameworks/PHP/workerman/workerman-php8-jit.dockerfile deleted file mode 100644 index 9ead4cd2124..00000000000 --- a/frameworks/PHP/workerman/workerman-php8-jit.dockerfile +++ /dev/null @@ -1,29 +0,0 @@ -FROM ubuntu:22.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 install -yqq php8.3-cli php8.3-pgsql php8.3-xml > /dev/null - -COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer - -RUN apt-get install -y php-pear php8.3-dev libevent-dev git > /dev/null -RUN pecl install event-3.0.8 > /dev/null && echo "extension=event.so" > /etc/php/8.3/cli/conf.d/event.ini - -COPY php-jit.ini /etc/php/8.3/cli/php.ini - -ADD ./ /workerman -WORKDIR /workerman - -RUN sed -i "s|'/app.php|'/app-pg.php|g" server.php -RUN sed -i "s|init()|DbRaw::init()|g" server.php -RUN sed -i "s|opcache.jit=off|opcache.jit=function|g" /etc/php/8.3/cli/conf.d/10-opcache.ini - -RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet - -EXPOSE 8080 - -CMD php /workerman/server.php start diff --git a/frameworks/PHP/workerman/workerman.dockerfile b/frameworks/PHP/workerman/workerman.dockerfile index 9b321d73ce5..8d93101166f 100644 --- a/frameworks/PHP/workerman/workerman.dockerfile +++ b/frameworks/PHP/workerman/workerman.dockerfile @@ -1,4 +1,8 @@ -FROM ubuntu:22.04 +FROM ubuntu:24.04 + +ENV TEST_TYPE default +ENV PROCESS_MULTIPLIER 1 +ENV EVENT_LOOP Select ARG DEBIAN_FRONTEND=noninteractive @@ -6,19 +10,18 @@ RUN apt-get update -yqq && apt-get install -yqq software-properties-common > /de 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 install -yqq php8.3-cli php8.3-mysql php8.3-xml > /dev/null +RUN apt-get install -yqq php8.4-cli php8.4-mysql php8.4-xml > /dev/null -COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer +COPY --from=composer/composer:latest-bin --link /composer /usr/local/bin/composer -RUN apt-get install -y php-pear php8.3-dev libevent-dev git > /dev/null -RUN pecl install event-3.0.8 > /dev/null && echo "extension=event.so" > /etc/php/8.3/cli/conf.d/event.ini - -COPY php-jit.ini /etc/php/8.3/cli/php.ini +RUN apt-get install -y php-pear php8.4-dev libevent-dev git > /dev/null && \ + pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.4/cli/conf.d/30-event.ini -ADD ./ /workerman WORKDIR /workerman +COPY --link . . RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet +COPY php.ini /etc/php/8.4/cli/php.ini EXPOSE 8080 diff --git a/frameworks/PHP/yii2/composer.json b/frameworks/PHP/yii2/composer.json index 695b189d305..03260f5041e 100755 --- a/frameworks/PHP/yii2/composer.json +++ b/frameworks/PHP/yii2/composer.json @@ -2,7 +2,7 @@ "require": { "yidas/yii2-composer-bower-skip": "~2.0.13", "yiisoft/yii2": "~2.0.49", - "joanhey/adapterman": "^0.6" + "joanhey/adapterman": "^0.7" }, "config": { "allow-plugins": { diff --git a/frameworks/PHP/yii2/deploy/conf/cli-php.ini b/frameworks/PHP/yii2/deploy/conf/cli-php.ini index ea3b9e510ae..82a3aec2efa 100644 --- a/frameworks/PHP/yii2/deploy/conf/cli-php.ini +++ b/frameworks/PHP/yii2/deploy/conf/cli-php.ini @@ -13,4 +13,4 @@ memory_limit = 512M opcache.jit_buffer_size=128M opcache.jit=tracing -disable_functions=header,header_remove,headers_sent,http_response_code,setcookie,session_create_id,session_id,session_name,session_save_path,session_status,session_start,session_write_close,session_regenerate_id,set_time_limit +disable_functions=header,header_remove,headers_sent,headers_list,http_response_code,setcookie,session_create_id,session_id,session_name,session_save_path,session_status,session_start,session_write_close,session_regenerate_id,session_unset,session_get_cookie_params,session_set_cookie_params,set_time_limit diff --git a/frameworks/PHP/yii2/server.php b/frameworks/PHP/yii2/server.php index 6cef4a7e10e..59fe04b19f1 100644 --- a/frameworks/PHP/yii2/server.php +++ b/frameworks/PHP/yii2/server.php @@ -3,7 +3,7 @@ use Adapterman\Adapterman; use Workerman\Worker; -use Workerman\Lib\Timer; +use Workerman\Timer; Adapterman::init(); @@ -11,6 +11,7 @@ $http_worker = new Worker('http://0.0.0.0:8080'); $http_worker->count = (int) shell_exec('nproc') * 4; +$http_worker->reusePort = true; $http_worker->name = 'AdapterMan-Yii2'; $http_worker->onWorkerStart = static function () { @@ -33,9 +34,9 @@ class WorkerTimer public static function init() { - self::$date = 'Date: '.gmdate('D, d M Y H:i:s').' GMT'; + self::$date = 'Date: ' . gmdate(DATE_RFC7231); Timer::add(1, function() { - WorkerTimer::$date = 'Date: '.gmdate('D, d M Y H:i:s').' GMT'; + WorkerTimer::$date = 'Date: ' . gmdate(DATE_RFC7231); }); } } diff --git a/frameworks/PHP/yii2/yii2-raw.dockerfile b/frameworks/PHP/yii2/yii2-raw.dockerfile index b7af0a36511..cfb0bf78a38 100644 --- a/frameworks/PHP/yii2/yii2-raw.dockerfile +++ b/frameworks/PHP/yii2/yii2-raw.dockerfile @@ -1,24 +1,24 @@ -FROM ubuntu:22.04 +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 > /dev/null && \ - apt-get install -yqq nginx git unzip php8.3 php8.3-common php8.3-cli php8.3-fpm php8.3-mysql php8.3-mbstring php8.3-dev > /dev/null + apt-get install -yqq nginx git unzip php8.4 php8.4-common php8.4-cli php8.4-fpm php8.4-mysql php8.4-mbstring php8.4-dev > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -COPY deploy/conf/* /etc/php/8.3/fpm/ +COPY deploy/conf/* /etc/php/8.4/fpm/ -ADD ./ /yii2 WORKDIR /yii2 +COPY --link . . -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.3/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.4/fpm/php-fpm.conf ; fi; RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet EXPOSE 8080 -CMD service php8.3-fpm start && \ +CMD service php8.4-fpm start && \ nginx -c /yii2/deploy/nginx.conf diff --git a/frameworks/PHP/yii2/yii2-workerman.dockerfile b/frameworks/PHP/yii2/yii2-workerman.dockerfile index e5502f5b455..204aeaf58a8 100644 --- a/frameworks/PHP/yii2/yii2-workerman.dockerfile +++ b/frameworks/PHP/yii2/yii2-workerman.dockerfile @@ -1,21 +1,21 @@ -FROM ubuntu:22.04 +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 > /dev/null && \ - apt-get install -yqq git php8.3-cli php8.3-mysql php8.3-mbstring php8.3-xml > /dev/null + apt-get install -yqq git php8.4-cli php8.4-mysql php8.4-mbstring php8.4-xml > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -RUN apt-get install -y php-pear php8.3-dev libevent-dev > /dev/null -RUN pecl install event-3.0.8 > /dev/null && echo "extension=event.so" > /etc/php/8.3/cli/conf.d/event.ini +RUN apt-get install -y php-pear php8.4-dev libevent-dev > /dev/null +RUN pecl install event-3.1.4 > /dev/null && echo "extension=event.so" > /etc/php/8.4/cli/conf.d/event.ini -COPY deploy/conf/cli-php.ini /etc/php/8.3/cli/php.ini +COPY --link deploy/conf/cli-php.ini /etc/php/8.4/cli/conf.d/20-adapterman.ini -ADD ./ /yii2 WORKDIR /yii2 +COPY --link . . RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet diff --git a/frameworks/PHP/yii2/yii2.dockerfile b/frameworks/PHP/yii2/yii2.dockerfile index b7af0a36511..cfb0bf78a38 100644 --- a/frameworks/PHP/yii2/yii2.dockerfile +++ b/frameworks/PHP/yii2/yii2.dockerfile @@ -1,24 +1,24 @@ -FROM ubuntu:22.04 +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 > /dev/null && \ - apt-get install -yqq nginx git unzip php8.3 php8.3-common php8.3-cli php8.3-fpm php8.3-mysql php8.3-mbstring php8.3-dev > /dev/null + apt-get install -yqq nginx git unzip php8.4 php8.4-common php8.4-cli php8.4-fpm php8.4-mysql php8.4-mbstring php8.4-dev > /dev/null COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer -COPY deploy/conf/* /etc/php/8.3/fpm/ +COPY deploy/conf/* /etc/php/8.4/fpm/ -ADD ./ /yii2 WORKDIR /yii2 +COPY --link . . -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/8.3/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.4/fpm/php-fpm.conf ; fi; RUN composer install --optimize-autoloader --classmap-authoritative --no-dev --quiet EXPOSE 8080 -CMD service php8.3-fpm start && \ +CMD service php8.4-fpm start && \ nginx -c /yii2/deploy/nginx.conf diff --git a/frameworks/PHP/zend/benchmark_config.json b/frameworks/PHP/zend/benchmark_config.json deleted file mode 100644 index 47743cd8a36..00000000000 --- a/frameworks/PHP/zend/benchmark_config.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "framework": "zend", - "tests": [{ - "default": { - "plaintext_url": "/plaintext", - "json_url": "/json", - "db_url": "/db", - "update_url": "/updates?queries=", - "query_url": "/queries?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "MySQL", - "framework": "Zend", - "language": "PHP", - "flavor": "PHP7", - "orm": "Full", - "platform": "FPM/FastCGI", - "webserver": "nginx", - "os": "Linux", - "database_os": "Linux", - "display_name": "zend", - "notes": "", - "versus": "php" - } - }] -} diff --git a/frameworks/PHP/zend/composer.json b/frameworks/PHP/zend/composer.json deleted file mode 100644 index ddce9e0aa74..00000000000 --- a/frameworks/PHP/zend/composer.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "zendframework/skeleton-application", - "description": "Skeleton Application for ZF", - "license": "BSD-3-Clause", - "keywords": [ - "framework", - "zf2" - ], - "homepage": "http://framework.zend.com/", - "require": { - "php": "^7.2", - "zendframework/zend-mvc": "^3.0.1", - "zendframework/zend-db": "^2.9.3" - }, - "autoload": { - "psr-0": { - "FrameworkBenchmarks": "module/FrameworkBenchmarks/src" - } - } -} diff --git a/frameworks/PHP/zend/composer.lock b/frameworks/PHP/zend/composer.lock deleted file mode 100644 index f4060f2da30..00000000000 --- a/frameworks/PHP/zend/composer.lock +++ /dev/null @@ -1,982 +0,0 @@ -{ - "_readme": [ - "This file locks the dependencies of your project to a known state", - "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", - "This file is @generated automatically" - ], - "content-hash": "1a71e90b2e2a74968245456d36c1f4e8", - "packages": [ - { - "name": "container-interop/container-interop", - "version": "1.2.0", - "source": { - "type": "git", - "url": "https://github.com/container-interop/container-interop.git", - "reference": "79cbf1341c22ec75643d841642dd5d6acd83bdb8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/container-interop/container-interop/zipball/79cbf1341c22ec75643d841642dd5d6acd83bdb8", - "reference": "79cbf1341c22ec75643d841642dd5d6acd83bdb8", - "shasum": "" - }, - "require": { - "psr/container": "^1.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Interop\\Container\\": "src/Interop/Container/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Promoting the interoperability of container objects (DIC, SL, etc.)", - "homepage": "https://github.com/container-interop/container-interop", - "time": "2017-02-14T19:40:03+00:00" - }, - { - "name": "psr/container", - "version": "1.0.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/container.git", - "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f", - "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Container\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" - } - ], - "description": "Common Container Interface (PHP FIG PSR-11)", - "homepage": "https://github.com/php-fig/container", - "keywords": [ - "PSR-11", - "container", - "container-interface", - "container-interop", - "psr" - ], - "time": "2017-02-14T16:28:37+00:00" - }, - { - "name": "zendframework/zend-config", - "version": "3.2.0", - "source": { - "type": "git", - "url": "https://github.com/zendframework/zend-config.git", - "reference": "6796f5dcba52c84ef2501d7313618989b5ef3023" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-config/zipball/6796f5dcba52c84ef2501d7313618989b5ef3023", - "reference": "6796f5dcba52c84ef2501d7313618989b5ef3023", - "shasum": "" - }, - "require": { - "ext-json": "*", - "php": "^5.6 || ^7.0", - "psr/container": "^1.0", - "zendframework/zend-stdlib": "^2.7.7 || ^3.1" - }, - "conflict": { - "container-interop/container-interop": "<1.2.0" - }, - "require-dev": { - "malukenho/docheader": "^0.1.6", - "phpunit/phpunit": "^5.7.27 || ^6.5.8 || ^7.1.2", - "zendframework/zend-coding-standard": "~1.0.0", - "zendframework/zend-filter": "^2.7.2", - "zendframework/zend-i18n": "^2.7.4", - "zendframework/zend-servicemanager": "^2.7.8 || ^3.3" - }, - "suggest": { - "zendframework/zend-filter": "^2.7.2; install if you want to use the Filter processor", - "zendframework/zend-i18n": "^2.7.4; install if you want to use the Translator processor", - "zendframework/zend-servicemanager": "^2.7.8 || ^3.3; if you need an extensible plugin manager for use with the Config Factory" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.2.x-dev", - "dev-develop": "3.3.x-dev" - } - }, - "autoload": { - "psr-4": { - "Zend\\Config\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "provides a nested object property based user interface for accessing this configuration data within application code", - "keywords": [ - "ZendFramework", - "config", - "zf" - ], - "time": "2018-04-24T19:26:44+00:00" - }, - { - "name": "zendframework/zend-db", - "version": "2.9.3", - "source": { - "type": "git", - "url": "https://github.com/zendframework/zend-db.git", - "reference": "5b4f2c42f94c9f7f4b2f456a0ebe459fab12b3d9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-db/zipball/5b4f2c42f94c9f7f4b2f456a0ebe459fab12b3d9", - "reference": "5b4f2c42f94c9f7f4b2f456a0ebe459fab12b3d9", - "shasum": "" - }, - "require": { - "php": "^5.6 || ^7.0", - "zendframework/zend-stdlib": "^2.7 || ^3.0" - }, - "require-dev": { - "phpunit/phpunit": "^5.7.25 || ^6.4.4", - "zendframework/zend-coding-standard": "~1.0.0", - "zendframework/zend-eventmanager": "^2.6.2 || ^3.0", - "zendframework/zend-hydrator": "^1.1 || ^2.1", - "zendframework/zend-servicemanager": "^2.7.5 || ^3.0.3" - }, - "suggest": { - "zendframework/zend-eventmanager": "Zend\\EventManager component", - "zendframework/zend-hydrator": "Zend\\Hydrator component for using HydratingResultSets", - "zendframework/zend-servicemanager": "Zend\\ServiceManager component" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.9-dev", - "dev-develop": "2.10-dev" - }, - "zf": { - "component": "Zend\\Db", - "config-provider": "Zend\\Db\\ConfigProvider" - } - }, - "autoload": { - "psr-4": { - "Zend\\Db\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "Database abstraction layer, SQL abstraction, result set abstraction, and RowDataGateway and TableDataGateway implementations", - "keywords": [ - "ZendFramework", - "db", - "zf" - ], - "time": "2018-04-09T13:21:36+00:00" - }, - { - "name": "zendframework/zend-escaper", - "version": "2.6.0", - "source": { - "type": "git", - "url": "https://github.com/zendframework/zend-escaper.git", - "reference": "31d8aafae982f9568287cb4dce987e6aff8fd074" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-escaper/zipball/31d8aafae982f9568287cb4dce987e6aff8fd074", - "reference": "31d8aafae982f9568287cb4dce987e6aff8fd074", - "shasum": "" - }, - "require": { - "php": "^5.6 || ^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^5.7.27 || ^6.5.8 || ^7.1.2", - "zendframework/zend-coding-standard": "~1.0.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.6.x-dev", - "dev-develop": "2.7.x-dev" - } - }, - "autoload": { - "psr-4": { - "Zend\\Escaper\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "Securely and safely escape HTML, HTML attributes, JavaScript, CSS, and URLs", - "keywords": [ - "ZendFramework", - "escaper", - "zf" - ], - "time": "2018-04-25T15:48:53+00:00" - }, - { - "name": "zendframework/zend-eventmanager", - "version": "3.2.1", - "source": { - "type": "git", - "url": "https://github.com/zendframework/zend-eventmanager.git", - "reference": "a5e2583a211f73604691586b8406ff7296a946dd" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-eventmanager/zipball/a5e2583a211f73604691586b8406ff7296a946dd", - "reference": "a5e2583a211f73604691586b8406ff7296a946dd", - "shasum": "" - }, - "require": { - "php": "^5.6 || ^7.0" - }, - "require-dev": { - "athletic/athletic": "^0.1", - "container-interop/container-interop": "^1.1.0", - "phpunit/phpunit": "^5.7.27 || ^6.5.8 || ^7.1.2", - "zendframework/zend-coding-standard": "~1.0.0", - "zendframework/zend-stdlib": "^2.7.3 || ^3.0" - }, - "suggest": { - "container-interop/container-interop": "^1.1.0, to use the lazy listeners feature", - "zendframework/zend-stdlib": "^2.7.3 || ^3.0, to use the FilterChain feature" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.2-dev", - "dev-develop": "3.3-dev" - } - }, - "autoload": { - "psr-4": { - "Zend\\EventManager\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "Trigger and listen to events within a PHP application", - "homepage": "https://github.com/zendframework/zend-eventmanager", - "keywords": [ - "event", - "eventmanager", - "events", - "zf2" - ], - "time": "2018-04-25T15:33:34+00:00" - }, - { - "name": "zendframework/zend-http", - "version": "2.8.2", - "source": { - "type": "git", - "url": "https://github.com/zendframework/zend-http.git", - "reference": "2c8aed3d25522618573194e7cc51351f8cd4a45b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-http/zipball/2c8aed3d25522618573194e7cc51351f8cd4a45b", - "reference": "2c8aed3d25522618573194e7cc51351f8cd4a45b", - "shasum": "" - }, - "require": { - "php": "^5.6 || ^7.0", - "zendframework/zend-loader": "^2.5.1", - "zendframework/zend-stdlib": "^3.1 || ^2.7.7", - "zendframework/zend-uri": "^2.5.2", - "zendframework/zend-validator": "^2.10.1" - }, - "require-dev": { - "phpunit/phpunit": "^5.7.27 || ^6.5.8 || ^7.1.3", - "zendframework/zend-coding-standard": "~1.0.0", - "zendframework/zend-config": "^3.1 || ^2.6" - }, - "suggest": { - "paragonie/certainty": "For automated management of cacert.pem" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.8.x-dev", - "dev-develop": "2.9.x-dev" - } - }, - "autoload": { - "psr-4": { - "Zend\\Http\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "Provides an easy interface for performing Hyper-Text Transfer Protocol (HTTP) requests", - "keywords": [ - "ZendFramework", - "http", - "http client", - "zend", - "zf" - ], - "time": "2018-08-13T18:47:03+00:00" - }, - { - "name": "zendframework/zend-json", - "version": "3.1.0", - "source": { - "type": "git", - "url": "https://github.com/zendframework/zend-json.git", - "reference": "4dd940e8e6f32f1d36ea6b0677ea57c540c7c19c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-json/zipball/4dd940e8e6f32f1d36ea6b0677ea57c540c7c19c", - "reference": "4dd940e8e6f32f1d36ea6b0677ea57c540c7c19c", - "shasum": "" - }, - "require": { - "php": "^5.6 || ^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^5.7.23 || ^6.4.3", - "zendframework/zend-coding-standard": "~1.0.0", - "zendframework/zend-stdlib": "^2.7.7 || ^3.1" - }, - "suggest": { - "zendframework/zend-json-server": "For implementing JSON-RPC servers", - "zendframework/zend-xml2json": "For converting XML documents to JSON" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.1.x-dev", - "dev-develop": "3.2.x-dev" - } - }, - "autoload": { - "psr-4": { - "Zend\\Json\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "provides convenience methods for serializing native PHP to JSON and decoding JSON to native PHP", - "keywords": [ - "ZendFramework", - "json", - "zf" - ], - "time": "2018-01-04T17:51:34+00:00" - }, - { - "name": "zendframework/zend-loader", - "version": "2.6.0", - "source": { - "type": "git", - "url": "https://github.com/zendframework/zend-loader.git", - "reference": "78f11749ea340f6ca316bca5958eef80b38f9b6c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-loader/zipball/78f11749ea340f6ca316bca5958eef80b38f9b6c", - "reference": "78f11749ea340f6ca316bca5958eef80b38f9b6c", - "shasum": "" - }, - "require": { - "php": "^5.6 || ^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^5.7.27 || ^6.5.8 || ^7.1.4", - "zendframework/zend-coding-standard": "~1.0.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.6.x-dev", - "dev-develop": "2.7.x-dev" - } - }, - "autoload": { - "psr-4": { - "Zend\\Loader\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "Autoloading and plugin loading strategies", - "keywords": [ - "ZendFramework", - "loader", - "zf" - ], - "time": "2018-04-30T15:20:54+00:00" - }, - { - "name": "zendframework/zend-modulemanager", - "version": "2.8.2", - "source": { - "type": "git", - "url": "https://github.com/zendframework/zend-modulemanager.git", - "reference": "394df6e12248ac430a312d4693f793ee7120baa6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-modulemanager/zipball/394df6e12248ac430a312d4693f793ee7120baa6", - "reference": "394df6e12248ac430a312d4693f793ee7120baa6", - "shasum": "" - }, - "require": { - "php": "^5.6 || ^7.0", - "zendframework/zend-config": "^3.1 || ^2.6", - "zendframework/zend-eventmanager": "^3.2 || ^2.6.3", - "zendframework/zend-stdlib": "^3.1 || ^2.7" - }, - "require-dev": { - "phpunit/phpunit": "^6.0.8 || ^5.7.15", - "zendframework/zend-coding-standard": "~1.0.0", - "zendframework/zend-console": "^2.6", - "zendframework/zend-di": "^2.6", - "zendframework/zend-loader": "^2.5", - "zendframework/zend-mvc": "^3.0 || ^2.7", - "zendframework/zend-servicemanager": "^3.0.3 || ^2.7.5" - }, - "suggest": { - "zendframework/zend-console": "Zend\\Console component", - "zendframework/zend-loader": "Zend\\Loader component if you are not using Composer autoloading for your modules", - "zendframework/zend-mvc": "Zend\\Mvc component", - "zendframework/zend-servicemanager": "Zend\\ServiceManager component" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.7-dev", - "dev-develop": "2.8-dev" - } - }, - "autoload": { - "psr-4": { - "Zend\\ModuleManager\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "Modular application system for zend-mvc applications", - "homepage": "https://github.com/zendframework/zend-modulemanager", - "keywords": [ - "ZendFramework", - "modulemanager", - "zf" - ], - "time": "2017-12-02T06:11:18+00:00" - }, - { - "name": "zendframework/zend-mvc", - "version": "3.1.1", - "source": { - "type": "git", - "url": "https://github.com/zendframework/zend-mvc.git", - "reference": "236e7e1e3757e988fa06530c0a3f96a148858ae8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-mvc/zipball/236e7e1e3757e988fa06530c0a3f96a148858ae8", - "reference": "236e7e1e3757e988fa06530c0a3f96a148858ae8", - "shasum": "" - }, - "require": { - "container-interop/container-interop": "^1.2", - "php": "^5.6 || ^7.0", - "zendframework/zend-eventmanager": "^3.2", - "zendframework/zend-http": "^2.7", - "zendframework/zend-modulemanager": "^2.8", - "zendframework/zend-router": "^3.0.2", - "zendframework/zend-servicemanager": "^3.3", - "zendframework/zend-stdlib": "^3.1", - "zendframework/zend-view": "^2.9" - }, - "require-dev": { - "http-interop/http-middleware": "^0.4.1", - "phpunit/phpunit": "^6.4.4 || ^5.7.14", - "zendframework/zend-coding-standard": "~1.0.0", - "zendframework/zend-json": "^2.6.1 || ^3.0", - "zendframework/zend-psr7bridge": "^1.0", - "zendframework/zend-stratigility": "^2.0.1" - }, - "suggest": { - "http-interop/http-middleware": "^0.4.1 to be used together with zend-stratigility", - "zendframework/zend-json": "(^2.6.1 || ^3.0) To auto-deserialize JSON body content in AbstractRestfulController extensions, when json_decode is unavailable", - "zendframework/zend-log": "^2.9.1 To provide log functionality via LogFilterManager, LogFormatterManager, and LogProcessorManager", - "zendframework/zend-mvc-console": "zend-mvc-console provides the ability to expose zend-mvc as a console application", - "zendframework/zend-mvc-i18n": "zend-mvc-i18n provides integration with zend-i18n, including a translation bridge and translatable route segments", - "zendframework/zend-mvc-plugin-fileprg": "To provide Post/Redirect/Get functionality around forms that container file uploads", - "zendframework/zend-mvc-plugin-flashmessenger": "To provide flash messaging capabilities between requests", - "zendframework/zend-mvc-plugin-identity": "To access the authenticated identity (per zend-authentication) in controllers", - "zendframework/zend-mvc-plugin-prg": "To provide Post/Redirect/Get functionality within controllers", - "zendframework/zend-paginator": "^2.7 To provide pagination functionality via PaginatorPluginManager", - "zendframework/zend-psr7bridge": "(^0.2) To consume PSR-7 middleware within the MVC workflow", - "zendframework/zend-servicemanager-di": "zend-servicemanager-di provides utilities for integrating zend-di and zend-servicemanager in your zend-mvc application", - "zendframework/zend-stratigility": "zend-stratigility is required to use middleware pipes in the MiddlewareListener" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.1-dev", - "dev-develop": "3.2-dev" - } - }, - "autoload": { - "psr-4": { - "Zend\\Mvc\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "Zend Framework's event-driven MVC layer, including MVC Applications, Controllers, and Plugins", - "keywords": [ - "ZendFramework", - "mvc", - "zf" - ], - "time": "2017-11-24T06:32:07+00:00" - }, - { - "name": "zendframework/zend-router", - "version": "3.2.0", - "source": { - "type": "git", - "url": "https://github.com/zendframework/zend-router.git", - "reference": "a80a7427afb8f736b9aeeb341a78dae855849291" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-router/zipball/a80a7427afb8f736b9aeeb341a78dae855849291", - "reference": "a80a7427afb8f736b9aeeb341a78dae855849291", - "shasum": "" - }, - "require": { - "container-interop/container-interop": "^1.2", - "php": "^5.6 || ^7.0", - "zendframework/zend-http": "^2.8.1", - "zendframework/zend-servicemanager": "^2.7.8 || ^3.3", - "zendframework/zend-stdlib": "^2.7.7 || ^3.1" - }, - "conflict": { - "zendframework/zend-mvc": "<3.0.0" - }, - "require-dev": { - "phpunit/phpunit": "^5.7.22 || ^6.4.1", - "zendframework/zend-coding-standard": "~1.0.0", - "zendframework/zend-i18n": "^2.7.4" - }, - "suggest": { - "zendframework/zend-i18n": "^2.7.4, if defining translatable HTTP path segments" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.2.x-dev", - "dev-develop": "3.3.x-dev" - }, - "zf": { - "component": "Zend\\Router", - "config-provider": "Zend\\Router\\ConfigProvider" - } - }, - "autoload": { - "psr-4": { - "Zend\\Router\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "Flexible routing system for HTTP and console applications", - "keywords": [ - "ZendFramework", - "mvc", - "routing", - "zend", - "zf" - ], - "time": "2018-08-01T22:24:35+00:00" - }, - { - "name": "zendframework/zend-servicemanager", - "version": "3.3.2", - "source": { - "type": "git", - "url": "https://github.com/zendframework/zend-servicemanager.git", - "reference": "9f35a104b8d4d3b32da5f4a3b6efc0dd62e5af42" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-servicemanager/zipball/9f35a104b8d4d3b32da5f4a3b6efc0dd62e5af42", - "reference": "9f35a104b8d4d3b32da5f4a3b6efc0dd62e5af42", - "shasum": "" - }, - "require": { - "container-interop/container-interop": "^1.2", - "php": "^5.6 || ^7.0", - "psr/container": "^1.0", - "zendframework/zend-stdlib": "^3.1" - }, - "provide": { - "container-interop/container-interop-implementation": "^1.2", - "psr/container-implementation": "^1.0" - }, - "require-dev": { - "mikey179/vfsstream": "^1.6.5", - "ocramius/proxy-manager": "^1.0 || ^2.0", - "phpbench/phpbench": "^0.13.0", - "phpunit/phpunit": "^5.7.25 || ^6.4.4", - "zendframework/zend-coding-standard": "~1.0.0" - }, - "suggest": { - "ocramius/proxy-manager": "ProxyManager 1.* to handle lazy initialization of services", - "zendframework/zend-stdlib": "zend-stdlib ^2.5 if you wish to use the MergeReplaceKey or MergeRemoveKey features in Config instances" - }, - "bin": [ - "bin/generate-deps-for-config-factory", - "bin/generate-factory-for-class" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.3-dev", - "dev-develop": "4.0-dev" - } - }, - "autoload": { - "psr-4": { - "Zend\\ServiceManager\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "Factory-Driven Dependency Injection Container", - "keywords": [ - "PSR-11", - "ZendFramework", - "dependency-injection", - "di", - "dic", - "service-manager", - "servicemanager", - "zf" - ], - "time": "2018-01-29T16:48:37+00:00" - }, - { - "name": "zendframework/zend-stdlib", - "version": "3.2.1", - "source": { - "type": "git", - "url": "https://github.com/zendframework/zend-stdlib.git", - "reference": "66536006722aff9e62d1b331025089b7ec71c065" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-stdlib/zipball/66536006722aff9e62d1b331025089b7ec71c065", - "reference": "66536006722aff9e62d1b331025089b7ec71c065", - "shasum": "" - }, - "require": { - "php": "^5.6 || ^7.0" - }, - "require-dev": { - "phpbench/phpbench": "^0.13", - "phpunit/phpunit": "^5.7.27 || ^6.5.8 || ^7.1.2", - "zendframework/zend-coding-standard": "~1.0.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.2.x-dev", - "dev-develop": "3.3.x-dev" - } - }, - "autoload": { - "psr-4": { - "Zend\\Stdlib\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "SPL extensions, array utilities, error handlers, and more", - "keywords": [ - "ZendFramework", - "stdlib", - "zf" - ], - "time": "2018-08-28T21:34:05+00:00" - }, - { - "name": "zendframework/zend-uri", - "version": "2.6.1", - "source": { - "type": "git", - "url": "https://github.com/zendframework/zend-uri.git", - "reference": "3b6463645c6766f78ce537c70cb4fdabee1e725f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-uri/zipball/3b6463645c6766f78ce537c70cb4fdabee1e725f", - "reference": "3b6463645c6766f78ce537c70cb4fdabee1e725f", - "shasum": "" - }, - "require": { - "php": "^5.6 || ^7.0", - "zendframework/zend-escaper": "^2.5", - "zendframework/zend-validator": "^2.10" - }, - "require-dev": { - "phpunit/phpunit": "^5.7.27 || ^6.5.8 || ^7.1.4", - "zendframework/zend-coding-standard": "~1.0.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.6.x-dev", - "dev-develop": "2.7.x-dev" - } - }, - "autoload": { - "psr-4": { - "Zend\\Uri\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "A component that aids in manipulating and validating » Uniform Resource Identifiers (URIs)", - "keywords": [ - "ZendFramework", - "uri", - "zf" - ], - "time": "2018-04-30T13:40:08+00:00" - }, - { - "name": "zendframework/zend-validator", - "version": "2.11.0", - "source": { - "type": "git", - "url": "https://github.com/zendframework/zend-validator.git", - "reference": "f0789b4c4c099afdd2ecc58cc209a26c64bd4f17" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-validator/zipball/f0789b4c4c099afdd2ecc58cc209a26c64bd4f17", - "reference": "f0789b4c4c099afdd2ecc58cc209a26c64bd4f17", - "shasum": "" - }, - "require": { - "container-interop/container-interop": "^1.1", - "php": "^5.6 || ^7.0", - "zendframework/zend-stdlib": "^2.7.6 || ^3.1" - }, - "require-dev": { - "phpunit/phpunit": "^6.0.8 || ^5.7.15", - "psr/http-message": "^1.0", - "zendframework/zend-cache": "^2.6.1", - "zendframework/zend-coding-standard": "~1.0.0", - "zendframework/zend-config": "^2.6", - "zendframework/zend-db": "^2.7", - "zendframework/zend-filter": "^2.6", - "zendframework/zend-http": "^2.5.4", - "zendframework/zend-i18n": "^2.6", - "zendframework/zend-math": "^2.6", - "zendframework/zend-servicemanager": "^2.7.5 || ^3.0.3", - "zendframework/zend-session": "^2.8", - "zendframework/zend-uri": "^2.5" - }, - "suggest": { - "psr/http-message": "psr/http-message, required when validating PSR-7 UploadedFileInterface instances via the Upload and UploadFile validators", - "zendframework/zend-db": "Zend\\Db component, required by the (No)RecordExists validator", - "zendframework/zend-filter": "Zend\\Filter component, required by the Digits validator", - "zendframework/zend-i18n": "Zend\\I18n component to allow translation of validation error messages", - "zendframework/zend-i18n-resources": "Translations of validator messages", - "zendframework/zend-math": "Zend\\Math component, required by the Csrf validator", - "zendframework/zend-servicemanager": "Zend\\ServiceManager component to allow using the ValidatorPluginManager and validator chains", - "zendframework/zend-session": "Zend\\Session component, ^2.8; required by the Csrf validator", - "zendframework/zend-uri": "Zend\\Uri component, required by the Uri and Sitemap\\Loc validators" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.11.x-dev", - "dev-develop": "2.12.x-dev" - }, - "zf": { - "component": "Zend\\Validator", - "config-provider": "Zend\\Validator\\ConfigProvider" - } - }, - "autoload": { - "psr-4": { - "Zend\\Validator\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "provides a set of commonly needed validators", - "homepage": "https://github.com/zendframework/zend-validator", - "keywords": [ - "validator", - "zf2" - ], - "time": "2018-12-13T21:23:15+00:00" - }, - { - "name": "zendframework/zend-view", - "version": "2.11.1", - "source": { - "type": "git", - "url": "https://github.com/zendframework/zend-view.git", - "reference": "0428d6b2a67c7058451394921c90c5576ac5b373" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-view/zipball/0428d6b2a67c7058451394921c90c5576ac5b373", - "reference": "0428d6b2a67c7058451394921c90c5576ac5b373", - "shasum": "" - }, - "require": { - "php": "^5.6 || ^7.0", - "zendframework/zend-eventmanager": "^2.6.2 || ^3.0", - "zendframework/zend-json": "^2.6.1 || ^3.0", - "zendframework/zend-loader": "^2.5", - "zendframework/zend-stdlib": "^2.7 || ^3.0" - }, - "require-dev": { - "phpunit/phpunit": "^5.7.15 || ^6.0.8", - "zendframework/zend-authentication": "^2.5", - "zendframework/zend-cache": "^2.6.1", - "zendframework/zend-coding-standard": "~1.0.0", - "zendframework/zend-config": "^2.6", - "zendframework/zend-console": "^2.6", - "zendframework/zend-escaper": "^2.5", - "zendframework/zend-feed": "^2.7", - "zendframework/zend-filter": "^2.6.1", - "zendframework/zend-http": "^2.5.4", - "zendframework/zend-i18n": "^2.6", - "zendframework/zend-log": "^2.7", - "zendframework/zend-modulemanager": "^2.7.1", - "zendframework/zend-mvc": "^2.7.14 || ^3.0", - "zendframework/zend-navigation": "^2.5", - "zendframework/zend-paginator": "^2.5", - "zendframework/zend-permissions-acl": "^2.6", - "zendframework/zend-router": "^3.0.1", - "zendframework/zend-serializer": "^2.6.1", - "zendframework/zend-servicemanager": "^2.7.5 || ^3.0.3", - "zendframework/zend-session": "^2.8.1", - "zendframework/zend-uri": "^2.5" - }, - "suggest": { - "zendframework/zend-authentication": "Zend\\Authentication component", - "zendframework/zend-escaper": "Zend\\Escaper component", - "zendframework/zend-feed": "Zend\\Feed component", - "zendframework/zend-filter": "Zend\\Filter component", - "zendframework/zend-http": "Zend\\Http component", - "zendframework/zend-i18n": "Zend\\I18n component", - "zendframework/zend-mvc": "Zend\\Mvc component", - "zendframework/zend-mvc-plugin-flashmessenger": "zend-mvc-plugin-flashmessenger component, if you want to use the FlashMessenger view helper with zend-mvc versions 3 and up", - "zendframework/zend-navigation": "Zend\\Navigation component", - "zendframework/zend-paginator": "Zend\\Paginator component", - "zendframework/zend-permissions-acl": "Zend\\Permissions\\Acl component", - "zendframework/zend-servicemanager": "Zend\\ServiceManager component", - "zendframework/zend-uri": "Zend\\Uri component" - }, - "bin": [ - "bin/templatemap_generator.php" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.11.x-dev", - "dev-develop": "2.12.x-dev" - } - }, - "autoload": { - "psr-4": { - "Zend\\View\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "provides a system of helpers, output filters, and variable escaping", - "homepage": "https://github.com/zendframework/zend-view", - "keywords": [ - "view", - "zf2" - ], - "time": "2018-12-10T16:37:55+00:00" - } - ], - "packages-dev": [], - "aliases": [], - "minimum-stability": "stable", - "stability-flags": [], - "prefer-stable": false, - "prefer-lowest": false, - "platform": { - "php": "^7.2" - }, - "platform-dev": [] -} diff --git a/frameworks/PHP/zend/config.toml b/frameworks/PHP/zend/config.toml deleted file mode 100644 index 5064274cae5..00000000000 --- a/frameworks/PHP/zend/config.toml +++ /dev/null @@ -1,18 +0,0 @@ -[framework] -name = "zend" - -[main] -urls.plaintext = "/plaintext" -urls.json = "/json" -urls.db = "/db" -urls.query = "/queries?queries=" -urls.update = "/updates?queries=" -approach = "Realistic" -classification = "Fullstack" -database = "MySQL" -database_os = "Linux" -os = "Linux" -orm = "Full" -platform = "FPM/FastCGI" -webserver = "nginx" -versus = "php" diff --git a/frameworks/PHP/zend/config/application.config.php b/frameworks/PHP/zend/config/application.config.php deleted file mode 100644 index 25dde8b67ec..00000000000 --- a/frameworks/PHP/zend/config/application.config.php +++ /dev/null @@ -1,18 +0,0 @@ - array( - 'Zend\Router', - 'Zend\Db', - 'FrameworkBenchmarks', - ), - 'module_listener_options' => array( - 'module_paths' => array(), - 'config_glob_paths' => array( - 'config/autoload/{,*.}{global,local}.php', - ), - 'config_cache_enabled' => true, - 'config_cache_key' => 'config_cache', - 'cache_dir' => 'data/cache', - 'check_dependencies' => false, - ), -); diff --git a/frameworks/PHP/zend/config/autoload/benchmarks.local.php b/frameworks/PHP/zend/config/autoload/benchmarks.local.php deleted file mode 100644 index 78528842719..00000000000 --- a/frameworks/PHP/zend/config/autoload/benchmarks.local.php +++ /dev/null @@ -1,13 +0,0 @@ - array( - 'driver' => 'Pdo', - 'dsn' => 'mysql:dbname=hello_world;host=tfb-database;port=3306', - 'username' => 'benchmarkdbuser', - 'password' => 'benchmarkdbpass', - 'driver_options' => array( - PDO::ATTR_PERSISTENT => true - ), - ), -); diff --git a/frameworks/PHP/zend/deploy/conf/php-fpm.conf b/frameworks/PHP/zend/deploy/conf/php-fpm.conf deleted file mode 100644 index 9c4744138df..00000000000 --- a/frameworks/PHP/zend/deploy/conf/php-fpm.conf +++ /dev/null @@ -1,551 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;; -; FPM Configuration ; -;;;;;;;;;;;;;;;;;;;;; - -; All relative paths in this configuration file are relative to PHP's install -; prefix (/usr). This prefix can be dynamically changed by using the -; '-p' argument from the command line. - -;;;;;;;;;;;;;;;;;; -; Global Options ; -;;;;;;;;;;;;;;;;;; - -[global] -; Pid file -; Note: the default prefix is /var -; Default Value: none -pid = /run/php/php7.3-fpm.pid - -; Error log file -; If it's set to "syslog", log is sent to syslogd instead of being written -; into a local file. -; Note: the default prefix is /var -; Default Value: log/php-fpm.log -;error_log = /var/log/php7.3-fpm.log -error_log = /dev/stderr - - -; syslog_facility is used to specify what type of program is logging the -; message. This lets syslogd specify that messages from different facilities -; will be handled differently. -; See syslog(3) for possible values (ex daemon equiv LOG_DAEMON) -; Default Value: daemon -;syslog.facility = daemon - -; syslog_ident is prepended to every message. If you have multiple FPM -; instances running on the same server, you can change the default value -; which must suit common needs. -; Default Value: php-fpm -;syslog.ident = php-fpm - -; Log level -; Possible Values: alert, error, warning, notice, debug -; Default Value: notice -;log_level = notice - -; If this number of child processes exit with SIGSEGV or SIGBUS within the time -; interval set by emergency_restart_interval then FPM will restart. A value -; of '0' means 'Off'. -; Default Value: 0 -;emergency_restart_threshold = 0 - -; Interval of time used by emergency_restart_interval to determine when -; a graceful restart will be initiated. This can be useful to work around -; accidental corruptions in an accelerator's shared memory. -; Available Units: s(econds), m(inutes), h(ours), or d(ays) -; Default Unit: seconds -; Default Value: 0 -;emergency_restart_interval = 0 - -; Time limit for child processes to wait for a reaction on signals from master. -; Available units: s(econds), m(inutes), h(ours), or d(ays) -; Default Unit: seconds -; Default Value: 0 -;process_control_timeout = 0 - -; The maximum number of processes FPM will fork. This has been designed to control -; the global number of processes when using dynamic PM within a lot of pools. -; Use it with caution. -; Note: A value of 0 indicates no limit -; Default Value: 0 -; process.max = 128 - -; Specify the nice(2) priority to apply to the master process (only if set) -; The value can vary from -19 (highest priority) to 20 (lowest priority) -; Note: - It will only work if the FPM master process is launched as root -; - The pool process will inherit the master process priority -; unless specified otherwise -; Default Value: no set -; process.priority = -19 - -; Send FPM to background. Set to 'no' to keep FPM in foreground for debugging. -; Default Value: yes -;daemonize = yes - -; Set open file descriptor rlimit for the master process. -; Default Value: system defined value -;rlimit_files = 1024 - -; Set max core size rlimit for the master process. -; Possible Values: 'unlimited' or an integer greater or equal to 0 -; Default Value: system defined value -;rlimit_core = 0 - -; Specify the event mechanism FPM will use. The following is available: -; - select (any POSIX os) -; - poll (any POSIX os) -; - epoll (linux >= 2.5.44) -; - kqueue (FreeBSD >= 4.1, OpenBSD >= 2.9, NetBSD >= 2.0) -; - /dev/poll (Solaris >= 7) -; - port (Solaris >= 10) -; Default Value: not set (auto detection) -;events.mechanism = epoll - -; When FPM is built with systemd integration, specify the interval, -; in seconds, between health report notification to systemd. -; Set to 0 to disable. -; Available Units: s(econds), m(inutes), h(ours) -; Default Unit: seconds -; Default value: 10 -systemd_interval = 0 - -;;;;;;;;;;;;;;;;;;;; -; Pool Definitions ; -;;;;;;;;;;;;;;;;;;;; - -; Multiple pools of child processes may be started with different listening -; ports and different management options. The name of the pool will be -; used in logs and stats. There is no limitation on the number of pools which -; FPM can handle. Your system will tell you anyway :) - -; Include one or more files. If glob(3) exists, it is used to include a bunch of -; files from a glob(3) pattern. This directive can be used everywhere in the -; file. -; Relative path can also be used. They will be prefixed by: -; - the global prefix if it's been set (-p argument) -; - /usr otherwise -;include=/etc/php/7.3/fpm/pool.d/*.conf - -; Start a new pool named 'www'. -; the variable $pool can be used in any directive and will be replaced by the -; pool name ('www' here) -[www] - -; Per pool prefix -; It only applies on the following directives: -; - 'access.log' -; - 'slowlog' -; - 'listen' (unixsocket) -; - 'chroot' -; - 'chdir' -; - 'php_values' -; - 'php_admin_values' -; When not set, the global prefix (or /usr) applies instead. -; Note: This directive can also be relative to the global prefix. -; Default Value: none -;prefix = /path/to/pools/$pool - -; Unix user/group of processes -; Note: The user is mandatory. If the group is not set, the default user's group -; will be used. -user = www-data -group = www-data - -; The address on which to accept FastCGI requests. -; Valid syntaxes are: -; 'ip.add.re.ss:port' - to listen on a TCP socket to a specific IPv4 address on -; a specific port; -; '[ip:6:addr:ess]:port' - to listen on a TCP socket to a specific IPv6 address on -; a specific port; -; 'port' - to listen on a TCP socket to all addresses -; (IPv6 and IPv4-mapped) on a specific port; -; '/path/to/unix/socket' - to listen on a unix socket. -; Note: This value is mandatory. -listen = /run/php/php7.3-fpm.sock - -; Set listen(2) backlog. -; Default Value: 511 (-1 on FreeBSD and OpenBSD) -listen.backlog = 65535 - -; Set permissions for unix socket, if one is used. In Linux, read/write -; permissions must be set in order to allow connections from a web server. Many -; BSD-derived systems allow connections regardless of permissions. -; Default Values: user and group are set as the running user -; mode is set to 0660 -listen.owner = www-data -listen.group = www-data -;listen.mode = 0660 -; When POSIX Access Control Lists are supported you can set them using -; these options, value is a comma separated list of user/group names. -; When set, listen.owner and listen.group are ignored -;listen.acl_users = -;listen.acl_groups = - -; List of addresses (IPv4/IPv6) of FastCGI clients which are allowed to connect. -; Equivalent to the FCGI_WEB_SERVER_ADDRS environment variable in the original -; PHP FCGI (5.2.2+). Makes sense only with a tcp listening socket. Each address -; must be separated by a comma. If this value is left blank, connections will be -; accepted from any ip address. -; Default Value: any -;listen.allowed_clients = 127.0.0.1 - -; Specify the nice(2) priority to apply to the pool processes (only if set) -; The value can vary from -19 (highest priority) to 20 (lower priority) -; Note: - It will only work if the FPM master process is launched as root -; - The pool processes will inherit the master process priority -; unless it specified otherwise -; Default Value: no set -; process.priority = -19 - -; Set the process dumpable flag (PR_SET_DUMPABLE prctl) even if the process user -; or group is differrent than the master process user. It allows to create process -; core dump and ptrace the process for the pool user. -; Default Value: no -; process.dumpable = yes - -; Choose how the process manager will control the number of child processes. -; Possible Values: -; static - a fixed number (pm.max_children) of child processes; -; dynamic - the number of child processes are set dynamically based on the -; following directives. With this process management, there will be -; always at least 1 children. -; pm.max_children - the maximum number of children that can -; be alive at the same time. -; pm.start_servers - the number of children created on startup. -; pm.min_spare_servers - the minimum number of children in 'idle' -; state (waiting to process). If the number -; of 'idle' processes is less than this -; number then some children will be created. -; pm.max_spare_servers - the maximum number of children in 'idle' -; state (waiting to process). If the number -; of 'idle' processes is greater than this -; number then some children will be killed. -; ondemand - no children are created at startup. Children will be forked when -; new requests will connect. The following parameter are used: -; pm.max_children - the maximum number of children that -; can be alive at the same time. -; pm.process_idle_timeout - The number of seconds after which -; an idle process will be killed. -; Note: This value is mandatory. -pm = static - -; The number of child processes to be created when pm is set to 'static' and the -; maximum number of child processes when pm is set to 'dynamic' or 'ondemand'. -; This value sets the limit on the number of simultaneous requests that will be -; served. Equivalent to the ApacheMaxClients directive with mpm_prefork. -; Equivalent to the PHP_FCGI_CHILDREN environment variable in the original PHP -; CGI. The below defaults are based on a server without much resources. Don't -; forget to tweak pm.* to fit your needs. -; Note: Used when pm is set to 'static', 'dynamic' or 'ondemand' -; Note: This value is mandatory. -pm.max_children = 1024 - -; The number of child processes created on startup. -; Note: Used only when pm is set to 'dynamic' -; Default Value: min_spare_servers + (max_spare_servers - min_spare_servers) / 2 -pm.start_servers = 512 - -; The desired minimum number of idle server processes. -; Note: Used only when pm is set to 'dynamic' -; Note: Mandatory when pm is set to 'dynamic' -pm.min_spare_servers = 50 - -; The desired maximum number of idle server processes. -; Note: Used only when pm is set to 'dynamic' -; Note: Mandatory when pm is set to 'dynamic' -pm.max_spare_servers = 512 - -; The number of seconds after which an idle process will be killed. -; Note: Used only when pm is set to 'ondemand' -; Default Value: 10s -;pm.process_idle_timeout = 10s; - -; The number of requests each child process should execute before respawning. -; This can be useful to work around memory leaks in 3rd party libraries. For -; endless request processing specify '0'. Equivalent to PHP_FCGI_MAX_REQUESTS. -; Default Value: 0 -;pm.max_requests = 500 - -; The URI to view the FPM status page. If this value is not set, no URI will be -; recognized as a status page. It shows the following informations: -; pool - the name of the pool; -; process manager - static, dynamic or ondemand; -; start time - the date and time FPM has started; -; start since - number of seconds since FPM has started; -; accepted conn - the number of request accepted by the pool; -; listen queue - the number of request in the queue of pending -; connections (see backlog in listen(2)); -; max listen queue - the maximum number of requests in the queue -; of pending connections since FPM has started; -; listen queue len - the size of the socket queue of pending connections; -; idle processes - the number of idle processes; -; active processes - the number of active processes; -; total processes - the number of idle + active processes; -; max active processes - the maximum number of active processes since FPM -; has started; -; max children reached - number of times, the process limit has been reached, -; when pm tries to start more children (works only for -; pm 'dynamic' and 'ondemand'); -; Value are updated in real time. -; Example output: -; pool: www -; process manager: static -; start time: 01/Jul/2011:17:53:49 +0200 -; start since: 62636 -; accepted conn: 190460 -; listen queue: 0 -; max listen queue: 1 -; listen queue len: 42 -; idle processes: 4 -; active processes: 11 -; total processes: 15 -; max active processes: 12 -; max children reached: 0 -; -; By default the status page output is formatted as text/plain. Passing either -; 'html', 'xml' or 'json' in the query string will return the corresponding -; output syntax. Example: -; http://www.foo.bar/status -; http://www.foo.bar/status?json -; http://www.foo.bar/status?html -; http://www.foo.bar/status?xml -; -; By default the status page only outputs short status. Passing 'full' in the -; query string will also return status for each pool process. -; Example: -; http://www.foo.bar/status?full -; http://www.foo.bar/status?json&full -; http://www.foo.bar/status?html&full -; http://www.foo.bar/status?xml&full -; The Full status returns for each process: -; pid - the PID of the process; -; state - the state of the process (Idle, Running, ...); -; start time - the date and time the process has started; -; start since - the number of seconds since the process has started; -; requests - the number of requests the process has served; -; request duration - the duration in µs of the requests; -; request method - the request method (GET, POST, ...); -; request URI - the request URI with the query string; -; content length - the content length of the request (only with POST); -; user - the user (PHP_AUTH_USER) (or '-' if not set); -; script - the main script called (or '-' if not set); -; last request cpu - the %cpu the last request consumed -; it's always 0 if the process is not in Idle state -; because CPU calculation is done when the request -; processing has terminated; -; last request memory - the max amount of memory the last request consumed -; it's always 0 if the process is not in Idle state -; because memory calculation is done when the request -; processing has terminated; -; If the process is in Idle state, then informations are related to the -; last request the process has served. Otherwise informations are related to -; the current request being served. -; Example output: -; ************************ -; pid: 31330 -; state: Running -; start time: 01/Jul/2011:17:53:49 +0200 -; start since: 63087 -; requests: 12808 -; request duration: 1250261 -; request method: GET -; request URI: /test_mem.php?N=10000 -; content length: 0 -; user: - -; script: /home/fat/web/docs/php/test_mem.php -; last request cpu: 0.00 -; last request memory: 0 -; -; Note: There is a real-time FPM status monitoring sample web page available -; It's available in: /usr/share/php/7.3/fpm/status.html -; -; Note: The value must start with a leading slash (/). The value can be -; anything, but it may not be a good idea to use the .php extension or it -; may conflict with a real PHP file. -; Default Value: not set -;pm.status_path = /status - -; The ping URI to call the monitoring page of FPM. If this value is not set, no -; URI will be recognized as a ping page. This could be used to test from outside -; that FPM is alive and responding, or to -; - create a graph of FPM availability (rrd or such); -; - remove a server from a group if it is not responding (load balancing); -; - trigger alerts for the operating team (24/7). -; Note: The value must start with a leading slash (/). The value can be -; anything, but it may not be a good idea to use the .php extension or it -; may conflict with a real PHP file. -; Default Value: not set -;ping.path = /ping - -; This directive may be used to customize the response of a ping request. The -; response is formatted as text/plain with a 200 response code. -; Default Value: pong -;ping.response = pong - -; The access log file -; Default: not set -;access.log = log/$pool.access.log - -; The access log format. -; The following syntax is allowed -; %%: the '%' character -; %C: %CPU used by the request -; it can accept the following format: -; - %{user}C for user CPU only -; - %{system}C for system CPU only -; - %{total}C for user + system CPU (default) -; %d: time taken to serve the request -; it can accept the following format: -; - %{seconds}d (default) -; - %{miliseconds}d -; - %{mili}d -; - %{microseconds}d -; - %{micro}d -; %e: an environment variable (same as $_ENV or $_SERVER) -; it must be associated with embraces to specify the name of the env -; variable. Some exemples: -; - server specifics like: %{REQUEST_METHOD}e or %{SERVER_PROTOCOL}e -; - HTTP headers like: %{HTTP_HOST}e or %{HTTP_USER_AGENT}e -; %f: script filename -; %l: content-length of the request (for POST request only) -; %m: request method -; %M: peak of memory allocated by PHP -; it can accept the following format: -; - %{bytes}M (default) -; - %{kilobytes}M -; - %{kilo}M -; - %{megabytes}M -; - %{mega}M -; %n: pool name -; %o: output header -; it must be associated with embraces to specify the name of the header: -; - %{Content-Type}o -; - %{X-Powered-By}o -; - %{Transfert-Encoding}o -; - .... -; %p: PID of the child that serviced the request -; %P: PID of the parent of the child that serviced the request -; %q: the query string -; %Q: the '?' character if query string exists -; %r: the request URI (without the query string, see %q and %Q) -; %R: remote IP address -; %s: status (response code) -; %t: server time the request was received -; it can accept a strftime(3) format: -; %d/%b/%Y:%H:%M:%S %z (default) -; The strftime(3) format must be encapsuled in a %{}t tag -; e.g. for a ISO8601 formatted timestring, use: %{%Y-%m-%dT%H:%M:%S%z}t -; %T: time the log has been written (the request has finished) -; it can accept a strftime(3) format: -; %d/%b/%Y:%H:%M:%S %z (default) -; The strftime(3) format must be encapsuled in a %{}t tag -; e.g. for a ISO8601 formatted timestring, use: %{%Y-%m-%dT%H:%M:%S%z}t -; %u: remote user -; -; Default: "%R - %u %t \"%m %r\" %s" -;access.format = "%R - %u %t \"%m %r%Q%q\" %s %f %{mili}d %{kilo}M %C%%" - -; The log file for slow requests -; Default Value: not set -; Note: slowlog is mandatory if request_slowlog_timeout is set -;slowlog = log/$pool.log.slow - -; The timeout for serving a single request after which a PHP backtrace will be -; dumped to the 'slowlog' file. A value of '0s' means 'off'. -; Available units: s(econds)(default), m(inutes), h(ours), or d(ays) -; Default Value: 0 -;request_slowlog_timeout = 0 - -; Depth of slow log stack trace. -; Default Value: 20 -;request_slowlog_trace_depth = 20 - -; The timeout for serving a single request after which the worker process will -; be killed. This option should be used when the 'max_execution_time' ini option -; does not stop script execution for some reason. A value of '0' means 'off'. -; Available units: s(econds)(default), m(inutes), h(ours), or d(ays) -; Default Value: 0 -;request_terminate_timeout = 0 - -; Set open file descriptor rlimit. -; Default Value: system defined value -;rlimit_files = 1024 - -; Set max core size rlimit. -; Possible Values: 'unlimited' or an integer greater or equal to 0 -; Default Value: system defined value -;rlimit_core = 0 - -; Chroot to this directory at the start. This value must be defined as an -; absolute path. When this value is not set, chroot is not used. -; Note: you can prefix with '$prefix' to chroot to the pool prefix or one -; of its subdirectories. If the pool prefix is not set, the global prefix -; will be used instead. -; Note: chrooting is a great security feature and should be used whenever -; possible. However, all PHP paths will be relative to the chroot -; (error_log, sessions.save_path, ...). -; Default Value: not set -;chroot = - -; Chdir to this directory at the start. -; Note: relative path can be used. -; Default Value: current directory or / when chroot -;chdir = /var/www - -; Redirect worker stdout and stderr into main error log. If not set, stdout and -; stderr will be redirected to /dev/null according to FastCGI specs. -; Note: on highloaded environement, this can cause some delay in the page -; process time (several ms). -; Default Value: no -;catch_workers_output = yes - -; Clear environment in FPM workers -; Prevents arbitrary environment variables from reaching FPM worker processes -; by clearing the environment in workers before env vars specified in this -; pool configuration are added. -; Setting to "no" will make all environment variables available to PHP code -; via getenv(), $_ENV and $_SERVER. -; Default Value: yes -;clear_env = no - -; Limits the extensions of the main script FPM will allow to parse. This can -; prevent configuration mistakes on the web server side. You should only limit -; FPM to .php extensions to prevent malicious users to use other extensions to -; execute php code. -; Note: set an empty value to allow all extensions. -; Default Value: .php -;security.limit_extensions = .php .php3 .php4 .php5 .php7 - -; Pass environment variables like LD_LIBRARY_PATH. All $VARIABLEs are taken from -; the current environment. -; Default Value: clean env -;env[HOSTNAME] = $HOSTNAME -;env[PATH] = /usr/local/bin:/usr/bin:/bin -;env[TMP] = /tmp -;env[TMPDIR] = /tmp -;env[TEMP] = /tmp - -; Additional php.ini defines, specific to this pool of workers. These settings -; overwrite the values previously defined in the php.ini. The directives are the -; same as the PHP SAPI: -; php_value/php_flag - you can set classic ini defines which can -; be overwritten from PHP call 'ini_set'. -; php_admin_value/php_admin_flag - these directives won't be overwritten by -; PHP call 'ini_set' -; For php_*flag, valid values are on, off, 1, 0, true, false, yes or no. - -; Defining 'extension' will load the corresponding shared extension from -; extension_dir. Defining 'disable_functions' or 'disable_classes' will not -; overwrite previously defined php.ini values, but will append the new value -; instead. - -; Note: path INI options can be relative and will be expanded with the prefix -; (pool, global or /usr) - -; Default Value: nothing is defined by default except the values in php.ini and -; specified at startup with the -d argument -;php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f www@my.domain.com -;php_flag[display_errors] = off -;php_admin_value[error_log] = /var/log/fpm-php.www.log -;php_admin_flag[log_errors] = on -;php_admin_value[memory_limit] = 32M \ No newline at end of file diff --git a/frameworks/PHP/zend/deploy/conf/php.ini b/frameworks/PHP/zend/deploy/conf/php.ini deleted file mode 100644 index d2e924cf326..00000000000 --- a/frameworks/PHP/zend/deploy/conf/php.ini +++ /dev/null @@ -1,1914 +0,0 @@ -[PHP] - -;;;;;;;;;;;;;;;;;;; -; About php.ini ; -;;;;;;;;;;;;;;;;;;; -; PHP's initialization file, generally called php.ini, is responsible for -; configuring many of the aspects of PHP's behavior. - -; PHP attempts to find and load this configuration from a number of locations. -; The following is a summary of its search order: -; 1. SAPI module specific location. -; 2. The PHPRC environment variable. (As of PHP 5.2.0) -; 3. A number of predefined registry keys on Windows (As of PHP 5.2.0) -; 4. Current working directory (except CLI) -; 5. The web server's directory (for SAPI modules), or directory of PHP -; (otherwise in Windows) -; 6. The directory from the --with-config-file-path compile time option, or the -; Windows directory (C:\windows or C:\winnt) -; See the PHP docs for more specific information. -; http://php.net/configuration.file - -; The syntax of the file is extremely simple. Whitespace and lines -; beginning with a semicolon are silently ignored (as you probably guessed). -; Section headers (e.g. [Foo]) are also silently ignored, even though -; they might mean something in the future. - -; Directives following the section heading [PATH=/www/mysite] only -; apply to PHP files in the /www/mysite directory. Directives -; following the section heading [HOST=www.example.com] only apply to -; PHP files served from www.example.com. Directives set in these -; special sections cannot be overridden by user-defined INI files or -; at runtime. Currently, [PATH=] and [HOST=] sections only work under -; CGI/FastCGI. -; http://php.net/ini.sections - -; Directives are specified using the following syntax: -; directive = value -; Directive names are *case sensitive* - foo=bar is different from FOO=bar. -; Directives are variables used to configure PHP or PHP extensions. -; There is no name validation. If PHP can't find an expected -; directive because it is not set or is mistyped, a default value will be used. - -; The value can be a string, a number, a PHP constant (e.g. E_ALL or M_PI), one -; of the INI constants (On, Off, True, False, Yes, No and None) or an expression -; (e.g. E_ALL & ~E_NOTICE), a quoted string ("bar"), or a reference to a -; previously set variable or directive (e.g. ${foo}) - -; Expressions in the INI file are limited to bitwise operators and parentheses: -; | bitwise OR -; ^ bitwise XOR -; & bitwise AND -; ~ bitwise NOT -; ! boolean NOT - -; Boolean flags can be turned on using the values 1, On, True or Yes. -; They can be turned off using the values 0, Off, False or No. - -; An empty string can be denoted by simply not writing anything after the equal -; sign, or by using the None keyword: - -; foo = ; sets foo to an empty string -; foo = None ; sets foo to an empty string -; foo = "None" ; sets foo to the string 'None' - -; If you use constants in your value, and these constants belong to a -; dynamically loaded extension (either a PHP extension or a Zend extension), -; you may only use these constants *after* the line that loads the extension. - -;;;;;;;;;;;;;;;;;;; -; About this file ; -;;;;;;;;;;;;;;;;;;; -; PHP comes packaged with two INI files. One that is recommended to be used -; in production environments and one that is recommended to be used in -; development environments. - -; php.ini-production contains settings which hold security, performance and -; best practices at its core. But please be aware, these settings may break -; compatibility with older or less security conscience applications. We -; recommending using the production ini in production and testing environments. - -; php.ini-development is very similar to its production variant, except it is -; much more verbose when it comes to errors. We recommend using the -; development version only in development environments, as errors shown to -; application users can inadvertently leak otherwise secure information. - -; This is php.ini-production INI file. - -;;;;;;;;;;;;;;;;;;; -; Quick Reference ; -;;;;;;;;;;;;;;;;;;; -; The following are all the settings which are different in either the production -; or development versions of the INIs with respect to PHP's default behavior. -; Please see the actual settings later in the document for more details as to why -; we recommend these changes in PHP's behavior. - -; display_errors -; Default Value: On -; Development Value: On -; Production Value: Off - -; display_startup_errors -; Default Value: Off -; Development Value: On -; Production Value: Off - -; error_reporting -; Default Value: E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED -; Development Value: E_ALL -; Production Value: E_ALL & ~E_DEPRECATED & ~E_STRICT - -; html_errors -; Default Value: On -; Development Value: On -; Production value: On - -; log_errors -; Default Value: Off -; Development Value: On -; Production Value: On - -; max_input_time -; Default Value: -1 (Unlimited) -; Development Value: 60 (60 seconds) -; Production Value: 60 (60 seconds) - -; output_buffering -; Default Value: Off -; Development Value: 4096 -; Production Value: 4096 - -; register_argc_argv -; Default Value: On -; Development Value: Off -; Production Value: Off - -; request_order -; Default Value: None -; Development Value: "GP" -; Production Value: "GP" - -; session.gc_divisor -; Default Value: 100 -; Development Value: 1000 -; Production Value: 1000 - -; session.sid_bits_per_character -; Default Value: 4 -; Development Value: 5 -; Production Value: 5 - -; short_open_tag -; Default Value: On -; Development Value: Off -; Production Value: Off - -; track_errors -; Default Value: Off -; Development Value: On -; Production Value: Off - -; variables_order -; Default Value: "EGPCS" -; Development Value: "GPCS" -; Production Value: "GPCS" - -;;;;;;;;;;;;;;;;;;;; -; php.ini Options ; -;;;;;;;;;;;;;;;;;;;; -; Name for user-defined php.ini (.htaccess) files. Default is ".user.ini" -;user_ini.filename = ".user.ini" - -; To disable this feature set this option to empty value -;user_ini.filename = - -; TTL for user-defined php.ini files (time-to-live) in seconds. Default is 300 seconds (5 minutes) -;user_ini.cache_ttl = 300 - -;;;;;;;;;;;;;;;;;;;; -; Language Options ; -;;;;;;;;;;;;;;;;;;;; - -; Enable the PHP scripting language engine under Apache. -; http://php.net/engine -engine = On - -; This directive determines whether or not PHP will recognize code between -; tags as PHP source which should be processed as such. It is -; generally recommended that should be used and that this feature -; should be disabled, as enabling it may result in issues when generating XML -; documents, however this remains supported for backward compatibility reasons. -; Note that this directive does not control the would work. -; http://php.net/syntax-highlighting -;highlight.string = #DD0000 -;highlight.comment = #FF9900 -;highlight.keyword = #007700 -;highlight.default = #0000BB -;highlight.html = #000000 - -; If enabled, the request will be allowed to complete even if the user aborts -; the request. Consider enabling it if executing long requests, which may end up -; being interrupted by the user or a browser timing out. PHP's default behavior -; is to disable this feature. -; http://php.net/ignore-user-abort -;ignore_user_abort = On - -; Determines the size of the realpath cache to be used by PHP. This value should -; be increased on systems where PHP opens many files to reflect the quantity of -; the file operations performed. -; http://php.net/realpath-cache-size -realpath_cache_size = 4096k - -; Duration of time, in seconds for which to cache realpath information for a given -; file or directory. For systems with rarely changing files, consider increasing this -; value. -; http://php.net/realpath-cache-ttl -realpath_cache_ttl = 600 - -; Enables or disables the circular reference collector. -; http://php.net/zend.enable-gc -zend.enable_gc = On - -; If enabled, scripts may be written in encodings that are incompatible with -; the scanner. CP936, Big5, CP949 and Shift_JIS are the examples of such -; encodings. To use this feature, mbstring extension must be enabled. -; Default: Off -;zend.multibyte = Off - -; Allows to set the default encoding for the scripts. This value will be used -; unless "declare(encoding=...)" directive appears at the top of the script. -; Only affects if zend.multibyte is set. -; Default: "" -;zend.script_encoding = - -;;;;;;;;;;;;;;;;; -; Miscellaneous ; -;;;;;;;;;;;;;;;;; - -; Decides whether PHP may expose the fact that it is installed on the server -; (e.g. by adding its signature to the Web server header). It is no security -; threat in any way, but it makes it possible to determine whether you use PHP -; on your server or not. -; http://php.net/expose-php -expose_php = Off - -;;;;;;;;;;;;;;;;;;; -; Resource Limits ; -;;;;;;;;;;;;;;;;;;; - -; Maximum execution time of each script, in seconds -; http://php.net/max-execution-time -; Note: This directive is hardcoded to 0 for the CLI SAPI -max_execution_time = 30 - -; Maximum amount of time each script may spend parsing request data. It's a good -; idea to limit this time on productions servers in order to eliminate unexpectedly -; long running scripts. -; Note: This directive is hardcoded to -1 for the CLI SAPI -; Default Value: -1 (Unlimited) -; Development Value: 60 (60 seconds) -; Production Value: 60 (60 seconds) -; http://php.net/max-input-time -max_input_time = 60 - -; Maximum input variable nesting level -; http://php.net/max-input-nesting-level -;max_input_nesting_level = 64 - -; How many GET/POST/COOKIE input variables may be accepted -; max_input_vars = 1000 - -; Maximum amount of memory a script may consume (128MB) -; http://php.net/memory-limit -memory_limit = 128M - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; Error handling and logging ; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -; This directive informs PHP of which errors, warnings and notices you would like -; it to take action for. The recommended way of setting values for this -; directive is through the use of the error level constants and bitwise -; operators. The error level constants are below here for convenience as well as -; some common settings and their meanings. -; By default, PHP is set to take action on all errors, notices and warnings EXCEPT -; those related to E_NOTICE and E_STRICT, which together cover best practices and -; recommended coding standards in PHP. For performance reasons, this is the -; recommend error reporting setting. Your production server shouldn't be wasting -; resources complaining about best practices and coding standards. That's what -; development servers and development settings are for. -; Note: The php.ini-development file has this setting as E_ALL. This -; means it pretty much reports everything which is exactly what you want during -; development and early testing. -; -; Error Level Constants: -; E_ALL - All errors and warnings (includes E_STRICT as of PHP 5.4.0) -; E_ERROR - fatal run-time errors -; E_RECOVERABLE_ERROR - almost fatal run-time errors -; E_WARNING - run-time warnings (non-fatal errors) -; E_PARSE - compile-time parse errors -; E_NOTICE - run-time notices (these are warnings which often result -; from a bug in your code, but it's possible that it was -; intentional (e.g., using an uninitialized variable and -; relying on the fact it is automatically initialized to an -; empty string) -; E_STRICT - run-time notices, enable to have PHP suggest changes -; to your code which will ensure the best interoperability -; and forward compatibility of your code -; E_CORE_ERROR - fatal errors that occur during PHP's initial startup -; E_CORE_WARNING - warnings (non-fatal errors) that occur during PHP's -; initial startup -; E_COMPILE_ERROR - fatal compile-time errors -; E_COMPILE_WARNING - compile-time warnings (non-fatal errors) -; E_USER_ERROR - user-generated error message -; E_USER_WARNING - user-generated warning message -; E_USER_NOTICE - user-generated notice message -; E_DEPRECATED - warn about code that will not work in future versions -; of PHP -; E_USER_DEPRECATED - user-generated deprecation warnings -; -; Common Values: -; E_ALL (Show all errors, warnings and notices including coding standards.) -; E_ALL & ~E_NOTICE (Show all errors, except for notices) -; E_ALL & ~E_NOTICE & ~E_STRICT (Show all errors, except for notices and coding standards warnings.) -; E_COMPILE_ERROR|E_RECOVERABLE_ERROR|E_ERROR|E_CORE_ERROR (Show only errors) -; Default Value: E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED -; Development Value: E_ALL -; Production Value: E_ALL & ~E_DEPRECATED & ~E_STRICT -; http://php.net/error-reporting -error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT - -; This directive controls whether or not and where PHP will output errors, -; notices and warnings too. Error output is very useful during development, but -; it could be very dangerous in production environments. Depending on the code -; which is triggering the error, sensitive information could potentially leak -; out of your application such as database usernames and passwords or worse. -; For production environments, we recommend logging errors rather than -; sending them to STDOUT. -; Possible Values: -; Off = Do not display any errors -; stderr = Display errors to STDERR (affects only CGI/CLI binaries!) -; On or stdout = Display errors to STDOUT -; Default Value: On -; Development Value: On -; Production Value: Off -; http://php.net/display-errors -display_errors = Off - -; The display of errors which occur during PHP's startup sequence are handled -; separately from display_errors. PHP's default behavior is to suppress those -; errors from clients. Turning the display of startup errors on can be useful in -; debugging configuration problems. We strongly recommend you -; set this to 'off' for production servers. -; Default Value: Off -; Development Value: On -; Production Value: Off -; http://php.net/display-startup-errors -display_startup_errors = Off - -; Besides displaying errors, PHP can also log errors to locations such as a -; server-specific log, STDERR, or a location specified by the error_log -; directive found below. While errors should not be displayed on productions -; servers they should still be monitored and logging is a great way to do that. -; Default Value: Off -; Development Value: On -; Production Value: On -; http://php.net/log-errors -log_errors = On - -; Set maximum length of log_errors. In error_log information about the source is -; added. The default is 1024 and 0 allows to not apply any maximum length at all. -; http://php.net/log-errors-max-len -log_errors_max_len = 1024 - -; Do not log repeated messages. Repeated errors must occur in same file on same -; line unless ignore_repeated_source is set true. -; http://php.net/ignore-repeated-errors -ignore_repeated_errors = Off - -; Ignore source of message when ignoring repeated messages. When this setting -; is On you will not log errors with repeated messages from different files or -; source lines. -; http://php.net/ignore-repeated-source -ignore_repeated_source = Off - -; If this parameter is set to Off, then memory leaks will not be shown (on -; stdout or in the log). This has only effect in a debug compile, and if -; error reporting includes E_WARNING in the allowed list -; http://php.net/report-memleaks -report_memleaks = On - -; This setting is on by default. -;report_zend_debug = 0 - -; Store the last error/warning message in $php_errormsg (boolean). Setting this value -; to On can assist in debugging and is appropriate for development servers. It should -; however be disabled on production servers. -; This directive is DEPRECATED. -; Default Value: Off -; Development Value: Off -; Production Value: Off -; http://php.net/track-errors -;track_errors = Off - -; Turn off normal error reporting and emit XML-RPC error XML -; http://php.net/xmlrpc-errors -;xmlrpc_errors = 0 - -; An XML-RPC faultCode -;xmlrpc_error_number = 0 - -; When PHP displays or logs an error, it has the capability of formatting the -; error message as HTML for easier reading. This directive controls whether -; the error message is formatted as HTML or not. -; Note: This directive is hardcoded to Off for the CLI SAPI -; Default Value: On -; Development Value: On -; Production value: On -; http://php.net/html-errors -html_errors = On - -; If html_errors is set to On *and* docref_root is not empty, then PHP -; produces clickable error messages that direct to a page describing the error -; or function causing the error in detail. -; You can download a copy of the PHP manual from http://php.net/docs -; and change docref_root to the base URL of your local copy including the -; leading '/'. You must also specify the file extension being used including -; the dot. PHP's default behavior is to leave these settings empty, in which -; case no links to documentation are generated. -; Note: Never use this feature for production boxes. -; http://php.net/docref-root -; Examples -;docref_root = "/phpmanual/" - -; http://php.net/docref-ext -;docref_ext = .html - -; String to output before an error message. PHP's default behavior is to leave -; this setting blank. -; http://php.net/error-prepend-string -; Example: -;error_prepend_string = "" - -; String to output after an error message. PHP's default behavior is to leave -; this setting blank. -; http://php.net/error-append-string -; Example: -;error_append_string = "" - -; Log errors to specified file. PHP's default behavior is to leave this value -; empty. -; http://php.net/error-log -; Example: -;error_log = php_errors.log -; Log errors to syslog (Event Log on Windows). -;error_log = syslog - -;windows.show_crt_warning -; Default value: 0 -; Development value: 0 -; Production value: 0 - -;;;;;;;;;;;;;;;;; -; Data Handling ; -;;;;;;;;;;;;;;;;; - -; The separator used in PHP generated URLs to separate arguments. -; PHP's default setting is "&". -; http://php.net/arg-separator.output -; Example: -;arg_separator.output = "&" - -; List of separator(s) used by PHP to parse input URLs into variables. -; PHP's default setting is "&". -; NOTE: Every character in this directive is considered as separator! -; http://php.net/arg-separator.input -; Example: -;arg_separator.input = ";&" - -; This directive determines which super global arrays are registered when PHP -; starts up. G,P,C,E & S are abbreviations for the following respective super -; globals: GET, POST, COOKIE, ENV and SERVER. There is a performance penalty -; paid for the registration of these arrays and because ENV is not as commonly -; used as the others, ENV is not recommended on productions servers. You -; can still get access to the environment variables through getenv() should you -; need to. -; Default Value: "EGPCS" -; Development Value: "GPCS" -; Production Value: "GPCS"; -; http://php.net/variables-order -variables_order = "GPCS" - -; This directive determines which super global data (G,P & C) should be -; registered into the super global array REQUEST. If so, it also determines -; the order in which that data is registered. The values for this directive -; are specified in the same manner as the variables_order directive, -; EXCEPT one. Leaving this value empty will cause PHP to use the value set -; in the variables_order directive. It does not mean it will leave the super -; globals array REQUEST empty. -; Default Value: None -; Development Value: "GP" -; Production Value: "GP" -; http://php.net/request-order -request_order = "GP" - -; This directive determines whether PHP registers $argv & $argc each time it -; runs. $argv contains an array of all the arguments passed to PHP when a script -; is invoked. $argc contains an integer representing the number of arguments -; that were passed when the script was invoked. These arrays are extremely -; useful when running scripts from the command line. When this directive is -; enabled, registering these variables consumes CPU cycles and memory each time -; a script is executed. For performance reasons, this feature should be disabled -; on production servers. -; Note: This directive is hardcoded to On for the CLI SAPI -; Default Value: On -; Development Value: Off -; Production Value: Off -; http://php.net/register-argc-argv -register_argc_argv = Off - -; When enabled, the ENV, REQUEST and SERVER variables are created when they're -; first used (Just In Time) instead of when the script starts. If these -; variables are not used within a script, having this directive on will result -; in a performance gain. The PHP directive register_argc_argv must be disabled -; for this directive to have any affect. -; http://php.net/auto-globals-jit -auto_globals_jit = On - -; Whether PHP will read the POST data. -; This option is enabled by default. -; Most likely, you won't want to disable this option globally. It causes $_POST -; and $_FILES to always be empty; the only way you will be able to read the -; POST data will be through the php://input stream wrapper. This can be useful -; to proxy requests or to process the POST data in a memory efficient fashion. -; http://php.net/enable-post-data-reading -;enable_post_data_reading = Off - -; Maximum size of POST data that PHP will accept. -; Its value may be 0 to disable the limit. It is ignored if POST data reading -; is disabled through enable_post_data_reading. -; http://php.net/post-max-size -post_max_size = 8M - -; Automatically add files before PHP document. -; http://php.net/auto-prepend-file -auto_prepend_file = - -; Automatically add files after PHP document. -; http://php.net/auto-append-file -auto_append_file = - -; By default, PHP will output a media type using the Content-Type header. To -; disable this, simply set it to be empty. -; -; PHP's built-in default media type is set to text/html. -; http://php.net/default-mimetype -default_mimetype = "text/html" - -; PHP's default character set is set to UTF-8. -; http://php.net/default-charset -default_charset = "UTF-8" - -; PHP internal character encoding is set to empty. -; If empty, default_charset is used. -; http://php.net/internal-encoding -;internal_encoding = - -; PHP input character encoding is set to empty. -; If empty, default_charset is used. -; http://php.net/input-encoding -;input_encoding = - -; PHP output character encoding is set to empty. -; If empty, default_charset is used. -; See also output_buffer. -; http://php.net/output-encoding -;output_encoding = - -;;;;;;;;;;;;;;;;;;;;;;;;; -; Paths and Directories ; -;;;;;;;;;;;;;;;;;;;;;;;;; - -; UNIX: "/path1:/path2" -;include_path = ".:/usr/share/php" -; -; Windows: "\path1;\path2" -;include_path = ".;c:\php\includes" -; -; PHP's default setting for include_path is ".;/path/to/php/pear" -; http://php.net/include-path - -; The root of the PHP pages, used only if nonempty. -; if PHP was not compiled with FORCE_REDIRECT, you SHOULD set doc_root -; if you are running php as a CGI under any web server (other than IIS) -; see documentation for security issues. The alternate is to use the -; cgi.force_redirect configuration below -; http://php.net/doc-root -doc_root = - -; The directory under which PHP opens the script using /~username used only -; if nonempty. -; http://php.net/user-dir -user_dir = - -; Directory in which the loadable extensions (modules) reside. -; http://php.net/extension-dir -; extension_dir = "./" -; On windows: -; extension_dir = "ext" - -; Directory where the temporary files should be placed. -; Defaults to the system default (see sys_get_temp_dir) -; sys_temp_dir = "/tmp" - -; Whether or not to enable the dl() function. The dl() function does NOT work -; properly in multithreaded servers, such as IIS or Zeus, and is automatically -; disabled on them. -; http://php.net/enable-dl -enable_dl = Off - -; cgi.force_redirect is necessary to provide security running PHP as a CGI under -; most web servers. Left undefined, PHP turns this on by default. You can -; turn it off here AT YOUR OWN RISK -; **You CAN safely turn this off for IIS, in fact, you MUST.** -; http://php.net/cgi.force-redirect -;cgi.force_redirect = 1 - -; if cgi.nph is enabled it will force cgi to always sent Status: 200 with -; every request. PHP's default behavior is to disable this feature. -;cgi.nph = 1 - -; if cgi.force_redirect is turned on, and you are not running under Apache or Netscape -; (iPlanet) web servers, you MAY need to set an environment variable name that PHP -; will look for to know it is OK to continue execution. Setting this variable MAY -; cause security issues, KNOW WHAT YOU ARE DOING FIRST. -; http://php.net/cgi.redirect-status-env -;cgi.redirect_status_env = - -; cgi.fix_pathinfo provides *real* PATH_INFO/PATH_TRANSLATED support for CGI. PHP's -; previous behaviour was to set PATH_TRANSLATED to SCRIPT_FILENAME, and to not grok -; what PATH_INFO is. For more information on PATH_INFO, see the cgi specs. Setting -; this to 1 will cause PHP CGI to fix its paths to conform to the spec. A setting -; of zero causes PHP to behave as before. Default is 1. You should fix your scripts -; to use SCRIPT_FILENAME rather than PATH_TRANSLATED. -; http://php.net/cgi.fix-pathinfo - cgi.fix_pathinfo=0 - -; if cgi.discard_path is enabled, the PHP CGI binary can safely be placed outside -; of the web tree and people will not be able to circumvent .htaccess security. -; http://php.net/cgi.dicard-path -;cgi.discard_path=1 - -; FastCGI under IIS (on WINNT based OS) supports the ability to impersonate -; security tokens of the calling client. This allows IIS to define the -; security context that the request runs under. mod_fastcgi under Apache -; does not currently support this feature (03/17/2002) -; Set to 1 if running under IIS. Default is zero. -; http://php.net/fastcgi.impersonate -;fastcgi.impersonate = 1 - -; Disable logging through FastCGI connection. PHP's default behavior is to enable -; this feature. -;fastcgi.logging = 0 - -; cgi.rfc2616_headers configuration option tells PHP what type of headers to -; use when sending HTTP response code. If set to 0, PHP sends Status: header that -; is supported by Apache. When this option is set to 1, PHP will send -; RFC2616 compliant header. -; Default is zero. -; http://php.net/cgi.rfc2616-headers -;cgi.rfc2616_headers = 0 - -; cgi.check_shebang_line controls whether CGI PHP checks for line starting with #! -; (shebang) at the top of the running script. This line might be needed if the -; script support running both as stand-alone script and via PHP CGI<. PHP in CGI -; mode skips this line and ignores its content if this directive is turned on. -; http://php.net/cgi.check-shebang-line -;cgi.check_shebang_line=1 - -;;;;;;;;;;;;;;;; -; File Uploads ; -;;;;;;;;;;;;;;;; - -; Whether to allow HTTP file uploads. -; http://php.net/file-uploads -file_uploads = On - -; Temporary directory for HTTP uploaded files (will use system default if not -; specified). -; http://php.net/upload-tmp-dir -;upload_tmp_dir = - -; Maximum allowed size for uploaded files. -; http://php.net/upload-max-filesize -upload_max_filesize = 2M - -; Maximum number of files that can be uploaded via a single request -max_file_uploads = 20 - -;;;;;;;;;;;;;;;;;; -; Fopen wrappers ; -;;;;;;;;;;;;;;;;;; - -; Whether to allow the treatment of URLs (like http:// or ftp://) as files. -; http://php.net/allow-url-fopen -allow_url_fopen = On - -; Whether to allow include/require to open URLs (like http:// or ftp://) as files. -; http://php.net/allow-url-include -allow_url_include = Off - -; Define the anonymous ftp password (your email address). PHP's default setting -; for this is empty. -; http://php.net/from -;from="john@doe.com" - -; Define the User-Agent string. PHP's default setting for this is empty. -; http://php.net/user-agent -;user_agent="PHP" - -; Default timeout for socket based streams (seconds) -; http://php.net/default-socket-timeout -default_socket_timeout = 60 - -; If your scripts have to deal with files from Macintosh systems, -; or you are running on a Mac and need to deal with files from -; unix or win32 systems, setting this flag will cause PHP to -; automatically detect the EOL character in those files so that -; fgets() and file() will work regardless of the source of the file. -; http://php.net/auto-detect-line-endings -;auto_detect_line_endings = Off - -;;;;;;;;;;;;;;;;;;;;;; -; Dynamic Extensions ; -;;;;;;;;;;;;;;;;;;;;;; - -; If you wish to have an extension loaded automatically, use the following -; syntax: -; -; extension=modulename -; -; For example: -; -; extension=mysqli -; -; When the extension library to load is not located in the default extension -; directory, You may specify an absolute path to the library file: -; -; extension=/path/to/extension/mysqli.so -; -; Note : The syntax used in previous PHP versions ('extension=.so' and -; 'extension='php_.dll') is supported for legacy reasons and may be -; deprecated in a future PHP major version. So, when it is possible, please -; move to the new ('extension=) syntax. -; -; Notes for Windows environments : -; -; - ODBC support is built in, so no dll is needed for it. -; - Many DLL files are located in the extensions/ (PHP 4) or ext/ (PHP 5+) -; extension folders as well as the separate PECL DLL download (PHP 5+). -; Be sure to appropriately set the extension_dir directive. -; -;extension=bz2 -;extension=curl -;extension=fileinfo -;extension=gd2 -;extension=gettext -;extension=gmp -;extension=intl -;extension=imap -;extension=interbase -;extension=ldap -;extension=mbstring -;extension=exif ; Must be after mbstring as it depends on it -;extension=mysqli -;extension=oci8_12c ; Use with Oracle Database 12c Instant Client -;extension=openssl -;extension=pdo_firebird -;extension=pdo_mysql -;extension=pdo_oci -;extension=pdo_odbc -;extension=pdo_pgsql -;extension=pdo_sqlite -;extension=pgsql -;extension=shmop - -; The MIBS data available in the PHP distribution must be installed. -; See http://www.php.net/manual/en/snmp.installation.php -;extension=snmp - -;extension=soap -;extension=sockets -;extension=sqlite3 -;extension=tidy -;extension=xmlrpc -;extension=xsl - -;;;;;;;;;;;;;;;;;;; -; Module Settings ; -;;;;;;;;;;;;;;;;;;; - -[CLI Server] -; Whether the CLI web server uses ANSI color coding in its terminal output. -cli_server.color = On - -[Date] -; Defines the default timezone used by the date functions -; http://php.net/date.timezone -date.timezone = UTC - -; http://php.net/date.default-latitude -;date.default_latitude = 31.7667 - -; http://php.net/date.default-longitude -;date.default_longitude = 35.2333 - -; http://php.net/date.sunrise-zenith -;date.sunrise_zenith = 90.583333 - -; http://php.net/date.sunset-zenith -;date.sunset_zenith = 90.583333 - -[filter] -; http://php.net/filter.default -;filter.default = unsafe_raw - -; http://php.net/filter.default-flags -;filter.default_flags = - -[iconv] -; Use of this INI entry is deprecated, use global input_encoding instead. -; If empty, default_charset or input_encoding or iconv.input_encoding is used. -; The precedence is: default_charset < intput_encoding < iconv.input_encoding -;iconv.input_encoding = - -; Use of this INI entry is deprecated, use global internal_encoding instead. -; If empty, default_charset or internal_encoding or iconv.internal_encoding is used. -; The precedence is: default_charset < internal_encoding < iconv.internal_encoding -;iconv.internal_encoding = - -; Use of this INI entry is deprecated, use global output_encoding instead. -; If empty, default_charset or output_encoding or iconv.output_encoding is used. -; The precedence is: default_charset < output_encoding < iconv.output_encoding -; To use an output encoding conversion, iconv's output handler must be set -; otherwise output encoding conversion cannot be performed. -;iconv.output_encoding = - -[intl] -;intl.default_locale = -; This directive allows you to produce PHP errors when some error -; happens within intl functions. The value is the level of the error produced. -; Default is 0, which does not produce any errors. -;intl.error_level = E_WARNING -;intl.use_exceptions = 0 - -[sqlite3] -;sqlite3.extension_dir = - -[Pcre] -;PCRE library backtracking limit. -; http://php.net/pcre.backtrack-limit -;pcre.backtrack_limit=100000 - -;PCRE library recursion limit. -;Please note that if you set this value to a high number you may consume all -;the available process stack and eventually crash PHP (due to reaching the -;stack size limit imposed by the Operating System). -; http://php.net/pcre.recursion-limit -;pcre.recursion_limit=100000 - -;Enables or disables JIT compilation of patterns. This requires the PCRE -;library to be compiled with JIT support. -;pcre.jit=1 - -[Pdo] -; Whether to pool ODBC connections. Can be one of "strict", "relaxed" or "off" -; http://php.net/pdo-odbc.connection-pooling -;pdo_odbc.connection_pooling=strict - -;pdo_odbc.db2_instance_name - -[Pdo_mysql] -; If mysqlnd is used: Number of cache slots for the internal result set cache -; http://php.net/pdo_mysql.cache_size -pdo_mysql.cache_size = 2000 - -; Default socket name for local MySQL connects. If empty, uses the built-in -; MySQL defaults. -; http://php.net/pdo_mysql.default-socket -pdo_mysql.default_socket= - -[Phar] -; http://php.net/phar.readonly -;phar.readonly = On - -; http://php.net/phar.require-hash -;phar.require_hash = On - -;phar.cache_list = - -[mail function] -; For Win32 only. -; http://php.net/smtp -SMTP = localhost -; http://php.net/smtp-port -smtp_port = 25 - -; For Win32 only. -; http://php.net/sendmail-from -;sendmail_from = me@example.com - -; For Unix only. You may supply arguments as well (default: "sendmail -t -i"). -; http://php.net/sendmail-path -;sendmail_path = - -; Force the addition of the specified parameters to be passed as extra parameters -; to the sendmail binary. These parameters will always replace the value of -; the 5th parameter to mail(). -;mail.force_extra_parameters = - -; Add X-PHP-Originating-Script: that will include uid of the script followed by the filename -mail.add_x_header = On - -; The path to a log file that will log all mail() calls. Log entries include -; the full path of the script, line number, To address and headers. -;mail.log = -; Log mail to syslog (Event Log on Windows). -;mail.log = syslog - -[ODBC] -; http://php.net/odbc.default-db -;odbc.default_db = Not yet implemented - -; http://php.net/odbc.default-user -;odbc.default_user = Not yet implemented - -; http://php.net/odbc.default-pw -;odbc.default_pw = Not yet implemented - -; Controls the ODBC cursor model. -; Default: SQL_CURSOR_STATIC (default). -;odbc.default_cursortype - -; Allow or prevent persistent links. -; http://php.net/odbc.allow-persistent -odbc.allow_persistent = On - -; Check that a connection is still valid before reuse. -; http://php.net/odbc.check-persistent -odbc.check_persistent = On - -; Maximum number of persistent links. -1 means no limit. -; http://php.net/odbc.max-persistent -odbc.max_persistent = -1 - -; Maximum number of links (persistent + non-persistent). -1 means no limit. -; http://php.net/odbc.max-links -odbc.max_links = -1 - -; Handling of LONG fields. Returns number of bytes to variables. 0 means -; passthru. -; http://php.net/odbc.defaultlrl -odbc.defaultlrl = 4096 - -; Handling of binary data. 0 means passthru, 1 return as is, 2 convert to char. -; See the documentation on odbc_binmode and odbc_longreadlen for an explanation -; of odbc.defaultlrl and odbc.defaultbinmode -; http://php.net/odbc.defaultbinmode -odbc.defaultbinmode = 1 - -;birdstep.max_links = -1 - -[Interbase] -; Allow or prevent persistent links. -ibase.allow_persistent = 1 - -; Maximum number of persistent links. -1 means no limit. -ibase.max_persistent = -1 - -; Maximum number of links (persistent + non-persistent). -1 means no limit. -ibase.max_links = -1 - -; Default database name for ibase_connect(). -;ibase.default_db = - -; Default username for ibase_connect(). -;ibase.default_user = - -; Default password for ibase_connect(). -;ibase.default_password = - -; Default charset for ibase_connect(). -;ibase.default_charset = - -; Default timestamp format. -ibase.timestampformat = "%Y-%m-%d %H:%M:%S" - -; Default date format. -ibase.dateformat = "%Y-%m-%d" - -; Default time format. -ibase.timeformat = "%H:%M:%S" - -[MySQLi] - -; Maximum number of persistent links. -1 means no limit. -; http://php.net/mysqli.max-persistent -mysqli.max_persistent = -1 - -; Allow accessing, from PHP's perspective, local files with LOAD DATA statements -; http://php.net/mysqli.allow_local_infile -;mysqli.allow_local_infile = On - -; Allow or prevent persistent links. -; http://php.net/mysqli.allow-persistent -mysqli.allow_persistent = On - -; Maximum number of links. -1 means no limit. -; http://php.net/mysqli.max-links -mysqli.max_links = -1 - -; If mysqlnd is used: Number of cache slots for the internal result set cache -; http://php.net/mysqli.cache_size -mysqli.cache_size = 2000 - -; Default port number for mysqli_connect(). If unset, mysqli_connect() will use -; the $MYSQL_TCP_PORT or the mysql-tcp entry in /etc/services or the -; compile-time value defined MYSQL_PORT (in that order). Win32 will only look -; at MYSQL_PORT. -; http://php.net/mysqli.default-port -mysqli.default_port = 3306 - -; Default socket name for local MySQL connects. If empty, uses the built-in -; MySQL defaults. -; http://php.net/mysqli.default-socket -mysqli.default_socket = - -; Default host for mysql_connect() (doesn't apply in safe mode). -; http://php.net/mysqli.default-host -mysqli.default_host = - -; Default user for mysql_connect() (doesn't apply in safe mode). -; http://php.net/mysqli.default-user -mysqli.default_user = - -; Default password for mysqli_connect() (doesn't apply in safe mode). -; Note that this is generally a *bad* idea to store passwords in this file. -; *Any* user with PHP access can run 'echo get_cfg_var("mysqli.default_pw") -; and reveal this password! And of course, any users with read access to this -; file will be able to reveal the password as well. -; http://php.net/mysqli.default-pw -mysqli.default_pw = - -; Allow or prevent reconnect -mysqli.reconnect = Off - -[mysqlnd] -; Enable / Disable collection of general statistics by mysqlnd which can be -; used to tune and monitor MySQL operations. -; http://php.net/mysqlnd.collect_statistics -mysqlnd.collect_statistics = Off - -; Enable / Disable collection of memory usage statistics by mysqlnd which can be -; used to tune and monitor MySQL operations. -; http://php.net/mysqlnd.collect_memory_statistics -mysqlnd.collect_memory_statistics = Off - -; Records communication from all extensions using mysqlnd to the specified log -; file. -; http://php.net/mysqlnd.debug -;mysqlnd.debug = - -; Defines which queries will be logged. -; http://php.net/mysqlnd.log_mask -;mysqlnd.log_mask = 0 - -; Default size of the mysqlnd memory pool, which is used by result sets. -; http://php.net/mysqlnd.mempool_default_size -;mysqlnd.mempool_default_size = 16000 - -; Size of a pre-allocated buffer used when sending commands to MySQL in bytes. -; http://php.net/mysqlnd.net_cmd_buffer_size -;mysqlnd.net_cmd_buffer_size = 2048 - -; Size of a pre-allocated buffer used for reading data sent by the server in -; bytes. -; http://php.net/mysqlnd.net_read_buffer_size -;mysqlnd.net_read_buffer_size = 32768 - -; Timeout for network requests in seconds. -; http://php.net/mysqlnd.net_read_timeout -;mysqlnd.net_read_timeout = 31536000 - -; SHA-256 Authentication Plugin related. File with the MySQL server public RSA -; key. -; http://php.net/mysqlnd.sha256_server_public_key -;mysqlnd.sha256_server_public_key = - -[OCI8] - -; Connection: Enables privileged connections using external -; credentials (OCI_SYSOPER, OCI_SYSDBA) -; http://php.net/oci8.privileged-connect -;oci8.privileged_connect = Off - -; Connection: The maximum number of persistent OCI8 connections per -; process. Using -1 means no limit. -; http://php.net/oci8.max-persistent -;oci8.max_persistent = -1 - -; Connection: The maximum number of seconds a process is allowed to -; maintain an idle persistent connection. Using -1 means idle -; persistent connections will be maintained forever. -; http://php.net/oci8.persistent-timeout -;oci8.persistent_timeout = -1 - -; Connection: The number of seconds that must pass before issuing a -; ping during oci_pconnect() to check the connection validity. When -; set to 0, each oci_pconnect() will cause a ping. Using -1 disables -; pings completely. -; http://php.net/oci8.ping-interval -;oci8.ping_interval = 60 - -; Connection: Set this to a user chosen connection class to be used -; for all pooled server requests with Oracle 11g Database Resident -; Connection Pooling (DRCP). To use DRCP, this value should be set to -; the same string for all web servers running the same application, -; the database pool must be configured, and the connection string must -; specify to use a pooled server. -;oci8.connection_class = - -; High Availability: Using On lets PHP receive Fast Application -; Notification (FAN) events generated when a database node fails. The -; database must also be configured to post FAN events. -;oci8.events = Off - -; Tuning: This option enables statement caching, and specifies how -; many statements to cache. Using 0 disables statement caching. -; http://php.net/oci8.statement-cache-size -;oci8.statement_cache_size = 20 - -; Tuning: Enables statement prefetching and sets the default number of -; rows that will be fetched automatically after statement execution. -; http://php.net/oci8.default-prefetch -;oci8.default_prefetch = 100 - -; Compatibility. Using On means oci_close() will not close -; oci_connect() and oci_new_connect() connections. -; http://php.net/oci8.old-oci-close-semantics -;oci8.old_oci_close_semantics = Off - -[PostgreSQL] -; Allow or prevent persistent links. -; http://php.net/pgsql.allow-persistent -pgsql.allow_persistent = On - -; Detect broken persistent links always with pg_pconnect(). -; Auto reset feature requires a little overheads. -; http://php.net/pgsql.auto-reset-persistent -pgsql.auto_reset_persistent = Off - -; Maximum number of persistent links. -1 means no limit. -; http://php.net/pgsql.max-persistent -pgsql.max_persistent = -1 - -; Maximum number of links (persistent+non persistent). -1 means no limit. -; http://php.net/pgsql.max-links -pgsql.max_links = -1 - -; Ignore PostgreSQL backends Notice message or not. -; Notice message logging require a little overheads. -; http://php.net/pgsql.ignore-notice -pgsql.ignore_notice = 0 - -; Log PostgreSQL backends Notice message or not. -; Unless pgsql.ignore_notice=0, module cannot log notice message. -; http://php.net/pgsql.log-notice -pgsql.log_notice = 0 - -[bcmath] -; Number of decimal digits for all bcmath functions. -; http://php.net/bcmath.scale -bcmath.scale = 0 - -[browscap] -; http://php.net/browscap -;browscap = extra/browscap.ini - -[Session] -; Handler used to store/retrieve data. -; http://php.net/session.save-handler -session.save_handler = files - -; Argument passed to save_handler. In the case of files, this is the path -; where data files are stored. Note: Windows users have to change this -; variable in order to use PHP's session functions. -; -; The path can be defined as: -; -; session.save_path = "N;/path" -; -; where N is an integer. Instead of storing all the session files in -; /path, what this will do is use subdirectories N-levels deep, and -; store the session data in those directories. This is useful if -; your OS has problems with many files in one directory, and is -; a more efficient layout for servers that handle many sessions. -; -; NOTE 1: PHP will not create this directory structure automatically. -; You can use the script in the ext/session dir for that purpose. -; NOTE 2: See the section on garbage collection below if you choose to -; use subdirectories for session storage -; -; The file storage module creates files using mode 600 by default. -; You can change that by using -; -; session.save_path = "N;MODE;/path" -; -; where MODE is the octal representation of the mode. Note that this -; does not overwrite the process's umask. -; http://php.net/session.save-path -;session.save_path = "/var/lib/php/sessions" - -; Whether to use strict session mode. -; Strict session mode does not accept uninitialized session ID and regenerate -; session ID if browser sends uninitialized session ID. Strict mode protects -; applications from session fixation via session adoption vulnerability. It is -; disabled by default for maximum compatibility, but enabling it is encouraged. -; https://wiki.php.net/rfc/strict_sessions -session.use_strict_mode = 0 - -; Whether to use cookies. -; http://php.net/session.use-cookies -session.use_cookies = 1 - -; http://php.net/session.cookie-secure -;session.cookie_secure = - -; This option forces PHP to fetch and use a cookie for storing and maintaining -; the session id. We encourage this operation as it's very helpful in combating -; session hijacking when not specifying and managing your own session id. It is -; not the be-all and end-all of session hijacking defense, but it's a good start. -; http://php.net/session.use-only-cookies -session.use_only_cookies = 1 - -; Name of the session (used as cookie name). -; http://php.net/session.name -session.name = PHPSESSID - -; Initialize session on request startup. -; http://php.net/session.auto-start -session.auto_start = 0 - -; Lifetime in seconds of cookie or, if 0, until browser is restarted. -; http://php.net/session.cookie-lifetime -session.cookie_lifetime = 0 - -; The path for which the cookie is valid. -; http://php.net/session.cookie-path -session.cookie_path = / - -; The domain for which the cookie is valid. -; http://php.net/session.cookie-domain -session.cookie_domain = - -; Whether or not to add the httpOnly flag to the cookie, which makes it inaccessible to browser scripting languages such as JavaScript. -; http://php.net/session.cookie-httponly -session.cookie_httponly = - -; Handler used to serialize data. php is the standard serializer of PHP. -; http://php.net/session.serialize-handler -session.serialize_handler = php - -; Defines the probability that the 'garbage collection' process is started -; on every session initialization. The probability is calculated by using -; gc_probability/gc_divisor. Where session.gc_probability is the numerator -; and gc_divisor is the denominator in the equation. Setting this value to 1 -; when the session.gc_divisor value is 100 will give you approximately a 1% chance -; the gc will run on any give request. -; Default Value: 1 -; Development Value: 1 -; Production Value: 1 -; http://php.net/session.gc-probability -session.gc_probability = 0 - -; Defines the probability that the 'garbage collection' process is started on every -; session initialization. The probability is calculated by using the following equation: -; gc_probability/gc_divisor. Where session.gc_probability is the numerator and -; session.gc_divisor is the denominator in the equation. Setting this value to 1 -; when the session.gc_divisor value is 100 will give you approximately a 1% chance -; the gc will run on any give request. Increasing this value to 1000 will give you -; a 0.1% chance the gc will run on any give request. For high volume production servers, -; this is a more efficient approach. -; Default Value: 100 -; Development Value: 1000 -; Production Value: 1000 -; http://php.net/session.gc-divisor -session.gc_divisor = 1000 - -; After this number of seconds, stored data will be seen as 'garbage' and -; cleaned up by the garbage collection process. -; http://php.net/session.gc-maxlifetime -session.gc_maxlifetime = 1440 - -; NOTE: If you are using the subdirectory option for storing session files -; (see session.save_path above), then garbage collection does *not* -; happen automatically. You will need to do your own garbage -; collection through a shell script, cron entry, or some other method. -; For example, the following script would is the equivalent of -; setting session.gc_maxlifetime to 1440 (1440 seconds = 24 minutes): -; find /path/to/sessions -cmin +24 -type f | xargs rm - -; Check HTTP Referer to invalidate externally stored URLs containing ids. -; HTTP_REFERER has to contain this substring for the session to be -; considered as valid. -; http://php.net/session.referer-check -session.referer_check = - -; Set to {nocache,private,public,} to determine HTTP caching aspects -; or leave this empty to avoid sending anti-caching headers. -; http://php.net/session.cache-limiter -session.cache_limiter = nocache - -; Document expires after n minutes. -; http://php.net/session.cache-expire -session.cache_expire = 180 - -; trans sid support is disabled by default. -; Use of trans sid may risk your users' security. -; Use this option with caution. -; - User may send URL contains active session ID -; to other person via. email/irc/etc. -; - URL that contains active session ID may be stored -; in publicly accessible computer. -; - User may access your site with the same session ID -; always using URL stored in browser's history or bookmarks. -; http://php.net/session.use-trans-sid -session.use_trans_sid = 0 - -; Set session ID character length. This value could be between 22 to 256. -; Shorter length than default is supported only for compatibility reason. -; Users should use 32 or more chars. -; http://php.net/session.sid-length -; Default Value: 32 -; Development Value: 26 -; Production Value: 26 -session.sid_length = 26 - -; The URL rewriter will look for URLs in a defined set of HTML tags. -; is special; if you include them here, the rewriter will -; add a hidden field with the info which is otherwise appended -; to URLs. tag's action attribute URL will not be modified -; unless it is specified. -; Note that all valid entries require a "=", even if no value follows. -; Default Value: "a=href,area=href,frame=src,form=" -; Development Value: "a=href,area=href,frame=src,form=" -; Production Value: "a=href,area=href,frame=src,form=" -; http://php.net/url-rewriter.tags -session.trans_sid_tags = "a=href,area=href,frame=src,form=" - -; URL rewriter does not rewrite absolute URLs by default. -; To enable rewrites for absolute pathes, target hosts must be specified -; at RUNTIME. i.e. use ini_set() -; tags is special. PHP will check action attribute's URL regardless -; of session.trans_sid_tags setting. -; If no host is defined, HTTP_HOST will be used for allowed host. -; Example value: php.net,www.php.net,wiki.php.net -; Use "," for multiple hosts. No spaces are allowed. -; Default Value: "" -; Development Value: "" -; Production Value: "" -;session.trans_sid_hosts="" - -; Define how many bits are stored in each character when converting -; the binary hash data to something readable. -; Possible values: -; 4 (4 bits: 0-9, a-f) -; 5 (5 bits: 0-9, a-v) -; 6 (6 bits: 0-9, a-z, A-Z, "-", ",") -; Default Value: 4 -; Development Value: 5 -; Production Value: 5 -; http://php.net/session.hash-bits-per-character -session.sid_bits_per_character = 5 - -; Enable upload progress tracking in $_SESSION -; Default Value: On -; Development Value: On -; Production Value: On -; http://php.net/session.upload-progress.enabled -;session.upload_progress.enabled = On - -; Cleanup the progress information as soon as all POST data has been read -; (i.e. upload completed). -; Default Value: On -; Development Value: On -; Production Value: On -; http://php.net/session.upload-progress.cleanup -;session.upload_progress.cleanup = On - -; A prefix used for the upload progress key in $_SESSION -; Default Value: "upload_progress_" -; Development Value: "upload_progress_" -; Production Value: "upload_progress_" -; http://php.net/session.upload-progress.prefix -;session.upload_progress.prefix = "upload_progress_" - -; The index name (concatenated with the prefix) in $_SESSION -; containing the upload progress information -; Default Value: "PHP_SESSION_UPLOAD_PROGRESS" -; Development Value: "PHP_SESSION_UPLOAD_PROGRESS" -; Production Value: "PHP_SESSION_UPLOAD_PROGRESS" -; http://php.net/session.upload-progress.name -;session.upload_progress.name = "PHP_SESSION_UPLOAD_PROGRESS" - -; How frequently the upload progress should be updated. -; Given either in percentages (per-file), or in bytes -; Default Value: "1%" -; Development Value: "1%" -; Production Value: "1%" -; http://php.net/session.upload-progress.freq -;session.upload_progress.freq = "1%" - -; The minimum delay between updates, in seconds -; Default Value: 1 -; Development Value: 1 -; Production Value: 1 -; http://php.net/session.upload-progress.min-freq -;session.upload_progress.min_freq = "1" - -; Only write session data when session data is changed. Enabled by default. -; http://php.net/session.lazy-write -;session.lazy_write = On - -[Assertion] -; Switch whether to compile assertions at all (to have no overhead at run-time) -; -1: Do not compile at all -; 0: Jump over assertion at run-time -; 1: Execute assertions -; Changing from or to a negative value is only possible in php.ini! (For turning assertions on and off at run-time, see assert.active, when zend.assertions = 1) -; Default Value: 1 -; Development Value: 1 -; Production Value: -1 -; http://php.net/zend.assertions -zend.assertions = -1 - -; Assert(expr); active by default. -; http://php.net/assert.active -;assert.active = On - -; Throw an AssertationException on failed assertions -; http://php.net/assert.exception -;assert.exception = On - -; Issue a PHP warning for each failed assertion. (Overridden by assert.exception if active) -; http://php.net/assert.warning -;assert.warning = On - -; Don't bail out by default. -; http://php.net/assert.bail -;assert.bail = Off - -; User-function to be called if an assertion fails. -; http://php.net/assert.callback -;assert.callback = 0 - -; Eval the expression with current error_reporting(). Set to true if you want -; error_reporting(0) around the eval(). -; http://php.net/assert.quiet-eval -;assert.quiet_eval = 0 - -[COM] -; path to a file containing GUIDs, IIDs or filenames of files with TypeLibs -; http://php.net/com.typelib-file -;com.typelib_file = - -; allow Distributed-COM calls -; http://php.net/com.allow-dcom -;com.allow_dcom = true - -; autoregister constants of a components typlib on com_load() -; http://php.net/com.autoregister-typelib -;com.autoregister_typelib = true - -; register constants casesensitive -; http://php.net/com.autoregister-casesensitive -;com.autoregister_casesensitive = false - -; show warnings on duplicate constant registrations -; http://php.net/com.autoregister-verbose -;com.autoregister_verbose = true - -; The default character set code-page to use when passing strings to and from COM objects. -; Default: system ANSI code page -;com.code_page= - -[mbstring] -; language for internal character representation. -; This affects mb_send_mail() and mbstring.detect_order. -; http://php.net/mbstring.language -;mbstring.language = Japanese - -; Use of this INI entry is deprecated, use global internal_encoding instead. -; internal/script encoding. -; Some encoding cannot work as internal encoding. (e.g. SJIS, BIG5, ISO-2022-*) -; If empty, default_charset or internal_encoding or iconv.internal_encoding is used. -; The precedence is: default_charset < internal_encoding < iconv.internal_encoding -;mbstring.internal_encoding = - -; Use of this INI entry is deprecated, use global input_encoding instead. -; http input encoding. -; mbstring.encoding_traslation = On is needed to use this setting. -; If empty, default_charset or input_encoding or mbstring.input is used. -; The precedence is: default_charset < intput_encoding < mbsting.http_input -; http://php.net/mbstring.http-input -;mbstring.http_input = - -; Use of this INI entry is deprecated, use global output_encoding instead. -; http output encoding. -; mb_output_handler must be registered as output buffer to function. -; If empty, default_charset or output_encoding or mbstring.http_output is used. -; The precedence is: default_charset < output_encoding < mbstring.http_output -; To use an output encoding conversion, mbstring's output handler must be set -; otherwise output encoding conversion cannot be performed. -; http://php.net/mbstring.http-output -;mbstring.http_output = - -; enable automatic encoding translation according to -; mbstring.internal_encoding setting. Input chars are -; converted to internal encoding by setting this to On. -; Note: Do _not_ use automatic encoding translation for -; portable libs/applications. -; http://php.net/mbstring.encoding-translation -;mbstring.encoding_translation = Off - -; automatic encoding detection order. -; "auto" detect order is changed according to mbstring.language -; http://php.net/mbstring.detect-order -;mbstring.detect_order = auto - -; substitute_character used when character cannot be converted -; one from another -; http://php.net/mbstring.substitute-character -;mbstring.substitute_character = none - -; overload(replace) single byte functions by mbstring functions. -; mail(), ereg(), etc are overloaded by mb_send_mail(), mb_ereg(), -; etc. Possible values are 0,1,2,4 or combination of them. -; For example, 7 for overload everything. -; 0: No overload -; 1: Overload mail() function -; 2: Overload str*() functions -; 4: Overload ereg*() functions -; http://php.net/mbstring.func-overload -;mbstring.func_overload = 0 - -; enable strict encoding detection. -; Default: Off -;mbstring.strict_detection = On - -; This directive specifies the regex pattern of content types for which mb_output_handler() -; is activated. -; Default: mbstring.http_output_conv_mimetype=^(text/|application/xhtml\+xml) -;mbstring.http_output_conv_mimetype= - -[gd] -; Tell the jpeg decode to ignore warnings and try to create -; a gd image. The warning will then be displayed as notices -; disabled by default -; http://php.net/gd.jpeg-ignore-warning -;gd.jpeg_ignore_warning = 1 - -[exif] -; Exif UNICODE user comments are handled as UCS-2BE/UCS-2LE and JIS as JIS. -; With mbstring support this will automatically be converted into the encoding -; given by corresponding encode setting. When empty mbstring.internal_encoding -; is used. For the decode settings you can distinguish between motorola and -; intel byte order. A decode setting cannot be empty. -; http://php.net/exif.encode-unicode -;exif.encode_unicode = ISO-8859-15 - -; http://php.net/exif.decode-unicode-motorola -;exif.decode_unicode_motorola = UCS-2BE - -; http://php.net/exif.decode-unicode-intel -;exif.decode_unicode_intel = UCS-2LE - -; http://php.net/exif.encode-jis -;exif.encode_jis = - -; http://php.net/exif.decode-jis-motorola -;exif.decode_jis_motorola = JIS - -; http://php.net/exif.decode-jis-intel -;exif.decode_jis_intel = JIS - -[Tidy] -; The path to a default tidy configuration file to use when using tidy -; http://php.net/tidy.default-config -;tidy.default_config = /usr/local/lib/php/default.tcfg - -; Should tidy clean and repair output automatically? -; WARNING: Do not use this option if you are generating non-html content -; such as dynamic images -; http://php.net/tidy.clean-output -tidy.clean_output = Off - -[soap] -; Enables or disables WSDL caching feature. -; http://php.net/soap.wsdl-cache-enabled -soap.wsdl_cache_enabled=1 - -; Sets the directory name where SOAP extension will put cache files. -; http://php.net/soap.wsdl-cache-dir -soap.wsdl_cache_dir="/tmp" - -; (time to live) Sets the number of second while cached file will be used -; instead of original one. -; http://php.net/soap.wsdl-cache-ttl -soap.wsdl_cache_ttl=86400 - -; Sets the size of the cache limit. (Max. number of WSDL files to cache) -soap.wsdl_cache_limit = 5 - -[sysvshm] -; A default size of the shared memory segment -;sysvshm.init_mem = 10000 - -[ldap] -; Sets the maximum number of open links or -1 for unlimited. -ldap.max_links = -1 - -[dba] -;dba.default_handler= - -[opcache] -; Determines if Zend OPCache is enabled -opcache.enable=1 - -; Determines if Zend OPCache is enabled for the CLI version of PHP -;opcache.enable_cli=0 - -; The OPcache shared memory storage size. -;opcache.memory_consumption=128 - -; The amount of memory for interned strings in Mbytes. -;opcache.interned_strings_buffer=8 - -; The maximum number of keys (scripts) in the OPcache hash table. -; Only numbers between 200 and 1000000 are allowed. -;opcache.max_accelerated_files=10000 - -; The maximum percentage of "wasted" memory until a restart is scheduled. -;opcache.max_wasted_percentage=5 - -; When this directive is enabled, the OPcache appends the current working -; directory to the script key, thus eliminating possible collisions between -; files with the same name (basename). Disabling the directive improves -; performance, but may break existing applications. -;opcache.use_cwd=1 - -; When disabled, you must reset the OPcache manually or restart the -; webserver for changes to the filesystem to take effect. -opcache.validate_timestamps=0 - -; How often (in seconds) to check file timestamps for changes to the shared -; memory storage allocation. ("1" means validate once per second, but only -; once per request. "0" means always validate) -;opcache.revalidate_freq=2 - -; Enables or disables file search in include_path optimization -;opcache.revalidate_path=0 - -; If disabled, all PHPDoc comments are dropped from the code to reduce the -; size of the optimized code. -opcache.save_comments=0 - -; Allow file existence override (file_exists, etc.) performance feature. -opcache.enable_file_override=1 - -; A bitmask, where each bit enables or disables the appropriate OPcache -; passes -;opcache.optimization_level=0xffffffff - -;opcache.inherited_hack=1 -;opcache.dups_fix=0 - -; The location of the OPcache blacklist file (wildcards allowed). -; Each OPcache blacklist file is a text file that holds the names of files -; that should not be accelerated. The file format is to add each filename -; to a new line. The filename may be a full path or just a file prefix -; (i.e., /var/www/x blacklists all the files and directories in /var/www -; that start with 'x'). Line starting with a ; are ignored (comments). -;opcache.blacklist_filename= - -; Allows exclusion of large files from being cached. By default all files -; are cached. -;opcache.max_file_size=0 - -; Check the cache checksum each N requests. -; The default value of "0" means that the checks are disabled. -;opcache.consistency_checks=0 - -; How long to wait (in seconds) for a scheduled restart to begin if the cache -; is not being accessed. -;opcache.force_restart_timeout=180 - -; OPcache error_log file name. Empty string assumes "stderr". -;opcache.error_log= - -; All OPcache errors go to the Web server log. -; By default, only fatal errors (level 0) or errors (level 1) are logged. -; You can also enable warnings (level 2), info messages (level 3) or -; debug messages (level 4). -;opcache.log_verbosity_level=1 - -; Preferred Shared Memory back-end. Leave empty and let the system decide. -;opcache.preferred_memory_model= - -; Protect the shared memory from unexpected writing during script execution. -; Useful for internal debugging only. -;opcache.protect_memory=0 - -; Allows calling OPcache API functions only from PHP scripts which path is -; started from specified string. The default "" means no restriction -;opcache.restrict_api= - -; Mapping base of shared memory segments (for Windows only). All the PHP -; processes have to map shared memory into the same address space. This -; directive allows to manually fix the "Unable to reattach to base address" -; errors. -;opcache.mmap_base= - -; Enables and sets the second level cache directory. -; It should improve performance when SHM memory is full, at server restart or -; SHM reset. The default "" disables file based caching. -;opcache.file_cache= - -; Enables or disables opcode caching in shared memory. -;opcache.file_cache_only=0 - -; Enables or disables checksum validation when script loaded from file cache. -;opcache.file_cache_consistency_checks=1 - -; Implies opcache.file_cache_only=1 for a certain process that failed to -; reattach to the shared memory (for Windows only). Explicitly enabled file -; cache is required. -;opcache.file_cache_fallback=1 - -; Enables or disables copying of PHP code (text segment) into HUGE PAGES. -; This should improve performance, but requires appropriate OS configuration. -opcache.huge_code_pages=1 - -; Validate cached file permissions. -;opcache.validate_permission=0 - -; Prevent name collisions in chroot'ed environment. -;opcache.validate_root=0 - -[curl] -; A default value for the CURLOPT_CAINFO option. This is required to be an -; absolute path. -;curl.cainfo = - -[openssl] -; The location of a Certificate Authority (CA) file on the local filesystem -; to use when verifying the identity of SSL/TLS peers. Most users should -; not specify a value for this directive as PHP will attempt to use the -; OS-managed cert stores in its absence. If specified, this value may still -; be overridden on a per-stream basis via the "cafile" SSL stream context -; option. -;openssl.cafile= - -; If openssl.cafile is not specified or if the CA file is not found, the -; directory pointed to by openssl.capath is searched for a suitable -; certificate. This value must be a correctly hashed certificate directory. -; Most users should not specify a value for this directive as PHP will -; attempt to use the OS-managed cert stores in its absence. If specified, -; this value may still be overridden on a per-stream basis via the "capath" -; SSL stream context option. -;openssl.capath= - -; Local Variables: -; tab-width: 4 -; End: \ No newline at end of file diff --git a/frameworks/PHP/zend/deploy/nginx.conf b/frameworks/PHP/zend/deploy/nginx.conf deleted file mode 100644 index 3fea2eb49b2..00000000000 --- a/frameworks/PHP/zend/deploy/nginx.conf +++ /dev/null @@ -1,43 +0,0 @@ -user www-data; -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; - keepalive_disable none; - keepalive_requests 10000; - - upstream fastcgi_backend { - server unix:/var/run/php/php7.3-fpm.sock; - keepalive 40; - } - - server { - listen 8080; - server_name localhost; - - root /zend/public/; - index index.php; - - location / { - fastcgi_pass fastcgi_backend; - fastcgi_keep_conn on; - fastcgi_param SCRIPT_FILENAME $document_root/index.php; - fastcgi_param PATH_INFO $uri; - include /etc/nginx/fastcgi_params; - } - } -} diff --git a/frameworks/PHP/zend/deploy/php-zend-framework b/frameworks/PHP/zend/deploy/php-zend-framework deleted file mode 100644 index fc48b0f8f0c..00000000000 --- a/frameworks/PHP/zend/deploy/php-zend-framework +++ /dev/null @@ -1,9 +0,0 @@ - - Alias /php-zend-framework/ "/home/ubuntu/FrameworkBenchmarks/php-zend-framework/public/" - - Options Indexes FollowSymLinks MultiViews - #AllowOverride None - Order allow,deny - allow from all - - diff --git a/frameworks/PHP/zend/module/FrameworkBenchmarks/src/FrameworkBenchmarks/Controller/BenchController.php b/frameworks/PHP/zend/module/FrameworkBenchmarks/src/FrameworkBenchmarks/Controller/BenchController.php deleted file mode 100644 index f685d1b73e9..00000000000 --- a/frameworks/PHP/zend/module/FrameworkBenchmarks/src/FrameworkBenchmarks/Controller/BenchController.php +++ /dev/null @@ -1,103 +0,0 @@ - - * @link http://www.techempower.com/benchmarks - */ -class BenchController extends AbstractActionController -{ - /** - * @var \Zend\Db\TableGateway\TableGateway - */ - protected $tableGateway; - - /** - * @param TableGateway $tableGateway - */ - public function __construct(TableGateway $tableGateway) - { - $this->tableGateway = $tableGateway; - } - - public function jsonAction() - { - return new JsonModel(array('message' => 'Hello, World!')); - } - - /** - * @return \Zend\View\Model\JsonModel - */ - public function dbAction() - { - $result = $this->tableGateway->select(array('id' => mt_rand(1, 10000))); - - foreach ($result as $return) { - return new JsonModel($return); - } - - return $this->notFoundAction(); - } - - /** - * @return \Zend\View\Model\JsonModel - */ - public function queriesAction() - { - /* @var $request \Zend\Http\Request */ - $request = $this->getRequest(); - $queries = (int) $request->getQuery('queries', 1); - $queries = max(1, $queries); - $queries = min(500, $queries); - - $worlds = array(); - - for ($i = 0; $i < $queries; $i += 1) { - foreach ($this->tableGateway->select(array('id' => mt_rand(1, 10000))) as $found) { - $worlds[] = $found; - } - } - - return new JsonModel($worlds); - } - - public function updatesAction() - { - $request = $this->getRequest(); - $queries = (int) $request->getQuery('queries', 1); - $queries = max(1, $queries); - $queries = min(500, $queries); - - $worlds = array(); - - for ($i = 0; $i < $queries; $i += 1) { - $id = mt_rand(1, 10000); - foreach ($this->tableGateway->select(array('id' => $id)) as $found) { - $random_number = mt_rand(1, 10000); - $found->randomNumber = $random_number; - $this->tableGateway->update(array('randomNumber' => $random_number), array('id' => $id)); - $worlds[] = $found; - } - } - - return new JsonModel($worlds); - } - - public function plaintextAction() - { - $response = $this->getResponse(); - $response->getHeaders()->addHeaders(array('COntent-Type' => 'text/plain')); - $response->setContent('Hello, World!'); - return $response; - } -} diff --git a/frameworks/PHP/zend/module/FrameworkBenchmarks/src/FrameworkBenchmarks/Entity/World.php b/frameworks/PHP/zend/module/FrameworkBenchmarks/src/FrameworkBenchmarks/Entity/World.php deleted file mode 100644 index 462a563e443..00000000000 --- a/frameworks/PHP/zend/module/FrameworkBenchmarks/src/FrameworkBenchmarks/Entity/World.php +++ /dev/null @@ -1,41 +0,0 @@ - - * @link http://www.techempower.com/benchmarks - */ -class World extends ArrayObject -{ - /** - * @var int - */ - public $id; - - /** - * @var int - */ - public $randomNumber; - - /** - * @param array $data - */ - public function exchangeArray($data) - { - $this->id = (int) $data['id']; - $this->randomNumber = (int) $data['randomNumber']; - } - - /** - * @return array - */ - public function toArray() - { - return array('id' => $this->id, 'randomNumber' => $this->randomNumber); - } -} diff --git a/frameworks/PHP/zend/module/FrameworkBenchmarks/src/FrameworkBenchmarks/Module.php b/frameworks/PHP/zend/module/FrameworkBenchmarks/src/FrameworkBenchmarks/Module.php deleted file mode 100644 index 1eb6c0e2761..00000000000 --- a/frameworks/PHP/zend/module/FrameworkBenchmarks/src/FrameworkBenchmarks/Module.php +++ /dev/null @@ -1,95 +0,0 @@ - - * @link http://www.techempower.com/benchmarks - */ -class Module -{ - /** - * @return array - */ - public function getConfig() - { - return array( - 'router' => array( - 'routes' => array( - 'plaintext' => array( - 'type' => 'Zend\Router\Http\Literal', - 'options' => array( - 'route' => '/plaintext', - 'defaults' => array( - 'controller' => 'FrameworkBenchmarks\Controller\BenchController', - 'action' => 'plaintext', - ), - ), - ), - 'json' => array( - 'type' => 'Zend\Router\Http\Literal', - 'options' => array( - 'route' => '/json', - 'defaults' => array( - 'controller' => 'FrameworkBenchmarks\Controller\BenchController', - 'action' => 'json', - ), - ), - ), - 'db' => array( - 'type' => 'Zend\Router\Http\Literal', - 'options' => array( - 'route' => '/db', - 'defaults' => array( - 'controller' => 'FrameworkBenchmarks\Controller\BenchController', - 'action' => 'db', - ), - ), - ), - 'queries' => array( - 'type' => 'Zend\Router\Http\Literal', - 'options' => array( - 'route' => '/queries', - 'defaults' => array( - 'controller' => 'FrameworkBenchmarks\Controller\BenchController', - 'action' => 'queries', - ), - ), - ), - 'updates' => array( - 'type' => 'Zend\Router\Http\Literal', - 'options' => array( - 'route' => '/updates', - 'defaults' => array( - 'controller' => 'FrameworkBenchmarks\Controller\BenchController', - 'action' => 'updates', - ), - ), - ), - ), - ), - 'db' => array( - 'driver' => 'Pdo', - 'dsn' => 'mysql:dbname=hello_world;host=localhost', - ), - 'controllers' => array( - 'factories' => array( - 'FrameworkBenchmarks\Controller\BenchController' - => 'FrameworkBenchmarks\ServiceFactory\BenchControllerServiceFactory' - ), - ), - 'service_manager' => array( - 'factories' => array( - 'Zend\Db\Adapter\Adapter' => 'Zend\Db\Adapter\AdapterServiceFactory', - ), - ), - 'view_manager' => array( - 'strategies' => array( - 'ViewJsonStrategy', - ), - ), - ); - } -} diff --git a/frameworks/PHP/zend/module/FrameworkBenchmarks/src/FrameworkBenchmarks/ServiceFactory/BenchControllerServiceFactory.php b/frameworks/PHP/zend/module/FrameworkBenchmarks/src/FrameworkBenchmarks/ServiceFactory/BenchControllerServiceFactory.php deleted file mode 100644 index 8d455eac51a..00000000000 --- a/frameworks/PHP/zend/module/FrameworkBenchmarks/src/FrameworkBenchmarks/ServiceFactory/BenchControllerServiceFactory.php +++ /dev/null @@ -1,40 +0,0 @@ - - * @link http://www.techempower.com/benchmarks - */ -class BenchControllerServiceFactory -{ - /** - * {@inheritDoc} - * - * @return \FrameworkBenchmarks\Controller\DbController - */ - public function __invoke(\Psr\Container\ContainerInterface $container) - { - /* @var $dbAdapter \Zend\Db\Adapter\AdapterInterface */ - $dbAdapter = $container->get('Zend\Db\Adapter\Adapter'); - $resultSetPrototype = new ResultSet(); - - $resultSetPrototype->setArrayObjectPrototype(new World()); - - return new BenchController(new TableGateway('World', $dbAdapter, null, $resultSetPrototype)); - } -} diff --git a/frameworks/PHP/zend/public/.htaccess b/frameworks/PHP/zend/public/.htaccess deleted file mode 100644 index a02263cb14a..00000000000 --- a/frameworks/PHP/zend/public/.htaccess +++ /dev/null @@ -1,16 +0,0 @@ -RewriteEngine On -# The following rule tells Apache that if the requested filename -# exists, simply serve it. -RewriteCond %{REQUEST_FILENAME} -s [OR] -RewriteCond %{REQUEST_FILENAME} -l [OR] -RewriteCond %{REQUEST_FILENAME} -d -RewriteRule ^.*$ - [NC,L] -# The following rewrites all other queries to index.php. The -# condition ensures that if you are using Apache aliases to do -# mass virtual hosting, the base path will be prepended to -# allow proper resolution of the index.php file; it will work -# in non-aliased environments as well, providing a safe, one-size -# fits all solution. -RewriteCond %{REQUEST_URI}::$1 ^(/.+)(.+)::\2$ -RewriteRule ^(.*) - [E=BASE:%1] -RewriteRule ^(.*)$ %{ENV:BASE}index.php [NC,L] \ No newline at end of file diff --git a/frameworks/PHP/zend/public/index.php b/frameworks/PHP/zend/public/index.php deleted file mode 100644 index e92f18ca1fc..00000000000 --- a/frameworks/PHP/zend/public/index.php +++ /dev/null @@ -1,6 +0,0 @@ -run(); diff --git a/frameworks/PHP/zend/zend.dockerfile b/frameworks/PHP/zend/zend.dockerfile deleted file mode 100644 index e5ef5281c8c..00000000000 --- a/frameworks/PHP/zend/zend.dockerfile +++ /dev/null @@ -1,28 +0,0 @@ -FROM ubuntu:20.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 > /dev/null && \ - apt-get install -yqq nginx git unzip php7.4 php7.4-common php7.4-cli php7.4-fpm php7.4-mysql > /dev/null -RUN apt-get install -yqq php7.4-xml php7.4-mbstring > /dev/null - -COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer - -COPY deploy/conf/* /etc/php/7.4/fpm/ - -ADD ./ /zend -WORKDIR /zend - -RUN if [ $(nproc) = 2 ]; then sed -i "s|pm.max_children = 1024|pm.max_children = 512|g" /etc/php/7.4/fpm/php-fpm.conf ; fi; - -RUN mkdir -p data/cache -RUN chmod 777 data/cache - -RUN composer install --optimize-autoloader --classmap-authoritative --quiet --no-dev - -EXPOSE 8080 - -CMD service php7.4-fpm start && \ - nginx -c /zend/deploy/nginx.conf -g "daemon off;" diff --git a/frameworks/Pascal/mormot/benchmark_config.json b/frameworks/Pascal/mormot/benchmark_config.json index 10bbf278270..378b0a6d9a0 100644 --- a/frameworks/Pascal/mormot/benchmark_config.json +++ b/frameworks/Pascal/mormot/benchmark_config.json @@ -9,8 +9,8 @@ "query_url": "/queries?queries=", "fortune_url": "/fortunes", "update_url": "/updates?queries=", - "plaintext_url": "/plaintext", "cached_query_url": "/cached-queries?count=", + "plaintext_url": "/plaintext", "port": 8080, "approach": "Realistic", "classification": "Fullstack", @@ -31,6 +31,7 @@ "dockerfile": "mormot.dockerfile", "db_url": "/rawdb", "query_url": "/rawqueries?queries=", + "cached_query_url": "/rawcached?count=", "fortune_url": "/rawfortunes", "update_url": "/rawupdates?queries=", "port": 8080, @@ -70,28 +71,6 @@ "display_name": "mormot [async]", "notes": "", "versus": "None" - }, - "postgres-async2": { - "dockerfile": "mormot.dockerfile", - "db_url": "/asyncdb", - "query_url": "/asyncqueries?queries=", - "fortune_url": "/asyncfortunes", - "update_url": "/asyncupdates?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "postgres", - "framework": "mormot", - "language": "Pascal", - "flavor": "None", - "orm": "Raw", - "platform": "None", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "mormot [async,nopin]", - "notes": "", - "versus": "None" } } ] diff --git a/frameworks/Pascal/mormot/mormot.dockerfile b/frameworks/Pascal/mormot/mormot.dockerfile index 831fa50b48f..cdb55defb26 100644 --- a/frameworks/Pascal/mormot/mormot.dockerfile +++ b/frameworks/Pascal/mormot/mormot.dockerfile @@ -9,7 +9,7 @@ COPY setup_and_build.sh . RUN /bin/bash -c ./setup_and_build.sh -FROM ubuntu:22.04 +FROM ubuntu:24.04 ARG TFB_TEST_NAME diff --git a/frameworks/Pascal/mormot/setup_and_build.sh b/frameworks/Pascal/mormot/setup_and_build.sh index 9afe8eff833..562d471de60 100755 --- a/frameworks/Pascal/mormot/setup_and_build.sh +++ b/frameworks/Pascal/mormot/setup_and_build.sh @@ -27,7 +27,7 @@ rm -rf ./libs mkdir -p ./libs/mORMot/static # echo "Getting the latest pre-release URL..." # USED_TAG=$(wget -qO- https://api.github.com/repos/synopse/mORMot2/releases/latest | jq -r '.tag_name') -USED_TAG="2.1.stable" +USED_TAG="2.3.stable" echo "Used release tag $USED_TAG" URL="https://github.com/synopse/mORMot2/releases/download/$USED_TAG/mormot2static.tgz" @@ -35,7 +35,7 @@ echo "Download statics from $URL ..." wget -qO- "$URL" | tar -xz -C ./libs/mORMot/static # uncomment for fixed commit URL -URL=https://github.com/synopse/mORMot2/tarball/c9cefa05e892763ff66a9a51a659b937def36195 +URL=https://github.com/synopse/mORMot2/tarball/bfe812b82a35361274324afb203bd6a5b213444a #URL="https://api.github.com/repos/synopse/mORMot2/tarball/$USED_TAG" echo "Download and unpacking mORMot sources from $URL ..." wget -qO- "$URL" | tar -xz -C ./libs/mORMot --strip-components=1 @@ -72,7 +72,7 @@ fi # Warning: (5090) Variable XXX of a managed type does not seem to be initialized SUPRESS_WARN=-vm11047,6058,5092,5091,5060,5058,5057,5028,5024,5023,4081,4079,4055,3187,3124,3123,5059,5036,5089,5090 echo "Start compiling..." -fpc -MDelphi -Sci -Ci -O4 -g -gl -gw2 -Xg -k'-rpath=$ORIGIN' -k-L$BIN \ +fpc -MDelphi -Sci -Ci -O3 -g -gl -gw2 -Xg -k'-rpath=$ORIGIN' -k-L$BIN \ -T$TARGET -P$ARCH \ -veiq -v-n-h- $SUPRESS_WARN \ -Fi"$BIN/fpc-$ARCH_TG/.dcu" -Fi"$MSRC" \ @@ -80,7 +80,7 @@ fpc -MDelphi -Sci -Ci -O4 -g -gl -gw2 -Xg -k'-rpath=$ORIGIN' -k-L$BIN \ -Fu"$MSRC/core" -Fu"$MSRC/db" -Fu"$MSRC/rest" -Fu"$MSRC/crypt" \ -Fu"$MSRC/app" -Fu"$MSRC/net" -Fu"$MSRC/lib" -Fu"$MSRC/orm" -Fu"$MSRC/soa" \ -FU"$BIN/fpc-$ARCH_TG/.dcu" -FE"$BIN/fpc-$ARCH_TG" -o"$BIN/fpc-$ARCH_TG/$dest_fn" \ - -dFPC_LIBCMM \ + -dFPC_LIBCMM -dFPC_LIBCMM_NOMSIZE \ -B -Se1 "./src/raw.pas" | grep "[Warning|Error|Fatal]:" script_successful \ No newline at end of file diff --git a/frameworks/Pascal/mormot/src/raw.pas b/frameworks/Pascal/mormot/src/raw.pas index b3695c8393c..2ea5735327e 100644 --- a/frameworks/Pascal/mormot/src/raw.pas +++ b/frameworks/Pascal/mormot/src/raw.pas @@ -46,7 +46,7 @@ type // data structures TMessageRec = packed record - message: RawUtf8; + message: PUtf8Char; end; TWorldRec = packed record id: integer; @@ -54,8 +54,8 @@ end; TWorlds = array of TWorldRec; TFortune = packed record - id: integer; - message: RawUtf8; + id: PtrUInt; + message: PUtf8Char; end; TFortunes = array of TFortune; @@ -85,13 +85,14 @@ TRawAsyncServer = class(TSynPersistent) fModel: TOrmModel; fStore: TRestServerDB; fTemplate: TSynMustache; - fCachedWorldsTable: POrmCacheTable; + fOrmCache: POrmCacheTable; + fRawCache: TOrmWorlds; fDbPool: TSqlDBPostgresConnectionProperties; - procedure OnAsyncDb(Statement: TSqlDBPostgresAsyncStatement; Context: TObject); - procedure OnAsyncFortunes(Statement: TSqlDBPostgresAsyncStatement; Context: TObject); + procedure OnAsyncDb(Statement: TSqlDBPostgresAsyncStatement; Context: PtrInt); + procedure OnAsyncFortunes(Statement: TSqlDBPostgresAsyncStatement; Context: PtrInt); // pipelined reading as used by /rawqueries and /rawupdates function GetRawRandomWorlds(cnt: PtrInt; out res: TWorlds): boolean; - function ComputeRawFortunes(stmt: TSqlDBStatement; ctxt: THttpServerRequest): integer; + function ComputeRawFortunes(stmt: TSqlDBStatement): RawUtf8; public constructor Create(threadCount: integer; flags: THttpServerOptions; pin2Core: integer); reintroduce; @@ -107,6 +108,7 @@ TRawAsyncServer = class(TSynPersistent) function updates(ctxt: THttpServerRequest): cardinal; function rawdb(ctxt: THttpServerRequest): cardinal; function rawqueries(ctxt: THttpServerRequest): cardinal; + function rawcached(ctxt: THttpServerRequest): cardinal; function rawfortunes(ctxt: THttpServerRequest): cardinal; function rawupdates(ctxt: THttpServerRequest): cardinal; // asynchronous PostgreSQL pipelined DB access @@ -144,13 +146,13 @@ TRawAsyncServer = class(TSynPersistent) ''; -function ComputeRandomWorld: integer; inline; +function ComputeRandomWorld(gen: PLecuyer): integer; inline; begin - result := Random32(WORLD_COUNT) + 1; + result := gen^.Next(WORLD_COUNT) + 1; end; function GetQueriesParamValue(ctxt: THttpServerRequest; - const search: RawUtf8 = 'QUERIES='): cardinal; + const search: RawUtf8 = 'QUERIES='): cardinal; inline; begin if not ctxt.UrlParam(search, result) or (result = 0) then @@ -168,7 +170,7 @@ constructor TRawAsyncServer.Create( inherited Create; fDbPool := TSqlDBPostgresConnectionProperties.Create( 'tfb-database:5432', 'hello_world', 'benchmarkdbuser', 'benchmarkdbpass'); - fDbPool.ArrayParamsAsBinary := true; + // fDbPool.ArrayParamsAsBinary := true; // seems not really faster // customize JSON serialization for TFB expectations TOrmWorld.OrmProps.Fields.JsonRenameProperties([ 'ID', 'id', @@ -186,10 +188,11 @@ constructor TRawAsyncServer.Create( fStore := TRestServerDB.Create(fModel, SQLITE_MEMORY_DATABASE_NAME); fStore.NoAjaxJson := true; fStore.Server.CreateMissingTables; // create SQlite3 virtual tables - // pre-fill the ORM + // ORM and raw caches warmup if fStore.Server.Cache.SetCache(TOrmCachedWorld) then fStore.Server.Cache.FillFromQuery(TOrmCachedWorld, '', []); - fCachedWorldsTable := fStore.Orm.Cache.Table(TOrmCachedWorld); + fOrmCache := fStore.Orm.Cache.Table(TOrmCachedWorld); + fStore.Orm.RetrieveListObjArray(fRawCache, TOrmCachedWorld, 'order by id', []); // initialize the mustache template for /fortunes fTemplate := TSynMustache.Parse(FORTUNES_TPL); // setup the HTTP server @@ -201,10 +204,11 @@ constructor TRawAsyncServer.Create( hsoNoStats, // disable low-level statistic counters //hsoThreadCpuAffinity, // worse scaling on multi-servers hsoThreadSmooting, // seems a good option, even if not magical + hsoEnablePipelining, // as expected by /plaintext {$ifdef WITH_LOGS} hsoLogVerbose, {$endif WITH_LOGS} - hsoIncludeDateHeader // required by TPW General Test Requirements #5 + hsoIncludeDateHeader // required by TFB General Test Requirements #5 ] + flags); if pin2Core <> -1 then fHttpServer.Async.SetCpuAffinity(pin2Core); @@ -221,22 +225,26 @@ destructor TRawAsyncServer.Destroy; fHttpServer.Free; fStore.Free; fModel.Free; - fDBPool.free; + fDBPool.Free; + ObjArrayClear(fRawCache); inherited Destroy; end; // query DB world table for /rawqueries and /rawupdates endpoints -function TRawAsyncServer.GetRawRandomWorlds(cnt: PtrInt; out res: TWorlds): boolean; +function TRawAsyncServer.GetRawRandomWorlds(cnt: PtrInt; + out res: TWorlds): boolean; var conn: TSqlDBConnection; stmt: ISqlDBStatement; pConn: TSqlDBPostgresConnection absolute conn; pStmt: TSqlDBPostgresStatement; + gen: PLecuyer; i: PtrInt; begin result := false; SetLength(res{%H-}, cnt); + gen := Lecuyer; conn := fDbPool.ThreadSafeConnection; // specific code to use PostgresSQL pipelining mode // see test_nosync in @@ -246,7 +254,7 @@ function TRawAsyncServer.GetRawRandomWorlds(cnt: PtrInt; out res: TWorlds): bool pStmt := TSqlDBPostgresStatement(stmt.Instance); for i := 0 to cnt - 1 do begin - pStmt.Bind(1, ComputeRandomWorld); + pStmt.Bind(1, ComputeRandomWorld(gen)); pStmt.SendPipelinePrepared; pConn.PipelineSync; end; @@ -269,15 +277,15 @@ function FortuneCompareByMessage(const A, B): integer; result := StrComp(pointer(TFortune(A).message), pointer(TFortune(B).message)); end; -function TRawAsyncServer.ComputeRawFortunes( - stmt: TSqlDBStatement; ctxt: THttpServerRequest): integer; +function TRawAsyncServer.ComputeRawFortunes(stmt: TSqlDBStatement): RawUtf8; var list: TFortunes; arr: TDynArray; n: integer; f: ^TFortune; + mus: TSynMustacheContextData; begin - result := HTTP_BADREQUEST; + result := ''; if stmt = nil then exit; arr.Init(TypeInfo(TFortunes), list, @n); @@ -285,15 +293,16 @@ function TRawAsyncServer.ComputeRawFortunes( begin f := arr.NewPtr; f.id := stmt.ColumnInt(0); - f.message := stmt.ColumnUtf8(1); + f.message := stmt.ColumnPUtf8(1); end; f := arr.NewPtr; f.id := 0; f.message := FORTUNES_MESSAGE; arr.Sort(FortuneCompareByMessage); - ctxt.OutContent := fTemplate.RenderDataArray(arr); - ctxt.OutContentType := HTML_CONTENT_TYPE; - result := HTTP_SUCCESS; + mus := stmt.Connection.GetThreadOwned(TSynMustacheContextData); + if mus = nil then + mus := stmt.Connection.SetThreadOwned(fTemplate.NewMustacheContextData); + result := mus.RenderArray(arr); end; // following methods implement the server endpoints @@ -309,19 +318,17 @@ function TRawAsyncServer.json(ctxt: THttpServerRequest): cardinal; var msgRec: TMessageRec; begin - msgRec.message := HELLO_WORLD; - ctxt.SetOutJson(@msgRec, TypeInfo(TMessageRec)); - result := HTTP_SUCCESS; + msgRec.message := pointer(HELLO_WORLD); + result := ctxt.SetOutJson(@msgRec, TypeInfo(TMessageRec)); end; function TRawAsyncServer.db(ctxt: THttpServerRequest): cardinal; var w: TOrmWorld; begin - w := TOrmWorld.Create(fStore.Orm, ComputeRandomWorld); + w := TOrmWorld.Create(fStore.Orm, ComputeRandomWorld(Lecuyer)); try - ctxt.SetOutJson(w); - result := HTTP_SUCCESS; + result := ctxt.SetOutJson(w); finally w.Free; end; @@ -331,25 +338,27 @@ function TRawAsyncServer.queries(ctxt: THttpServerRequest): cardinal; var i: PtrInt; res: TOrmWorlds; + gen: PLecuyer; begin SetLength(res, GetQueriesParamValue(ctxt, 'QUERIES=')); + gen := Lecuyer; for i := 0 to length(res) - 1 do - res[i] := TOrmWorld.Create(fStore.Orm, ComputeRandomWorld); - ctxt.SetOutJson(@res, TypeInfo(TOrmWorlds)); + res[i] := TOrmWorld.Create(fStore.Orm, ComputeRandomWorld(gen)); + result := ctxt.SetOutJson(@res, TypeInfo(TOrmWorlds)); ObjArrayClear(res); - result := HTTP_SUCCESS; end; function TRawAsyncServer.cached_queries(ctxt: THttpServerRequest): cardinal; var i: PtrInt; res: TOrmWorlds; + gen: PLecuyer; begin SetLength(res, GetQueriesParamValue(ctxt, 'COUNT=')); + gen := Lecuyer; for i := 0 to length(res) - 1 do - res[i] := fCachedWorldsTable.Get(ComputeRandomWorld); - ctxt.SetOutJson(@res, TypeInfo(TOrmWorlds)); - result := HTTP_SUCCESS; + res[i] := fOrmCache.Get(ComputeRandomWorld(gen)); + result := ctxt.SetOutJson(@res, TypeInfo(TOrmWorlds)); end; function OrmFortuneCompareByMessage(const A, B): integer; @@ -385,19 +394,21 @@ function TRawAsyncServer.updates(ctxt: THttpServerRequest): cardinal; res: TOrmWorlds; w: TOrmWorld; b: TRestBatch; + gen: PLecuyer; begin result := HTTP_SERVERERROR; SetLength(res, GetQueriesParamValue(ctxt)); b := TRestBatch.Create(fStore.ORM, TOrmWorld, {transrows=}0, [boExtendedJson, boNoModelEncoding, boPutNoCacheFlush]); try + gen := Lecuyer; for i := 0 to length(res) - 1 do begin w := TOrmWorld.Create; res[i] := w; - if not fStore.Orm.Retrieve(ComputeRandomWorld, w) then + if not fStore.Orm.Retrieve(ComputeRandomWorld(gen), w) then exit; - w.RandomNumber := ComputeRandomWorld; + w.RandomNumber := ComputeRandomWorld(gen); b.Update(w); end; result := b.Send; @@ -417,13 +428,12 @@ function TRawAsyncServer.rawdb(ctxt: THttpServerRequest): cardinal; result := HTTP_SERVERERROR; conn := fDbPool.ThreadSafeConnection; stmt := conn.NewStatementPrepared(WORLD_READ_SQL, true, true); - stmt.Bind(1, ComputeRandomWorld); + stmt.Bind(1, ComputeRandomWorld(Lecuyer)); stmt.ExecutePrepared; if stmt.Step then begin - ctxt.SetOutJson( + result := ctxt.SetOutJson( '{"id":%,"randomNumber":%}', [stmt.ColumnInt(0), stmt.ColumnInt(1)]); - result := HTTP_SUCCESS; stmt.ReleaseRows; end; stmt := nil; @@ -435,8 +445,20 @@ function TRawAsyncServer.rawqueries(ctxt: THttpServerRequest): cardinal; begin if not GetRawRandomWorlds(GetQueriesParamValue(ctxt), res) then exit(HTTP_SERVERERROR); - ctxt.SetOutJson(@res, TypeInfo(TWorlds)); - result := HTTP_SUCCESS; + result := ctxt.SetOutJson(@res, TypeInfo(TWorlds)); +end; + +function TRawAsyncServer.rawcached(ctxt: THttpServerRequest): cardinal; +var + i: PtrInt; + res: TOrmWorlds; + gen: PLecuyer; +begin + SetLength(res, GetQueriesParamValue(ctxt, 'COUNT=')); + gen := Lecuyer; + for i := 0 to length(res) - 1 do + res[i] := fRawCache[ComputeRandomWorld(gen) - 1]; + result := ctxt.SetOutJson(@res, TypeInfo(TOrmWorlds)); end; function TRawAsyncServer.rawfortunes(ctxt: THttpServerRequest): cardinal; @@ -447,7 +469,9 @@ function TRawAsyncServer.rawfortunes(ctxt: THttpServerRequest): cardinal; conn := fDbPool.ThreadSafeConnection; stmt := conn.NewStatementPrepared(FORTUNES_SQL, true, true); stmt.ExecutePrepared; - result := ComputeRawFortunes(stmt.Instance, ctxt); + ctxt.OutContent := ComputeRawFortunes(stmt.Instance); + ctxt.OutContentType := HTML_CONTENT_TYPE; + result := HTTP_SUCCESS; end; var @@ -470,10 +494,8 @@ function ComputeUpdateSql(cnt: integer): RawUtf8; W := TTextWriter.CreateOwnedStream(tmp{%H-}); try W.AddShort('UPDATE world SET randomNumber = v.randomNumber FROM (VALUES'); - for i := 1 to cnt do begin - W.AddShort('(?::integer, ?::integer)'); - W.Add(','); - end; + for i := 1 to cnt do + W.AddShort('(?::integer, ?::integer),'); W.CancelLastComma; W.AddShort(' order by 1) AS v (id, randomNumber) WHERE world.id = v.id'); W.SetText(LastComputeUpdateSql); @@ -489,7 +511,8 @@ function TRawAsyncServer.rawupdates(ctxt: THttpServerRequest): cardinal; var cnt, i: PtrInt; res: TWorlds; - ids, nums: TInt64DynArray; + params: TInt64DynArray; + gen: PLecuyer; conn: TSqlDBConnection; stmt: ISqlDBStatement; begin @@ -499,21 +522,20 @@ function TRawAsyncServer.rawupdates(ctxt: THttpServerRequest): cardinal; if not getRawRandomWorlds(cnt, res) then exit; // generate new randoms + gen := Lecuyer; for i := 0 to cnt - 1 do - res[i].randomNumber := ComputeRandomWorld; + res[i].randomNumber := ComputeRandomWorld(gen); if cnt > 20 then begin // fill parameters arrays for update with nested select (PostgreSQL only) - setLength(ids{%H-}, cnt); - setLength(nums{%H-}, cnt); - for i := 0 to cnt - 1 do - begin - ids[i] := res[i].id; - nums[i] := res[i].randomNumber; - end; stmt := conn.NewStatementPrepared(WORLD_UPDATE_SQLN, false, true); - stmt.BindArray(1, ids); - stmt.BindArray(2, nums); + SetLength(params{%H-}, cnt); + for i := 0 to cnt - 1 do + params[i] := res[i].id; + stmt.BindArray(1, params); + for i := 0 to cnt - 1 do + params[i] := res[i].randomNumber; + stmt.BindArray(2, params); end else begin @@ -526,8 +548,7 @@ function TRawAsyncServer.rawupdates(ctxt: THttpServerRequest): cardinal; end; end; stmt.ExecutePrepared; - ctxt.SetOutJson(@res, TypeInfo(TWorlds)); - result := HTTP_SUCCESS; + result := ctxt.SetOutJson(@res, TypeInfo(TWorlds)); end; // asynchronous PostgreSQL pipelined DB access @@ -540,106 +561,107 @@ function TRawAsyncServer.asyncdb(ctxt: THttpServerRequest): cardinal; begin with fDbPool.Async.PrepareLocked(WORLD_READ_SQL, {res=}true, ASYNC_OPT) do try - Bind(1, ComputeRandomWorld); - ExecuteAsync(ctxt, OnAsyncDb); + Bind(1, ComputeRandomWorld(Lecuyer)); + ExecuteAsync(ctxt.AsyncHandle, OnAsyncDb); finally UnLock; end; - result := ctxt.SetAsyncResponse; + result := HTTP_ASYNCRESPONSE; end; procedure TRawAsyncServer.OnAsyncDb(Statement: TSqlDBPostgresAsyncStatement; - Context: TObject); -var - ctxt: THttpServerRequest absolute Context; + Context: PtrInt); begin if (Statement = nil) or not Statement.Step then - ctxt.ErrorMessage := 'asyncdb failed' + fHttpServer.AsyncResponseError(Context, 'asyncdb failed') else - ctxt.SetOutJson('{"id":%,"randomNumber":%}', + fHttpServer.AsyncResponseFmt(Context, '{"id":%,"randomNumber":%}', [Statement.ColumnInt(0), Statement.ColumnInt(1)]); - ctxt.OnAsyncResponse(ctxt); end; function TRawAsyncServer.asyncfortunes(ctxt: THttpServerRequest): cardinal; begin fDbPool.Async.PrepareLocked(FORTUNES_SQL, {res=}true, ASYNC_OPT). - ExecuteAsyncNoParam(ctxt, OnAsyncFortunes); - result := ctxt.SetAsyncResponse; + ExecuteAsyncNoParam(ctxt.AsyncHandle, OnAsyncFortunes); + result := HTTP_ASYNCRESPONSE; end; procedure TRawAsyncServer.OnAsyncFortunes(Statement: TSqlDBPostgresAsyncStatement; - Context: TObject); -var - ctxt: THttpServerRequest absolute Context; + Context: PtrInt); begin - ctxt.OnAsyncResponse(ctxt, ComputeRawFortunes(Statement, ctxt)); + fHttpServer.AsyncResponse(Context, ComputeRawFortunes(Statement), HTML_CONTENT_TYPE); end; type // simple state machine used for /asyncqueries and /asyncupdates TAsyncWorld = class public - request: THttpServerRequest; + http: THttpAsyncServer; + connection: TConnectionAsyncHandle; res: TWorlds; count, current: integer; update: TSqlDBPostgresAsyncStatement; // prepared before any callback - function Queries(async: TSqlDBPostgresAsync; ctxt: THttpServerRequest): cardinal; - function Updates(async: TSqlDBPostgresAsync; ctxt: THttpServerRequest): cardinal; + async: TSqlDBPostgresAsync; + function Queries(server: TRawAsyncServer; ctxt: THttpServerRequest): cardinal; + function Updates(server: TRawAsyncServer; ctxt: THttpServerRequest): cardinal; procedure DoUpdates; - procedure OnQueries(Statement: TSqlDBPostgresAsyncStatement; Context: TObject); - procedure OnRes({%H-}Statement: TSqlDBPostgresAsyncStatement; Context: TObject); + procedure OnQueries(Statement: TSqlDBPostgresAsyncStatement; Context: PtrInt); + procedure OnRes({%H-}Statement: TSqlDBPostgresAsyncStatement; Context: PtrInt); end; function TRawAsyncServer.asyncqueries(ctxt: THttpServerRequest): cardinal; begin - result := TAsyncWorld.Create.Queries(fDBPool.Async, ctxt); + result := TAsyncWorld.Create.Queries(self, ctxt); end; function TRawAsyncServer.asyncupdates(ctxt: THttpServerRequest): cardinal; begin - result := TAsyncWorld.Create.Updates(fDBPool.Async, ctxt); + result := TAsyncWorld.Create.Updates(self, ctxt); end; { TAsyncWorld } -function TAsyncWorld.Queries(async: TSqlDBPostgresAsync; ctxt: THttpServerRequest): cardinal; +function TAsyncWorld.Queries(server: TRawAsyncServer; ctxt: THttpServerRequest): cardinal; var n: integer; - opt: TSqlDBPostgresAsyncStatementOptions; // for modified libpq -begin - request := ctxt; + opt: TSqlDBPostgresAsyncStatementOptions; // forced options for modified libpq + gen: PLecuyer; + select: TSqlDBPostgresAsyncStatement; +begin + http := server.fHttpServer; + connection := ctxt.AsyncHandle; + if async = nil then + async := server.fDbPool.Async; if count = 0 then count := getQueriesParamValue(ctxt); SetLength(res, count); // count is > 0 - with async.PrepareLocked(WORLD_READ_SQL, {res=}true, ASYNC_OPT) do - try - opt := AsyncOptions - [asoForceConnectionFlush]; - n := count; - repeat - dec(n); - Bind(1, ComputeRandomWorld); - if n = 0 then // last item should include asoForceConnectionFlush (if set) - opt := AsyncOptions; - ExecuteAsync(ctxt, OnQueries, @opt); - until n = 0; - finally - UnLock; - end; - result := ctxt.SetAsyncResponse; + select := async.PrepareLocked(WORLD_READ_SQL, {res=}true, ASYNC_OPT); + opt := ASYNC_OPT - [asoForceConnectionFlush]; + n := count; + gen := Lecuyer; + repeat + select.Bind(1, ComputeRandomWorld(gen)); + dec(n); + if n = 0 then // last item should include asoForceConnectionFlush (if set) + opt := ASYNC_OPT; + select.ExecuteAsync(connection, OnQueries, @opt); + until n = 0; + select.UnLock; + result := HTTP_ASYNCRESPONSE; end; -function TAsyncWorld.Updates(async: TSqlDBPostgresAsync; ctxt: THttpServerRequest): cardinal; +function TAsyncWorld.Updates(server: TRawAsyncServer; ctxt: THttpServerRequest): cardinal; begin + async := server.fDbPool.Async; count := getQueriesParamValue(ctxt); - update := async.Prepare(WORLD_UPDATE_SQLN, false, ASYNC_OPT); - result := Queries(async, ctxt); + update := async.Prepare(WORLD_UPDATE_SQLN, false, ASYNC_OPT); // to trigger DoUpdates + result := Queries(server, ctxt); // will set http and connection fields end; procedure TAsyncWorld.OnQueries(Statement: TSqlDBPostgresAsyncStatement; - Context: TObject); + Context: PtrInt); begin if (Statement <> nil) and Statement.Step then @@ -660,9 +682,11 @@ procedure TAsyncWorld.DoUpdates; var i: PtrInt; params: TIntegerDynArray; + gen: PLecuyer; begin + gen := Lecuyer; for i := 0 to count - 1 do - res[i].randomNumber := ComputeRandomWorld; + res[i].randomNumber := ComputeRandomWorld(gen); SetLength(params, count); for i := 0 to count - 1 do params[i] := res[i].id; @@ -670,14 +694,13 @@ procedure TAsyncWorld.DoUpdates; for i := 0 to count - 1 do params[i] := res[i].randomNumber; update.BindArrayInt32(2, params); - update.ExecuteAsync(request, OnRes); + update.ExecuteAsync(connection, OnRes); end; procedure TAsyncWorld.OnRes(Statement: TSqlDBPostgresAsyncStatement; - Context: TObject); + Context: PtrInt); begin - request.SetOutJson(@res, TypeInfo(TWorlds)); - request.OnAsyncResponse(Context as THttpServerRequest); + http.AsyncResponseJson(Context, @res, TypeInfo(TWorlds)); Free; // we don't need this state machine any more end; @@ -695,39 +718,35 @@ procedure TAsyncWorld.OnRes(Statement: TSqlDBPostgresAsyncStatement; TSynLog.Family.HighResolutionTimestamp := true; TSynLog.Family.PerThreadLog := ptIdentifiedInOneFile; TSynLog.Family.AutoFlushTimeOut := 1; + TSynLog.Family.RotateFileCount := 10; + TSynLog.Family.RotateFileSizeKB := 500000; + LogCompressAlgo := nil; // keep 10 x 512MB uncompressed files {$else} SynDBLog := nil; // slightly faster: no need to check log level {$endif WITH_LOGS} // register some RTTI for records JSON serialization Rtti.RegisterFromText([ - TypeInfo(TMessageRec), 'message:RawUtf8', - TypeInfo(TWorldRec), 'id,randomNumber:integer', - TypeInfo(TFortune), 'id:integer message:RawUtf8']); + TypeInfo(TMessageRec), 'message:PUtf8Char', + TypeInfo(TWorldRec), 'id,randomNumber:cardinal', + TypeInfo(TFortune), 'id:PtrUInt message:PUtf8Char']); // compute default execution context from HW information cpuCount := CurrentCpuSet(cpuMask); // may run from a "taskset" command - if cpuCount >= 6 then + if GetEnvironmentVariable('TFB_TEST_NAME') = 'mormot-postgres-async' then + begin + // asynchronous tests do not require several listeners + servers := 1; + threads := cpucount * 4; + pinServers2Cores := false; + end + else if cpuCount >= 6 then begin // high-end CPU would scale better using several listeners (one per core) // see https://synopse.info/forum/viewtopic.php?pid=39263#p39263 servers := cpuCount; threads := 8; pinServers2Cores := true; - if GetEnvironmentVariable('TFB_TEST_NAME') = 'mormot-postgres-async' then - begin - // asynchronus test - servers := cpuCount; - threads := 8; - end - else - if GetEnvironmentVariable('TFB_TEST_NAME') = 'mormot-postgres-async2' then - begin - // asynchronus test with single listener socket and no CPU pinning - servers := 1; - threads := cpuCount * 2; - pinServers2Cores := false; - end; end else begin @@ -740,19 +759,13 @@ procedure TAsyncWorld.OnRes(Statement: TSqlDBPostgresAsyncStatement; // parse command line parameters with Executable.Command do begin - ExeDescription := 'TFB Server using mORMot 2'; - if Option(['p', 'pin'], 'pin each server to a CPU') then + if Option('&pin', 'pin each server to a CPU') then pinServers2Cores := true; if Option('nopin', 'disable the CPU pinning') then pinServers2Cores := false; // no option would keep the default boolean - Get(['s', 'servers'], servers, '#count of servers (listener sockets)', servers); - Get(['t', 'threads'], threads, 'per-server thread pool #size', threads); - if Option(['?', 'help'], 'display this message') then - begin - ConsoleWrite(FullDescription); - exit; - end; - if ConsoleWriteUnknown then + Get('&servers', servers, '#count of servers (listener sockets)', servers); + Get('&threads', threads, 'per-server thread pool #size', threads); + if ConsoleHelpFailed('TFB Server using mORMot 2') then exit; end; @@ -776,43 +789,41 @@ procedure TAsyncWorld.OnRes(Statement: TSqlDBPostgresAsyncStatement; if GetBit(cpuMask, cpuIdx) then dec(k); until k = -1; - writeln('Pin #', i, ' server to #', cpuIdx, ' CPU'); + ConsoleWrite(['Pin #', i, ' server to #', cpuIdx, ' CPU']); end; rawServers[i] := TRawAsyncServer.Create(threads, flags, cpuIdx) end; try // display some information and wait for SIGTERM - writeln; - writeln(rawServers[0].fHttpServer.ClassName, - ' running on localhost:', rawServers[0].fHttpServer.SockPort); - writeln(' num servers=', servers, - ', threads per server=', threads, - ', total threads=', threads * servers, - ', total CPU=', SystemInfo.dwNumberOfProcessors, - ', accessible CPU=', cpuCount, - ', pinned=', pinServers2Cores, - ', db=', rawServers[0].fDbPool.DbmsEngineName); - writeln(' options=', GetSetName(TypeInfo(THttpServerOptions), flags)); - writeln('Press [Enter] or Ctrl+C or send SIGTERM to terminate'); + ConsoleWrite([CRLF, rawServers[0].fHttpServer.ClassName, + ' running on localhost:', rawServers[0].fHttpServer.SockPort], ccWhite); + ConsoleWrite([' num servers=', servers, + ', threads per server=', threads, + ', total threads=', threads * servers, + ', total CPU=', SystemInfo.dwNumberOfProcessors, + ', accessible CPU=', cpuCount, + ', pinned=', pinServers2Cores, + ', db=', rawServers[0].fDbPool.DbmsEngineName, CRLF, + ' options=', GetSetName(TypeInfo(THttpServerOptions), flags), CRLF]); + ConsoleWrite('Press [Enter] or Ctrl+C or send SIGTERM to terminate', ccWhite); ConsoleWaitForEnterKey; //TSynLog.Family.Level := LOG_VERBOSE; // enable shutdown logs for debug if servers = 1 then - writeln(ObjectToJsonDebug(rawServers[0].fHttpServer, - [woDontStoreVoid, woHumanReadable])) + ConsoleObject(rawServers[0].fHttpServer) else begin - writeln('Per-server accepted connections:'); + ConsoleWrite('Per-server accepted connections:'); for i := 0 to servers - 1 do - write(' ', rawServers[i].fHttpServer.Async.Accepted); - writeln(#10'Please wait: Shutdown ', servers, ' servers and ', - threads * servers, ' threads'); + ConsoleWrite([' ', rawServers[i].fHttpServer.Async.Accepted], ccLightGray, true); + ConsoleWrite([#10'Please wait: Shutdown ', servers, ' servers and ', + threads * servers, ' threads']); end; finally // clear all server instance(s) ObjArrayClear(rawServers); end; - write('Shutdown complete'#10); + ConsoleWrite('Shutdown complete'#10); {$ifdef FPC_X64MM} WriteHeapStatus(' ', 16, 8, {compileflags=}true); {$endif FPC_X64MM} diff --git a/frameworks/Perl/dancer/README.md b/frameworks/Perl/dancer/README.md index c2afcf7639c..56b1d27d773 100644 --- a/frameworks/Perl/dancer/README.md +++ b/frameworks/Perl/dancer/README.md @@ -8,7 +8,7 @@ * Dancer * Dancer::Plugin::Database -* DBD::mysql +* DBD::MariaDB * Starman (if using Starman as web server) * Plack (for plackup) * nginx (if you want to front Dancer with nginx, nginx.conf provided) @@ -22,3 +22,4 @@ Something along the lines of if you want to front it with nginx, otherwise plackup -E production -s Starman --port=8080 --workers=2 -a ./app.pl + diff --git a/frameworks/Perl/dancer/app.pl b/frameworks/Perl/dancer/app.pl index dd58de39896..65ab9d2a6a3 100755 --- a/frameworks/Perl/dancer/app.pl +++ b/frameworks/Perl/dancer/app.pl @@ -8,8 +8,8 @@ set serializer => 'JSON'; -my $dsn = "dbi:mysql:database=hello_world;host=tfb-database;port=3306"; -my $dbh = DBI->connect( $dsn, 'benchmarkdbuser', 'benchmarkdbpass', { mysql_auto_reconnect=>1 } ); +my $dsn = "dbi:MariaDB:database=hello_world;host=tfb-database;port=3306"; +my $dbh = DBI->connect( $dsn, 'benchmarkdbuser', 'benchmarkdbpass' ); my $sth = $dbh->prepare("SELECT * FROM World where id = ?"); get '/json' => sub { @@ -20,7 +20,7 @@ my $queries = params->{queries} || 1; $queries = 1 if ( $queries !~ /^\d+$/ || $queries < 1 ); $queries = 500 if $queries > 500; - + my @response; for ( 1 .. $queries ) { my $id = int rand 10000 + 1; @@ -42,3 +42,4 @@ }; Dancer->dance; + diff --git a/frameworks/Perl/dancer/benchmark_config.json b/frameworks/Perl/dancer/benchmark_config.json index 94408b910f7..306909555ae 100644 --- a/frameworks/Perl/dancer/benchmark_config.json +++ b/frameworks/Perl/dancer/benchmark_config.json @@ -19,7 +19,8 @@ "display_name": "dancer", "notes": "", "versus": "", - "tags": ["broken"] + "tags": [] } }] } + diff --git a/frameworks/Perl/dancer/dancer.dockerfile b/frameworks/Perl/dancer/dancer.dockerfile index 687c3825ae9..0094ff8fca8 100644 --- a/frameworks/Perl/dancer/dancer.dockerfile +++ b/frameworks/Perl/dancer/dancer.dockerfile @@ -1,4 +1,4 @@ -FROM perl:5.26 +FROM perl:5.40 RUN apt-get update -yqq && apt-get install -yqq nginx @@ -10,7 +10,7 @@ RUN cpanm --notest --no-man-page \ Dancer@1.3134 \ Dancer::Plugin::Database@2.10 \ DBI@1.633 \ - DBD::mysql@4.033 \ + DBD::MariaDB@1.23 \ JSON::XS@3.01 \ Plack@1.0034 \ Starman@0.4011 @@ -18,4 +18,5 @@ RUN cpanm --notest --no-man-page \ EXPOSE 8080 CMD nginx -c /dancer/nginx.conf && \ - plackup -E production -s Starman --workers=$(nproc) -l /tmp/perl-dancer.sock -a ./app.pl + plackup -E production -s Starman --workers=$(nproc) --max-requests=100000 -l /tmp/perl-dancer.sock -a ./app.pl + diff --git a/frameworks/Perl/feersum/README.md b/frameworks/Perl/feersum/README.md new file mode 100644 index 00000000000..a620bf8e9de --- /dev/null +++ b/frameworks/Perl/feersum/README.md @@ -0,0 +1,12 @@ +# About + +[Feersum](https://metacpan.org/dist/Feersum) - HTTP 1.0/1.1 handler for Perl based on +[EV](https://metacpan.org/dist/EV) and [picohttpparser](https://github.com/h2o/picohttpparser) + +# Requirements + +* Perl 5.40) +* [JSON::XS](https://metacpan.org/dist/JSON-XS) +* [DBI](https://metacpan.org/dist/DBI) +* [Text::Xslate](https://metacpan.org/dist/Text-Xslate) +* [LMDB](https://metacpan.org/dist/LMDB_File) diff --git a/frameworks/Perl/feersum/app.pl b/frameworks/Perl/feersum/app.pl new file mode 100644 index 00000000000..f826a2791a0 --- /dev/null +++ b/frameworks/Perl/feersum/app.pl @@ -0,0 +1,334 @@ +use v5.40; +use warnings; +use Feersum::Runner; +use EV; use AnyEvent; +use DBI 'SQL_INTEGER'; +use DBD::Pg ':async'; +use Scalar::Util 'weaken'; +use List::Util qw'min max pairmap'; +use JSON::XS; +use Text::Xslate; +use LMDB_File qw':flags :error'; + +use constant { + host_port => $ENV{host_port} || '0.0.0.0:8080', + debug => $ENV{debug} // 0, + db => lc($ENV{db} || 'postgres'), # postgres / mysql / maria (will use for constant folding) + db_name => $ENV{db_name} || 'hello_world', + db_host => $ENV{db_host} || 'tfb-database', + db_port => $ENV{db_port}, + db_user => $ENV{db_user} || 'benchmarkdbuser', + db_pass => $ENV{db_pass} || 'benchmarkdbpass', + empty => [], o => +{}, + reconnect_interval => 60, + max_db_connections => 512, + max_update_tries => 3 +}; +use constant max_batch_update_size => 1; # db eq 'postgres' ? 5 : 10; # rule of thumb +use constant server => qw'Server Feersum'; +use constant { + text => [server, qw'Content-Type text/plain'], + json => [server, qw'Content-Type application/json'], + html => [server, 'Content-Type', 'text/html; charset=utf-8'], + nocontent => [server], +}; + +my @dsn = ( + (sprintf 'dbi:%s:port=%d;host=%s;database=%s;', + (db eq 'mysql' ? ('mysql', db_port // 3306) : + db eq 'maria' ? ('MariaDB', db_port // 3306) : + db eq 'postgres' ? ('Pg', db_port // 5432) + : die 'unknown db'), db_host, db_name), + db_user, db_pass, + +{qw'AutoCommit 1 RaiseError 0 PrintError 1', + (db eq 'maria' ? (qw'mariadb_server_prepare 1 mariadb_ssl 0') : + db eq 'mysql' ? (qw'mysql_server_prepare 1 mysql_ssl 0 mysql_get_server_pubkey 1') : + db eq 'postgres' ? (qw'pg_server_prepare 1 sslmode 0') : ())} +); + +chomp(my $cpus = `nproc`); +say "$cpus cpus available" if debug; +my $pool_size = int max_db_connections / $cpus; # number of db connections in each worker +my $js = JSON::XS->new; + +my $html = render(); +cache('init'); + +my %prepare = ( + world => ['select randomNumber, id from World where id = ?', SQL_INTEGER], + fortune => ['select id, message from Fortune'], + update1 => ['update World set randomNumber = ? where id = ?', (SQL_INTEGER) x 2], + (map { + 'update'.$_ => + [sprintf( + (db eq 'mysql' || db eq 'maria') ? 'with t(v,i) as (values %s) update World w join t on t.i = w.id set w.randomNumber = t.v' : + db eq 'postgres' ? 'with t(v,i) as (values %s) update World w set randomNumber = t.v from t where t.i = w.id' : undef, + (join ',', ((db eq 'mysql' || db eq 'maria') ? 'row(?,?)' : '(?,?)') x $_) + ), (SQL_INTEGER) x ($_ * 2)] + } 2..max_batch_update_size) +); + +my ($pool, $cache); +my $w = EV::fork sub { # child init + $pool = db_pool($pool_size, \@dsn, \%prepare); # db connection pool in each worker + $cache = cache('use'); # cache +}; + +my %route = controllers(); + +my $runner = Feersum::Runner->new( + pre_fork => $cpus, + quiet => !debug, keepalive => 1, + max_connection_reqs => 1000, + read_timeout => 60, + listen => [host_port] +)->run(sub ($h) { ($route{$h->path} // $route{404})->($h) }); + +sub controllers {( + '/plaintext', sub ($h) { $h->send_response(200, text, \'Hello, World!') }, + '/json', sub ($h) { $h->send_response(200, json, \$js->encode(+{ message => 'Hello, World!' })) }, + (map +('/db', $_, '/queries', $_, '/updates', $_ ), sub ($h) { + my ($n) = (my $q = $h->query // '') =~ m/queries=(\d+)/a; + $n = max(1, min($n//1, 500)); + my ($cv, @rs) = (AE::cv); + my $on_done = sub { $h->send_response(200, json, \$js->encode($q ? \@rs : ($rs[0] // o))) }; + $cv->begin( + $h->path ne '/updates' + ? $on_done # select + : sub { # update + if (@rs) { + my ($i, $j) = (0, 0); + my $cv = AE::cv; + $cv->begin($on_done); + while () { + $j = min($i + max_batch_update_size - 1, $#rs); + say "$i $j" if debug; + $cv->begin; + $_->{randomNumber} = int(rand 10000) + 1 for @rs[$i..$j]; + my $tries = max_update_tries; + my $st = 'update'.($j - $i + 1); + my $args = [map @$_{qw/randomNumber id/}, @rs[$i..$j]]; + my $update = sub ($rv = undef, $sth_or_e = undef) { + $cv->end, return if $rv; + say 'retryin update on '.$sth_or_e if $tries < max_update_tries; + say 'fail to update on '.max_update_tries.' tries ' and $cv->end unless $tries--; + db_execute($pool, $st, $args, __SUB__); + }; + $update->(); + $i += max_batch_update_size; + last if $i >= @rs; + } + $cv->end; + } else { $on_done->() } + } + ); + for (1..$n) { + my $id = int(rand 10000) + 1; + $cv->begin; + db_execute($pool, world => [$id], sub ($rows, $sth) { + push @rs, @{$sth->fetchall_arrayref(+{ randomNumber => 1, id => 1 })} if $rows > 0; + $cv->end + }); + } + $cv->end + }), + '/fortunes' => sub ($h) { + db_execute($pool, fortune => empty, sub ($rows, $sth) { + $h->send_response(200, html, \$html->render('fortune.tx', +{ rows => [ + sort { $a->[1] cmp $b->[1] } + @{$sth->fetchall_arrayref}, + [0, 'Additional fortune added at request time.'] + ]})) + }); + }, + '/cached-queries' => sub ($h) { + my ($n) = (my $q = $h->query // '') =~ m/count=(\d+)/a; + $n = max(1, min($n//1, 500)); + my @rs = map +{ id => $_ , randomNumber => $cache->($_) }, map int(rand 10000) + 1, 1..$n; + $h->send_response(200, json, \$js->encode(\@rs)); + }, + '/' => sub ($h) { $h->send_response(204, nocontent, empty) }, + 404 => sub ($h) { $h->send_response(404, nocontent, empty) } +)} + +sub render { + my $t = Text::Xslate->new(path => +{ + (my $file = 'fortune.tx') => <<~\html =~ s/(?<=[\r\n])\s+//sgr + + + Fortunes + + + + : for $rows -> $i { + + : } +
idmessage
<: $i.0 :><: $i.1 :>
+ + + html + }); + $t->load_file($file); + $t +} + +sub cache ($type = 'init') { + my $path = '/dev/shm/feersum'; + say "clearing $path" and unlink glob "$path*" if $type eq 'init' && -e $path; + my $env = LMDB::Env->new($path, +{ + mapsize => 1024*512, + flags => MDB_WRITEMAP|MDB_NOSYNC|MDB_NOMETASYNC|MDB_NOTLS|MDB_NOSUBDIR|MDB_NORDAHEAD + }) or die $LMDB_File::last_err; + if ($type eq 'init') { + die unless defined(my $tx = $env->BeginTxn); + my $handle = $tx->open(undef, MDB_CREATE|MDB_INTEGERKEY); + my $dbh = DBI->connect(@dsn); + $tx->put($handle, $_->[0], pack S => $_->[1]) for @{$dbh->selectall_arrayref('select id, randomNumber from World')}; + $tx->commit; + $dbh->disconnect; + say 'cache populated' if debug; + return; + } + my $tx = $env->BeginTxn(MDB_RDONLY); + my $handle = $tx->open(undef, MDB_INTEGERKEY); + sub ($k) { $tx->renew; $tx->get($handle, $k, my $v); unpack S => $v } +} + +sub db_pool ($size, $dsn, $prepare = undef) { + my %pool = (slot => [], active => +{}, free => [], pending => [], prepare => $prepare); + db_connect(\%pool, $_, $dsn) for 0 .. $size - 1; + \%pool +} + +sub db_connect ($pool, $id, $dsn) { + say "db[$id] connection.." if debug; + my $dbh = DBI->connect(@$dsn); + unless ($dbh) { + warn sprintf 'err: %s. will try reconnect %d sec', $DBI::errstr, reconnect_interval; + $pool->{slot}[$id] = AE::timer +reconnect_interval, 0, sub { db_connect($pool, $id, $dsn) }; # try later + return + } + my $fd = db eq 'maria' ? $dbh->mariadb_sockfd : db eq 'mysql' ? $dbh->mysql_fd : db eq 'postgres' ? $dbh->{pg_socket} : undef; + open my $fh, "<&=", $fd or die $!; # dup handle + state $st_opt = +{ + db eq 'maria' ? (mariadb_async => 1) : + db eq 'mysql' ? (async => 1) : + db eq 'postgres' ? (pg_async => PG_ASYNC + PG_OLDQUERY_CANCEL) : () + }; + my %conn = ( + id => $id, db => $dbh, fd => $fd, fh => $fh, dsn => $dsn, + st => +{ $pool->{prepare} ? (pairmap { + my $sth = $dbh->prepare($b->[0], $st_opt); + $sth->bind_param($_, undef, $b->[$_]) for 1..$#$b; + ($a, $sth) + } %{$pool->{prepare}}) : () }, + connected => 1, + ); + $conn{w} = EV::io $fh, EV::READ, sub { + my $e; + { ; + $e = 'inactive', last unless defined(my $st = $conn{active}); + if ($st) { # executed st + $e = 'nost', last unless my $sth = $conn{st}{$st}; + $e = 'unready', last unless + db eq 'maria' ? $sth->mariadb_async_ready : + db eq 'mysql' ? $sth->mysql_async_ready : + db eq 'postgres' ? $sth->pg_ready : undef; + $e = 'noresult', $sth->finish unless defined( + my $rows = + db eq 'maria' ? $sth->mariadb_async_result : + db eq 'mysql' ? $sth->mysql_async_result : + db eq 'postgres' ? $sth->pg_result : undef + ); + say "db[$id $fd] calling cb: ".$st if debug; + if (my $cb = $conn{cb}) { $cb->($rows, $e // $sth) } + else { say "db[$id $fd] no handler for response with $rows rows" } + $sth->finish unless $e; + } else { # db do + $e = 'nodb', last unless my $dbh = $conn{db}; + $e = 'unready', last unless + db eq 'maria' ? $dbh->mariadb_async_ready : + db eq 'mysql' ? $dbh->mysql_async_ready : + db eq 'postgres' ? $dbh->pg_ready : undef; + $e = 'noresult' unless defined( + my $rv = + db eq 'maria' ? $dbh->mariadb_async_result : + db eq 'mysql' ? $dbh->mysql_async_result : + db eq 'postgres' ? $dbh->pg_result : undef + ); + say "db[$id $fd] calling cb: db do query" if debug; + if (my $cb = $conn{cb}) { $cb->($rv, $e) } + else { say "db[$id $fd] no handler response with $rv return" } + } + say "db[$id $fd] error: $e " if debug && $e; + say "db[$id $fd] finish" if debug; + delete $conn{active}; + delete $pool->{active}{$id}; + push @{$pool->{free}}, \%conn; + if (defined(my $pending = shift @{$pool->{pending}})) { + my $code = shift @$pending; + $code->($pool, splice @$pending) + } + return + } + say "db[$id $fd] $e" if debug; + if (eof($fh) || (my $inactive = $e eq 'inactive')) { + say "db[$id $fd] disconnected" if debug; + delete @conn{qw/w connected/}; + $conn{db}->disconnect if $inactive; + $conn{cb}->(-1, undef) if $conn{st} && $conn{active} && $conn{cb}; + db_connect($pool, $id, $dsn); # reconnect + } else { + say "db[$id $fd] stalled?"; + } + }; + say "db[$id $fd] connected" if debug; + $pool->{slot}[$id] = \%conn; + weaken(my $weak = $pool->{slot}[$id]); + push @{$pool->{free}}, $weak; + if (defined(my $pending = shift @{$pool->{pending}})) { + my $code = shift @$pending; + $code->($pool, splice @$pending) + } +} + +sub db_execute ($pool, $st, $args, $cb) { + say 'db executing..' if debug; + while (my $conn = shift @{$pool->{free}}) { + (debug and say 'skip unconnected'), next unless defined($conn) && $conn->{connected}; + say 'on connection..'.$conn->{id} if debug; + if ($conn->{st}{$st}->execute(@$args)) { + (@$conn{qw/cb active/}, $pool->{active}{$conn->{id}}) = ($cb, $st, 1); + return; + } else { + say 'error: ', $conn->{st}{$st}->errstr; + db_connect($pool, @$conn{qw/id dsn/}); # reconnect + next; + } + } + say '..put to pending..' if debug; + push @{$pool->{pending}}, [__SUB__, $st, $args, $cb]; +} + +sub db_do ($pool, $query, $args, $cb) { + say 'db doing..' if debug; + state $db_opt = +{ + db eq 'maria' ? (mariadb_async => 1) : + db eq 'mysql' ? (async => 1) : + db eq 'postgres' ? (pg_async => PG_ASYNC + PG_OLDQUERY_CANCEL) : () + }; + while (my $conn = shift @{$pool->{free}}) { + (debug and say 'skip unconnected'), next unless defined($conn) && $conn->{connected}; + say 'on connection..'.$conn->{id} if debug; + if ($conn->{db}->do($query, $db_opt, defined($args) ? @$args : ())) { + (@$conn{qw/cb active/}, $pool->{active}{$conn->{id}}) = ($cb, 0, 1); + return; + } else { + say 'error: ', $conn->{db}->errstr; + db_connect($pool, @$conn{qw/id dsn/}); # reconnect + next; + } + } + say '..put to pending..' if debug; + push @{$pool->{pending}}, [__SUB__, $query, $args, $cb]; +} diff --git a/frameworks/Perl/feersum/benchmark_config.json b/frameworks/Perl/feersum/benchmark_config.json new file mode 100644 index 00000000000..383b356f644 --- /dev/null +++ b/frameworks/Perl/feersum/benchmark_config.json @@ -0,0 +1,54 @@ +{ + "framework": "feersum", + "maintainers": ["vividsnow"], + "tests": [{ + "default": { + "dockerfile": "feersum.dockerfile", + "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", + "classification": "Platform", + "database": "Postgres", + "database_os": "Linux", + "framework": "feersum", + "language": "Perl", + "flavor": "None", + "orm": "Raw", + "platform": "None", + "webserver": "feersum", + "os": "Linux", + "database_os": "Linux", + "display_name": "feersum", + "notes": "" + }, + "mysql": { + "dockerfile": "feersum.dockerfile", + "db_url": "/db", + "query_url": "/queries?queries=", + "fortune_url": "/fortunes", + "update_url": "/updates?queries=", + "cached_query_url": "/cached-queries?count=", + "port": 8080, + "approach": "Realistic", + "classification": "Platform", + "database": "MySQL", + "database_os": "Linux", + "framework": "feersum", + "language": "Perl", + "flavor": "None", + "orm": "Raw", + "platform": "None", + "webserver": "feersum", + "os": "Linux", + "database_os": "Linux", + "display_name": "feersum", + "notes": "" + } + }] +} diff --git a/frameworks/Perl/feersum/cpanfile b/frameworks/Perl/feersum/cpanfile new file mode 100644 index 00000000000..02a462a22e4 --- /dev/null +++ b/frameworks/Perl/feersum/cpanfile @@ -0,0 +1,8 @@ +requires 'Feersum', '== 1.505'; +requires 'JSON::XS', '== 4.03'; +requires 'DBD::MariaDB', '== 1.23'; +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'; diff --git a/frameworks/Perl/feersum/cpanfile_alt b/frameworks/Perl/feersum/cpanfile_alt new file mode 100644 index 00000000000..7b26f606c2d --- /dev/null +++ b/frameworks/Perl/feersum/cpanfile_alt @@ -0,0 +1 @@ +requires 'DBD::mysql', '== 5.009'; diff --git a/frameworks/Perl/feersum/feersum.dockerfile b/frameworks/Perl/feersum/feersum.dockerfile new file mode 100644 index 00000000000..ed8865deb4f --- /dev/null +++ b/frameworks/Perl/feersum/feersum.dockerfile @@ -0,0 +1,28 @@ +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 + +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 + +run apt-get clean +run rm -rf $HOME/.perl-cpm +add app.pl . +expose 8080 + +arg TFB_TEST_DATABASE +env db=$TFB_TEST_DATABASE + +stopsignal SIGKILL + +cmd perl app.pl diff --git a/frameworks/Perl/kelp/README.md b/frameworks/Perl/kelp/README.md index f66a3470d67..8be16d73c02 100644 --- a/frameworks/Perl/kelp/README.md +++ b/frameworks/Perl/kelp/README.md @@ -1,18 +1,17 @@ # Setup -* Perl 5.10+ -* MySQL 5.5 -* MongoDB -* Wrk 2.0 +* Perl 5.36+ +* MariaDB or MongoDB # Requirements * Kelp (install from CPAN) -* Kelp::Module::JSON::XS (install from CPAN) * Kelp::Module::Template::Toolkit (install from CPAN) -* DBD::mysql (install from CPAN) +* DBI + DBD::mysql or MongoDB (install from CPAN) +* Gazelle (install from CPAN) * Starman (install from CPAN) -* MongoDB (install from CPAN) +* Starlet (install from CPAN) +* Twiggy::Prefork (install from CPAN) * nginx (if you want to front with nginx, nginx.conf provided) # Deployment @@ -24,16 +23,38 @@ ./uwsgi --plugins psgi --init app.ini -## Plack + Starman +## Plack + plack handler -1. Deploy via plackup +Recommended handler is `Gazelle`. - plackup -E deployment -s Starman --workers=25 -l /tmp/frameworks-benchmark.sock -a ./app.pl +1. Deploy via `start_server`, if you want to front it with nginx. -2. If you want to front it with nginx, otherwise + start_server --path /tmp/perl-kelp.sock --backlog 16384 -- plackup -E production -s Gazelle --max-workers=25 --max-reqs-per-child=10000 -a ./app.psgi - plackup -E deployment -s Starman --port=8080 --workers=25 -a ./app.pl +2. Otherwise + + plackup -E deployment -s Gazelle --port=8080 --max-workers=25 -a ./app.psgi + +# Code information + +`lib/KelpBench.pm` contains all action-handling and helper code. It is a full +Kelp app with `Template::Toolkit` module and standard Kelp configuration files. +While it could've been coded as a one-file Kelp app, full app style gives us +more control on the behavior of the app. It lazy-loads `DBI.pm` or `Mongo.pm` +from `lib/KelpBench/` directory based on environmental variable `MONGO`, so it +only needs one database driver at a time. + +The app is written in a relaxed style, not trying very hard to achieve the best +possible result. It very much resembles production code. For example, a proper +templating engine is used to produce the HTML document instead of inline HTML +(which is obviously much faster). + +App can be tested using mock database by running `prove -l`. In this case, it +only requires `Kelp` and `Kelp::Module::Template::Toolkit` from CPAN to be +installed. # Expert contact +@bbrtj (contact@bbrtj.eu) @naturalist (minimal@cpan.org) + diff --git a/frameworks/Perl/kelp/app.ini b/frameworks/Perl/kelp/app.ini index 7a53ad301ae..ebeb49abedf 100644 --- a/frameworks/Perl/kelp/app.ini +++ b/frameworks/Perl/kelp/app.ini @@ -1,4 +1,5 @@ [uwsgi] http-socket = :8080 -psgi = app.pl +psgi = app.psgi disable-logging = True + diff --git a/frameworks/Perl/kelp/app.pl b/frameworks/Perl/kelp/app.pl deleted file mode 100755 index 8db36540926..00000000000 --- a/frameworks/Perl/kelp/app.pl +++ /dev/null @@ -1,145 +0,0 @@ -#!/usr/bin/env perl - -use Kelp::Less; -use HTML::Escape 'escape_html'; -use MongoDB; -use DBI; -use utf8; - -module 'JSON::XS'; - -my $mongo; -my $mdb; -my $world; -my $fortune; -my @sth; -my $dbh; - -if ($ENV{MONGO}) { - $mongo = MongoDB::MongoClient->new( host => 'tfb-database', port => 27017 ); - $mdb = $mongo->get_database('hello_world'); - $world = $mdb->get_collection('world'); - $fortune = $mdb->get_collection('fortune'); -} else { - $dbh = DBI->connect( - "dbi:mysql:database=hello_world;host=tfb-database;port=3306", - 'benchmarkdbuser', - 'benchmarkdbpass', - { RaiseError => 0, PrintError => 0, mysql_enable_utf8 => 1 } - ); - @sth = map { $dbh->prepare($_) } ( - "SELECT * FROM World WHERE id = ?", - "SELECT * FROM Fortune", - "UPDATE World SET randomNumber = ? WHERE id = ?", - ); -} - -get '/json' => sub { - { message => 'Hello, World!' }; -}; - -get '/db/?db' => sub { - my ( $self, $db ) = @_; - my $id = int rand 10000 + 1; - my $row; - if ( $db eq 'mongo' ) { - $row = $world->find_one( { _id => $id } ); - } - else { - $sth[0]->execute($id); - $row = $sth[0]->fetchrow_hashref; - } - return { id => $id, randomNumber => $row->{randomNumber} }; -}; - -get '/queries/?db' => sub { - my ( $self, $db ) = @_; - query( $db // 'mongo', $self->param('queries') ); -}; - -get '/fortunes/?db' => sub { - my ( $self, $db ) = @_; - $db //= 'mongo'; - my @objects; - if ( $db eq 'mongo' ) { - my $cursor = $fortune->query( {} ); - @objects = $cursor->all; - } - else { - $sth[1]->execute(); - @objects = @{ $sth[1]->fetchall_arrayref( {} ) }; - } - push @objects, { id => 0, message => "Additional fortune added at request time." }; - fortunes( \@objects ); -}; - -get '/update/?db' => sub { - my ( $self, $db ) = @_; - $db //= 'mongo'; - - my $arr = query( $db, $self->param('queries') ); - $arr = [$arr] unless ref($arr) eq 'ARRAY'; - for my $row (@$arr) { - $row->{randomNumber} = int( rand(10_000) ) + 1; - if ( $db eq 'mongo' ) { - $world->update( { _id => $row->{id} }, - { randomNumber => $row->{randomNumber} } ); - } - else { - $row->{randomNumber} = int( rand(10_000) ) + 1; - $sth[2]->execute( $row->{randomNumber}, $row->{id} ); - } - } - - return $arr; -}; - -get '/plaintext' => sub { - shift->res->text->render('Hello, World!'); -}; - -run; - -sub query { - my ( $db, $count ) = @_; - $count //= 1; - $count = 1 if ( $count !~ /^\d+$/ || $count < 1 ); - $count = 500 if $count > 500; - my @response; - for ( 1 .. $count ) { - my $id = int rand 10000 + 1; - my $row; - if ( $db eq 'mongo' ) { - $row = $world->find_one( { _id => $id } ); - } - else { - $sth[0]->execute($id); - $row = $sth[0]->fetchrow_hashref; - } - if ($row) { - push @response, - { id => $id, randomNumber => $row->{randomNumber} }; - } - } - return \@response; -} - -sub fortunes { - my ($objects) = @_; - my $res = q[Fortunes]; - $res .= q[]; - - for my $item ( sort { $a->{message} cmp $b->{message} } @$objects ) { - my $id = $item->{id}; - my $message = escape_html( $item->{message} ); - - # HTML::Escape encodes apostrophe as ' because IE8 does not - # support '. We forse an ' here in order to pass the - # test - $message =~ s/'/&apos/g; - $res .= ""; - } - - $res .= q[
idmessage
$id$message
]; - return $res; -} diff --git a/frameworks/Perl/kelp/app.psgi b/frameworks/Perl/kelp/app.psgi new file mode 100755 index 00000000000..5a8182549bd --- /dev/null +++ b/frameworks/Perl/kelp/app.psgi @@ -0,0 +1,8 @@ +#!/usr/bin/env perl + +use Path::Tiny qw(path); +use lib path(__FILE__)->parent->child('lib'); +use KelpBench; + +KelpBench->new->run; + diff --git a/frameworks/Perl/kelp/benchmark_config.json b/frameworks/Perl/kelp/benchmark_config.json index 036f68fd31f..dc164a11576 100644 --- a/frameworks/Perl/kelp/benchmark_config.json +++ b/frameworks/Perl/kelp/benchmark_config.json @@ -2,10 +2,60 @@ "framework": "kelp", "tests": [{ "default": { - "db_url": "/db/mysql", - "query_url": "/queries/mysql?queries=", - "fortune_url": "/fortunes/mysql", + "dockerfile": "kelp.dockerfile", "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": "MySQL", + "framework": "kelp", + "language": "Perl", + "orm": "Raw", + "platform": "Plack", + "webserver": "Gazelle", + "os": "Linux", + "database_os": "Linux", + "notes": "", + "versus": "", + "tags": [] + }, + "gazelle-mongodb": { + "dockerfile": "kelp.dockerfile", + "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": "MongoDB", + "framework": "kelp", + "language": "Perl", + "orm": "Raw", + "platform": "Plack", + "webserver": "Gazelle", + "os": "Linux", + "database_os": "Linux", + "notes": "", + "versus": "", + "tags": [] + }, + + "starman-mysql": { + "dockerfile": "kelp.dockerfile", + "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", @@ -17,16 +67,18 @@ "webserver": "Starman", "os": "Linux", "database_os": "Linux", - "display_name": "kelp", "notes": "", "versus": "", - "tags": ["broken"] + "tags": [] }, - "mongodb": { - "db_url": "/db/mongo", - "query_url": "/queries/mongo?queries=", - "fortune_url": "/fortunes/mongo", + "starman-mongodb": { + "dockerfile": "kelp.dockerfile", "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", @@ -38,10 +90,102 @@ "webserver": "Starman", "os": "Linux", "database_os": "Linux", - "display_name": "kelp", "notes": "", "versus": "", - "tags": ["broken"] + "tags": [] + }, + + "starlet-mysql": { + "dockerfile": "kelp.dockerfile", + "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": "MySQL", + "framework": "kelp", + "language": "Perl", + "orm": "Raw", + "platform": "Plack", + "webserver": "Starlet", + "os": "Linux", + "database_os": "Linux", + "notes": "", + "versus": "", + "tags": [] + }, + "starlet-mongodb": { + "dockerfile": "kelp.dockerfile", + "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": "MongoDB", + "framework": "kelp", + "language": "Perl", + "orm": "Raw", + "platform": "Plack", + "webserver": "Starlet", + "os": "Linux", + "database_os": "Linux", + "notes": "", + "versus": "", + "tags": [] + }, + + "twiggy-mysql": { + "dockerfile": "kelp.dockerfile", + "plaintext_url": "/plaintext", + "json_url": "/json", + "db_url": "/db", + "query_url": "/queries?queries=", + "fortune_url": "/fortunes", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "database": "MySQL", + "framework": "kelp", + "language": "Perl", + "orm": "Raw", + "platform": "Plack", + "webserver": "Twiggy", + "os": "Linux", + "database_os": "Linux", + "notes": "", + "versus": "", + "tags": [] + }, + "twiggy-mongodb": { + "dockerfile": "kelp.dockerfile", + "plaintext_url": "/plaintext", + "json_url": "/json", + "db_url": "/db", + "query_url": "/queries?queries=", + "fortune_url": "/fortunes", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "database": "MongoDB", + "framework": "kelp", + "language": "Perl", + "orm": "Raw", + "platform": "Plack", + "webserver": "Twiggy", + "os": "Linux", + "database_os": "Linux", + "notes": "", + "versus": "", + "tags": [] } }] } + diff --git a/frameworks/Perl/kelp/conf/config.pl b/frameworks/Perl/kelp/conf/config.pl new file mode 100644 index 00000000000..ce7f3527f59 --- /dev/null +++ b/frameworks/Perl/kelp/conf/config.pl @@ -0,0 +1,12 @@ +{ + modules => [qw(JSON Template::Toolkit)], + modules_init => { + 'Template::Toolkit' => { + STRICT => 1, + OUTLINE_TAG => qr{\V*%%}, # https://github.com/abw/Template2/issues/320 + ENCODING => 'utf8', + INCLUDE_PATH => 'views', + }, + }, +} + diff --git a/frameworks/Perl/kelp/conf/test.pl b/frameworks/Perl/kelp/conf/test.pl new file mode 100644 index 00000000000..f480597ed9b --- /dev/null +++ b/frameworks/Perl/kelp/conf/test.pl @@ -0,0 +1,23 @@ +{ + '+modules' => [qw(Logger)], + + modules_init => { + Logger => { + outputs => [ + [ + 'Screen', + name => 'logs', + min_level => 'debug', + stderr => 1, + newline => 1, + utf8 => 1, + ], + ], + }, + + 'Template::Toolkit' => { + DEBUG => 1, + }, + }, +} + diff --git a/frameworks/Perl/kelp/config.toml b/frameworks/Perl/kelp/config.toml deleted file mode 100644 index 7e997486fb2..00000000000 --- a/frameworks/Perl/kelp/config.toml +++ /dev/null @@ -1,32 +0,0 @@ -[framework] -name = "kelp" - -[main] -urls.plaintext = "/plaintext" -urls.db = "/db/mysql" -urls.query = "/queries/mysql?queries=" -urls.fortune = "/fortunes/mysql" -approach = "Realistic" -classification = "Fullstack" -database = "MySQL" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "Plack" -webserver = "Starman" -versus = "" - -[mongodb] -urls.plaintext = "/plaintext" -urls.db = "/db/mongo" -urls.query = "/queries/mongo?queries=" -urls.fortune = "/fortunes/mongo" -approach = "Realistic" -classification = "Fullstack" -database = "MongoDB" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "Plack" -webserver = "Starman" -versus = "" diff --git a/frameworks/Perl/kelp/kelp-mongodb.dockerfile b/frameworks/Perl/kelp/kelp-mongodb.dockerfile deleted file mode 100644 index 783c7e4d263..00000000000 --- a/frameworks/Perl/kelp/kelp-mongodb.dockerfile +++ /dev/null @@ -1,27 +0,0 @@ -FROM perl:5.26 - -RUN apt-get update -yqq && apt-get install -yqq nginx - -WORKDIR /kelp - -RUN cpanm --notest --no-man-page \ - JSON JSON::XS IO::Socket::IP IO::Socket::SSL \ - Kelp@0.9071 \ - DBI@1.636 \ - DBD::mysql@4.033 \ - MongoDB@1.8.1 \ - Kelp::Module::JSON::XS@0.502 \ - HTML::Escape@1.10 \ - HTTP::Parser::XS@0.17 \ - Starman@0.4014 - -ADD ./app.ini /kelp/ -ADD ./app.pl /kelp/ -ADD ./nginx.conf /kelp/ - -ENV MONGO=1 - -EXPOSE 8080 - -CMD nginx -c /kelp/nginx.conf && \ - plackup -E production -s Starman --workers=$(nproc) -l /tmp/perl-kelp.sock -a ./app.pl diff --git a/frameworks/Perl/kelp/kelp.dockerfile b/frameworks/Perl/kelp/kelp.dockerfile index 7bfd6f33521..b8bd3453317 100644 --- a/frameworks/Perl/kelp/kelp.dockerfile +++ b/frameworks/Perl/kelp/kelp.dockerfile @@ -1,25 +1,33 @@ -FROM perl:5.26 +FROM perl:5.40 + +ARG TFB_TEST_NAME +ARG TFB_TEST_DATABASE RUN apt-get update -yqq && apt-get install -yqq nginx WORKDIR /kelp RUN cpanm --notest --no-man-page \ - JSON JSON::XS IO::Socket::IP IO::Socket::SSL \ - Kelp@0.9071 \ - DBI@1.636 \ - DBD::mysql@4.033 \ - MongoDB@1.8.1 \ - Kelp::Module::JSON::XS@0.502 \ - HTML::Escape@1.10 \ - HTTP::Parser::XS@0.17 \ - Starman@0.4014 - -ADD ./app.ini /kelp/ -ADD ./app.pl /kelp/ -ADD ./nginx.conf /kelp/ + Kelp::Module::Template::Toolkit@0.301 \ + Kelp \ + DBI@1.643 \ + DBD::MariaDB@1.23 \ + MongoDB@2.2.2 \ + Cpanel::JSON::XS@4.38 \ + Gazelle@0.49 \ + Starman@0.4017 \ + Starlet@0.31 \ + Twiggy::Prefork@0.08 \ + Net::Server::SS::PreFork@0.05 + +ADD ./ /kelp/ + +ENV TEST_NAME=$TFB_TEST_NAME +ENV DATABASE=$TFB_TEST_DATABASE +ENV MAX_REQS=100000 +ENV SOCKET_FILE=/tmp/perl-kelp.sock EXPOSE 8080 -CMD nginx -c /kelp/nginx.conf && \ - plackup -E production -s Starman --workers=$(nproc) -l /tmp/perl-kelp.sock -a ./app.pl +CMD nginx -c /kelp/nginx.conf && ./run.pl + diff --git a/frameworks/Perl/kelp/lib/KelpBench.pm b/frameworks/Perl/kelp/lib/KelpBench.pm new file mode 100644 index 00000000000..d20a72a31ed --- /dev/null +++ b/frameworks/Perl/kelp/lib/KelpBench.pm @@ -0,0 +1,130 @@ +package KelpBench; + +use v5.36; +use Kelp::Base 'Kelp'; + +## Attributes + +attr database => sub { + if (lc $ENV{DATABASE} eq 'mongodb') { + require KelpBench::Mongo; + return KelpBench::Mongo->new; + } + elsif (lc $ENV{DATABASE} eq 'mysql') { + require KelpBench::DBI; + return KelpBench::DBI->new; + } + else { + die "unknown database chosen: $ENV{DATABASE}"; + } +}; + +## Utilities + +sub validate_number ($self, $num, $min, $max) +{ + return $min unless length($num // '') && $num !~ /\D/; + return $min if $num < $min; + return $max if $num > $max; + return $num; +} + +sub random_number ($self, $max = 10_000) +{ + return int(rand($max) + 1); +} + +sub random_id ($self) +{ + # in case random ids were not the same as random numbers + return $self->random_number(10_000); +} + +sub get_random_entries ($self, $count) +{ + $count = $self->validate_number($count, 1, 500); + + my @result; + for (1 .. $count) { + my $id = $self->random_id; + my $row = $self->database->random_number($id); + next unless $row; + + push @result, { + id => $id, + randomNumber => $row->{randomNumber} + }; + } + + return \@result; +} + +## Framework code + +sub before_dispatch {} # skip trying to log access +sub before_finalize {} # skip adding X-Framework + +sub build ($self) +{ + $self->add_route([GET => '/plaintext'] => 'action_plaintext'); + $self->add_route([GET => '/json'] => 'action_json'); + $self->add_route([GET => '/db'] => 'action_db'); + $self->add_route([GET => '/queries'] => 'action_queries'); + $self->add_route([GET => '/fortunes'] => 'action_fortunes'); + $self->add_route([GET => '/updates'] => 'action_updates'); +} + +## Registered route handlers +## Names prefixed with _action, because we did not separate a controller +## (Controllers would slow this down a bit due to reblessing of app object) + +sub action_plaintext ($self) +{ + $self->res->text; + return 'Hello, World!'; +} + +sub action_json ($self) +{ + return { message => 'Hello, World!' }; +} + +sub action_db ($self) +{ + my $id = $self->random_id; + my $row = $self->database->random_number($id); + + return { id => $id, randomNumber => $row->{randomNumber} }; +} + +sub action_queries ($self) +{ + return $self->get_random_entries($self->req->query_param('queries')); +} + +sub action_fortunes ($self) { + my $objects = $self->database->fortune; + + push $objects->@*, { + id => 0, + message => "Additional fortune added at request time." + }; + + $objects->@* = sort { $a->{message} cmp $b->{message} } $objects->@*; + return $self->template('fortunes', { rows => $objects }); +} + +sub action_updates ($self) +{ + my $arr = $self->get_random_entries($self->req->query_param('queries')); + + foreach my $row ($arr->@*) { + $row->{randomNumber} = $self->random_number; + $self->database->update($row->@{qw(id randomNumber)}); + } + + return $arr; +}; + +1; + diff --git a/frameworks/Perl/kelp/lib/KelpBench/DBI.pm b/frameworks/Perl/kelp/lib/KelpBench/DBI.pm new file mode 100644 index 00000000000..15440bff07e --- /dev/null +++ b/frameworks/Perl/kelp/lib/KelpBench/DBI.pm @@ -0,0 +1,47 @@ +package KelpBench::DBI; + +use v5.36; +use Kelp::Base 'Kelp'; +use DBI; + +attr dbh => sub { + DBI->connect( + "dbi:MariaDB:database=hello_world;host=tfb-database;port=3306", + 'benchmarkdbuser', + 'benchmarkdbpass', + { RaiseError => 1, PrintError => 0 } + ); +}; + +attr _world => sub ($self) { + $self->dbh->prepare("SELECT * FROM World WHERE id = ?"); +}; + +attr _fortune => sub ($self) { + $self->dbh->prepare("SELECT * FROM Fortune"); +}; + +attr _update => sub ($self) { + $self->dbh->prepare("UPDATE World SET randomNumber = ? WHERE id = ?"); +}; + +sub random_number ($self, $id) +{ + $self->_world->execute($id); + return $self->_world->fetchrow_hashref; +} + +sub fortune ($self) +{ + $self->_fortune->execute(); + return $self->_fortune->fetchall_arrayref({}); +} + +sub update ($self, $id, $random_number) +{ + $self->_update->execute($random_number, $id); + return; +} + +1; + diff --git a/frameworks/Perl/kelp/lib/KelpBench/Mongo.pm b/frameworks/Perl/kelp/lib/KelpBench/Mongo.pm new file mode 100644 index 00000000000..3af50e54c12 --- /dev/null +++ b/frameworks/Perl/kelp/lib/KelpBench/Mongo.pm @@ -0,0 +1,43 @@ +package KelpBench::Mongo; + +use v5.36; +use Kelp::Base 'Kelp'; +use MongoDB; + +attr dbh => sub { + MongoDB::MongoClient->new( + host => 'tfb-database', + port => 27017 + )->get_database('hello_world'); +}; + +attr _world => sub ($self) { + $self->dbh->get_collection('world'); +}; + +attr _fortune => sub ($self) { + $self->dbh->get_collection('fortune'); +}; + +sub random_number ($self, $id) +{ + return $self->_world->find_one({ _id => $id }); +} + +sub fortune ($self) +{ + return [$self->_fortune->find->all]; +} + +sub update ($self, $id, $random_number) +{ + $self->_world->update_one( + { _id => $id }, + { '$set' => { randomNumber => $random_number } }, + ); + + return; +} + +1; + diff --git a/frameworks/Perl/kelp/run.pl b/frameworks/Perl/kelp/run.pl new file mode 100755 index 00000000000..3aaed8d4cf7 --- /dev/null +++ b/frameworks/Perl/kelp/run.pl @@ -0,0 +1,82 @@ +#!/usr/bin/env perl + +use v5.36; +use Data::Dumper; + +my $max_reqs = $ENV{MAX_REQS}; +my $test_name = $ENV{TEST_NAME}; +my $socket_file = $ENV{SOCKET_FILE}; +my $app_runner = 'app.psgi'; + +my $max_workers = `nproc`; +chomp $max_workers; + +my %runner_map = ( + gazelle => [ + 'start_server', + '--path' => $socket_file, + '--backlog' => 16384, + '--', + 'plackup', + '-E' => 'production', + '-s' => 'Gazelle', + '--max-workers' => $max_workers, + '--max-reqs-per-child' => $max_reqs, + '-a' => $app_runner, + ], + starman => [ + 'start_server', + '--backlog' => 16384, + '--', + 'plackup', + '-E' => 'production', + '-s' => 'Starman', + '-l' => $socket_file, + '--workers' => $max_workers, + '--max-requests' => $max_reqs, + '-a' => $app_runner, + ], + starlet => [ + 'start_server', + '--path' => $socket_file, + '--backlog' => 16384, + '--', + 'plackup', + '-E' => 'production', + '-s' => 'Starlet', + '--max-workers' => $max_workers, + '--max-reqs-per-child' => $max_reqs, + '-a' => $app_runner, + ], + # NOTE: twiggy does not play well with Server::Starter + # NOTE: twiggy couldn't pass update tests, so I disabled them + twiggy => [ + 'plackup', + '-E' => 'production', + '-s' => 'Twiggy::Prefork', + '-l' => $socket_file, + '--backlog' => 16384, + '--max-workers' => $max_workers, + '--max-reqs-per-child' => $max_reqs, + '-a' => $app_runner, + ], +); + +# default is gazelle-mysql (techempower will warn if there is no default) +$test_name = 'kelp-gazelle-mysql' + if $test_name eq 'kelp'; + +die "invalid test name $test_name" + unless $test_name =~ m{^kelp-(\w+)-(\w+)$}; + +die 'database mismatch' + unless $2 eq $ENV{DATABASE}; + +my $command = $runner_map{$1}; +die "invalid server $1" + unless $command; + +say 'Running command: ' . Dumper($command); + +exec @$command; + diff --git a/frameworks/Perl/kelp/t/main.t b/frameworks/Perl/kelp/t/main.t index 8d816c95324..a682ca112cf 100644 --- a/frameworks/Perl/kelp/t/main.t +++ b/frameworks/Perl/kelp/t/main.t @@ -1,56 +1,107 @@ -use strict; -use warnings; +use v5.36; use utf8; use Kelp::Test; use Test::More; use Test::Deep; use HTTP::Request::Common; +use KelpBench; -my $t = Kelp::Test->new( psgi => 'app.pl'); -my $world = { randomNumber => re(qr{^\d+$}), id => re(qr{^\d+$}) }; +# use mock to avoid the need for DB modules and actual running DB +# (however, we do not test for DB code correctness this way) +package DBMock { + use v5.36; + use utf8; -subtest 'json' => sub { - $t->request( GET '/json' )->json_cmp( { message => 'Hello, World!' } ); + use Kelp::Base; + + sub random_number ($self, $id) + { + return { + id => $id, + randomNumber => int(rand(10_000) + 1), + }; + } + + sub fortune ($self) + { + return [ + { + id => 1, + message => 'フレームワークのベンチマーク', + }, + { + id => 2, + message => '', + }, + { + id => 3, + message => '&&/\\+?', + }, + ]; + } + + sub update ($self, $id, $random_number) + { + return; + } }; +my $app = KelpBench->new(mode => 'test', database => DBMock->new); +my $t = Kelp::Test->new(app => $app); +my $world = { randomNumber => re(qr{^\d+$}), id => re(qr{^\d+$}) }; + subtest plaintext => sub { - $t->request( GET '/plaintext' ) - ->content_type_is('text/plain') - ->content_is('Hello, World!'); + my $uri = '/plaintext'; + + $t->request(GET $uri) + ->content_type_is('text/plain') + ->content_is('Hello, World!'); +}; + +subtest 'json' => sub { + my $uri = '/json'; + + $t->request(GET $uri) + ->json_cmp({ message => 'Hello, World!' }); }; subtest db => sub { - for my $uri (qw{/db /db/mongo}) { - $t->request( GET $uri )->json_cmp($world); - } + my $uri = '/db'; + + $t->request(GET $uri) + ->json_cmp($world); }; subtest queries => sub { - for my $uri (qw{/queries /queries/mongo}) { - $t->request( GET $uri )->json_cmp($world); - $t->request( GET "$uri?queries=3" ) - ->json_cmp( [ $world, $world, $world ] ); - $t->request( GET "$uri?queries=0" )->json_cmp($world); - } + my $uri = '/queries'; + + $t->request(GET $uri) + ->json_cmp([$world]); + $t->request(GET "$uri?queries=3") + ->json_cmp([$world, $world, $world]); + $t->request(GET "$uri?queries=0") + ->json_cmp([$world]); }; subtest update => sub { - for my $uri (qw{/update /update/mongo}) { - $t->request( GET $uri )->json_cmp([$world]); - $t->request( GET "$uri?queries=3" ) - ->json_cmp( [ $world, $world, $world ] ); - } + my $uri = '/updates'; + + $t->request(GET $uri) + ->json_cmp([$world]); + $t->request(GET "$uri?queries=3") + ->json_cmp([ $world, $world, $world ]); }; subtest fortunes => sub { - for my $uri (qw{/fortunes /fortunes/mongo}) { - $t->request( GET $uri ) - ->content_type_is('text/html') - ->content_like(qr{<script>}) - ->content_like(qr{フレームワークのベンチマーク}) - ->content_like(qr{Additional fortune added at request time.}); - } + my $uri = '/fortunes'; + + $t->request(GET $uri) + ->content_type_is('text/html') + ->content_like(qr{<script>}) + ->content_like(qr{フレームワークのベンチマーク}) + ->content_like(qr{Additional fortune added at request time.}); }; done_testing; + diff --git a/frameworks/Perl/kelp/views/fortunes.tt b/frameworks/Perl/kelp/views/fortunes.tt new file mode 100644 index 00000000000..9667485892f --- /dev/null +++ b/frameworks/Perl/kelp/views/fortunes.tt @@ -0,0 +1,22 @@ + + + + Fortunes + + + + + + + + + %% FOREACH row IN rows + + + + + %% END +
idmessage
[% row.id %][% row.message | html %]
+ + + diff --git a/frameworks/Perl/mojolicious/app.pl b/frameworks/Perl/mojolicious/app.pl index a1e38dd48f6..465c2c7381c 100644 --- a/frameworks/Perl/mojolicious/app.pl +++ b/frameworks/Perl/mojolicious/app.pl @@ -1,18 +1,19 @@ +use v5.36; use Mojolicious::Lite; use Mojo::Pg; use Mojo::Promise; -use Cpanel::JSON::XS 'encode_json'; use Scalar::Util 'looks_like_number'; -use Data::Dumper; # configuration +use constant MAX_DB_CONCURRENCY => 50; + { my $nproc = `nproc`; app->config(hypnotoad => { - accepts => 0, - clients => int( 256 / $nproc ) + 1, + accepts => 100000, + clients => MAX_DB_CONCURRENCY, graceful_timeout => 1, requests => 10000, workers => $nproc, @@ -20,41 +21,33 @@ }); } -{ - my $db_host = 'tfb-database'; - helper pg => sub { state $pg = Mojo::Pg->new('postgresql://benchmarkdbuser:benchmarkdbpass@' . $db_host . '/hello_world')->max_connections(50) }; -} - -helper render_json => sub { - my $c = shift; - $c->res->headers->content_type('application/json'); - $c->render( data => encode_json(shift) ); -}; - # Routes -get '/json' => sub { shift->helpers->render_json({message => 'Hello, World!'}) }; +get '/json' => sub ($c) { + $c->render(json => {message => 'Hello, World!'}); +}; -get '/db' => sub { shift->helpers->render_query(1, {single => 1}) }; +get '/db' => sub ($c) { + $c->helpers->render_query(1, {single => 1}); +}; -get '/queries' => sub { - my $c = shift; +get '/queries' => sub ($c) { $c->helpers->render_query(scalar $c->param('queries')); }; -get '/fortunes' => sub { - my $c = shift; +get '/fortunes' => sub ($c) { $c->render_later; - my $docs = $c->helpers->pg->db->query_p('SELECT id, message FROM Fortune') - ->then(sub{ - my $docs = $_[0]->arrays; - push @$docs, [0, 'Additional fortune added at request time.']; - $c->render(fortunes => docs => $docs->sort(sub{ $a->[1] cmp $b->[1] }) ) - }); + + $c->helpers->pg->db->query_p('SELECT id, message FROM Fortune') + ->then(sub ($query) { + my $docs = $query->arrays; + push @$docs, [0, 'Additional fortune added at request time.']; + + $c->render(fortunes => docs => $docs->sort(sub { $a->[1] cmp $b->[1] })); + }); }; -get '/updates' => sub { - my $c = shift; +get '/updates' => sub ($c) { $c->helpers->render_query(scalar $c->param('queries'), {update => 1}); }; @@ -62,55 +55,47 @@ # Additional helpers (shared code) -helper 'render_query' => sub { - my ($self, $q, $args) = @_; +helper pg => sub { + state $pg = Mojo::Pg + ->new('postgresql://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world') + ->max_connections(MAX_DB_CONCURRENCY + 1); +}; + +helper 'render_query' => sub ($self, $q, $args = {}) { $self->render_later; - $args ||= {}; - my $update = $args->{update}; $q = 1 unless looks_like_number($q); $q = 1 if $q < 1; $q = 500 if $q > 500; - my $r = []; - my $tx = $self->tx; + Mojo::Promise->map({concurrency => MAX_DB_CONCURRENCY}, sub { + my $db = $self->helpers->pg->db; + my $id = 1 + int rand 10_000; + my $query = $db->query('SELECT id, randomnumber FROM World WHERE id=?', $id); + my $number = $query->array->[1]; - my @queries; - foreach (1 .. $q) { - my $id = 1 + int rand 10_000; + if ($args->{update}) { + $number = 1 + int rand 10_000; + $db->query('UPDATE World SET randomnumber=? WHERE id=?', $number, $id); + } - push @queries, $self->helpers->pg->db->query_p('SELECT id,randomnumber FROM World WHERE id=?', $id) - ->then(sub{ - my $randomNumber = $_[0]->array->[0]; - - return Mojo::Promise->new->resolve($id, $randomNumber) - ->then(sub{ - if($update) { - $randomNumber = 1 + int rand 10_000; - return Mojo::Promise->all( - Mojo::Promise->new->resolve($_[0], $randomNumber), - $self->helpers->pg->db->query_p('UPDATE World SET randomnumber=? WHERE id=?', $randomNumber, $id) - ) - ->then(sub { - return $_[0]; - }) - } - return [shift, shift]; - }) - }); - } + return Mojo::Promise->resolve([$id, $number]); + }, 1 .. $q) + ->then(sub (@responses) { + my @results; - Mojo::Promise->all(@queries) - ->then(sub{ - my @responses = @_; foreach my $resp (@responses) { - push @$r, { id => $resp->[0][0], randomNumber => $resp->[0][1] }; + push @results, { id => $resp->[0][0], randomNumber => $resp->[0][1] }; } - $r = $r->[0] if $args->{single}; - $self->helpers->render_json($r); - }) + if ($args->{single}) { + $self->render(json => $results[0]); + } + else { + $self->render(json => \@results); + } + }); }; app->start; @@ -133,3 +118,4 @@ + diff --git a/frameworks/Perl/mojolicious/cpanfile b/frameworks/Perl/mojolicious/cpanfile index 12f340c183e..68299a759ce 100644 --- a/frameworks/Perl/mojolicious/cpanfile +++ b/frameworks/Perl/mojolicious/cpanfile @@ -1,7 +1,8 @@ requires 'Mojolicious', '7.84'; requires 'Mojo::Pg', '4.08'; -requires 'Cpanel::JSON::XS', '4.02'; +requires 'Cpanel::JSON::XS', '4.38'; requires 'EV', '4.22'; recommends 'IO::Socket::IP', '0.36'; recommends 'IO::Socket::SSL'; + diff --git a/frameworks/Perl/mojolicious/cpanfile.snapshot b/frameworks/Perl/mojolicious/cpanfile.snapshot index a43dcb6688e..c3f7c9e074b 100644 --- a/frameworks/Perl/mojolicious/cpanfile.snapshot +++ b/frameworks/Perl/mojolicious/cpanfile.snapshot @@ -1,15 +1,15 @@ # carton snapshot format: version 1.0 DISTRIBUTIONS - Canary-Stability-2012 - pathname: M/ML/MLEHMANN/Canary-Stability-2012.tar.gz + Canary-Stability-2013 + pathname: M/ML/MLEHMANN/Canary-Stability-2013.tar.gz provides: - Canary::Stability 2012 + Canary::Stability 2013 requirements: ExtUtils::MakeMaker 0 - Class-Method-Modifiers-2.12 - pathname: E/ET/ETHER/Class-Method-Modifiers-2.12.tar.gz + Class-Method-Modifiers-2.15 + pathname: E/ET/ETHER/Class-Method-Modifiers-2.15.tar.gz provides: - Class::Method::Modifiers 2.12 + Class::Method::Modifiers 2.15 requirements: B 0 Carp 0 @@ -27,27 +27,36 @@ DISTRIBUTIONS ExtUtils::MakeMaker 0 Storable 0 perl 5.008001 - Cpanel-JSON-XS-4.02 - pathname: R/RU/RURBAN/Cpanel-JSON-XS-4.02.tar.gz + Cpanel-JSON-XS-4.38 + pathname: R/RU/RURBAN/Cpanel-JSON-XS-4.38.tar.gz provides: - Cpanel::JSON::XS 4.02 + 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 - DBD-Pg-3.7.4 - pathname: T/TU/TURNSTEP/DBD-Pg-3.7.4.tar.gz + 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.7.4 - DBD::Pg v3.7.4 + Bundle::DBD::Pg v3.18.0 + DBD::Pg v3.18.0 requirements: DBI 1.614 - ExtUtils::MakeMaker 6.11 + ExtUtils::MakeMaker 6.58 + File::Temp 0 Test::More 0.88 Time::HiRes 0 version 0 - DBI-1.641 - pathname: T/TI/TIMB/DBI-1.641.tar.gz + DBI-1.643 + pathname: T/TI/TIMB/DBI-1.643.tar.gz provides: Bundle::DBI 12.008696 DBD::DBM 0.08 @@ -103,7 +112,7 @@ DISTRIBUTIONS DBD::Sponge::dr 12.010003 DBD::Sponge::st 12.010003 DBDI 12.015129 - DBI 1.641 + DBI 1.643 DBI::Const::GetInfo::ANSI 2.008697 DBI::Const::GetInfo::ODBC 2.011374 DBI::Const::GetInfoReturn 2.008697 @@ -143,128 +152,60 @@ DISTRIBUTIONS DBI::SQL::Nano::Table_ 1.015544 DBI::Util::CacheMemory 0.010315 DBI::Util::_accessor 0.009479 - DBI::common 1.641 + DBI::common 1.643 requirements: ExtUtils::MakeMaker 6.48 Test::Simple 0.90 - perl 5.008 - Devel-GlobalDestruction-0.14 - pathname: H/HA/HAARG/Devel-GlobalDestruction-0.14.tar.gz - provides: - Devel::GlobalDestruction 0.14 - requirements: - ExtUtils::MakeMaker 0 - Sub::Exporter::Progressive 0.001011 - perl 5.006 - EV-4.22 - pathname: M/ML/MLEHMANN/EV-4.22.tar.gz + perl 5.008001 + EV-4.34 + pathname: M/ML/MLEHMANN/EV-4.34.tar.gz provides: - EV 4.22 + EV 4.34 EV::MakeMaker undef requirements: Canary::Stability 0 ExtUtils::MakeMaker 6.52 common::sense 0 - Hash-Merge-0.300 - pathname: R/RE/REHSACK/Hash-Merge-0.300.tar.gz + Hash-Merge-0.302 + pathname: H/HE/HERMES/Hash-Merge-0.302.tar.gz provides: - Hash::Merge 0.300 + Hash::Merge 0.302 requirements: Clone::Choose 0.008 ExtUtils::MakeMaker 6.64 Scalar::Util 0 perl 5.008001 - MRO-Compat-0.13 - pathname: H/HA/HAARG/MRO-Compat-0.13.tar.gz + MRO-Compat-0.15 + pathname: H/HA/HAARG/MRO-Compat-0.15.tar.gz provides: - MRO::Compat 0.13 + MRO::Compat 0.15 requirements: ExtUtils::MakeMaker 0 perl 5.006 - Module-Build-0.4224 - pathname: L/LE/LEONT/Module-Build-0.4224.tar.gz - provides: - Module::Build 0.4224 - Module::Build::Base 0.4224 - Module::Build::Compat 0.4224 - Module::Build::Config 0.4224 - Module::Build::Cookbook 0.4224 - Module::Build::Dumper 0.4224 - Module::Build::Notes 0.4224 - Module::Build::PPMMaker 0.4224 - Module::Build::Platform::Default 0.4224 - Module::Build::Platform::MacOS 0.4224 - Module::Build::Platform::Unix 0.4224 - Module::Build::Platform::VMS 0.4224 - Module::Build::Platform::VOS 0.4224 - Module::Build::Platform::Windows 0.4224 - Module::Build::Platform::aix 0.4224 - Module::Build::Platform::cygwin 0.4224 - Module::Build::Platform::darwin 0.4224 - Module::Build::Platform::os2 0.4224 - Module::Build::PodParser 0.4224 - requirements: - CPAN::Meta 2.142060 - CPAN::Meta::YAML 0.003 - Cwd 0 - Data::Dumper 0 - ExtUtils::CBuilder 0.27 - ExtUtils::Install 0 - ExtUtils::Manifest 0 - ExtUtils::Mkbootstrap 0 - ExtUtils::ParseXS 2.21 - File::Basename 0 - File::Compare 0 - File::Copy 0 - File::Find 0 - File::Path 0 - File::Spec 0.82 - File::Temp 0.15 - Getopt::Long 0 - Module::Metadata 1.000002 - Parse::CPAN::Meta 1.4401 - Perl::OSType 1 - Pod::Man 2.17 - TAP::Harness 3.29 - Test::More 0.49 - Text::Abbrev 0 - Text::ParseWords 0 - perl 5.006001 - version 0.87 - Module-Runtime-0.016 - pathname: Z/ZE/ZEFRAM/Module-Runtime-0.016.tar.gz - provides: - Module::Runtime 0.016 - requirements: - Module::Build 0 - Test::More 0.41 - perl 5.006 - strict 0 - warnings 0 - Mojo-Pg-4.08 - pathname: S/SR/SRI/Mojo-Pg-4.08.tar.gz + Mojo-Pg-4.27 + pathname: S/SR/SRI/Mojo-Pg-4.27.tar.gz provides: - Mojo::Pg 4.08 + Mojo::Pg 4.27 Mojo::Pg::Database undef Mojo::Pg::Migrations undef Mojo::Pg::PubSub undef Mojo::Pg::Results undef Mojo::Pg::Transaction undef - SQL::Abstract::Pg undef requirements: - DBD::Pg 3.005001 + DBD::Pg 3.007004 ExtUtils::MakeMaker 0 - Mojolicious 7.53 - SQL::Abstract 1.85 - perl 5.010001 - Mojolicious-7.84 - pathname: S/SR/SRI/Mojolicious-7.84.tar.gz + 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 @@ -278,6 +219,7 @@ DISTRIBUTIONS Mojo::DOM::CSS undef Mojo::DOM::HTML undef Mojo::Date undef + Mojo::DynamicMethods undef Mojo::EventEmitter undef Mojo::Exception undef Mojo::File undef @@ -286,13 +228,8 @@ DISTRIBUTIONS Mojo::Home undef Mojo::IOLoop undef Mojo::IOLoop::Client undef - Mojo::IOLoop::Delay undef Mojo::IOLoop::Server undef Mojo::IOLoop::Stream undef - Mojo::IOLoop::Stream::HTTPClient undef - Mojo::IOLoop::Stream::HTTPServer undef - Mojo::IOLoop::Stream::WebSocketClient undef - Mojo::IOLoop::Stream::WebSocketServer undef Mojo::IOLoop::Subprocess undef Mojo::IOLoop::TLS undef Mojo::JSON undef @@ -316,7 +253,6 @@ DISTRIBUTIONS Mojo::Server::Morbo::Backend undef Mojo::Server::Morbo::Backend::Poll undef Mojo::Server::PSGI undef - Mojo::Server::PSGI::_IO undef Mojo::Server::Prefork undef Mojo::Template undef Mojo::Transaction undef @@ -331,37 +267,36 @@ DISTRIBUTIONS Mojo::UserAgent::Transactor undef Mojo::Util undef Mojo::WebSocket undef - Mojolicious 7.84 + 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::cpanify undef Mojolicious::Command::daemon undef Mojolicious::Command::eval undef - Mojolicious::Command::generate undef - Mojolicious::Command::generate::app undef - Mojolicious::Command::generate::lite_app undef - Mojolicious::Command::generate::makefile undef - Mojolicious::Command::generate::plugin undef Mojolicious::Command::get undef - Mojolicious::Command::inflate undef Mojolicious::Command::prefork undef Mojolicious::Command::psgi undef Mojolicious::Command::routes undef - Mojolicious::Command::test undef Mojolicious::Command::version undef Mojolicious::Commands undef Mojolicious::Controller undef Mojolicious::Lite undef Mojolicious::Plugin undef Mojolicious::Plugin::Config undef - Mojolicious::Plugin::Config::Sandbox 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::PODRenderer undef + Mojolicious::Plugin::NotYAMLConfig undef Mojolicious::Plugin::TagHelpers undef Mojolicious::Plugins undef Mojolicious::Renderer undef @@ -379,52 +314,55 @@ DISTRIBUTIONS requirements: ExtUtils::MakeMaker 0 IO::Socket::IP 0.37 - JSON::PP 2.27103 - Pod::Simple 3.09 - Time::Local 1.2 - perl 5.010001 - Moo-2.003004 - pathname: H/HA/HAARG/Moo-2.003004.tar.gz + 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.003004 + Moo 2.005005 Moo::HandleMoose undef Moo::HandleMoose::FakeConstructor undef Moo::HandleMoose::FakeMetaClass undef Moo::HandleMoose::_TypeMap undef Moo::Object undef - Moo::Role 2.003004 + Moo::Role 2.005005 Moo::_Utils undef - Moo::_mro undef - Moo::_strictures undef Moo::sification undef oo undef requirements: - Class::Method::Modifiers 1.1 - Devel::GlobalDestruction 0.11 - Exporter 5.57 + Carp 0 + Class::Method::Modifiers 1.10 + Exporter 0 ExtUtils::MakeMaker 0 - Module::Runtime 0.014 - Role::Tiny 2.000004 - Scalar::Util 0 - Sub::Defer 2.003001 - Sub::Quote 2.003001 + Role::Tiny 2.002003 + Scalar::Util 1.00 + Sub::Defer 2.006006 + Sub::Quote 2.006006 perl 5.006 - Role-Tiny-2.000006 - pathname: H/HA/HAARG/Role-Tiny-2.000006.tar.gz + Role-Tiny-2.002004 + pathname: H/HA/HAARG/Role-Tiny-2.002004.tar.gz provides: - Role::Tiny 2.000006 - Role::Tiny::With 2.000006 + Role::Tiny 2.002004 + Role::Tiny::With 2.002004 requirements: Exporter 5.57 perl 5.006 - SQL-Abstract-1.85 - pathname: I/IL/ILMARI/SQL-Abstract-1.85.tar.gz + SQL-Abstract-2.000001 + pathname: M/MS/MSTROUT/SQL-Abstract-2.000001.tar.gz provides: - SQL::Abstract 1.85 + 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: @@ -436,26 +374,91 @@ DISTRIBUTIONS 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 - Sub-Exporter-Progressive-0.001013 - pathname: F/FR/FREW/Sub-Exporter-Progressive-0.001013.tar.gz + SQL-Abstract-Pg-1.0 + pathname: S/SR/SRI/SQL-Abstract-Pg-1.0.tar.gz provides: - Sub::Exporter::Progressive 0.001013 + SQL::Abstract::Pg 1.0 requirements: ExtUtils::MakeMaker 0 - Sub-Quote-2.005001 - pathname: H/HA/HAARG/Sub-Quote-2.005001.tar.gz + 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.005001 - Sub::Quote 2.005001 + Sub::Defer 2.006008 + Sub::Quote 2.006008 requirements: ExtUtils::MakeMaker 0 Scalar::Util 0 perl 5.006 - common-sense-3.74 - pathname: M/ML/MLEHMANN/common-sense-3.74.tar.gz + 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.74 + common::sense 3.75 requirements: ExtUtils::MakeMaker 0 diff --git a/frameworks/Perl/mojolicious/mojolicious.dockerfile b/frameworks/Perl/mojolicious/mojolicious.dockerfile index fe9197e6233..1fec0cc3952 100644 --- a/frameworks/Perl/mojolicious/mojolicious.dockerfile +++ b/frameworks/Perl/mojolicious/mojolicious.dockerfile @@ -1,4 +1,4 @@ -FROM perl:5.26 +FROM perl:5.40 WORKDIR /mojo @@ -19,3 +19,4 @@ ADD ./app.pl ./ EXPOSE 8080 CMD hypnotoad -f /mojo/app.pl + diff --git a/frameworks/Perl/plack/README.md b/frameworks/Perl/plack/README.md index f8172775ec1..d08e9a91a20 100644 --- a/frameworks/Perl/plack/README.md +++ b/frameworks/Perl/plack/README.md @@ -9,4 +9,5 @@ Plack * Twiggy::Prefork * JSON::XS * AnyEvent::DBI -* DBD::mysql +* DBD::MariaDB + diff --git a/frameworks/Perl/plack/app-async.psgi b/frameworks/Perl/plack/app-async.psgi index 93df1c50b2d..b5397d1ca5e 100644 --- a/frameworks/Perl/plack/app-async.psgi +++ b/frameworks/Perl/plack/app-async.psgi @@ -5,7 +5,7 @@ use AnyEvent::DBI; use Unix::Processors; use List::Util qw'min max'; -my @dsn = ('dbi:mysql:database=hello_world;host=tfb-database;port=3306', 'benchmarkdbuser', 'benchmarkdbpass'); +my @dsn = ('dbi:MariaDB:database=hello_world;host=tfb-database;port=3306', 'benchmarkdbuser', 'benchmarkdbpass'); my $query = 'select randomNumber, id from World where id = ?'; sub { @@ -37,3 +37,4 @@ sub { } [404, [qw(Content-Type application/json)], ['not found']] } + diff --git a/frameworks/Perl/plack/app.pl b/frameworks/Perl/plack/app.pl index c1a1172b277..b62eaa6acdc 100644 --- a/frameworks/Perl/plack/app.pl +++ b/frameworks/Perl/plack/app.pl @@ -7,10 +7,10 @@ my @cmd = ( ($opts->{a} # async server - ? [qw'plackup -s Twiggy::Prefork -E production --max-reqs-per-child=0 --backlog 16384 + ? [qw'plackup -s Twiggy::Prefork -E production --max-reqs-per-child=100000 --backlog 16384 --max-workers', $cpus, qw'-l /dev/shm/app.sock -a app-async.psgi'] : [qw'start_server --backlog 16384 --path /dev/shm/app.sock -- - plackup -s Gazelle -E production --max-reqs-per-child 10000000 + plackup -s Gazelle -E production --max-reqs-per-child 100000 --max-workers', $cpus, qw'-a app.psgi']), [qw'nginx -c nginx.conf -p', getcwd] ); diff --git a/frameworks/Perl/plack/app.psgi b/frameworks/Perl/plack/app.psgi index 4f5d8579d38..dc625076660 100644 --- a/frameworks/Perl/plack/app.psgi +++ b/frameworks/Perl/plack/app.psgi @@ -5,9 +5,9 @@ use List::Util qw'min max'; sub { state $dbh = DBI->connect( - 'dbi:mysql:database=hello_world;host=tfb-database;port=3306', + 'dbi:MariaDB:database=hello_world;host=tfb-database;port=3306', 'benchmarkdbuser', 'benchmarkdbpass', - +{ qw'RaiseError 0 PrintError 0 mysql_enable_utf8 1' } + +{ qw'RaiseError 0 PrintError 0' } ) || die $!; state $sth = $dbh->prepare('select id,randomnumber from world where id = ?'); my $env = shift; @@ -25,3 +25,4 @@ sub { } [ 404, [], ['not found']]; } + diff --git a/frameworks/Perl/plack/benchmark_config.json b/frameworks/Perl/plack/benchmark_config.json index 6cf3d2a19ff..d3b26a6f800 100644 --- a/frameworks/Perl/plack/benchmark_config.json +++ b/frameworks/Perl/plack/benchmark_config.json @@ -39,6 +39,7 @@ "database_os": "Linux", "display_name": "plack-async", "notes": "", + "tags": ["broken"], "versus": "plack" } }] diff --git a/frameworks/Perl/plack/plack-async.dockerfile b/frameworks/Perl/plack/plack-async.dockerfile index 4af66083005..8ef1ac76b04 100644 --- a/frameworks/Perl/plack/plack-async.dockerfile +++ b/frameworks/Perl/plack/plack-async.dockerfile @@ -1,7 +1,7 @@ FROM perl:latest RUN apt-get update -yqq && apt-get install -yqq nginx -RUN cpanm --notest --no-man-page Plack JSON::XS Unix::Processors DBI DBD::mysql +RUN cpanm --notest --no-man-page Plack JSON::XS Unix::Processors DBI DBD::MariaDB RUN cpanm --notest --no-man-page Cookie::Baker::XS Twiggy::Prefork HTTP::Parser::XS EV AnyEvent::DBI ADD nginx.conf ./ @@ -11,3 +11,4 @@ ADD app-async.psgi ./ EXPOSE 8080 CMD perl app.pl -a + diff --git a/frameworks/Perl/plack/plack.dockerfile b/frameworks/Perl/plack/plack.dockerfile index f2a14dd5b4c..a0391f2f4ca 100644 --- a/frameworks/Perl/plack/plack.dockerfile +++ b/frameworks/Perl/plack/plack.dockerfile @@ -1,7 +1,7 @@ FROM perl:latest RUN apt-get update -yqq && apt-get install -yqq nginx -RUN cpanm --notest --no-man-page Plack JSON::XS Unix::Processors DBI DBD::mysql +RUN cpanm --notest --no-man-page Plack JSON::XS Unix::Processors DBI DBD::MariaDB RUN cpanm --notest --no-man-page Gazelle Cookie::Baker::XS ADD nginx.conf ./ @@ -11,3 +11,4 @@ ADD app.psgi ./ EXPOSE 8080 CMD perl app.pl + diff --git a/frameworks/Perl/web-simple/README.md b/frameworks/Perl/web-simple/README.md index d169c515914..98e8d6a836e 100644 --- a/frameworks/Perl/web-simple/README.md +++ b/frameworks/Perl/web-simple/README.md @@ -7,7 +7,7 @@ # Requirements * Web::Simple -* DBD::mysql +* DBD::MariaDB * Starman (if using Starman as web server) * Plack (for plackup) * nginx (if you want to front Dancer with nginx, nginx.conf provided) @@ -21,3 +21,4 @@ Something along the lines of if you want to front it with nginx, otherwise plackup -E production -s Starman --port=8080 --workers=8 -a ./app.pl + diff --git a/frameworks/Perl/web-simple/app.pl b/frameworks/Perl/web-simple/app.pl index d2db3e11299..2447c765c01 100755 --- a/frameworks/Perl/web-simple/app.pl +++ b/frameworks/Perl/web-simple/app.pl @@ -4,7 +4,7 @@ use DBI; sub get_database_handle { - DBI->connect_cached('dbi:mysql:database=hello_world;host=tfb-database', 'benchmarkdbuser', 'benchmarkdbpass', { RaiseError => 1 }); + DBI->connect_cached('dbi:MariaDB:database=hello_world;host=tfb-database', 'benchmarkdbuser', 'benchmarkdbpass', { RaiseError => 1 }); } sub dispatch_request { @@ -54,3 +54,4 @@ sub dispatch_request { } __PACKAGE__->run_if_script; + diff --git a/frameworks/Perl/web-simple/benchmark_config.json b/frameworks/Perl/web-simple/benchmark_config.json index 629b19df0c1..6725005d211 100644 --- a/frameworks/Perl/web-simple/benchmark_config.json +++ b/frameworks/Perl/web-simple/benchmark_config.json @@ -19,7 +19,8 @@ "display_name": "web-simple", "notes": "", "versus": "", - "tags": ["broken"] + "tags": [] } }] } + diff --git a/frameworks/Perl/web-simple/web-simple.dockerfile b/frameworks/Perl/web-simple/web-simple.dockerfile index f3b83b7a7c0..5a2678bfe1b 100644 --- a/frameworks/Perl/web-simple/web-simple.dockerfile +++ b/frameworks/Perl/web-simple/web-simple.dockerfile @@ -1,4 +1,4 @@ -FROM perl:5.26 +FROM perl:5.40 RUN apt-get update -yqq && apt-get install -yqq nginx @@ -8,7 +8,7 @@ RUN cpanm --notest --no-man-page \ JSON JSON::XS IO::Socket::IP IO::Socket::SSL \ Web::Simple@0.033 \ DBI@1.637 \ - DBD::mysql@4.043 \ + DBD::MariaDB@1.23 \ Plack@1.0044 \ Starman@0.4014 \ JSON::XS@3.04 @@ -21,4 +21,6 @@ EXPOSE 8080 CMD nginx -c /simple/nginx.conf && \ plackup -E production -s Starman --workers=$(nproc) \ + --max-requests=100000 \ -l /tmp/perl-simple.sock -a /simple/app.pl + diff --git a/frameworks/Prolog/tuProlog/pom.xml b/frameworks/Prolog/tuProlog/pom.xml index c707a7e3221..6705fd2ebed 100644 --- a/frameworks/Prolog/tuProlog/pom.xml +++ b/frameworks/Prolog/tuProlog/pom.xml @@ -12,8 +12,8 @@ 16 16 0.18.2 - 4.3.8 - 2.13.4.2 + 4.5.22 + 2.16.0 diff --git a/frameworks/Python/aiohttp/README.md b/frameworks/Python/aiohttp/README.md index 280e739f8a0..f323e61a7e8 100644 --- a/frameworks/Python/aiohttp/README.md +++ b/frameworks/Python/aiohttp/README.md @@ -35,7 +35,7 @@ This will switch which database engine the app uses to execute queries with test ### Server -gunicorn+uvloop on CPython +nginx+uvloop on CPython ## Test URLs diff --git a/frameworks/Python/aiohttp/aiohttp-gunicorn.dockerfile b/frameworks/Python/aiohttp/aiohttp-gunicorn.dockerfile new file mode 100644 index 00000000000..71c8048b2af --- /dev/null +++ b/frameworks/Python/aiohttp/aiohttp-gunicorn.dockerfile @@ -0,0 +1,13 @@ +FROM python:3.13 + +ADD ./ /aiohttp + +WORKDIR aiohttp + +RUN pip3 install -r /aiohttp/requirements-cpython.txt + +ENV CONNECTION=RAW + +EXPOSE 8080 + +CMD python3 -O -m gunicorn app.gunicorn:app -c gunicorn_conf.py diff --git a/frameworks/Python/aiohttp/aiohttp-nginx.dockerfile b/frameworks/Python/aiohttp/aiohttp-nginx.dockerfile new file mode 100644 index 00000000000..2c96a25f9b9 --- /dev/null +++ b/frameworks/Python/aiohttp/aiohttp-nginx.dockerfile @@ -0,0 +1,17 @@ +FROM python:3.13 + +RUN apt-get update && apt-get install -y nginx + +ADD ./ /aiohttp + +WORKDIR /aiohttp + +RUN pip3 install -r /aiohttp/requirements-cpython.txt + +ENV CONNECTION=RAW + +EXPOSE 8080 + +RUN chmod +x /aiohttp/nginx-entrypoint.sh + +ENTRYPOINT ["/aiohttp/nginx-entrypoint.sh"] diff --git a/frameworks/Python/aiohttp/aiohttp-orm.dockerfile b/frameworks/Python/aiohttp/aiohttp-orm.dockerfile new file mode 100644 index 00000000000..c63f3e1689e --- /dev/null +++ b/frameworks/Python/aiohttp/aiohttp-orm.dockerfile @@ -0,0 +1,13 @@ +FROM python:3.13 + +ADD ./ /aiohttp + +WORKDIR /aiohttp + +RUN pip3 install -r /aiohttp/requirements-cpython.txt + +ENV CONNECTION=ORM + +EXPOSE 8080 + +CMD python3 -O -m app.server diff --git a/frameworks/Python/aiohttp/aiohttp-pg-raw.dockerfile b/frameworks/Python/aiohttp/aiohttp-pg-raw.dockerfile deleted file mode 100644 index ddcb349006a..00000000000 --- a/frameworks/Python/aiohttp/aiohttp-pg-raw.dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM python:3.8 - -ADD ./ /aiohttp - -WORKDIR aiohttp - -RUN pip3 install cython==0.29.23 && \ - pip3 install -r /aiohttp/requirements.txt - -ENV CONNECTION=RAW - -EXPOSE 8080 - -CMD gunicorn app.gunicorn:app -c gunicorn_conf.py diff --git a/frameworks/Python/aiohttp/aiohttp-pypy.dockerfile b/frameworks/Python/aiohttp/aiohttp-pypy.dockerfile new file mode 100644 index 00000000000..bc7770b7e7d --- /dev/null +++ b/frameworks/Python/aiohttp/aiohttp-pypy.dockerfile @@ -0,0 +1,13 @@ +FROM pypy:3.11 + +ADD ./ /aiohttp + +WORKDIR /aiohttp + +RUN pip3 install -r /aiohttp/requirements.txt + +ENV CONNECTION=RAW + +EXPOSE 8080 + +CMD python3 -O -m app.server diff --git a/frameworks/Python/aiohttp/aiohttp.dockerfile b/frameworks/Python/aiohttp/aiohttp.dockerfile index b817ec61264..3edfb605a1c 100644 --- a/frameworks/Python/aiohttp/aiohttp.dockerfile +++ b/frameworks/Python/aiohttp/aiohttp.dockerfile @@ -1,14 +1,13 @@ -FROM python:3.8 +FROM python:3.13 ADD ./ /aiohttp -WORKDIR aiohttp +WORKDIR /aiohttp -RUN pip3 install cython==0.29.23 && \ - pip3 install -r /aiohttp/requirements.txt +RUN pip3 install -r /aiohttp/requirements-cpython.txt -WORKDIR /aiohttp +ENV CONNECTION=RAW EXPOSE 8080 -CMD gunicorn app.gunicorn:app -c gunicorn_conf.py +CMD python3 -O -m app.server diff --git a/frameworks/Python/aiohttp/app/app.py b/frameworks/Python/aiohttp/app/app.py new file mode 100644 index 00000000000..40d33382e10 --- /dev/null +++ b/frameworks/Python/aiohttp/app/app.py @@ -0,0 +1,18 @@ +import argparse +import platform + +from aiohttp import web + +from .main import create_app + + +if __name__ == '__main__': + if platform.python_implementation() != "PyPy": + import uvloop + uvloop.install() + parser = argparse.ArgumentParser() + parser.add_argument('--socket', type=str, required=True) + args = parser.parse_args() + + app = create_app() + web.run_app(app, path=args.socket, access_log=None) diff --git a/frameworks/Python/aiohttp/app/main.py b/frameworks/Python/aiohttp/app/main.py index 087bd39f56d..a4defbc20c6 100644 --- a/frameworks/Python/aiohttp/app/main.py +++ b/frameworks/Python/aiohttp/app/main.py @@ -1,11 +1,10 @@ -import os import multiprocessing +import os +import platform -import asyncpg from aiohttp import web from sqlalchemy.engine.url import URL -from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine -from sqlalchemy.orm import sessionmaker +from sqlalchemy.ext.asyncio import async_sessionmaker, create_async_engine from .views import ( json, @@ -21,6 +20,15 @@ updates_raw, ) +if platform.python_implementation() != "PyPy": + import asyncpg + + class NoResetConnection(asyncpg.Connection): + __slots__ = () + + def get_reset_query(self): + return "" + CONNECTION_ORM = os.getenv('CONNECTION', 'ORM').upper() == 'ORM' @@ -28,47 +36,50 @@ def pg_dsn(dialect=None) -> str: """ :return: DSN url suitable for sqlalchemy and aiopg. """ - return str(URL.create( + url = URL.create( database='hello_world', password=os.getenv('PGPASS', 'benchmarkdbpass'), host='tfb-database', port='5432', username=os.getenv('PGUSER', 'benchmarkdbuser'), drivername='postgresql+{}'.format(dialect) if dialect else 'postgresql', - )) - + ) + return url.render_as_string(hide_password=False) async def db_ctx(app: web.Application): # number of gunicorn workers = multiprocessing.cpu_count() as per gunicorn_conf.py # max_connections = 2000 as per toolset/setup/linux/databases/postgresql/postgresql.conf:64 - # give 10% leeway - max_size = min(1800 / multiprocessing.cpu_count(), 160) - max_size = max(int(max_size), 1) - min_size = max(int(max_size / 2), 1) + # since the world table contains only 10,000 rows, a large connection pool is unnecessary + # the server hardware provides 56 CPU cores producing high concurrency + # https://wiki.postgresql.org/wiki/Number_Of_Database_Connections + max_size = 2 + min_size = 2 print(f'connection pool: min size: {min_size}, max size: {max_size}, orm: {CONNECTION_ORM}') if CONNECTION_ORM: dsn = pg_dsn('asyncpg') - engine = create_async_engine(dsn, future=True, pool_size=max_size) - app['db_session'] = sessionmaker(engine, class_=AsyncSession) + engine = create_async_engine(dsn, pool_size=max_size) + app['db_session'] = async_sessionmaker(engine) else: dsn = pg_dsn() - app['pg'] = await asyncpg.create_pool(dsn=dsn, min_size=min_size, max_size=max_size, loop=app.loop) + app['pg'] = await asyncpg.create_pool(dsn=dsn, min_size=min_size, max_size=max_size, loop=app.loop, connection_class=NoResetConnection) yield - if not CONNECTION_ORM: + if CONNECTION_ORM: + await app['db_session'].dispose() + else: await app['pg'].close() def setup_routes(app): if CONNECTION_ORM: - app.router.add_get('/json', json) app.router.add_get('/db', single_database_query_orm) app.router.add_get('/queries/{queries:.*}', multiple_database_queries_orm) app.router.add_get('/fortunes', fortunes) app.router.add_get('/updates/{queries:.*}', updates) - app.router.add_get('/plaintext', plaintext) else: + app.router.add_get('/json', json) + app.router.add_get('/plaintext', plaintext) app.router.add_get('/db', single_database_query_raw) app.router.add_get('/queries/{queries:.*}', multiple_database_queries_raw) app.router.add_get('/fortunes', fortunes_raw) @@ -77,6 +88,7 @@ def setup_routes(app): def create_app(): app = web.Application() - app.cleanup_ctx.append(db_ctx) + if platform.python_implementation() != "PyPy": + app.cleanup_ctx.append(db_ctx) setup_routes(app) return app diff --git a/frameworks/Python/aiohttp/app/models.py b/frameworks/Python/aiohttp/app/models.py index 69f9f3858a1..c614124cbe4 100644 --- a/frameworks/Python/aiohttp/app/models.py +++ b/frameworks/Python/aiohttp/app/models.py @@ -1,20 +1,20 @@ -from sqlalchemy import Column, Integer, String -from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column -Base = declarative_base() +class Base(DeclarativeBase): + """Base for models.""" class World(Base): __tablename__ = 'world' - id = Column(Integer, primary_key=True) - randomnumber = Column(Integer) + id: Mapped[int] = mapped_column(primary_key=True) + randomnumber: Mapped[int] sa_worlds = World.__table__ class Fortune(Base): __tablename__ = 'fortune' - id = Column(Integer, primary_key=True) - message = Column(String) + id: Mapped[int] = mapped_column(primary_key=True) + message: Mapped[str] sa_fortunes = Fortune.__table__ diff --git a/frameworks/Python/aiohttp/app/server.py b/frameworks/Python/aiohttp/app/server.py new file mode 100644 index 00000000000..c1f48b3d4be --- /dev/null +++ b/frameworks/Python/aiohttp/app/server.py @@ -0,0 +1,50 @@ +import multiprocessing +import os +import platform +import socket + +from aiohttp import web + +from .main import create_app + +SERVERS_COUNT = multiprocessing.cpu_count() +BACKLOG = 2048 +SOCKET_BACKLOG = BACKLOG * SERVERS_COUNT + +def start_server(sock, cpu_id): + if hasattr(os, "sched_setaffinity"): + os.sched_setaffinity(0, {cpu_id}) + if platform.python_implementation() != "PyPy": + import uvloop + uvloop.install() + app = create_app() + + web.run_app(app, sock=sock, backlog=BACKLOG, access_log=None) + + +def create_reusable_socket(host='0.0.0.0', port=8080): + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) + sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) + + sock.bind((host, port)) + sock.setblocking(False) + sock.set_inheritable(True) + + sock.listen(SOCKET_BACKLOG) + + return sock + + +if __name__ == '__main__': + sock = create_reusable_socket() + workers = [] + for cpu_id in range(SERVERS_COUNT): + worker = multiprocessing.Process(target=start_server, args=(sock, cpu_id)) + worker.daemon = True + worker.start() + workers.append(worker) + + for worker in workers: + worker.join() diff --git a/frameworks/Python/aiohttp/app/views.py b/frameworks/Python/aiohttp/app/views.py index 8fd659aa93f..91366d66eb7 100644 --- a/frameworks/Python/aiohttp/app/views.py +++ b/frameworks/Python/aiohttp/app/views.py @@ -1,22 +1,34 @@ -from functools import partial +import platform from operator import attrgetter, itemgetter from pathlib import Path -from random import randint +from random import randint, sample import jinja2 -import ujson -from aiohttp.web import Response, json_response -from sqlalchemy import select +from aiohttp.web import Response +from sqlalchemy import bindparam, select +from sqlalchemy.orm.attributes import flag_modified -from .models import sa_fortunes, sa_worlds, Fortune, World +from .models import Fortune, World + +if platform.python_implementation() == "PyPy": + from aiohttp.web import json_response +else: + from orjson import dumps + + def json_response(payload): + return Response( + body=dumps(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) +READ_SELECT_ORM = select(World.randomnumber).where(World.id == bindparam("id")) +READ_FORTUNES_ORM = select(Fortune.id, Fortune.message) WRITE_ROW_SQL = 'UPDATE "world" SET "randomnumber"=$2 WHERE id=$1' +WRITE_ROW_BATCH_SQL = 'UPDATE "world" w SET "randomnumber"=u.new_val FROM (SELECT unnest($1::int[]) as id, unnest($2::int[]) as new_val) u WHERE w.id = u.id' -json_response = partial(json_response, dumps=ujson.dumps) template_path = Path(__file__).parent / 'templates' / 'fortune.jinja' template = jinja2.Template(template_path.read_text()) sort_fortunes_orm = attrgetter('message') @@ -25,8 +37,8 @@ def get_num_queries(request): try: - num_queries = int(request.match_info.get('queries', 1)) - except ValueError: + num_queries = int(request.match_info['queries']) + except (KeyError, ValueError): return 1 if num_queries < 1: return 1 @@ -48,7 +60,7 @@ async def single_database_query_orm(request): """ id_ = randint(1, 10000) async with request.app['db_session']() as sess: - num = await sess.scalar(select(World.randomnumber).filter_by(id=id_)) + num = await sess.scalar(READ_SELECT_ORM, {"id": id_}) return json_response({'id': id_, 'randomNumber': num}) @@ -59,7 +71,7 @@ async def single_database_query_raw(request): id_ = randint(1, 10000) async with request.app['pg'].acquire() as conn: - r = await conn.fetchval('SELECT id,randomnumber FROM world WHERE id = $1', id_) + r = await conn.fetchval(READ_ROW_SQL, id_) return json_response({'id': id_, 'randomNumber': r}) @@ -74,7 +86,7 @@ async def multiple_database_queries_orm(request): result = [] async with request.app['db_session']() as sess: for id_ in ids: - num = await sess.scalar(READ_SELECT_ORM.filter_by(id=id_)) + num = await sess.scalar(READ_SELECT_ORM, {"id": id_}) result.append({'id': id_, 'randomNumber': num}) return json_response(result) @@ -85,16 +97,11 @@ async def multiple_database_queries_raw(request): """ num_queries = get_num_queries(request) - ids = [randint(1, 10000) for _ in range(num_queries)] + ids = [(randint(1, 10000), ) for _ in range(num_queries)] - result = [] async with request.app['pg'].acquire() as conn: - stmt = await conn.prepare(READ_ROW_SQL) - for id_ in ids: - result.append({ - 'id': id_, - 'randomNumber': await stmt.fetchval(id_), - }) + rows = await conn.fetchmany(READ_ROW_SQL, ids) + result = [{'id': id_[0], 'randomNumber': row[0]} for id_, row in zip(ids, rows)] return json_response(result) @@ -103,7 +110,7 @@ async def fortunes(request): Test 4 ORM """ async with request.app['db_session']() as sess: - ret = await sess.execute(select(Fortune.id, Fortune.message)) + ret = await sess.execute(READ_FORTUNES_ORM) fortunes = ret.all() fortunes.append(ADDITIONAL_FORTUNE_ORM) fortunes.sort(key=sort_fortunes_orm) @@ -128,14 +135,18 @@ async def updates(request): Test 5 ORM """ num_queries = get_num_queries(request) - updates = [(randint(1, 10000), randint(1, 10000)) for _ in range(num_queries)] - updates.sort() + update_ids = sample(range(1, 10001), num_queries) + update_ids.sort() + updates = tuple(zip(update_ids, sample(range(1, 10001), num_queries))) worlds = [{'id': row_id, 'randomNumber': number} for row_id, number in updates] async with request.app['db_session'].begin() as sess: for id_, number in updates: world = await sess.get(World, id_, populate_existing=True) world.randomnumber = number + # Force sqlalchemy to UPDATE entry even if the value has not changed + # doesn't make sense in a real application, added only to pass tests. + flag_modified(world, "randomnumber") return json_response(worlds) async def updates_raw(request): @@ -143,17 +154,22 @@ async def updates_raw(request): Test 5 RAW """ num_queries = get_num_queries(request) - updates = [(randint(1, 10000), randint(1, 10000)) for _ in range(num_queries)] - updates.sort() - worlds = [{'id': row_id, 'randomNumber': number} for row_id, number in updates] + update_ids = sample(range(1, 10001), num_queries) + update_ids.sort() - async with request.app['pg'].acquire() as conn: - stmt = await conn.prepare(READ_ROW_SQL) - for id_, _ in updates: - # the result of this is the int previous random number which we don't actually use - await stmt.fetchval(id_) - await conn.executemany(WRITE_ROW_SQL, updates) + numbers = sample(range(1, 10001), num_queries) + fetch_params = [(i,) for i in update_ids] + row_updates = [*zip(update_ids, numbers)] + async with request.app['pg'].acquire() as conn: + # the result of this is the int previous random number which we don't actually use + await conn.executemany(READ_ROW_SQL, fetch_params) + if num_queries <= 5: + await conn.executemany(WRITE_ROW_SQL, row_updates) + else: + await conn.execute(WRITE_ROW_BATCH_SQL, update_ids, numbers) + + worlds = [{'id': row_id, 'randomNumber': number} for row_id, number in row_updates] return json_response(worlds) diff --git a/frameworks/Python/aiohttp/benchmark_config.json b/frameworks/Python/aiohttp/benchmark_config.json index dad6b2fcc87..487ab2fc7cc 100644 --- a/frameworks/Python/aiohttp/benchmark_config.json +++ b/frameworks/Python/aiohttp/benchmark_config.json @@ -15,19 +15,63 @@ "framework": "aiohttp", "language": "Python", "flavor": "Python3", - "orm": "Full", + "orm": "Raw", "platform": "asyncio", - "webserver": "gunicorn", + "webserver": "None", "os": "Linux", "database_os": "Linux", "display_name": "aiohttp", - "notes": "uses aiopg with sqlalchemy for database access" + "notes": "uses asyncpg for database access" + }, + "pypy": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "Postgres", + "framework": "aiohttp", + "language": "Python", + "flavor": "Pypy3", + "orm": "Raw", + "platform": "asyncio", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "aiohttp-pypy", + "notes": "uses Pypy instead of CPython", + "versus": "default" }, - "pg-raw": { + "nginx": { + "json_url": "/json", "db_url": "/db", "query_url": "/queries/", "fortune_url": "/fortunes", "update_url": "/updates/", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "Postgres", + "framework": "aiohttp", + "language": "Python", + "flavor": "Python3", + "orm": "Raw", + "platform": "asyncio", + "webserver": "nginx", + "os": "Linux", + "database_os": "Linux", + "display_name": "aiohttp-nginx", + "notes": "uses nginx as proxy", + "versus": "default" + }, + "gunicorn": { + "json_url": "/json", + "db_url": "/db", + "query_url": "/queries/", + "fortune_url": "/fortunes", + "update_url": "/updates/", + "plaintext_url": "/plaintext", "port": 8080, "approach": "Realistic", "classification": "Micro", @@ -40,8 +84,29 @@ "webserver": "gunicorn", "os": "Linux", "database_os": "Linux", - "display_name": "aiohttp-pg-raw", - "notes": "uses asyncpg for database access", + "display_name": "aiohttp-gunicorn", + "notes": "uses gunicorn as proxy server", + "versus": "default" + }, + "orm": { + "db_url": "/db", + "query_url": "/queries/", + "fortune_url": "/fortunes", + "update_url": "/updates/", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "Postgres", + "framework": "aiohttp", + "language": "Python", + "flavor": "Python3", + "orm": "Full", + "platform": "asyncio", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "aiohttp-orm", + "notes": "uses sqlalchemy for database access", "versus": "default" } }] diff --git a/frameworks/Python/aiohttp/config.toml b/frameworks/Python/aiohttp/config.toml index d22b4c5bcc2..47a6c33bb28 100644 --- a/frameworks/Python/aiohttp/config.toml +++ b/frameworks/Python/aiohttp/config.toml @@ -13,12 +13,44 @@ classification = "Micro" database = "Postgres" database_os = "Linux" os = "Linux" -orm = "Full" +orm = "Raw" platform = "asyncio" -webserver = "gunicorn" +webserver = "None" versus = "None" -[pg-raw] +[pypy] +urls.plaintext = "/plaintext" +urls.json = "/json" +approach = "Realistic" +classification = "Micro" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "asyncio" +webserver = "None" +versus = "default" + +[nginx] +urls.plaintext = "/plaintext" +urls.json = "/json" +urls.db = "/db" +urls.query = "/queries/" +urls.update = "/updates/" +urls.fortune = "/fortunes" +approach = "Realistic" +classification = "Micro" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "asyncio" +webserver = "nginx" +versus = "default" + +[gunicorn] +urls.plaintext = "/plaintext" +urls.json = "/json" urls.db = "/db" urls.query = "/queries/" urls.update = "/updates/" @@ -32,3 +64,18 @@ orm = "Raw" platform = "asyncio" webserver = "gunicorn" versus = "default" + +[orm] +urls.db = "/db" +urls.query = "/queries/" +urls.update = "/updates/" +urls.fortune = "/fortunes" +approach = "Realistic" +classification = "Micro" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "Full" +platform = "asyncio" +webserver = "None" +versus = "default" diff --git a/frameworks/Python/aiohttp/nginx-entrypoint.sh b/frameworks/Python/aiohttp/nginx-entrypoint.sh new file mode 100644 index 00000000000..8cca36df363 --- /dev/null +++ b/frameworks/Python/aiohttp/nginx-entrypoint.sh @@ -0,0 +1,64 @@ +#!/bin/sh +set -e +CORES=$(nproc) +echo "$CORES cores detected, starting $CORES aiohttp workers..." + +for i in $(seq 0 $((CORES-1))); do + SOCKET="/run/aiohttp-$i.sock" + echo "Starting worker on socket $SOCKET" + python3 -O -m app.app --socket $SOCKET & +done + +echo "Waiting for all workers to be ready..." +for i in $(seq 0 $((CORES-1))); do + SOCKET="/run/aiohttp-$i.sock" + until [ -S "$SOCKET" ]; do + echo "Waiting for socket $SOCKET..." + sleep 0.2 + done + chown root:www-data "$SOCKET" + chmod 660 "$SOCKET" +done + +cat > /aiohttp/nginx.conf <> /aiohttp/nginx.conf +done + +cat >> /aiohttp/nginx.conf <dataclasses and TypedDict annotation for python3.8+. - -## Test Paths & Sources - -The default test implementations are located within the file ([app.py](app.py)). -The core module test implementations are located within the file ([coreapp.py](coreapp.py)). - -All the tests are based on the ones for FastAPI, as APIDaora is an asgi application and have the same principles of using typing annotations for validation/serialization of data. - -## Resources - -* [APIDaora source code on GitHub](https://github.com/dutradda/apidaora) -* [APIDaora website - documentation](https://dutradda.github.io/apidaora/) diff --git a/frameworks/Python/apidaora/apidaora-core.dockerfile b/frameworks/Python/apidaora/apidaora-core.dockerfile deleted file mode 100644 index 2598be52dd1..00000000000 --- a/frameworks/Python/apidaora/apidaora-core.dockerfile +++ /dev/null @@ -1,17 +0,0 @@ -FROM python:3.8 - -ADD templates/fortune.html /apidaora/templates/ - -WORKDIR /apidaora - -ADD requirements.txt /apidaora/ - -RUN pip3 install cython==0.29.13 - -RUN pip3 install -r /apidaora/requirements.txt - -ADD apidaora_core_conf.py coreapp.py /apidaora/ - -EXPOSE 8080 - -CMD gunicorn coreapp:app -k uvicorn.workers.UvicornWorker -c apidaora_core_conf.py diff --git a/frameworks/Python/apidaora/apidaora.dockerfile b/frameworks/Python/apidaora/apidaora.dockerfile deleted file mode 100644 index 0dcdcd1909d..00000000000 --- a/frameworks/Python/apidaora/apidaora.dockerfile +++ /dev/null @@ -1,17 +0,0 @@ -FROM python:3.8 - -ADD templates/fortune.html /apidaora/templates/ - -WORKDIR /apidaora - -ADD requirements.txt /apidaora/ - -RUN pip3 install cython==0.29.13 - -RUN pip3 install -r /apidaora/requirements.txt - -ADD apidaora_conf.py app.py /apidaora/ - -EXPOSE 8080 - -CMD gunicorn app:app -k uvicorn.workers.UvicornWorker -c apidaora_conf.py diff --git a/frameworks/Python/apidaora/apidaora_conf.py b/frameworks/Python/apidaora/apidaora_conf.py deleted file mode 100644 index c7e9f3e4c9c..00000000000 --- a/frameworks/Python/apidaora/apidaora_conf.py +++ /dev/null @@ -1,14 +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/apidaora.pid' -loglevel = 'error' diff --git a/frameworks/Python/apidaora/apidaora_core_conf.py b/frameworks/Python/apidaora/apidaora_core_conf.py deleted file mode 100644 index 16db2539e21..00000000000 --- a/frameworks/Python/apidaora/apidaora_core_conf.py +++ /dev/null @@ -1,14 +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/apidaora-core.pid' -loglevel = 'error' diff --git a/frameworks/Python/apidaora/app.py b/frameworks/Python/apidaora/app.py deleted file mode 100755 index 6c1455e3a82..00000000000 --- a/frameworks/Python/apidaora/app.py +++ /dev/null @@ -1,144 +0,0 @@ -import asyncio -import asyncpg -import os -import jinja2 -from logging import getLogger -from apidaora import appdaora, html, route, text -from random import randint -from operator import itemgetter -from typing import TypedDict, Optional - - -logger = getLogger(__name__) - - -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.'] - - -async def setup_database(): - global connection_pool - connection_pool = await asyncpg.create_pool( - user=os.getenv('PGUSER', 'benchmarkdbuser'), - password=os.getenv('PGPASS', 'benchmarkdbpass'), - database='hello_world', - host='tfb-database', - port=5432 - ) - - -def load_fortunes_template(): - path = os.path.join('templates', 'fortune.html') - with open(path, 'r') as template_file: - template_text = template_file.read() - return jinja2.Template(template_text) - - -def get_num_queries(queries): - try: - query_count = int(queries) - except (ValueError, TypeError): - return 1 - - if query_count < 1: - return 1 - if query_count > 500: - return 500 - return query_count - - -connection_pool = None -sort_fortunes_key = itemgetter(1) -template = load_fortunes_template() -loop = asyncio.get_event_loop() -loop.run_until_complete(setup_database()) - - -@route.get('/json') -async def json_serialization(): - return {'message': 'Hello, world!'} - - -class DatabaseObject(TypedDict): - id: int - randomNumber: float - - -@route.get('/db') -async def single_database_query(): - row_id = randint(1, 10000) - - async with connection_pool.acquire() as connection: - number = await connection.fetchval(READ_ROW_SQL, row_id) - - return DatabaseObject(id=row_id, randomNumber=number) - - -@route.get('/queries') -async def multiple_database_queries(queries: Optional[str] = None): - num_queries = get_num_queries(queries) - row_ids = [randint(1, 10000) for _ in range(num_queries)] - worlds = [] - - async with connection_pool.acquire() as connection: - statement = await connection.prepare(READ_ROW_SQL) - for row_id in row_ids: - number = await statement.fetchval(row_id) - worlds.append( - DatabaseObject( - id=row_id, - randomNumber=number - ) - ) - - return worlds - - -@route.get('/fortunes') -async def fortunes(): - async with connection_pool.acquire() as connection: - fortunes = await connection.fetch('SELECT * FROM Fortune') - - fortunes.append(ADDITIONAL_ROW) - fortunes.sort(key=sort_fortunes_key) - content = template.render(fortunes=fortunes) - return html(content) - - -@route.get('/updates') -async def database_updates(queries: Optional[str] = None): - worlds = [] - updates = set() - - async with connection_pool.acquire() as connection: - statement = await connection.prepare(READ_ROW_SQL_TO_UPDATE) - - for _ in range(get_num_queries(queries)): - record = await statement.fetchrow(randint(1, 10000)) - world = DatabaseObject( - id=record['id'], randomNumber=record['randomnumber'] - ) - world['randomNumber'] = randint(1, 10000) - worlds.append(world) - updates.add((world['id'], world['randomNumber'])) - - await connection.executemany(WRITE_ROW_SQL, updates) - - return worlds - - -@route.get('/plaintext') -async def plaintext(): - return text('Hello, world!') - - -app = appdaora([ - json_serialization, - single_database_query, - multiple_database_queries, - fortunes, - database_updates, - plaintext -]) diff --git a/frameworks/Python/apidaora/benchmark_config.json b/frameworks/Python/apidaora/benchmark_config.json deleted file mode 100755 index 4859e2dfc75..00000000000 --- a/frameworks/Python/apidaora/benchmark_config.json +++ /dev/null @@ -1,53 +0,0 @@ -{ - "framework": "apidaora", - "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": "Micro", - "database": "Postgres", - "framework": "APIDaora", - "language": "Python", - "flavor": "Python3.8", - "orm": "Raw", - "platform": "None", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "APIDaora", - "notes": "", - "versus": "None" - }, - "core": { - "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": "Micro", - "database": "Postgres", - "framework": "APIDaora", - "language": "Python", - "flavor": "Python3.8", - "orm": "Raw", - "platform": "None", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "APIDaora Core", - "notes": "", - "versus": "None" - } - } - ] -} diff --git a/frameworks/Python/apidaora/config.toml b/frameworks/Python/apidaora/config.toml deleted file mode 100644 index 6d9599d812d..00000000000 --- a/frameworks/Python/apidaora/config.toml +++ /dev/null @@ -1,36 +0,0 @@ -[framework] -name = "apidaora" - -[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" - -[core] -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/Python/apidaora/coreapp.py b/frameworks/Python/apidaora/coreapp.py deleted file mode 100644 index e441532a5d1..00000000000 --- a/frameworks/Python/apidaora/coreapp.py +++ /dev/null @@ -1,143 +0,0 @@ -import asyncio -import asyncpg -import os -import jinja2 -import orjson -from logging import getLogger -from random import randint -from operator import itemgetter -from apidaora.asgi.app import asgi_app -from apidaora.asgi.responses import ( - JSON_RESPONSE, HTML_RESPONSE, PLAINTEXT_RESPONSE -) -from apidaora.asgi.router import Route, make_router -from apidaora.method import MethodType - - -logger = getLogger(__name__) - - -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.'] - - -async def setup_database(): - global connection_pool - connection_pool = await asyncpg.create_pool( - user=os.getenv('PGUSER', 'benchmarkdbuser'), - password=os.getenv('PGPASS', 'benchmarkdbpass'), - database='hello_world', - host='tfb-database', - port=5432 - ) - - -def load_fortunes_template(): - path = os.path.join('templates', 'fortune.html') - with open(path, 'r') as template_file: - template_text = template_file.read() - return jinja2.Template(template_text) - - -def get_num_queries(queries): - try: - query_count = int(queries[0]) - except (ValueError, TypeError): - return 1 - - if query_count < 1: - return 1 - if query_count > 500: - return 500 - return query_count - - -connection_pool = None -sort_fortunes_key = itemgetter(1) -template = load_fortunes_template() -loop = asyncio.get_event_loop() -loop.run_until_complete(setup_database()) - - -def json_serialization(request): - return JSON_RESPONSE, orjson.dumps({'message': 'Hello, world!'}) - - -async def single_database_query(request): - row_id = randint(1, 10000) - - async with connection_pool.acquire() as connection: - number = await connection.fetchval(READ_ROW_SQL, row_id) - - return JSON_RESPONSE, orjson.dumps( - {'id': row_id, 'randomNumber': number} - ) - - -async def multiple_database_queries(request): - num_queries = get_num_queries(request.query_dict.get('queries', 1)) - row_ids = [randint(1, 10000) for _ in range(num_queries)] - worlds = [] - - async with connection_pool.acquire() as connection: - statement = await connection.prepare(READ_ROW_SQL) - for row_id in row_ids: - number = await statement.fetchval(row_id) - worlds.append( - dict( - id=row_id, - randomNumber=number - ) - ) - - return JSON_RESPONSE, orjson.dumps(worlds) - - -async def fortunes(request): - async with connection_pool.acquire() as connection: - fortunes = await connection.fetch('SELECT * FROM Fortune') - - fortunes.append(ADDITIONAL_ROW) - fortunes.sort(key=sort_fortunes_key) - content = template.render(fortunes=fortunes).encode('utf-8') - return HTML_RESPONSE, content - - -async def database_updates(request): - worlds = [] - updates = set() - queries = request.query_dict.get('queries', 1) - - async with connection_pool.acquire() as connection: - statement = await connection.prepare(READ_ROW_SQL_TO_UPDATE) - - for _ in range(get_num_queries(queries)): - record = await statement.fetchrow(randint(1, 10000)) - world = dict( - id=record['id'], randomNumber=record['randomnumber'] - ) - world['randomNumber'] = randint(1, 10000) - worlds.append(world) - updates.add((world['id'], world['randomNumber'])) - - await connection.executemany(WRITE_ROW_SQL, updates) - - return JSON_RESPONSE, orjson.dumps(worlds) - - -def plaintext(request): - return PLAINTEXT_RESPONSE, b'Hello, world!' - - -routes = ( - Route('/json', MethodType.GET, json_serialization), - Route('/db', MethodType.GET, single_database_query), - Route('/queries', MethodType.GET, multiple_database_queries, has_query=True), - Route('/fortunes', MethodType.GET, fortunes), - Route('/updates', MethodType.GET, database_updates, has_query=True), - Route('/plaintext', MethodType.GET, plaintext), -) -router = make_router(routes) -app = asgi_app(router) diff --git a/frameworks/Python/apidaora/requirements.txt b/frameworks/Python/apidaora/requirements.txt deleted file mode 100644 index 90e4dfac0b7..00000000000 --- a/frameworks/Python/apidaora/requirements.txt +++ /dev/null @@ -1,6 +0,0 @@ -asyncpg==0.21.0 -gunicorn==20.0.4 -jinja2==3.0.3 -uvloop==0.14.0 -uvicorn==0.11.7 -apidaora==0.26.0 diff --git a/frameworks/Python/async-worker/Pipfile b/frameworks/Python/async-worker/Pipfile deleted file mode 100644 index 0cf91e337f9..00000000000 --- a/frameworks/Python/async-worker/Pipfile +++ /dev/null @@ -1,17 +0,0 @@ -[[source]] -url = "https://pypi.org/simple" -verify_ssl = true -name = "pypi" - -[packages] -async-worker = "==0.19.1" -cchardet = "==2.1.7" - -[dev-packages] -black = "*" - -[requires] -python_version = "3.9" - -[pipenv] -allow_prereleases = true diff --git a/frameworks/Python/async-worker/Pipfile.lock b/frameworks/Python/async-worker/Pipfile.lock deleted file mode 100644 index e1c3bbb5bbc..00000000000 --- a/frameworks/Python/async-worker/Pipfile.lock +++ /dev/null @@ -1,384 +0,0 @@ -{ - "_meta": { - "hash": { - "sha256": "872880755bbf439ce862323482273dd3539044167e90014909fbfe789adaa25a" - }, - "pipfile-spec": 6, - "requires": { - "python_version": "3.9" - }, - "sources": [ - { - "name": "pypi", - "url": "https://pypi.org/simple", - "verify_ssl": true - } - ] - }, - "default": { - "aioamqp": { - "hashes": [ - "sha256:55fa703a70e71bc958ad546b9ee0c68387cab366c82fc44c0742d6ad0303745a", - "sha256:eef5c23a7fedee079d8326406f5c7a5725dfe36c359373da3499fffa16f79915" - ], - "version": "==0.14.0" - }, - "aiohttp": { - "hashes": [ - "sha256:119feb2bd551e58d83d1b38bfa4cb921af8ddedec9fad7183132db334c3133e0", - "sha256:16d0683ef8a6d803207f02b899c928223eb219111bd52420ef3d7a8aa76227b6", - "sha256:2eb3efe243e0f4ecbb654b08444ae6ffab37ac0ef8f69d3a2ffb958905379daf", - "sha256:2ffea7904e70350da429568113ae422c88d2234ae776519549513c8f217f58a9", - "sha256:40bd1b101b71a18a528ffce812cc14ff77d4a2a1272dfb8b11b200967489ef3e", - "sha256:418597633b5cd9639e514b1d748f358832c08cd5d9ef0870026535bd5eaefdd0", - "sha256:481d4b96969fbfdcc3ff35eea5305d8565a8300410d3d269ccac69e7256b1329", - "sha256:4c1bdbfdd231a20eee3e56bd0ac1cd88c4ff41b64ab679ed65b75c9c74b6c5c2", - "sha256:5563ad7fde451b1986d42b9bb9140e2599ecf4f8e42241f6da0d3d624b776f40", - "sha256:58c62152c4c8731a3152e7e650b29ace18304d086cb5552d317a54ff2749d32a", - "sha256:5b50e0b9460100fe05d7472264d1975f21ac007b35dcd6fd50279b72925a27f4", - "sha256:5d84ecc73141d0a0d61ece0742bb7ff5751b0657dab8405f899d3ceb104cc7de", - "sha256:5dde6d24bacac480be03f4f864e9a67faac5032e28841b00533cd168ab39cad9", - "sha256:5e91e927003d1ed9283dee9abcb989334fc8e72cf89ebe94dc3e07e3ff0b11e9", - "sha256:62bc216eafac3204877241569209d9ba6226185aa6d561c19159f2e1cbb6abfb", - "sha256:6c8200abc9dc5f27203986100579fc19ccad7a832c07d2bc151ce4ff17190076", - "sha256:6ca56bdfaf825f4439e9e3673775e1032d8b6ea63b8953d3812c71bd6a8b81de", - "sha256:71680321a8a7176a58dfbc230789790639db78dad61a6e120b39f314f43f1907", - "sha256:7c7820099e8b3171e54e7eedc33e9450afe7cd08172632d32128bd527f8cb77d", - "sha256:7dbd087ff2f4046b9b37ba28ed73f15fd0bc9f4fdc8ef6781913da7f808d9536", - "sha256:822bd4fd21abaa7b28d65fc9871ecabaddc42767884a626317ef5b75c20e8a2d", - "sha256:8ec1a38074f68d66ccb467ed9a673a726bb397142c273f90d4ba954666e87d54", - "sha256:950b7ef08b2afdab2488ee2edaff92a03ca500a48f1e1aaa5900e73d6cf992bc", - "sha256:99c5a5bf7135607959441b7d720d96c8e5c46a1f96e9d6d4c9498be8d5f24212", - "sha256:b84ad94868e1e6a5e30d30ec419956042815dfaea1b1df1cef623e4564c374d9", - "sha256:bc3d14bf71a3fb94e5acf5bbf67331ab335467129af6416a437bd6024e4f743d", - "sha256:c2a80fd9a8d7e41b4e38ea9fe149deed0d6aaede255c497e66b8213274d6d61b", - "sha256:c44d3c82a933c6cbc21039326767e778eface44fca55c65719921c4b9661a3f7", - "sha256:cc31e906be1cc121ee201adbdf844522ea3349600dd0a40366611ca18cd40e81", - "sha256:d5d102e945ecca93bcd9801a7bb2fa703e37ad188a2f81b1e65e4abe4b51b00c", - "sha256:dd7936f2a6daa861143e376b3a1fb56e9b802f4980923594edd9ca5670974895", - "sha256:dee68ec462ff10c1d836c0ea2642116aba6151c6880b688e56b4c0246770f297", - "sha256:e76e78863a4eaec3aee5722d85d04dcbd9844bc6cd3bfa6aa880ff46ad16bfcb", - "sha256:eab51036cac2da8a50d7ff0ea30be47750547c9aa1aa2cf1a1b710a1827e7dbe", - "sha256:f4496d8d04da2e98cc9133e238ccebf6a13ef39a93da2e87146c8c8ac9768242", - "sha256:fbd3b5e18d34683decc00d9a360179ac1e7a320a5fee10ab8053ffd6deab76e0", - "sha256:feb24ff1226beeb056e247cf2e24bba5232519efb5645121c4aea5b6ad74c1f2" - ], - "markers": "python_version >= '3.6'", - "version": "==3.7.4" - }, - "aiologger": { - "hashes": [ - "sha256:5e1493a2c9819a5d751b9e775c79b9afe628387ee80a1d5e91ff719bb2f511b9" - ], - "version": "==0.5.0" - }, - "async-timeout": { - "hashes": [ - "sha256:0c3c816a028d47f659d6ff5c745cb2acf1f966da1fe5c19c77a70282b25f4c5f", - "sha256:4291ca197d287d274d0b6cb5d6f8f8f82d434ed288f962539ff18cc9012f9ea3" - ], - "markers": "python_full_version >= '3.5.3'", - "version": "==3.0.1" - }, - "async-worker": { - "hashes": [ - "sha256:ca60175a50430fd06817163d7edb0d19d0978b54fc65d3df59af3663f2c05ba0" - ], - "index": "pypi", - "version": "==0.19.1" - }, - "attrs": { - "hashes": [ - "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1", - "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==21.2.0" - }, - "cached-property": { - "hashes": [ - "sha256:3a026f1a54135677e7da5ce819b0c690f156f37976f3e30c5430740725203d7f", - "sha256:9217a59f14a5682da7c4b8829deadbfc194ac22e9908ccf7c8820234e80a1504" - ], - "version": "==1.5.1" - }, - "cchardet": { - "hashes": [ - "sha256:0b859069bbb9d27c78a2c9eb997e6f4b738db2d7039a03f8792b4058d61d1109", - "sha256:228d2533987c450f39acf7548f474dd6814c446e9d6bd228e8f1d9a2d210f10b", - "sha256:2309ff8fc652b0fc3c0cff5dbb172530c7abb92fe9ba2417c9c0bcf688463c1c", - "sha256:24974b3e40fee9e7557bb352be625c39ec6f50bc2053f44a3d1191db70b51675", - "sha256:273699c4e5cd75377776501b72a7b291a988c6eec259c29505094553ee505597", - "sha256:27a9ba87c9f99e0618e1d3081189b1217a7d110e5c5597b0b7b7c3fedd1c340a", - "sha256:302aa443ae2526755d412c9631136bdcd1374acd08e34f527447f06f3c2ddb98", - "sha256:45456c59ec349b29628a3c6bfb86d818ec3a6fbb7eb72de4ff3bd4713681c0e3", - "sha256:48ba829badef61441e08805cfa474ccd2774be2ff44b34898f5854168c596d4d", - "sha256:50ad671e8d6c886496db62c3bd68b8d55060688c655873aa4ce25ca6105409a1", - "sha256:54341e7e1ba9dc0add4c9d23b48d3a94e2733065c13920e85895f944596f6150", - "sha256:54d0b26fd0cd4099f08fb9c167600f3e83619abefeaa68ad823cc8ac1f7bcc0c", - "sha256:5a25f9577e9bebe1a085eec2d6fdd72b7a9dd680811bba652ea6090fb2ff472f", - "sha256:6b6397d8a32b976a333bdae060febd39ad5479817fabf489e5596a588ad05133", - "sha256:70eeae8aaf61192e9b247cf28969faef00578becd2602526ecd8ae7600d25e0e", - "sha256:80e6faae75ecb9be04a7b258dc4750d459529debb6b8dee024745b7b5a949a34", - "sha256:90086e5645f8a1801350f4cc6cb5d5bf12d3fa943811bb08667744ec1ecc9ccd", - "sha256:a39526c1c526843965cec589a6f6b7c2ab07e3e56dc09a7f77a2be6a6afa4636", - "sha256:b154effa12886e9c18555dfc41a110f601f08d69a71809c8d908be4b1ab7314f", - "sha256:b59ddc615883835e03c26f81d5fc3671fab2d32035c87f50862de0da7d7db535", - "sha256:bd7f262f41fd9caf5a5f09207a55861a67af6ad5c66612043ed0f81c58cdf376", - "sha256:c428b6336545053c2589f6caf24ea32276c6664cb86db817e03a94c60afa0eaf", - "sha256:c6f70139aaf47ffb94d89db603af849b82efdf756f187cdd3e566e30976c519f", - "sha256:c96aee9ebd1147400e608a3eff97c44f49811f8904e5a43069d55603ac4d8c97", - "sha256:ec3eb5a9c475208cf52423524dcaf713c394393e18902e861f983c38eeb77f18", - "sha256:eee4f5403dc3a37a1ca9ab87db32b48dc7e190ef84601068f45397144427cc5e", - "sha256:f16517f3697569822c6d09671217fdeab61dfebc7acb5068634d6b0728b86c0b", - "sha256:f86e0566cb61dc4397297696a4a1b30f6391b50bc52b4f073507a48466b6255a", - "sha256:fdac1e4366d0579fff056d1280b8dc6348be964fda8ebb627c0269e097ab37fa" - ], - "index": "pypi", - "version": "==2.1.7" - }, - "chardet": { - "hashes": [ - "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", - "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691" - ], - "version": "==3.0.4" - }, - "idna": { - "hashes": [ - "sha256:5205d03e7bcbb919cc9c19885f9920d622ca52448306f2377daede5cf3faac16", - "sha256:c5b02147e01ea9920e6b0a3f1f7bb833612d507592c837a6c49552768f4054e1" - ], - "markers": "python_version >= '3.4'", - "version": "==3.1" - }, - "multidict": { - "hashes": [ - "sha256:018132dbd8688c7a69ad89c4a3f39ea2f9f33302ebe567a879da8f4ca73f0d0a", - "sha256:051012ccee979b2b06be928a6150d237aec75dd6bf2d1eeeb190baf2b05abc93", - "sha256:05c20b68e512166fddba59a918773ba002fdd77800cad9f55b59790030bab632", - "sha256:07b42215124aedecc6083f1ce6b7e5ec5b50047afa701f3442054373a6deb656", - "sha256:0e3c84e6c67eba89c2dbcee08504ba8644ab4284863452450520dad8f1e89b79", - "sha256:0e929169f9c090dae0646a011c8b058e5e5fb391466016b39d21745b48817fd7", - "sha256:1ab820665e67373de5802acae069a6a05567ae234ddb129f31d290fc3d1aa56d", - "sha256:25b4e5f22d3a37ddf3effc0710ba692cfc792c2b9edfb9c05aefe823256e84d5", - "sha256:2e68965192c4ea61fff1b81c14ff712fc7dc15d2bd120602e4a3494ea6584224", - "sha256:2f1a132f1c88724674271d636e6b7351477c27722f2ed789f719f9e3545a3d26", - "sha256:37e5438e1c78931df5d3c0c78ae049092877e5e9c02dd1ff5abb9cf27a5914ea", - "sha256:3a041b76d13706b7fff23b9fc83117c7b8fe8d5fe9e6be45eee72b9baa75f348", - "sha256:3a4f32116f8f72ecf2a29dabfb27b23ab7cdc0ba807e8459e59a93a9be9506f6", - "sha256:46c73e09ad374a6d876c599f2328161bcd95e280f84d2060cf57991dec5cfe76", - "sha256:46dd362c2f045095c920162e9307de5ffd0a1bfbba0a6e990b344366f55a30c1", - "sha256:4b186eb7d6ae7c06eb4392411189469e6a820da81447f46c0072a41c748ab73f", - "sha256:54fd1e83a184e19c598d5e70ba508196fd0bbdd676ce159feb412a4a6664f952", - "sha256:585fd452dd7782130d112f7ddf3473ffdd521414674c33876187e101b588738a", - "sha256:5cf3443199b83ed9e955f511b5b241fd3ae004e3cb81c58ec10f4fe47c7dce37", - "sha256:6a4d5ce640e37b0efcc8441caeea8f43a06addace2335bd11151bc02d2ee31f9", - "sha256:7df80d07818b385f3129180369079bd6934cf70469f99daaebfac89dca288359", - "sha256:806068d4f86cb06af37cd65821554f98240a19ce646d3cd24e1c33587f313eb8", - "sha256:830f57206cc96ed0ccf68304141fec9481a096c4d2e2831f311bde1c404401da", - "sha256:929006d3c2d923788ba153ad0de8ed2e5ed39fdbe8e7be21e2f22ed06c6783d3", - "sha256:9436dc58c123f07b230383083855593550c4d301d2532045a17ccf6eca505f6d", - "sha256:9dd6e9b1a913d096ac95d0399bd737e00f2af1e1594a787e00f7975778c8b2bf", - "sha256:ace010325c787c378afd7f7c1ac66b26313b3344628652eacd149bdd23c68841", - "sha256:b47a43177a5e65b771b80db71e7be76c0ba23cc8aa73eeeb089ed5219cdbe27d", - "sha256:b797515be8743b771aa868f83563f789bbd4b236659ba52243b735d80b29ed93", - "sha256:b7993704f1a4b204e71debe6095150d43b2ee6150fa4f44d6d966ec356a8d61f", - "sha256:d5c65bdf4484872c4af3150aeebe101ba560dcfb34488d9a8ff8dbcd21079647", - "sha256:d81eddcb12d608cc08081fa88d046c78afb1bf8107e6feab5d43503fea74a635", - "sha256:dc862056f76443a0db4509116c5cd480fe1b6a2d45512a653f9a855cc0517456", - "sha256:ecc771ab628ea281517e24fd2c52e8f31c41e66652d07599ad8818abaad38cda", - "sha256:f200755768dc19c6f4e2b672421e0ebb3dd54c38d5a4f262b872d8cfcc9e93b5", - "sha256:f21756997ad8ef815d8ef3d34edd98804ab5ea337feedcd62fb52d22bf531281", - "sha256:fc13a9524bc18b6fb6e0dbec3533ba0496bbed167c56d0aabefd965584557d80" - ], - "markers": "python_version >= '3.6'", - "version": "==5.1.0" - }, - "pamqp": { - "hashes": [ - "sha256:2f81b5c186f668a67f165193925b6bfd83db4363a6222f599517f29ecee60b02", - "sha256:5cd0f5a85e89f20d5f8e19285a1507788031cfca4a9ea6f067e3cf18f5e294e8" - ], - "version": "==2.3.0" - }, - "prometheus-client": { - "hashes": [ - "sha256:71cd24a2b3eb335cb800c7159f423df1bd4dcd5171b234be15e3f31ec9f622da" - ], - "version": "==0.7.1" - }, - "pydantic": { - "hashes": [ - "sha256:0b71ca069c16470cb00be0acaf0657eb74cbc4ff5f11b42e79647f170956cda3", - "sha256:12ed0b175bba65e29dfc5859cd539d3512f58bb776bf620a3d3338501fd0f389", - "sha256:22fe5756c6c57279234e4c4027a3549507aca29e9ee832d6aa39c367cb43c99f", - "sha256:26821f61623b01d618bd8b3243f790ac8bd7ae31b388c0e41aa586002cf350eb", - "sha256:2bc9e9f5d91a29dec53346efc5c719d82297885d89c8a62b971492fba222c68d", - "sha256:42b8fb1e4e4783c4aa31df44b64714f96aa4deeacbacf3713a8a238ee7df3b2b", - "sha256:4a83d24bcf9ce8e6fa55c379bba1359461eedb85721bfb3151e240871e2b13a8", - "sha256:5759a4b276bda5ac2360f00e9b1e711aaac51fabd155b422d27f3339710f4264", - "sha256:77e04800d19acc2a8fbb95fe3d47ff397ce137aa5a2b32cc23a87bac70dda343", - "sha256:865410a6df71fb60294887770d19c67d499689f7ce64245182653952cdbd4183", - "sha256:91baec8ed771d4c53d71ef549d8e36b0f92a31c32296062d562d1d7074dd1d6e", - "sha256:999cc108933425752e45d1bf2f57d3cf091f2a5e8b9b8afab5b8872d2cc7645f", - "sha256:a0ff36e3f929d76b91d1624c6673dbdc1407358700d117bb7f29d5696c52d288", - "sha256:a989924324513215ad2b2cfd187426e6372f76f507b17361142c0b792294960c", - "sha256:ad2fae68e185cfae5b6d83e7915352ff0b6e5fa84d84bc6a94c3e2de58327114", - "sha256:b4e03c84f4e96e3880c9d34508cccbd0f0df6e7dc14b17f960ea8c71448823a3", - "sha256:c26d380af3e9a8eb9abe3b6337cea28f057b5425330817c918cf74d0a0a2303d", - "sha256:c8a3600435b83a4f28f5379f3bb574576521180f691828268268e9f172f1b1eb", - "sha256:ccc2ab0a240d01847f3d5f0f9e1582d450a2fc3389db33a7af8e7447b205a935", - "sha256:d361d181a3fb53ebfdc2fb1e3ca55a6b2ad717578a5e119c99641afd11b31a47", - "sha256:d5aeab86837f8799df0d84bec1190e6cc0062d5c5374636b5599234f2b39fe0a", - "sha256:edf37d30ea60179ef067add9772cf42299ea6cd490b3c94335a68f1021944ac4" - ], - "markers": "python_full_version >= '3.6.1'", - "version": "==1.8" - }, - "typing-extensions": { - "hashes": [ - "sha256:0ac0f89795dd19de6b97debb0c6af1c70987fd80a2d62d1958f7e56fcc31b497", - "sha256:50b6f157849174217d0656f99dc82fe932884fb250826c18350e159ec6cdf342", - "sha256:779383f6086d90c99ae41cf0ff39aac8a7937a9283ce0a414e5dd782f4c94a84" - ], - "version": "==3.10.0.0" - }, - "yarl": { - "hashes": [ - "sha256:00d7ad91b6583602eb9c1d085a2cf281ada267e9a197e8b7cae487dadbfa293e", - "sha256:0355a701b3998dcd832d0dc47cc5dedf3874f966ac7f870e0f3a6788d802d434", - "sha256:15263c3b0b47968c1d90daa89f21fcc889bb4b1aac5555580d74565de6836366", - "sha256:2ce4c621d21326a4a5500c25031e102af589edb50c09b321049e388b3934eec3", - "sha256:31ede6e8c4329fb81c86706ba8f6bf661a924b53ba191b27aa5fcee5714d18ec", - "sha256:324ba3d3c6fee56e2e0b0d09bf5c73824b9f08234339d2b788af65e60040c959", - "sha256:329412812ecfc94a57cd37c9d547579510a9e83c516bc069470db5f75684629e", - "sha256:4736eaee5626db8d9cda9eb5282028cc834e2aeb194e0d8b50217d707e98bb5c", - "sha256:4953fb0b4fdb7e08b2f3b3be80a00d28c5c8a2056bb066169de00e6501b986b6", - "sha256:4c5bcfc3ed226bf6419f7a33982fb4b8ec2e45785a0561eb99274ebbf09fdd6a", - "sha256:547f7665ad50fa8563150ed079f8e805e63dd85def6674c97efd78eed6c224a6", - "sha256:5b883e458058f8d6099e4420f0cc2567989032b5f34b271c0827de9f1079a424", - "sha256:63f90b20ca654b3ecc7a8d62c03ffa46999595f0167d6450fa8383bab252987e", - "sha256:68dc568889b1c13f1e4745c96b931cc94fdd0defe92a72c2b8ce01091b22e35f", - "sha256:69ee97c71fee1f63d04c945f56d5d726483c4762845400a6795a3b75d56b6c50", - "sha256:6d6283d8e0631b617edf0fd726353cb76630b83a089a40933043894e7f6721e2", - "sha256:72a660bdd24497e3e84f5519e57a9ee9220b6f3ac4d45056961bf22838ce20cc", - "sha256:73494d5b71099ae8cb8754f1df131c11d433b387efab7b51849e7e1e851f07a4", - "sha256:7356644cbed76119d0b6bd32ffba704d30d747e0c217109d7979a7bc36c4d970", - "sha256:8a9066529240171b68893d60dca86a763eae2139dd42f42106b03cf4b426bf10", - "sha256:8aa3decd5e0e852dc68335abf5478a518b41bf2ab2f330fe44916399efedfae0", - "sha256:97b5bdc450d63c3ba30a127d018b866ea94e65655efaf889ebeabc20f7d12406", - "sha256:9ede61b0854e267fd565e7527e2f2eb3ef8858b301319be0604177690e1a3896", - "sha256:b2e9a456c121e26d13c29251f8267541bd75e6a1ccf9e859179701c36a078643", - "sha256:b5dfc9a40c198334f4f3f55880ecf910adebdcb2a0b9a9c23c9345faa9185721", - "sha256:bafb450deef6861815ed579c7a6113a879a6ef58aed4c3a4be54400ae8871478", - "sha256:c49ff66d479d38ab863c50f7bb27dee97c6627c5fe60697de15529da9c3de724", - "sha256:ce3beb46a72d9f2190f9e1027886bfc513702d748047b548b05dab7dfb584d2e", - "sha256:d26608cf178efb8faa5ff0f2d2e77c208f471c5a3709e577a7b3fd0445703ac8", - "sha256:d597767fcd2c3dc49d6eea360c458b65643d1e4dbed91361cf5e36e53c1f8c96", - "sha256:d5c32c82990e4ac4d8150fd7652b972216b204de4e83a122546dce571c1bdf25", - "sha256:d8d07d102f17b68966e2de0e07bfd6e139c7c02ef06d3a0f8d2f0f055e13bb76", - "sha256:e46fba844f4895b36f4c398c5af062a9808d1f26b2999c58909517384d5deda2", - "sha256:e6b5460dc5ad42ad2b36cca524491dfcaffbfd9c8df50508bddc354e787b8dc2", - "sha256:f040bcc6725c821a4c0665f3aa96a4d0805a7aaf2caf266d256b8ed71b9f041c", - "sha256:f0b059678fd549c66b89bed03efcabb009075bd131c248ecdf087bdb6faba24a", - "sha256:fcbb48a93e8699eae920f8d92f7160c03567b421bc17362a9ffbbd706a816f71" - ], - "markers": "python_version >= '3.6'", - "version": "==1.6.3" - } - }, - "develop": { - "appdirs": { - "hashes": [ - "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41", - "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128" - ], - "version": "==1.4.4" - }, - "black": { - "hashes": [ - "sha256:23695358dbcb3deafe7f0a3ad89feee5999a46be5fec21f4f1d108be0bcdb3b1", - "sha256:8a60071a0043876a4ae96e6c69bd3a127dad2c1ca7c8083573eb82f92705d008" - ], - "index": "pypi", - "version": "==21.5b1" - }, - "click": { - "hashes": [ - "sha256:8c04c11192119b1ef78ea049e0a6f0463e4c48ef00a30160c704337586f3ad7a", - "sha256:fba402a4a47334742d782209a7c79bc448911afe1149d07bdabdf480b3e2f4b6" - ], - "markers": "python_version >= '3.6'", - "version": "==8.0.1" - }, - "mypy-extensions": { - "hashes": [ - "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d", - "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8" - ], - "version": "==0.4.3" - }, - "pathspec": { - "hashes": [ - "sha256:86379d6b86d75816baba717e64b1a3a3469deb93bb76d613c9ce79edc5cb68fd", - "sha256:aa0cb481c4041bf52ffa7b0d8fa6cd3e88a2ca4879c533c9153882ee2556790d" - ], - "version": "==0.8.1" - }, - "regex": { - "hashes": [ - "sha256:01afaf2ec48e196ba91b37451aa353cb7eda77efe518e481707e0515025f0cd5", - "sha256:11d773d75fa650cd36f68d7ca936e3c7afaae41b863b8c387a22aaa78d3c5c79", - "sha256:18c071c3eb09c30a264879f0d310d37fe5d3a3111662438889ae2eb6fc570c31", - "sha256:1e1c20e29358165242928c2de1482fb2cf4ea54a6a6dea2bd7a0e0d8ee321500", - "sha256:281d2fd05555079448537fe108d79eb031b403dac622621c78944c235f3fcf11", - "sha256:314d66636c494ed9c148a42731b3834496cc9a2c4251b1661e40936814542b14", - "sha256:32e65442138b7b76dd8173ffa2cf67356b7bc1768851dded39a7a13bf9223da3", - "sha256:339456e7d8c06dd36a22e451d58ef72cef293112b559010db3d054d5560ef439", - "sha256:3916d08be28a1149fb97f7728fca1f7c15d309a9f9682d89d79db75d5e52091c", - "sha256:3a9cd17e6e5c7eb328517969e0cb0c3d31fd329298dd0c04af99ebf42e904f82", - "sha256:47bf5bf60cf04d72bf6055ae5927a0bd9016096bf3d742fa50d9bf9f45aa0711", - "sha256:4c46e22a0933dd783467cf32b3516299fb98cfebd895817d685130cc50cd1093", - "sha256:4c557a7b470908b1712fe27fb1ef20772b78079808c87d20a90d051660b1d69a", - "sha256:52ba3d3f9b942c49d7e4bc105bb28551c44065f139a65062ab7912bef10c9afb", - "sha256:563085e55b0d4fb8f746f6a335893bda5c2cef43b2f0258fe1020ab1dd874df8", - "sha256:598585c9f0af8374c28edd609eb291b5726d7cbce16be6a8b95aa074d252ee17", - "sha256:619d71c59a78b84d7f18891fe914446d07edd48dc8328c8e149cbe0929b4e000", - "sha256:67bdb9702427ceddc6ef3dc382455e90f785af4c13d495f9626861763ee13f9d", - "sha256:6d1b01031dedf2503631d0903cb563743f397ccaf6607a5e3b19a3d76fc10480", - "sha256:741a9647fcf2e45f3a1cf0e24f5e17febf3efe8d4ba1281dcc3aa0459ef424dc", - "sha256:7c2a1af393fcc09e898beba5dd59196edaa3116191cc7257f9224beaed3e1aa0", - "sha256:7d9884d86dd4dd489e981d94a65cd30d6f07203d90e98f6f657f05170f6324c9", - "sha256:90f11ff637fe8798933fb29f5ae1148c978cccb0452005bf4c69e13db951e765", - "sha256:919859aa909429fb5aa9cf8807f6045592c85ef56fdd30a9a3747e513db2536e", - "sha256:96fcd1888ab4d03adfc9303a7b3c0bd78c5412b2bfbe76db5b56d9eae004907a", - "sha256:97f29f57d5b84e73fbaf99ab3e26134e6687348e95ef6b48cfd2c06807005a07", - "sha256:980d7be47c84979d9136328d882f67ec5e50008681d94ecc8afa8a65ed1f4a6f", - "sha256:a91aa8619b23b79bcbeb37abe286f2f408d2f2d6f29a17237afda55bb54e7aac", - "sha256:ade17eb5d643b7fead300a1641e9f45401c98eee23763e9ed66a43f92f20b4a7", - "sha256:b9c3db21af35e3b3c05764461b262d6f05bbca08a71a7849fd79d47ba7bc33ed", - "sha256:bd28bc2e3a772acbb07787c6308e00d9626ff89e3bfcdebe87fa5afbfdedf968", - "sha256:bf5824bfac591ddb2c1f0a5f4ab72da28994548c708d2191e3b87dd207eb3ad7", - "sha256:c0502c0fadef0d23b128605d69b58edb2c681c25d44574fc673b0e52dce71ee2", - "sha256:c38c71df845e2aabb7fb0b920d11a1b5ac8526005e533a8920aea97efb8ec6a4", - "sha256:ce15b6d103daff8e9fee13cf7f0add05245a05d866e73926c358e871221eae87", - "sha256:d3029c340cfbb3ac0a71798100ccc13b97dddf373a4ae56b6a72cf70dfd53bc8", - "sha256:e512d8ef5ad7b898cdb2d8ee1cb09a8339e4f8be706d27eaa180c2f177248a10", - "sha256:e8e5b509d5c2ff12f8418006d5a90e9436766133b564db0abaec92fd27fcee29", - "sha256:ee54ff27bf0afaf4c3b3a62bcd016c12c3fdb4ec4f413391a90bd38bc3624605", - "sha256:fa4537fb4a98fe8fde99626e4681cc644bdcf2a795038533f9f711513a862ae6", - "sha256:fd45ff9293d9274c5008a2054ecef86a9bfe819a67c7be1afb65e69b405b3042" - ], - "version": "==2021.4.4" - }, - "toml": { - "hashes": [ - "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", - "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f" - ], - "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==0.10.2" - } - } -} diff --git a/frameworks/Python/async-worker/README.md b/frameworks/Python/async-worker/README.md deleted file mode 100644 index fbdcb7e215a..00000000000 --- a/frameworks/Python/async-worker/README.md +++ /dev/null @@ -1,14 +0,0 @@ -# [async-worker](https://github.com/async-worker/async-worker) Benchmark Test - -### Server -Server is exposed at `:8080` - -## Test URLs - -### Test 1: JSON Encoding - - http://localhost:8080/json - -### Test 6: Plaintext - - http://localhost:8080/plaintext diff --git a/frameworks/Python/async-worker/async-worker.dockerfile b/frameworks/Python/async-worker/async-worker.dockerfile deleted file mode 100644 index 2023fb97fb9..00000000000 --- a/frameworks/Python/async-worker/async-worker.dockerfile +++ /dev/null @@ -1,19 +0,0 @@ -FROM python:3.9-alpine - -LABEL description="Image used to run async-worker benchmark tests." -LABEL version='0.1' - -ENV ASYNCWORKER_HTTP_HOST=0.0.0.0 -ENV ASYNCWORKER_HTTP_PORT=8080 - -WORKDIR /app - -COPY /src /app -COPY Pipfile /app -COPY Pipfile.lock /app - -RUN apk add --virtual .deps gcc g++ make openssl-dev libxml2 libffi-dev && \ - pip install pipenv && \ - pipenv install --system --ignore-pipfile - -CMD ["python", "./hello_world.py"] diff --git a/frameworks/Python/async-worker/benchmark_config.json b/frameworks/Python/async-worker/benchmark_config.json deleted file mode 100644 index f27f1806581..00000000000 --- a/frameworks/Python/async-worker/benchmark_config.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "framework": "async-worker", - "tests": [{ - "default": { - "json_url": "/json", - "plaintext_url": "/plaintext", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "framework": "async-worker", - "language": "Python", - "flavor": "Python3", - "orm": "Raw", - "platform": "asyncio", - "os": "Linux", - "display_name": "async-worker", - "versus": "aiohttp" - } - }] -} diff --git a/frameworks/Python/async-worker/src/hello_world.py b/frameworks/Python/async-worker/src/hello_world.py deleted file mode 100644 index ca785cd583b..00000000000 --- a/frameworks/Python/async-worker/src/hello_world.py +++ /dev/null @@ -1,18 +0,0 @@ -from aiohttp import web -from asyncworker import App - -app = App() - - -@app.http.get(["/plaintext"]) -async def handler(request: web.Request) -> web.Response: - return web.Response(body="Hello, World!") - - -@app.http.get(["/json"]) -async def handler(request: web.Request) -> web.Response: - return web.json_response({"message": "Hello, World!"}) - - -if __name__ == "__main__": - app.run() diff --git a/frameworks/Python/bareasgi/README.md b/frameworks/Python/bareasgi/README.md deleted file mode 100755 index de493eec242..00000000000 --- a/frameworks/Python/bareasgi/README.md +++ /dev/null @@ -1,22 +0,0 @@ -# bareASGI Benchmark Test - -This is the bareASGI portion of a [benchmarking tests suite](../../) -comparing a variety of web development platforms. - -The information below is specific to bareASGI. 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 - -[bareASGI](https://github.com/rob-blackbourn/bareASGI) is a lightweight ASGI web server framework. - -## Test Paths & Sources - -All of the test implementations are located within a single file ([app.py](app.py)). - -## Resources - -* [bareASGI on GitHub](https://github.com/rob-blackbourn/bareASGI) -* [ASGI specification](https://asgi.readthedocs.io/en/latest/) diff --git a/frameworks/Python/bareasgi/app.py b/frameworks/Python/bareasgi/app.py deleted file mode 100644 index 794754dfaf0..00000000000 --- a/frameworks/Python/bareasgi/app.py +++ /dev/null @@ -1,136 +0,0 @@ -#!/usr/bin/env python3 -from random import randint, sample -import os -import os.path -from typing import Any, Dict, List, Tuple -from urllib.parse import parse_qs - -import asyncpg -import jinja2 -import orjson - -from bareasgi import Application, HttpRequest, HttpResponse, LifespanRequest -from bareasgi_jinja2 import add_jinja2, Jinja2TemplateProvider - -GET_WORLD = "SELECT id, randomnumber FROM world WHERE id = $1" -UPDATE_WORLD = "UPDATE world SET randomNumber = $2 WHERE id = $1" -GET_FORTUNES = "SELECT * FROM fortune" -ADDITIONAL_ROW = (0, "Additional fortune added at request time.") - - -async def on_startup(_request: LifespanRequest) -> None: - app.info['db'] = await asyncpg.create_pool( - user=os.getenv("PGUSER", "benchmarkdbuser"), - password=os.getenv("PGPASS", "benchmarkdbpass"), - database="hello_world", - host="tfb-database", - port=5432, - ) - - -async def on_shutdown(_request: LifespanRequest) -> None: - await app.info['db'].close() - - -async def handle_json_request(_request: HttpRequest) -> HttpResponse: - return HttpResponse.from_json( - {"message": "Hello, World!"}, - encode_bytes=orjson.dumps - ) - - -async def handle_plaintext_request(_request: HttpRequest) -> HttpResponse: - return HttpResponse.from_text("Hello, World!") - - -async def handle_db_request(_request: HttpRequest) -> HttpResponse: - key = randint(1, 10000) - - async with app.info['db'].acquire() as conn: - number = await conn.fetchval(GET_WORLD, key) - - return HttpResponse.from_json( - {"id": key, "randomNumber": number}, - encode_bytes=orjson.dumps - ) - - -def get_query_count(request: HttpRequest): - try: - qs = parse_qs(request.scope["query_string"]) - num_queries = int(qs.get(b'queries', (1, ))[0]) - except ValueError: - num_queries = 1 - if num_queries < 1: - return 1 - if num_queries > 500: - return 500 - - return num_queries - - -async def handle_queries_request(request: HttpRequest) -> HttpResponse: - queries = get_query_count(request) - - worlds: List[Dict[str, Any]] = [] - async with app.info['db'].acquire() as conn: - pst = await conn.prepare(GET_WORLD) - for key in sample(range(1, 10000), queries): - number = await pst.fetchval(key) - worlds.append({"id": key, "randomNumber": number}) - - return HttpResponse.from_json( - worlds, - encode_bytes=orjson.dumps - ) - - -async def handle_updates_request(request: HttpRequest) -> HttpResponse: - queries = get_query_count(request) - updates = [(row_id, randint(1, 10000)) for row_id in sample(range(1, 10000), queries)] - updates.sort() - worlds = [{'id': row_id, 'randomNumber': number} for row_id, number in updates] - - async with app.info['db'].acquire() as connection: - statement = await connection.prepare(GET_WORLD) - for row_id, number in updates: - await statement.fetchval(row_id) - await connection.executemany(UPDATE_WORLD, updates) - - return HttpResponse.from_json( - worlds, - encode_bytes=orjson.dumps - ) - -async def handle_fortunes_request(request: HttpRequest) -> HttpResponse: - async with app.info['db'].acquire() as conn: - rows = await conn.fetch(GET_FORTUNES) - rows.append(ADDITIONAL_ROW) - rows.sort(key=lambda row: row[1]) - - return await Jinja2TemplateProvider.apply( - request, - "fortune.html", - { "fortunes": rows } - ) - -app = Application( - startup_handlers=[on_startup], - shutdown_handlers=[on_shutdown] -) - -here = os.path.abspath(os.path.dirname(__file__)) -env = jinja2.Environment( - loader=jinja2.FileSystemLoader(os.path.join(here, 'templates')), - autoescape=jinja2.select_autoescape(['html', 'xml']), - enable_async=True -) - -add_jinja2(app, env) - -app.http_router.add({"GET"}, "/json", handle_json_request) -app.http_router.add({"GET"}, "/plaintext", handle_plaintext_request) -app.http_router.add({"GET"}, "/db", handle_db_request) -app.http_router.add({"GET"}, "/queries", handle_queries_request) -app.http_router.add({"GET"}, "/updates", handle_updates_request) -app.http_router.add({"GET"}, "/fortunes", handle_fortunes_request) diff --git a/frameworks/Python/bareasgi/bareasgi.dockerfile b/frameworks/Python/bareasgi/bareasgi.dockerfile deleted file mode 100644 index 2306153b5c0..00000000000 --- a/frameworks/Python/bareasgi/bareasgi.dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM python:3.10 - -ADD ./ /bareasgi - -WORKDIR /bareasgi - -RUN pip install -r /bareasgi/requirements.txt - -EXPOSE 8080 - -CMD hypercorn app:app --config=file:hypercorn_conf.py diff --git a/frameworks/Python/bareasgi/benchmark_config.json b/frameworks/Python/bareasgi/benchmark_config.json deleted file mode 100755 index cb1521cc63d..00000000000 --- a/frameworks/Python/bareasgi/benchmark_config.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "framework": "bareasgi", - "tests": [ - { - "default": { - "json_url": "/json", - "plaintext_url": "/plaintext", - "fortune_url": "/fortunes", - "db_url": "/db", - "query_url": "/queries?queries=", - "update_url": "/updates?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "Postgres", - "framework": "bareasgi", - "language": "Python", - "flavor": "Python3", - "orm": "Raw", - "platform": "asyncio", - "webserver": "Hypercorn", - "os": "Linux", - "database_os": "Linux", - "display_name": "bareASGI", - "notes": "", - "versus": "None" - } - } - ] -} diff --git a/frameworks/Python/bareasgi/config.toml b/frameworks/Python/bareasgi/config.toml deleted file mode 100644 index 4f803119e49..00000000000 --- a/frameworks/Python/bareasgi/config.toml +++ /dev/null @@ -1,19 +0,0 @@ -[framework] -name = "bareasgi" - -[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/Python/bareasgi/hypercorn_conf.py b/frameworks/Python/bareasgi/hypercorn_conf.py deleted file mode 100644 index 79865d7583c..00000000000 --- a/frameworks/Python/bareasgi/hypercorn_conf.py +++ /dev/null @@ -1,13 +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"] -keep_alive_timeout = 120 -loglevel = "error" -worker_class = "uvloop" diff --git a/frameworks/Python/bareasgi/requirements.txt b/frameworks/Python/bareasgi/requirements.txt deleted file mode 100644 index 4a81ab13c0a..00000000000 --- a/frameworks/Python/bareasgi/requirements.txt +++ /dev/null @@ -1,17 +0,0 @@ -asyncpg==0.26.0 -bareasgi==4.3.0 -bareasgi-jinja2==4.0.1 -bareutils==4.0.2 -h11==0.14.0 -h2==4.1.0 -hpack==4.0.0 -hypercorn==0.14.3 -hyperframe==6.0.1 -jetblack-asgi-typing==0.4.0 -Jinja2==3.1.2 -MarkupSafe==2.1.1 -orjson==3.8.0 -priority==2.0.0 -toml==0.10.2 -uvloop==0.17.0 -wsproto==1.2.0 diff --git a/frameworks/Python/bareasgi/templates/fortune.html b/frameworks/Python/bareasgi/templates/fortune.html deleted file mode 100644 index 1c90834285d..00000000000 --- a/frameworks/Python/bareasgi/templates/fortune.html +++ /dev/null @@ -1,10 +0,0 @@ - - -Fortunes - - - -{% for fortune in fortunes %} -{% endfor %}
idmessage
{{ fortune[0] }}{{ fortune[1]|e }}
- - diff --git a/frameworks/Python/blacksheep/app-socketify.py b/frameworks/Python/blacksheep/app-socketify.py new file mode 100644 index 00000000000..d75fe084db3 --- /dev/null +++ b/frameworks/Python/blacksheep/app-socketify.py @@ -0,0 +1,141 @@ +import multiprocessing +import os +# import psycopg +import platform +import random +import asyncio +import blacksheep as bs +import jinja2 +from pathlib import Path +# from psycopg_pool import AsyncConnectionPool +import psqlpy +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 + +MAX_POOL_SIZE = min(CORE_COUNT * 2, MAX_DB_CONNECTIONS // CORE_COUNT, 35) +db_pool = None + +async def setup_db(app): + global db_pool + conninfo = ( + f"postgresql://{os.getenv('PGUSER', 'benchmarkdbuser')}:{os.getenv('PGPASS', 'benchmarkdbpass')}" + f"@tfb-database:5432/hello_world" + ) + db_pool = ( + ConnectionPoolBuilder() + .max_pool_size(MAX_POOL_SIZE) + .user(os.getenv('PGUSER', 'benchmarkdbuser')) + .password(os.getenv('PGPASS', 'benchmarkdbpass')) + .dbname("hello_world") + .host("tfb-database") + .port(5432) + .build() + ) + # await db_pool.open() + +async def shutdown_db(app): + global db_pool + if db_pool is not None: + await db_pool.close() + db_pool = None + +def load_fortunes_template(): + with Path("templates/fortune.html").open("r") as f: + return jinja2.Template(f.read()) + +fortune_template = load_fortunes_template() + +app = bs.Application() +app.on_start += setup_db +app.on_stop += shutdown_db + +def get_num_queries(request): + try: + value = request.query.get('queries') + if value is None: + return 1 + query_count = int(value[0]) + except (KeyError, IndexError, ValueError): + return 1 + return min(max(query_count, 1), 500) + +JSON_CONTENT_TYPE = b"application/json" + +@bs.get('/json') +async def json_test(request): + return bs.json({'message': 'Hello, world!'}) + +@bs.get('/db') +async def single_db_query_test(request): + row_id = random.randint(1, 10000) + async with db_pool.acquire() as connection: + number = await connection.fetch_val( + READ_ROW_SQL, [row_id] + ) + return bs.json({'id': row_id, 'randomNumber': number}) + +@bs.get('/queries') +async def multiple_db_queries_test(request): + num_queries = get_num_queries(request) + row_ids = random.sample(range(1, 10000), num_queries) + worlds = [] + async with db_pool.acquire() as connection: + for row_id in row_ids: + number = await connection.fetch_val( + READ_ROW_SQL, [row_id] + ) + worlds.append({"id": row_id, "randomNumber": number}) + return bs.json(worlds) + +@bs.get('/fortunes') +async def fortunes_test(request): + async with db_pool.acquire() as connection: + 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.sort(key=lambda row: row[1]) + data = fortune_template.render(fortunes=fortunes) + return bs.html(data) + +@bs.get('/updates') +async def db_updates_test(request): + num_queries = get_num_queries(request) + updates = sorted(zip( + random.sample(range(1, 10000), num_queries), + random.sample(range(1, 10000), num_queries) + ), key=lambda x: x[1]) + worlds = [{"id": row_id, "randomNumber": number} for row_id, number in updates] + async with db_pool.acquire() as connection: + for row_id, _ in updates: + await connection.fetch_val(READ_ROW_SQL, [row_id]) + # await db_conn.executemany(WRITE_ROW_SQL, updates) + await connection.execute_many(WRITE_ROW_SQL, updates) + return bs.json(worlds) + +@bs.get('/plaintext') +async def plaintext_test(request): + return bs.Response(200, content=bs.Content(b"text/plain", b'Hello, World!')) + +if platform.python_implementation() == 'PyPy': + import logging + from socketify import ASGI + workers = int(multiprocessing.cpu_count()) + if os.environ.get('TRAVIS') == 'true': + 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() + if not n > 0: + run_app() + + for i in range(1, workers): + create_fork() + run_app() \ No newline at end of file diff --git a/frameworks/Python/blacksheep/app.py b/frameworks/Python/blacksheep/app.py index b26474cb577..80dd48919e9 100644 --- a/frameworks/Python/blacksheep/app.py +++ b/frameworks/Python/blacksheep/app.py @@ -1,72 +1,58 @@ +import multiprocessing import os -import ujson import asyncpg -import multiprocessing +import platform import random +import asyncio import blacksheep as bs import jinja2 -from email.utils import formatdate - +import msgspec +from pathlib import Path try: - from ujson import dumps as jsonify -except: - from json import dumps as jsonify - - -_is_travis = os.environ.get('TRAVIS') == 'true' - -_is_gunicorn = "gunicorn" in os.environ.get("SERVER_SOFTWARE", "") - -_cpu_count = multiprocessing.cpu_count() -if _is_travis: - _cpu_count = 2 - - -#from blacksheep.settings.json import json_settings -#json_settings.use(dumps=jsonify) - -DBDRV = "postgres" -DBHOST = "tfb-database" -DBUSER = "benchmarkdbuser" -DBPSWD = "benchmarkdbpass" + import uvloop + asyncio.set_event_loop_policy(uvloop.EventLoopPolicy()) +except Exception: + ... 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) +MAX_CONNECTIONS = 1900 +CORE_COUNT = multiprocessing.cpu_count() +MAX_POOL_SIZE = max(1,int(os.getenv('MAX_POOL_SIZE', MAX_CONNECTIONS // CORE_COUNT))) +MIN_POOL_SIZE = max(1,int(os.getenv('MIN_POOL_SIZE', MAX_POOL_SIZE // 2))) db_pool = None -g_response_server = None -g_response_add_date = False - - async def setup_db(app): global db_pool db_pool = await asyncpg.create_pool( - user=os.getenv('PGUSER', DBUSER), - password=os.getenv('PGPASS', DBPSWD), + user=os.getenv('PGUSER', "benchmarkdbuser"), + password=os.getenv('PGPASS', "benchmarkdbpass"), database='hello_world', - host=DBHOST, + host="tfb-database", port=5432, min_size=MIN_POOL_SIZE, - max_size=MAX_POOL_SIZE, + max_size=MAX_POOL_SIZE, ) +async def shutdown_db(app): + """Close asyncpg connection pool for the current process.""" + global db_pool + if db_pool is not None: + await db_pool.close() + db_pool = None def load_fortunes_template(): - path = os.path.join('templates', 'fortune.html') - with open(path, 'r') as template_file: - template_text = template_file.read() - return jinja2.Template(template_text) + with Path("templates/fortune.html").open("r") as f: + return jinja2.Template(f.read()) fortune_template = load_fortunes_template() app = bs.Application() app.on_start += setup_db - +app.on_stop += shutdown_db def get_num_queries(request): try: @@ -76,135 +62,105 @@ def get_num_queries(request): query_count = int(value[0]) except (KeyError, IndexError, ValueError): return 1 - if query_count < 1: - return 1 - if query_count > 500: - return 500 - return query_count + return min(max(query_count, 1), 500) + +ENCODER = msgspec.json.Encoder() +JSON_CONTENT_TYPE = b"application/json" +def jsonify( + data, + status=200, + headers=None, +): + """ + Returns a response with application/json content, + and given status (default HTTP 200 OK). + """ + return bs.Response( + status=status, + headers=headers, + content=bs.Content(content_type=JSON_CONTENT_TYPE, data=ENCODER.encode(data)), + ) +class Result(msgspec.Struct): + id: int + randomNumber: int # ------------------------------------------------------------------------------------------ -async def bs_middleware(request, handler): - global g_response_server, g_response_add_date - response = await handler(request) - if g_response_server: - response.headers[b'Server'] = g_response_server - if g_response_add_date: - response.headers[b'Date'] = formatdate(timeval=None, localtime=False, usegmt=True) - return response - - -@app.route('/json') +@bs.get('/json') async def json_test(request): - return bs.json( {'message': 'Hello, world!'} ) + return jsonify( {'message': 'Hello, world!'} ) - -@app.route('/db') +@bs.get('/db') async def single_db_query_test(request): row_id = random.randint(1, 10000) async with db_pool.acquire() as db_conn: number = await db_conn.fetchval(READ_ROW_SQL, row_id) - world = {'id': row_id, 'randomNumber': number} - return bs.json(world) + return jsonify(Result(id=row_id, randomNumber=number)) + # return ({'id': row_id, 'randomNumber': number}) -@app.route('/queries') +@bs.get('/queries') async def multiple_db_queries_test(request): num_queries = get_num_queries(request) row_ids = random.sample(range(1, 10000), num_queries) - worlds = [ ] + worlds = [] async with db_pool.acquire() as db_conn: statement = await db_conn.prepare(READ_ROW_SQL) for row_id in row_ids: number = await statement.fetchval(row_id) - worlds.append( {"id": row_id, "randomNumber": number} ) + # worlds.append( {"id": row_id, "randomNumber": number} ) + worlds.append(Result(id=row_id, randomNumber=number)) - return bs.json(worlds) + return jsonify(worlds) -@app.route('/fortunes') +@bs.get('/fortunes') 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.sort(key = lambda row: row[1]) + fortunes.sort(key=lambda row: row[1]) data = fortune_template.render(fortunes=fortunes) return bs.html(data) -@app.route('/updates') +@bs.get('/updates') async def db_updates_test(request): num_queries = get_num_queries(request) - ids = sorted(random.sample(range(1, 10000 + 1), num_queries)) - numbers = sorted(random.sample(range(1, 10000), num_queries)) - updates = list(zip(ids, numbers)) - - worlds = [ {"id": row_id, "randomNumber": number} for row_id, number in updates ] - + updates = list(zip( + random.sample(range(1, 10000), num_queries), + sorted(random.sample(range(1, 10000), num_queries)) + )) + worlds = [Result(id=row_id, randomNumber=number) for row_id, number in updates] + # worlds = [ {"id": row_id, "randomNumber": number} for row_id, number in updates ] async with db_pool.acquire() as db_conn: statement = await db_conn.prepare(READ_ROW_SQL) for row_id, _ in updates: await statement.fetchval(row_id) await db_conn.executemany(WRITE_ROW_SQL, updates) - - return bs.json(worlds) + return jsonify(worlds) -@app.route('/plaintext') +@bs.get('/plaintext') async def plaintext_test(request): return bs.Response(200, content=bs.Content(b"text/plain", b'Hello, World!')) #return bs.text('Hello, World!') -# ----------------------------------------------------------------------------------- - -if __name__ == "__main__": - import optparse - import logging - import re - - 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="uvicorn", 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() - - workers = _cpu_count - if workers > 0: - workers = opt.workers - +if platform.python_implementation() == 'PyPy': + from socketify import ASGI + workers = int(multiprocessing.cpu_count()) if _is_travis: workers = 2 def run_app(): - global g_response_server, g_response_add_date - - if opt.gateway == "uvicorn": - import uvicorn - log_level = logging.ERROR - uvicorn.run(app, host=opt.host, port=opt.port, workers=1, loop="uvloop", log_level=log_level, access_log=False) - - if opt.server == 'fastwsgi': - import fastwsgi - from blacksheep.utils.aio import get_running_loop - g_response_server = b'FastWSGI' - app.middlewares.append(bs_middleware) - loop = get_running_loop() - loop.run_until_complete(app.start()) - fastwsgi.run(app, host=opt.host, port=opt.port, loglevel=opt.verbose) - - if opt.server == 'socketify': - import socketify - msg = "Listening on http://0.0.0.0:{port} now\n".format(port=opt.port) - socketify.WSGI(app).listen(opt.port, lambda config: logging.info(msg)).run() + 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() @@ -212,9 +168,9 @@ def create_fork(): 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 :) - + run_app() \ No newline at end of file diff --git a/frameworks/Python/blacksheep/benchmark_config.json b/frameworks/Python/blacksheep/benchmark_config.json index 7fc1dd7a3a5..db211d08363 100644 --- a/frameworks/Python/blacksheep/benchmark_config.json +++ b/frameworks/Python/blacksheep/benchmark_config.json @@ -23,6 +23,52 @@ "display_name": "blacksheep", "versus": "None", "notes": "" + }, + "nginx-unit": { + "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": "Micro", + "framework": "blacksheep", + "language": "Python", + "flavor": "Python3", + "platform": "ASGI", + "webserver": "nginx-unit", + "os": "Linux", + "orm": "Raw", + "database_os": "Linux", + "database": "Postgres", + "display_name": "blacksheep-nginx-unit", + "versus": "None", + "notes": "" + }, + "pypy-socketify": { + "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": "Micro", + "framework": "blacksheep", + "language": "Python", + "flavor": "Python3", + "platform": "ASGI", + "webserver": "Socketify.py", + "os": "Linux", + "orm": "Raw", + "database_os": "Linux", + "database": "Postgres", + "display_name": "Blacksheep [Socketify.py PyPy3]", + "versus": "None", + "notes": "" } }] } diff --git a/frameworks/Python/blacksheep/blacksheep-nginx-unit.dockerfile b/frameworks/Python/blacksheep/blacksheep-nginx-unit.dockerfile new file mode 100644 index 00000000000..3014ba7cfdb --- /dev/null +++ b/frameworks/Python/blacksheep/blacksheep-nginx-unit.dockerfile @@ -0,0 +1,23 @@ +FROM unit:python3.13-slim + +WORKDIR /blacksheep + +COPY ./ /blacksheep + +RUN apt-get update; apt-get install libuv1 -y + +RUN pip3 install -U pip -q +RUN pip3 install Cython==3.0.12 -q +RUN pip3 install -r /blacksheep/requirements.txt -q +RUN pip3 install -r /blacksheep/requirements-uvicorn.txt -q + +ENV PGSSLMODE=disable +RUN CORE_COUNT=$(nproc) && \ + sed -i "s|\"processes\": [0-9]*|\"processes\": $CORE_COUNT|g" /blacksheep/unit-config.json + +RUN chmod +x start-unit.sh +ENTRYPOINT [] +EXPOSE 8080 + +# CMD ["unitd", "--no-daemon", "--control", "unix:/var/run/control.unit.sock"] +CMD ["./start-unit.sh"] \ No newline at end of file diff --git a/frameworks/Python/blacksheep/blacksheep-pypy-socketify.dockerfile b/frameworks/Python/blacksheep/blacksheep-pypy-socketify.dockerfile new file mode 100644 index 00000000000..b730747562f --- /dev/null +++ b/frameworks/Python/blacksheep/blacksheep-pypy-socketify.dockerfile @@ -0,0 +1,15 @@ +FROM pypy:3.11-bookworm + +ADD ./ /blacksheep + +WORKDIR /blacksheep + +RUN apt-get update; apt-get install libuv1 libpq5 -y + +RUN pip3 install -r /blacksheep/requirements.txt +RUN pip3 install -r /blacksheep/requirements-pypy.txt + +EXPOSE 8080 + +CMD python ./app-socketify.py + diff --git a/frameworks/Python/blacksheep/blacksheep.dockerfile b/frameworks/Python/blacksheep/blacksheep.dockerfile index f382fad20bb..9948bd51766 100644 --- a/frameworks/Python/blacksheep/blacksheep.dockerfile +++ b/frameworks/Python/blacksheep/blacksheep.dockerfile @@ -1,15 +1,16 @@ -FROM python:3.11-bullseye +FROM python:3.13 WORKDIR /blacksheep COPY ./ /blacksheep -RUN pip3 install -U pip -RUN pip3 install cython==0.29.34 -RUN pip3 install -r /blacksheep/requirements.txt -RUN pip3 install -r /blacksheep/requirements-gunicorn.txt -RUN pip3 install -r /blacksheep/requirements-uvicorn.txt +RUN apt-get update; apt-get install libuv1 -y +RUN pip3 install -U pip -q +RUN pip3 install Cython==3.0.12 -q +RUN pip3 install -r /blacksheep/requirements.txt -q +RUN pip3 install -r /blacksheep/requirements-uvicorn.txt -q +ENV GUNICORN=1 EXPOSE 8080 -CMD gunicorn app:app -k uvicorn.workers.UvicornWorker -c blacksheep_conf.py +CMD gunicorn app:app -k uvicorn_worker.UvicornWorker -c blacksheep_conf.py diff --git a/frameworks/Python/blacksheep/blacksheep_conf.py b/frameworks/Python/blacksheep/blacksheep_conf.py index 4f4e08a729e..7324c9efddb 100644 --- a/frameworks/Python/blacksheep/blacksheep_conf.py +++ b/frameworks/Python/blacksheep/blacksheep_conf.py @@ -2,13 +2,18 @@ import os _is_travis = os.environ.get('TRAVIS') == 'true' +CPU_CORES = multiprocessing.cpu_count() +MAX_CONNECTIONS = 1900 +CONNECTIONS_PER_WORKER = 100 +max_pg_workers = MAX_CONNECTIONS // CONNECTIONS_PER_WORKER -workers = multiprocessing.cpu_count() +workers = CPU_CORES if _is_travis: workers = 2 bind = "0.0.0.0:8080" -keepalive = 120 +keepalive = 1 +timeout = 0 errorlog = '-' pidfile = '/tmp/blacksheep.pid' loglevel = 'error' diff --git a/frameworks/Python/blacksheep/config.toml b/frameworks/Python/blacksheep/config.toml index 287c64b64a8..ea30e9cad43 100644 --- a/frameworks/Python/blacksheep/config.toml +++ b/frameworks/Python/blacksheep/config.toml @@ -17,3 +17,39 @@ orm = "Raw" platform = "ASGI" webserver = "uvicorn" 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 = "Platform" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "ASGI" +webserver = "nginx-unit" +versus = "None" + + +[pypy-socketify] +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 = "ASGI" +webserver = "Socketify.py" +versus = "None" diff --git a/frameworks/Python/blacksheep/requirements-gunicorn.txt b/frameworks/Python/blacksheep/requirements-gunicorn.txt deleted file mode 100644 index 9d41f264a67..00000000000 --- a/frameworks/Python/blacksheep/requirements-gunicorn.txt +++ /dev/null @@ -1 +0,0 @@ -gunicorn==20.1.0 diff --git a/frameworks/Python/blacksheep/requirements-hypercorn.txt b/frameworks/Python/blacksheep/requirements-hypercorn.txt deleted file mode 100644 index 3d99222e2c6..00000000000 --- a/frameworks/Python/blacksheep/requirements-hypercorn.txt +++ /dev/null @@ -1 +0,0 @@ -hypercorn==0.14.3 diff --git a/frameworks/Python/blacksheep/requirements-pypy.txt b/frameworks/Python/blacksheep/requirements-pypy.txt new file mode 100644 index 00000000000..217009599a2 --- /dev/null +++ b/frameworks/Python/blacksheep/requirements-pypy.txt @@ -0,0 +1,3 @@ +psqlpy +git+https://github.com/cirospaciari/socketify.py.git@main#egg=socketify +h11 \ No newline at end of file diff --git a/frameworks/Python/blacksheep/requirements-uvicorn.txt b/frameworks/Python/blacksheep/requirements-uvicorn.txt index 108304a1202..4784617228a 100644 --- a/frameworks/Python/blacksheep/requirements-uvicorn.txt +++ b/frameworks/Python/blacksheep/requirements-uvicorn.txt @@ -1,3 +1,7 @@ -uvloop==0.17.0 -uvicorn==0.21.1 -httptools==0.5.0 +uvloop==0.21.0 +uvicorn==0.34.2 +uvicorn-worker +httptools==0.6.4 +gunicorn==23.0.0 +msgspec==0.19.0 +asyncpg==0.30.0 \ No newline at end of file diff --git a/frameworks/Python/blacksheep/requirements.txt b/frameworks/Python/blacksheep/requirements.txt index c1a8d3d22a3..12af6e9f9b2 100644 --- a/frameworks/Python/blacksheep/requirements.txt +++ b/frameworks/Python/blacksheep/requirements.txt @@ -1,4 +1,3 @@ -asyncpg==0.27.0 -Jinja2==3.1.2 -blacksheep==1.2.13 -ujson==5.7.0 +Jinja2==3.1.6 +blacksheep==2.3.1 +psycopg \ No newline at end of file diff --git a/frameworks/Python/blacksheep/start-unit.sh b/frameworks/Python/blacksheep/start-unit.sh new file mode 100644 index 00000000000..016ee8c1020 --- /dev/null +++ b/frameworks/Python/blacksheep/start-unit.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +CORE_COUNT=$(nproc) +sysctl -w net.core.somaxconn=65535 +sysctl -w net.ipv4.tcp_max_syn_backlog=65535 +ulimit -n 65535 +taskset -c 0-$(($CORE_COUNT-1)) unitd --no-daemon --control unix:/var/run/control.unit.sock & + +# unitd --no-daemon --control unix:/var/run/control.unit.sock & + +# wait UNIT started +sleep 1 + +# PUT configure +curl -X PUT \ + --data-binary @unit-config.json \ + --unix-socket /var/run/control.unit.sock \ + http://localhost/config + +# Then keep the container alive +wait \ No newline at end of file diff --git a/frameworks/Python/blacksheep/unit-config.json b/frameworks/Python/blacksheep/unit-config.json new file mode 100644 index 00000000000..186d581296f --- /dev/null +++ b/frameworks/Python/blacksheep/unit-config.json @@ -0,0 +1,19 @@ +{ + "listeners": { + "*:8080": { + "pass": "applications/blacksheep" + } + }, + "applications": { + "blacksheep": { + "type": "python", + "path": "/blacksheep", + "working_directory": "/blacksheep", + "processes": 14, + "protocol": "asgi", + "module": "app", + "callable": "app" + } + }, + "access_log": "/dev/null" +} \ No newline at end of file diff --git a/frameworks/Python/bottle/benchmark_config.json b/frameworks/Python/bottle/benchmark_config.json index e37735b8353..c895cf1e4e7 100644 --- a/frameworks/Python/bottle/benchmark_config.json +++ b/frameworks/Python/bottle/benchmark_config.json @@ -45,7 +45,8 @@ "database_os": "Linux", "display_name": "Bottle", "notes": "PyPy2", - "versus": "wsgi" + "versus": "wsgi", + "tags": ["broken"] }, "raw": { "db_url": "/raw-db", diff --git a/frameworks/Python/bottle/bottle-raw.dockerfile b/frameworks/Python/bottle/bottle-raw.dockerfile index 24a59598829..8ba573a7a2b 100644 --- a/frameworks/Python/bottle/bottle-raw.dockerfile +++ b/frameworks/Python/bottle/bottle-raw.dockerfile @@ -1,4 +1,4 @@ -FROM python:3.6.6-stretch +FROM python:3.9-bookworm WORKDIR /bottle COPY views views diff --git a/frameworks/Python/bottle/bottle.dockerfile b/frameworks/Python/bottle/bottle.dockerfile index 24a59598829..8ba573a7a2b 100644 --- a/frameworks/Python/bottle/bottle.dockerfile +++ b/frameworks/Python/bottle/bottle.dockerfile @@ -1,4 +1,4 @@ -FROM python:3.6.6-stretch +FROM python:3.9-bookworm WORKDIR /bottle COPY views views diff --git a/frameworks/Python/bottle/requirements-pypy.txt b/frameworks/Python/bottle/requirements-pypy.txt index c42dadb2ef0..0e66864a04e 100644 --- a/frameworks/Python/bottle/requirements-pypy.txt +++ b/frameworks/Python/bottle/requirements-pypy.txt @@ -1,6 +1,6 @@ bottle==0.12.19 bottle-sqlalchemy==0.4.3 -gunicorn==19.9.0 +gunicorn==23.0.0 PyMySQL==0.8.0 SQLAlchemy==1.3.0 -tornado==4.5.3 +tornado==6.5 diff --git a/frameworks/Python/bottle/requirements.txt b/frameworks/Python/bottle/requirements.txt index 75f9c033488..b5dd9bbd4c5 100644 --- a/frameworks/Python/bottle/requirements.txt +++ b/frameworks/Python/bottle/requirements.txt @@ -1,8 +1,8 @@ -bottle==0.12.19 +bottle==0.12.25 bottle-sqlalchemy==0.4.3 -greenlet==0.4.14 -gunicorn==19.9.0 -meinheld==0.6.1 +greenlet==0.4.17 +gunicorn==23.0.0 +meinheld==1.0.2 mysqlclient==1.3.12 SQLAlchemy==1.3.0 ujson==1.35 diff --git a/frameworks/Python/cherrypy/app.py b/frameworks/Python/cherrypy/app.py index bf090cfd69b..d92177d379c 100755 --- a/frameworks/Python/cherrypy/app.py +++ b/frameworks/Python/cherrypy/app.py @@ -153,8 +153,8 @@ def fortunes(self): cherrypy.tools.db = SATool() cherrypy.server.socket_host = '0.0.0.0' cherrypy.server.socket_port = 8080 - cherrypy.server.thread_pool = workers - cherrypy.server.socket_queue_size = 25 + cherrypy.server.thread_pool = workers * 2 + cherrypy.server.socket_queue_size = 100 cherrypy.quickstart(CherryPyBenchmark(), '', { '/': { diff --git a/frameworks/Python/cherrypy/benchmark_config.json b/frameworks/Python/cherrypy/benchmark_config.json index 62e51834960..9d4f3c1c8ef 100644 --- a/frameworks/Python/cherrypy/benchmark_config.json +++ b/frameworks/Python/cherrypy/benchmark_config.json @@ -2,29 +2,6 @@ "framework": "cherrypy", "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": "MySQL", - "framework": "None", - "language": "Python", - "flavor": "Python2", - "orm": "Full", - "platform": "None", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "CherryPy [py2]", - "notes": "CPython 2.7", - "tags": ["broken"] - }, - "py3": { "json_url": "/json", "db_url": "/db", "query_url": "/queries?queries=", @@ -44,7 +21,7 @@ "os": "Linux", "database_os": "Linux", "display_name": "CherryPy", - "notes": "CPython 3.9" + "notes": "CPython 3.13" } }] } diff --git a/frameworks/Python/cherrypy/cherrypy-py3.dockerfile b/frameworks/Python/cherrypy/cherrypy-py3.dockerfile deleted file mode 100644 index 8a8af2211d8..00000000000 --- a/frameworks/Python/cherrypy/cherrypy-py3.dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM python:3.9-bullseye - -ADD ./ /cherrypy - -WORKDIR /cherrypy - -RUN pip3 install -r /cherrypy/requirements.txt - -EXPOSE 8080 - -CMD python3 app.py diff --git a/frameworks/Python/cherrypy/cherrypy.dockerfile b/frameworks/Python/cherrypy/cherrypy.dockerfile index ccf988da6a6..eae3768b5fe 100644 --- a/frameworks/Python/cherrypy/cherrypy.dockerfile +++ b/frameworks/Python/cherrypy/cherrypy.dockerfile @@ -1,11 +1,11 @@ -FROM python:2.7.15-stretch +FROM python:3.13-bullseye ADD ./ /cherrypy WORKDIR /cherrypy -RUN pip install -r /cherrypy/requirements.txt +RUN pip3 install -r /cherrypy/requirements.txt EXPOSE 8080 -CMD python app.py +CMD python3 app.py diff --git a/frameworks/Python/cherrypy/requirements.txt b/frameworks/Python/cherrypy/requirements.txt index fc63cbf2a2a..f71069db433 100644 --- a/frameworks/Python/cherrypy/requirements.txt +++ b/frameworks/Python/cherrypy/requirements.txt @@ -1,10 +1,6 @@ -cheroot==8.6.0 -CherryPy==17.4.2 ; python_version=='2.7' CherryPy==18.8.0 ; python_version>'3.5' -more-itertools==4.1.0 -mysqlclient==1.3.12 -portend==2.2 -pytz==2017.3 -six==1.11.0 -SQLAlchemy==1.4.47 -tempora==1.10 +mysqlclient==2.2.4 +pytz==2024.1 +SQLAlchemy==1.4.53 +six==1.17.0 +legacy-cgi==2.6.4 \ No newline at end of file diff --git a/frameworks/Python/crax/README.md b/frameworks/Python/crax/README.md deleted file mode 100644 index ffb69935b57..00000000000 --- a/frameworks/Python/crax/README.md +++ /dev/null @@ -1,22 +0,0 @@ -# [Crax](https://crax.wiki/) Benchmark Test - -This is the Crax portion of a [benchmarking tests suite](../../) -comparing a variety of web development platforms. - -The information below is specific to Crax. 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 - -[Crax](https://github.com/crax-framework/crax) is a framework or a pack of tools for web development. - -## Test Paths & Sources - -All of the test implementations are located within a single file ([app.py](hello/app.py)). - -## Resources - -* [Crax on GitHub](https://github.com/crax-framework/crax) -* [Crax Wiki](https://crax.wiki/) diff --git a/frameworks/Python/crax/benchmark_config.json b/frameworks/Python/crax/benchmark_config.json deleted file mode 100644 index a461cd62fab..00000000000 --- a/frameworks/Python/crax/benchmark_config.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "framework": "crax", - "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": "micro", - "framework": "crax", - "language": "Python", - "flavor": "Python3", - "platform": "None", - "webserver": "None", - "os": "Linux", - "orm": "Raw", - "database_os": "Linux", - "database": "Postgres", - "display_name": "Crax", - "notes": "" - } - }] -} \ No newline at end of file diff --git a/frameworks/Python/crax/config.toml b/frameworks/Python/crax/config.toml deleted file mode 100644 index b640dfaac07..00000000000 --- a/frameworks/Python/crax/config.toml +++ /dev/null @@ -1,19 +0,0 @@ -[framework] -name = "crax" - -[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/Python/crax/crax.dockerfile b/frameworks/Python/crax/crax.dockerfile deleted file mode 100644 index 4b33e3a0fb6..00000000000 --- a/frameworks/Python/crax/crax.dockerfile +++ /dev/null @@ -1,12 +0,0 @@ -FROM python:3.8 - -ADD ./ /crax - -WORKDIR /crax - -RUN pip3 install cython==0.29.13 && \ - pip3 install -r /crax/requirements.txt - -EXPOSE 8080 - -CMD gunicorn hello.app:app -k uvicorn.workers.UvicornWorker -c crax_conf.py \ No newline at end of file diff --git a/frameworks/Python/crax/crax_conf.py b/frameworks/Python/crax/crax_conf.py deleted file mode 100644 index 042c7445e6d..00000000000 --- a/frameworks/Python/crax/crax_conf.py +++ /dev/null @@ -1,14 +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/crax.pid' -loglevel = 'error' diff --git a/frameworks/Python/crax/hello/app.py b/frameworks/Python/crax/hello/app.py deleted file mode 100644 index 718489d18a1..00000000000 --- a/frameworks/Python/crax/hello/app.py +++ /dev/null @@ -1,90 +0,0 @@ -import os -from operator import itemgetter -from random import randint -import asyncpg -from crax import Crax -from crax.response_types import BaseResponse, JSONResponse -from crax.urls import Route, Url -from crax.views import JSONView, TemplateView - -READ_ROW_SQL = 'SELECT "id", "randomnumber" FROM "world" WHERE id = $1' -WRITE_ROW_SQL = 'UPDATE "world" SET "randomnumber"=$1 WHERE id=$2' - - -async def setup_database(): - global connection_pool - connection_pool = await asyncpg.create_pool( - user=os.getenv('PGUSER', 'benchmarkdbuser'), - password=os.getenv('PGPASS', 'benchmarkdbpass'), - database='hello_world', - host='tfb-database', - port=5432 - ) - - -def get_num_queries(request): - try: - query_count = int(request.query["queries"][0]) - except (KeyError, IndexError, ValueError): - return 1 - if query_count < 1: - return 1 - if query_count > 500: - return 500 - return query_count - - -class TestSingleQuery(JSONView): - async def get(self): - row_id = randint(1, 10000) - async with connection_pool.acquire() as connection: - if self.request.path == '/db': - res = await connection.fetchval(READ_ROW_SQL, row_id) - self.context = {'id': row_id, 'randomNumber': res} - - -class TestMultiQueries(JSONView): - async def get(self): - row_ids = [randint(1, 10000) for _ in range(get_num_queries(self.request))] - worlds = [] - async with connection_pool.acquire() as connection: - statement = await connection.prepare(READ_ROW_SQL) - for row_id in row_ids: - number = await statement.fetchval(row_id) - worlds.append({'id': row_id, 'randomNumber': number}) - self.context = worlds - - -class TestUpdates(JSONView): - async def get(self): - updates = [(randint(1, 10000), randint(1, 10000)) for _ in range(get_num_queries(self.request))] - worlds = [{'id': row_id, 'randomNumber': number} for row_id, number in updates] - async with connection_pool.acquire() as connection: - statement = await connection.prepare(READ_ROW_SQL) - for row_id, number in updates: - await statement.fetchval(row_id) - await connection.executemany(WRITE_ROW_SQL, updates) - self.context = worlds - - -class TestSingleFortunes(TemplateView): - template = "fortune.html" - - async def get(self): - async with connection_pool.acquire() as connection: - fortunes = await connection.fetch('SELECT * FROM Fortune') - fortunes.append([0, 'Additional fortune added at request time.']) - fortunes.sort(key=itemgetter(1)) - self.context["fortunes"] = fortunes - - -APPLICATIONS = ["hello"] -URL_PATTERNS = [ - Route(Url('/json'), JSONResponse(None, {'message': 'Hello, world!'})), - Route(Url('/plaintext'), BaseResponse(None, b'Hello, world!')), - Route(Url('/db'), TestSingleQuery), - Route(Url('/queries'), TestMultiQueries), - Route(Url('/updates'), TestUpdates), - Route(Url('/fortunes'), TestSingleFortunes) -] -app = Crax('hello.app', debug=True, on_startup=setup_database) diff --git a/frameworks/Python/crax/hello/templates/fortune.html b/frameworks/Python/crax/hello/templates/fortune.html deleted file mode 100644 index 4f0b3db447c..00000000000 --- a/frameworks/Python/crax/hello/templates/fortune.html +++ /dev/null @@ -1,10 +0,0 @@ - - -Fortunes - - - -{% for fortune in fortunes %} -{% endfor %}
idmessage
{{ fortune[0] }}{{ fortune[1]|e }}
- - \ No newline at end of file diff --git a/frameworks/Python/crax/requirements.txt b/frameworks/Python/crax/requirements.txt deleted file mode 100644 index 714d2fb4f27..00000000000 --- a/frameworks/Python/crax/requirements.txt +++ /dev/null @@ -1,5 +0,0 @@ -crax[postgresql]==0.1.5 -gunicorn==20.1.0 -uvloop==0.17.0 -uvicorn==0.20.0 -httptools==0.5.0 diff --git a/frameworks/Python/django/benchmark_config.json b/frameworks/Python/django/benchmark_config.json index 47ff6ff7135..c4e3d51a143 100644 --- a/frameworks/Python/django/benchmark_config.json +++ b/frameworks/Python/django/benchmark_config.json @@ -17,7 +17,7 @@ "flavor": "Python3", "orm": "Full", "platform": "WSGI", - "webserver": "Meinheld", + "webserver": "Gunicorn", "os": "Linux", "database_os": "Linux", "display_name": "Django", @@ -77,7 +77,7 @@ "flavor": "Python3", "orm": "Full", "platform": "WSGI", - "webserver": "Meinheld", + "webserver": "Gunicorn", "os": "Linux", "database_os": "Linux", "display_name": "Django [Postgres]", diff --git a/frameworks/Python/django/django-postgresql.dockerfile b/frameworks/Python/django/django-postgresql.dockerfile index 51870d2750d..ff554710097 100644 --- a/frameworks/Python/django/django-postgresql.dockerfile +++ b/frameworks/Python/django/django-postgresql.dockerfile @@ -1,4 +1,4 @@ -FROM python:3.9-bullseye +FROM python:3.12-bullseye ADD ./ /django diff --git a/frameworks/Python/django/django.dockerfile b/frameworks/Python/django/django.dockerfile index 261bd05fa12..a5b5182eabf 100644 --- a/frameworks/Python/django/django.dockerfile +++ b/frameworks/Python/django/django.dockerfile @@ -1,4 +1,4 @@ -FROM python:3.9-bullseye +FROM python:3.12-bullseye ADD ./ /django diff --git a/frameworks/Python/django/gunicorn_conf.py b/frameworks/Python/django/gunicorn_conf.py index 356e04d1d4a..c6848f685b7 100644 --- a/frameworks/Python/django/gunicorn_conf.py +++ b/frameworks/Python/django/gunicorn_conf.py @@ -5,7 +5,7 @@ _is_pypy = hasattr(sys, 'pypy_version_info') _is_travis = os.environ.get('TRAVIS') == 'true' -workers = int(multiprocessing.cpu_count() * 2.5) +workers = int(multiprocessing.cpu_count()) if _is_travis: workers = 2 @@ -14,16 +14,4 @@ errorlog = '-' pidfile = 'gunicorn.pid' pythonpath = 'hello' - -if _is_pypy: - worker_class = "sync" -else: - worker_class = "meinheld.gmeinheld.MeinheldWorker" - - def post_fork(server, worker): - import meinheld - import meinheld.server - import meinheld.patch - meinheld.server.set_access_logger(None) - meinheld.set_keepalive(keepalive) - meinheld.patch.patch_all() +worker_class = 'sync' \ No newline at end of file diff --git a/frameworks/Python/django/requirements-gunicorn.txt b/frameworks/Python/django/requirements-gunicorn.txt index 4dae00dbf65..7ec2e47c136 100644 --- a/frameworks/Python/django/requirements-gunicorn.txt +++ b/frameworks/Python/django/requirements-gunicorn.txt @@ -1,4 +1,4 @@ -r requirements.txt -greenlet==0.4.17 -gunicorn==20.1.0 -meinheld==1.0.2 +greenlet==3.1.1 +gunicorn==21.2.0 +gevent==24.10.2 \ No newline at end of file diff --git a/frameworks/Python/django/requirements.txt b/frameworks/Python/django/requirements.txt index a337c00f8d9..c7765c2c549 100644 --- a/frameworks/Python/django/requirements.txt +++ b/frameworks/Python/django/requirements.txt @@ -1,6 +1,5 @@ -Django==3.2.23 -mysqlclient==1.4.6 -psycopg2==2.9.6; implementation_name=='cpython' -psycopg2cffi==2.9.0; implementation_name=='pypy' -pytz==2020.4 -ujson==5.4.0 +Django==3.2.25 +mysqlclient==2.2.6 +psycopg2==2.9.9; implementation_name=='cpython' +pytz==2023.2 +ujson==5.8.0 diff --git a/frameworks/Python/emmett/app.py b/frameworks/Python/emmett/app.py index 50a942ce7ad..7d012fe70b3 100644 --- a/frameworks/Python/emmett/app.py +++ b/frameworks/Python/emmett/app.py @@ -32,7 +32,7 @@ def _serialize(self, row): app.config.db.user = 'benchmarkdbuser' app.config.db.password = 'benchmarkdbpass' app.config.db.database = 'hello_world' -app.config.db.pool_size = 10 +app.config.db.pool_size = 16 db = Database(app) db.define_models(World, Fortune) diff --git a/frameworks/Python/emmett/requirements.txt b/frameworks/Python/emmett/requirements.txt index 2c329705017..c322f0a38a1 100644 --- a/frameworks/Python/emmett/requirements.txt +++ b/frameworks/Python/emmett/requirements.txt @@ -1,2 +1,2 @@ -emmett[orjson]>=2.5.3,<2.6.0 -psycopg2-binary==2.9.5 +emmett[orjson,uvloop]>=2.7.0,<2.8.0 +psycopg2-binary==2.9.9 diff --git a/frameworks/Python/emmett/run.py b/frameworks/Python/emmett/run.py index 658eadb7d5f..258b6d87ba0 100644 --- a/frameworks/Python/emmett/run.py +++ b/frameworks/Python/emmett/run.py @@ -1,20 +1,20 @@ import multiprocessing -from emmett.server import run +from emmett_core.server import run if __name__ == "__main__": - cpus = multiprocessing.cpu_count() + workers = multiprocessing.cpu_count() run( "rsgi", ("app", "app"), host="0.0.0.0", port=8080, - workers=cpus, - threads=2, - backlog=2048, - threading_mode='runtime', + workers=workers, + backlog=16384, + runtime_mode="mt", + http="1", enable_websockets=False, log_level="warn" ) diff --git a/frameworks/Python/emmett55/README.md b/frameworks/Python/emmett55/README.md new file mode 100644 index 00000000000..0e36619cfc8 --- /dev/null +++ b/frameworks/Python/emmett55/README.md @@ -0,0 +1,26 @@ +# Emmett55 Benchmark Test + +This is the Emmett55 portion of a [benchmarking tests suite](../../) comparing a variety of web development platforms. + +The information below is specific to Emmett55. 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 + +[Emmett55](https://github.com/emmett-framework/emmett55) is a Python asyncIO micro web framework. + +## Test Paths & Source + +* [JSON Serialization](app.py): "/json" +* [Single Database Query](app.py): "/db" +* [Multiple Database Queries](app.py): "queries?queries=#" +* [Fortunes](app.py): "/fortunes" +* [Database Updates](app.py): "updates?queries=#" +* [Plaintext](app.py): "/plaintext" + +*Replace # with an actual number.* + +### Resources + +* [Github repository](https://github.com/emmett-framework/emmett55) diff --git a/frameworks/Python/emmett55/app.py b/frameworks/Python/emmett55/app.py new file mode 100644 index 00000000000..e417e8f75fa --- /dev/null +++ b/frameworks/Python/emmett55/app.py @@ -0,0 +1,129 @@ +import os +from operator import itemgetter +from random import randint, sample + +import asyncpg +from emmett55 import App, Pipe, current, request, response +from emmett55.extensions import Extension, Signals, listen_signal +from emmett55.tools import service +from renoir import Renoir + + +class AsyncPG(Extension): + __slots__ = ["pool"] + + def on_load(self): + self.pool = None + self.pipe = AsyncPGPipe(self) + + async def build_pool(self): + self.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=16, + max_size=16, + max_queries=64_000_000_000, + max_inactive_connection_lifetime=0 + ) + + @listen_signal(Signals.after_loop) + def _init_pool(self, loop): + loop.run_until_complete(self.build_pool()) + + +class AsyncPGPipe(Pipe): + __slots__ = ["ext"] + + def __init__(self, ext): + self.ext = ext + + async def open(self): + conn = current._db_conn = self.ext.pool.acquire() + current.db = await conn.__aenter__() + + async def close(self): + await current._db_conn.__aexit__() + + +app = App(__name__) +app.config.handle_static = False +templates = Renoir() + +db_ext = app.use_extension(AsyncPG) + +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) + + +@app.route() +@service.json +async def json(): + return {'message': 'Hello, World!'} + + +@app.route("/db", pipeline=[db_ext.pipe]) +@service.json +async def get_random_world(): + row_id = randint(1, 10000) + number = await current.db.fetchval(SQL_SELECT, row_id) + return {'id': row_id, 'randomNumber': number} + + +def get_qparam(): + try: + rv = int(request.query_params.queries or 1) + except ValueError: + return 1 + if rv < 1: + return 1 + if rv > 500: + return 500 + return rv + + +@app.route("/queries", pipeline=[db_ext.pipe]) +@service.json +async def get_random_worlds(): + num_queries = get_qparam() + row_ids = sample(range(1, 10000), num_queries) + worlds = [] + statement = await current.db.prepare(SQL_SELECT) + for row_id in row_ids: + number = await statement.fetchval(row_id) + worlds.append({'id': row_id, 'randomNumber': number}) + return worlds + + +@app.route(pipeline=[db_ext.pipe], output='str') +async def fortunes(): + response.content_type = "text/html; charset=utf-8" + fortunes = await current.db.fetch('SELECT * FROM Fortune') + fortunes.append(ROW_ADD) + fortunes.sort(key=sort_key) + return templates.render("templates/fortunes.html", {"fortunes": fortunes}) + + +@app.route(pipeline=[db_ext.pipe]) +@service.json +async def updates(): + num_queries = get_qparam() + 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] + statement = await current.db.prepare(SQL_SELECT) + for row_id, _ in updates: + await statement.fetchval(row_id) + await current.db.executemany(SQL_UPDATE, updates) + return worlds + + +@app.route(output='bytes') +async def plaintext(): + return b'Hello, World!' diff --git a/frameworks/Python/emmett55/benchmark_config.json b/frameworks/Python/emmett55/benchmark_config.json new file mode 100644 index 00000000000..e842529efcb --- /dev/null +++ b/frameworks/Python/emmett55/benchmark_config.json @@ -0,0 +1,27 @@ +{ + "framework": "emmett55", + "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": "Emmett55", + "language": "Python", + "orm": "Raw", + "platform": "RSGI", + "webserver": "granian", + "os": "Linux", + "database_os": "Linux", + "display_name": "Emmett55", + "notes": "CPython 3.7", + "versus": "uvicorn" + } + }] +} diff --git a/frameworks/Python/emmett55/config.toml b/frameworks/Python/emmett55/config.toml new file mode 100644 index 00000000000..11586c4e530 --- /dev/null +++ b/frameworks/Python/emmett55/config.toml @@ -0,0 +1,19 @@ +[framework] +name = "emmett55" + +[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 = "RSGI" +webserver = "granian" +versus = "uvicorn" diff --git a/frameworks/Python/emmett55/emmett55.dockerfile b/frameworks/Python/emmett55/emmett55.dockerfile new file mode 100644 index 00000000000..49438fd442d --- /dev/null +++ b/frameworks/Python/emmett55/emmett55.dockerfile @@ -0,0 +1,11 @@ +FROM python:3.11-slim + +ADD ./ /emmett55 + +WORKDIR /emmett55 + +RUN pip install --no-cache-dir -r /emmett55/requirements.txt + +EXPOSE 8080 + +CMD python run.py diff --git a/frameworks/Python/emmett55/requirements.txt b/frameworks/Python/emmett55/requirements.txt new file mode 100644 index 00000000000..341cf834957 --- /dev/null +++ b/frameworks/Python/emmett55/requirements.txt @@ -0,0 +1,3 @@ +asyncpg==0.29.0 +emmett55[orjson,uvloop]>=1.2.0,<1.3.0 +renoir==1.8.0 diff --git a/frameworks/Python/emmett55/run.py b/frameworks/Python/emmett55/run.py new file mode 100644 index 00000000000..258b6d87ba0 --- /dev/null +++ b/frameworks/Python/emmett55/run.py @@ -0,0 +1,20 @@ +import multiprocessing + +from emmett_core.server import run + + +if __name__ == "__main__": + workers = multiprocessing.cpu_count() + + run( + "rsgi", + ("app", "app"), + host="0.0.0.0", + port=8080, + workers=workers, + backlog=16384, + runtime_mode="mt", + http="1", + enable_websockets=False, + log_level="warn" + ) diff --git a/frameworks/Python/emmett55/templates/fortunes.html b/frameworks/Python/emmett55/templates/fortunes.html new file mode 100644 index 00000000000..c64ff16ec6f --- /dev/null +++ b/frameworks/Python/emmett55/templates/fortunes.html @@ -0,0 +1,20 @@ + + + + Fortunes + + + + + + + + {{ for fortune in fortunes: }} + + + + + {{ pass }} +
idmessage
{{ =fortune[0] }}{{ =fortune[1] }}
+ + diff --git a/frameworks/Python/eve/benchmark_config.json b/frameworks/Python/eve/benchmark_config.json index 3e9e7cdc102..cb11c1586d1 100644 --- a/frameworks/Python/eve/benchmark_config.json +++ b/frameworks/Python/eve/benchmark_config.json @@ -18,6 +18,7 @@ "database_os": "Linux", "display_name": "Eve", "notes": "", + "tags": ["broken"], "versus": "" } }] diff --git a/frameworks/Python/eve/requirements.txt b/frameworks/Python/eve/requirements.txt index 7e89c0bc0b4..f054d6baf97 100644 --- a/frameworks/Python/eve/requirements.txt +++ b/frameworks/Python/eve/requirements.txt @@ -3,6 +3,6 @@ Flask==1.0 greenlet==0.4.14 gunicorn==19.9.0 itsdangerous==0.24 -meinheld==0.6.1 +meinheld==1.0.2 uWSGI==2.0.22 Werkzeug==0.15.5 diff --git a/frameworks/Python/falcon/requirements-meinheld.txt b/frameworks/Python/falcon/requirements-meinheld.txt index ab4da943513..c816f95c997 100644 --- a/frameworks/Python/falcon/requirements-meinheld.txt +++ b/frameworks/Python/falcon/requirements-meinheld.txt @@ -1,2 +1,2 @@ -gunicorn==20.1.0 +gunicorn==23.0.0 meinheld==1.0.2 diff --git a/frameworks/Python/falcon/requirements-pypy.txt b/frameworks/Python/falcon/requirements-pypy.txt index 9d41f264a67..4afe40e70ce 100644 --- a/frameworks/Python/falcon/requirements-pypy.txt +++ b/frameworks/Python/falcon/requirements-pypy.txt @@ -1 +1 @@ -gunicorn==20.1.0 +gunicorn==23.0.0 diff --git a/frameworks/Python/falcon/requirements-uvicorn.txt b/frameworks/Python/falcon/requirements-uvicorn.txt index 23016ffc9d7..fcbed985e7e 100644 --- a/frameworks/Python/falcon/requirements-uvicorn.txt +++ b/frameworks/Python/falcon/requirements-uvicorn.txt @@ -1,4 +1,4 @@ -gunicorn==20.1.0 +gunicorn==23.0.0 httptools==0.5.0 uvloop==0.17.0 uvicorn==0.21.1 diff --git a/frameworks/Python/falcon/requirements.txt b/frameworks/Python/falcon/requirements.txt index 4e7ea05ad81..97f6b1390f8 100644 --- a/frameworks/Python/falcon/requirements.txt +++ b/frameworks/Python/falcon/requirements.txt @@ -1,2 +1,2 @@ falcon==3.1.1 -jinja2==3.0.3 +jinja2==3.1.6 diff --git a/frameworks/Python/fastapi/fastapi-gunicorn-orjson.dockerfile b/frameworks/Python/fastapi/fastapi-gunicorn-orjson.dockerfile index ac1f4c475f5..4f0712849e5 100644 --- a/frameworks/Python/fastapi/fastapi-gunicorn-orjson.dockerfile +++ b/frameworks/Python/fastapi/fastapi-gunicorn-orjson.dockerfile @@ -1,11 +1,11 @@ -FROM python:3.11 +FROM python:3.13 WORKDIR /fastapi RUN python -m venv /opt/venv ENV PATH="/opt/venv/bin:$PATH" -RUN pip3 install cython==0.29.33 +RUN pip3 install cython==3.0.12 COPY requirements.txt requirements-orjson.txt requirements-gunicorn.txt requirements-uvicorn.txt ./ diff --git a/frameworks/Python/fastapi/fastapi-gunicorn-orm.dockerfile b/frameworks/Python/fastapi/fastapi-gunicorn-orm.dockerfile index fdc730bc121..64dab70e99b 100644 --- a/frameworks/Python/fastapi/fastapi-gunicorn-orm.dockerfile +++ b/frameworks/Python/fastapi/fastapi-gunicorn-orm.dockerfile @@ -1,11 +1,11 @@ -FROM python:3.11 +FROM python:3.13 WORKDIR /fastapi RUN python -m venv /opt/venv ENV PATH="/opt/venv/bin:$PATH" -RUN pip3 install cython==0.29.33 +RUN pip3 install cython==3.0.12 COPY requirements.txt requirements-sqlalchemy.txt requirements-gunicorn.txt requirements-uvicorn.txt ./ diff --git a/frameworks/Python/fastapi/fastapi-hypercorn-orjson.dockerfile b/frameworks/Python/fastapi/fastapi-hypercorn-orjson.dockerfile index 231a1c218cc..fc50bd7ddae 100644 --- a/frameworks/Python/fastapi/fastapi-hypercorn-orjson.dockerfile +++ b/frameworks/Python/fastapi/fastapi-hypercorn-orjson.dockerfile @@ -1,11 +1,11 @@ -FROM python:3.11 +FROM python:3.13 WORKDIR /fastapi RUN python -m venv /opt/venv ENV PATH="/opt/venv/bin:$PATH" -RUN pip3 install cython==0.29.33 +RUN pip3 install cython==3.0.12 COPY requirements.txt requirements-orjson.txt requirements-hypercorn.txt ./ diff --git a/frameworks/Python/fastapi/fastapi-hypercorn.dockerfile b/frameworks/Python/fastapi/fastapi-hypercorn.dockerfile index 761073478a7..58f2d166d12 100644 --- a/frameworks/Python/fastapi/fastapi-hypercorn.dockerfile +++ b/frameworks/Python/fastapi/fastapi-hypercorn.dockerfile @@ -1,11 +1,11 @@ -FROM python:3.11 +FROM python:3.13 WORKDIR /fastapi RUN python -m venv /opt/venv ENV PATH="/opt/venv/bin:$PATH" -RUN pip3 install cython==0.29.33 +RUN pip3 install cython==3.0.12 COPY requirements.txt requirements-hypercorn.txt ./ diff --git a/frameworks/Python/fastapi/fastapi-nginx-unit-orjson.dockerfile b/frameworks/Python/fastapi/fastapi-nginx-unit-orjson.dockerfile index c8d825ad1e0..af3ed2bd75d 100644 --- a/frameworks/Python/fastapi/fastapi-nginx-unit-orjson.dockerfile +++ b/frameworks/Python/fastapi/fastapi-nginx-unit-orjson.dockerfile @@ -1,11 +1,11 @@ -FROM nginx/unit:1.29.1-python3.11 +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==0.29.33 +RUN pip3 install cython==3.0.12 COPY requirements.txt requirements-orjson.txt ./ diff --git a/frameworks/Python/fastapi/fastapi-nginx-unit.dockerfile b/frameworks/Python/fastapi/fastapi-nginx-unit.dockerfile index 2c68413be7a..261c84d5520 100644 --- a/frameworks/Python/fastapi/fastapi-nginx-unit.dockerfile +++ b/frameworks/Python/fastapi/fastapi-nginx-unit.dockerfile @@ -1,11 +1,11 @@ -FROM nginx/unit:1.29.1-python3.11 +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==0.29.33 +RUN pip3 install cython==3.0.12 COPY requirements.txt ./ diff --git a/frameworks/Python/fastapi/fastapi-socketify-asgi-pypy.dockerfile b/frameworks/Python/fastapi/fastapi-socketify-asgi-pypy.dockerfile index 8881c600daa..39a7e0c5b05 100644 --- a/frameworks/Python/fastapi/fastapi-socketify-asgi-pypy.dockerfile +++ b/frameworks/Python/fastapi/fastapi-socketify-asgi-pypy.dockerfile @@ -1,4 +1,4 @@ -FROM pypy:3.9-bullseye +FROM pypy:3.11-bookworm WORKDIR /fastapi @@ -13,4 +13,4 @@ COPY . ./ EXPOSE 8080 -CMD python ./app-socketify-asgi.py \ No newline at end of file +CMD python ./app-socketify-asgi.py diff --git a/frameworks/Python/fastapi/fastapi-socketify-asgi.dockerfile b/frameworks/Python/fastapi/fastapi-socketify-asgi.dockerfile index 7af7345cd37..58c39a397cd 100644 --- a/frameworks/Python/fastapi/fastapi-socketify-asgi.dockerfile +++ b/frameworks/Python/fastapi/fastapi-socketify-asgi.dockerfile @@ -1,4 +1,4 @@ -FROM python:3.10-bullseye +FROM python:3.13-bullseye WORKDIR /fastapi @@ -6,7 +6,7 @@ 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==0.29.33 +RUN pip3 install cython==3.0.12 COPY requirements-socketify.txt ./ @@ -16,4 +16,4 @@ COPY . ./ EXPOSE 8080 -CMD python ./app-socketify-asgi.py \ No newline at end of file +CMD python ./app-socketify-asgi.py diff --git a/frameworks/Python/fastapi/fastapi-uvicorn-orjson.dockerfile b/frameworks/Python/fastapi/fastapi-uvicorn-orjson.dockerfile index 2a8bfca032a..59a6e040cd0 100644 --- a/frameworks/Python/fastapi/fastapi-uvicorn-orjson.dockerfile +++ b/frameworks/Python/fastapi/fastapi-uvicorn-orjson.dockerfile @@ -1,11 +1,11 @@ -FROM python:3.11 +FROM python:3.13 WORKDIR /fastapi RUN python -m venv /opt/venv ENV PATH="/opt/venv/bin:$PATH" -RUN pip3 install cython==0.29.33 +RUN pip3 install cython==3.0.12 COPY requirements.txt requirements-orjson.txt requirements-uvicorn.txt ./ @@ -15,4 +15,4 @@ COPY . ./ EXPOSE 8080 -CMD uvicorn app:app --host 0.0.0.0 --port 8080 --workers $(nproc) --log-level error +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 8a29e86ff26..115104e3e49 100644 --- a/frameworks/Python/fastapi/fastapi-uvicorn.dockerfile +++ b/frameworks/Python/fastapi/fastapi-uvicorn.dockerfile @@ -1,11 +1,11 @@ -FROM python:3.11 +FROM python:3.13 WORKDIR /fastapi RUN python -m venv /opt/venv ENV PATH="/opt/venv/bin:$PATH" -RUN pip3 install cython==0.29.33 +RUN pip3 install cython==3.0.12 COPY requirements.txt requirements-uvicorn.txt ./ @@ -15,4 +15,4 @@ COPY . ./ EXPOSE 8080 -CMD uvicorn app:app --host 0.0.0.0 --port 8080 --workers $(nproc) --log-level error +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 3f0791259e0..7208575d191 100644 --- a/frameworks/Python/fastapi/fastapi.dockerfile +++ b/frameworks/Python/fastapi/fastapi.dockerfile @@ -1,11 +1,11 @@ -FROM python:3.11 +FROM python:3.13 WORKDIR /fastapi RUN python -m venv /opt/venv ENV PATH="/opt/venv/bin:$PATH" -RUN pip3 install cython==0.29.33 +RUN pip3 install cython==3.0.12 COPY requirements.txt requirements-gunicorn.txt requirements-uvicorn.txt ./ diff --git a/frameworks/Python/fastapi/requirements-gunicorn.txt b/frameworks/Python/fastapi/requirements-gunicorn.txt index 9d41f264a67..4afe40e70ce 100644 --- a/frameworks/Python/fastapi/requirements-gunicorn.txt +++ b/frameworks/Python/fastapi/requirements-gunicorn.txt @@ -1 +1 @@ -gunicorn==20.1.0 +gunicorn==23.0.0 diff --git a/frameworks/Python/fastapi/requirements-hypercorn.txt b/frameworks/Python/fastapi/requirements-hypercorn.txt index 3d99222e2c6..3e0a21f2fe2 100644 --- a/frameworks/Python/fastapi/requirements-hypercorn.txt +++ b/frameworks/Python/fastapi/requirements-hypercorn.txt @@ -1 +1 @@ -hypercorn==0.14.3 +hypercorn==0.17.3 diff --git a/frameworks/Python/fastapi/requirements-orjson.txt b/frameworks/Python/fastapi/requirements-orjson.txt index 93befc16cdf..c4a1a897890 100644 --- a/frameworks/Python/fastapi/requirements-orjson.txt +++ b/frameworks/Python/fastapi/requirements-orjson.txt @@ -1 +1 @@ -orjson==3.8.7 +orjson==3.10.16 diff --git a/frameworks/Python/fastapi/requirements-socketify-pypy.txt b/frameworks/Python/fastapi/requirements-socketify-pypy.txt index 76a50bee96a..d9e462113ce 100644 --- a/frameworks/Python/fastapi/requirements-socketify-pypy.txt +++ b/frameworks/Python/fastapi/requirements-socketify-pypy.txt @@ -1,2 +1,2 @@ -fastapi==0.92.0 -git+https://github.com/cirospaciari/socketify.py.git@main#socketify \ No newline at end of file +fastapi==0.115.12 +git+https://github.com/cirospaciari/socketify.py.git@main#socketify diff --git a/frameworks/Python/fastapi/requirements-socketify.txt b/frameworks/Python/fastapi/requirements-socketify.txt index 03e6d8df2d2..1a2da3e0ef2 100644 --- a/frameworks/Python/fastapi/requirements-socketify.txt +++ b/frameworks/Python/fastapi/requirements-socketify.txt @@ -1,3 +1,3 @@ -orjson==3.8.7 -fastapi==0.92.0 -git+https://github.com/cirospaciari/socketify.py.git@main#socketify \ No newline at end of file +orjson==3.10.16 +fastapi==0.115.12 +git+https://github.com/cirospaciari/socketify.py.git@main#socketify diff --git a/frameworks/Python/fastapi/requirements-sqlalchemy.txt b/frameworks/Python/fastapi/requirements-sqlalchemy.txt index 15b6756829e..2c6c181a0fe 100644 --- a/frameworks/Python/fastapi/requirements-sqlalchemy.txt +++ b/frameworks/Python/fastapi/requirements-sqlalchemy.txt @@ -1,2 +1,2 @@ -psycopg2==2.9.5 -SQLAlchemy==1.4.45 +psycopg2==2.9.10 +SQLAlchemy==2.0.40 diff --git a/frameworks/Python/fastapi/requirements-uvicorn.txt b/frameworks/Python/fastapi/requirements-uvicorn.txt index acd5eba32da..18c6d74e2ad 100644 --- a/frameworks/Python/fastapi/requirements-uvicorn.txt +++ b/frameworks/Python/fastapi/requirements-uvicorn.txt @@ -1,3 +1,3 @@ -uvicorn==0.20.0 -uvloop==0.17.0 -httptools==0.5.0 +uvicorn==0.34.0 +uvloop==0.21.0 +httptools==0.6.4 diff --git a/frameworks/Python/fastapi/requirements.txt b/frameworks/Python/fastapi/requirements.txt index fb2fbfdbf25..51c4ec7c426 100644 --- a/frameworks/Python/fastapi/requirements.txt +++ b/frameworks/Python/fastapi/requirements.txt @@ -1,4 +1,4 @@ -asyncpg==0.27.0 -fastapi==0.93.0 -Jinja2==3.1.2 -ujson==5.7.0 +asyncpg==0.30.0 +fastapi==0.115.12 +Jinja2==3.1.6 +ujson==5.10.0 \ No newline at end of file diff --git a/frameworks/Python/fastwsgi/app-asgi.py b/frameworks/Python/fastwsgi/app-asgi.py index bda51b38cec..a3721c7174b 100644 --- a/frameworks/Python/fastwsgi/app-asgi.py +++ b/frameworks/Python/fastwsgi/app-asgi.py @@ -17,6 +17,14 @@ db_pool = None +PG_POOL_SIZE = 4 + +class NoResetConnection(asyncpg.Connection): + __slots__ = () + + def get_reset_query(self): + return "" + async def db_setup(): global db_pool db_pool = await asyncpg.create_pool( @@ -24,7 +32,10 @@ async def db_setup(): password=os.getenv('PGPASS', 'benchmarkdbpass'), database='hello_world', host='tfb-database', - port=5432 + port=5432, + min_size=PG_POOL_SIZE, + max_size=PG_POOL_SIZE, + connection_class=NoResetConnection, ) READ_ROW_SQL = 'SELECT "randomnumber", "id" FROM "world" WHERE id = $1' @@ -102,15 +113,10 @@ async def multiple_database_queries(scope, receive, send): row_ids = random.sample(range(1, 10000), num_queries) worlds = [ ] - db_conn = await db_pool.acquire() - try: - statement = await db_conn.prepare(READ_ROW_SQL) - for row_id in row_ids: - number = await statement.fetchval(row_id) - worlds.append( {'id': row_id, 'randomNumber': number} ) - finally: - await db_pool.release(db_conn) + async with db_pool.acquire() as db_conn: + rows = await db_conn.fetchmany(READ_ROW_SQL, [ (v, ) for v in row_ids ] ) + worlds = [ { 'id': row_id, 'randomNumber': number[0] } for row_id, number in zip(row_ids, rows) ] content = jsonify(worlds) await send(JSON_RESPONSE) await send({ @@ -154,14 +160,9 @@ async def database_updates(scope, receive, send): worlds = [ {"id": row_id, "randomNumber": number} for row_id, number in updates ] - db_conn = await db_pool.acquire() - try: - statement = await db_conn.prepare(READ_ROW_SQL) - for row_id, _ in updates: - await statement.fetchval(row_id) + async with db_pool.acquire() as db_conn: + await db_conn.executemany(READ_ROW_SQL, [ (i[0], ) for i in updates ] ) await db_conn.executemany(WRITE_ROW_SQL, updates) - finally: - await db_pool.release(db_conn) content = jsonify(worlds) await send(JSON_RESPONSE) diff --git a/frameworks/Python/fastwsgi/requirements.txt b/frameworks/Python/fastwsgi/requirements.txt index 8b326799874..c98614bf3bd 100644 --- a/frameworks/Python/fastwsgi/requirements.txt +++ b/frameworks/Python/fastwsgi/requirements.txt @@ -1,8 +1,8 @@ click==8.0.1 -ujson==5.7.0 +ujson==5.10.0 #fastwsgi==0.0.9 -git+https://github.com/jamesroberts/fastwsgi.git@5572bb31b859d690be225707b9e7e25af397544b -asyncpg==0.27.0 -Jinja2==3.1.2 +git+https://github.com/jamesroberts/fastwsgi.git@eb6e60babab73e769f49c183cfc46bb270ca84bd +asyncpg==0.30.0 +jinja2==3.1.6 cachetools==5.3.0 asyncache==0.3.1 diff --git a/frameworks/Python/flask/benchmark_config.json b/frameworks/Python/flask/benchmark_config.json index dad6b8ef11a..ee505a984c0 100644 --- a/frameworks/Python/flask/benchmark_config.json +++ b/frameworks/Python/flask/benchmark_config.json @@ -45,7 +45,7 @@ "display_name": "Flask [Meinheld] [Raw]", "notes": "", "versus": "wsgi", - "tags": [ ] + "tags": [ "broken" ] }, "socketify-wsgi": { "json_url": "/json-raw", @@ -83,6 +83,7 @@ "database_os": "Linux", "display_name": "Flask [socketify.py] [PyPy3]", "notes": "PyPy", + "tags": ["broken"], "versus": "wsgi" }, "pypy": { diff --git a/frameworks/Python/flask/requirements-gunicorn.txt b/frameworks/Python/flask/requirements-gunicorn.txt index 26385a38109..1469261d7ee 100644 --- a/frameworks/Python/flask/requirements-gunicorn.txt +++ b/frameworks/Python/flask/requirements-gunicorn.txt @@ -1,4 +1,4 @@ -r requirements.txt greenlet<0.5 -gunicorn==20.1.0 +gunicorn==23.0.0 meinheld==1.0.2 diff --git a/frameworks/Python/flask/requirements.txt b/frameworks/Python/flask/requirements.txt index 2865cf8986a..a9a51e871b3 100644 --- a/frameworks/Python/flask/requirements.txt +++ b/frameworks/Python/flask/requirements.txt @@ -6,7 +6,8 @@ psycopg2-binary==2.9.3; implementation_name=='cpython' psycopg2-pool==1.1; implementation_name=='cpython' psycopg2cffi==2.9.0; implementation_name=='pypy' itsdangerous==2.1.2 -Jinja2==3.0.3 +Jinja2==3.1.6 MarkupSafe==2.1.2 ujson==5.4.0 orjson==3.8.7; implementation_name=='cpython' +Werkzeug==2.3.8 diff --git a/frameworks/Python/granian/app_asgi.py b/frameworks/Python/granian/app_asgi.py index f7cc2324175..d7c7b732c27 100644 --- a/frameworks/Python/granian/app_asgi.py +++ b/frameworks/Python/granian/app_asgi.py @@ -1,4 +1,3 @@ -import asyncio import os from operator import itemgetter @@ -10,6 +9,15 @@ 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 @@ -18,7 +26,10 @@ async def pg_setup(): password=os.getenv('PGPASS', 'benchmarkdbpass'), database='hello_world', host='tfb-database', - port=5432 + port=5432, + min_size=PG_POOL_SIZE, + max_size=PG_POOL_SIZE, + connection_class=NoResetConnection, ) @@ -55,8 +66,6 @@ async def pg_setup(): with Path('templates/fortune.html').open('r') as f: template = jinja2.Template(f.read()) -asyncio.get_event_loop().run_until_complete(pg_setup()) - def get_num_queries(scope): try: @@ -100,11 +109,9 @@ async def route_queries(scope, receive, send): worlds = [] async with pool.acquire() as connection: - statement = await connection.prepare(SQL_SELECT) - for row_id in row_ids: - number = await statement.fetchval(row_id) - worlds.append({'id': row_id, 'randomNumber': number}) + 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', @@ -137,9 +144,7 @@ async def route_updates(scope, receive, send): worlds = [{'id': row_id, 'randomNumber': number} for row_id, number in updates] async with pool.acquire() as connection: - statement = await connection.prepare(SQL_SELECT) - for row_id, _ in updates: - await statement.fetchval(row_id) + await connection.executemany(SQL_SELECT, [(i[0],) for i in updates]) await connection.executemany(SQL_UPDATE, updates) await send(JSON_RESPONSE) @@ -178,6 +183,26 @@ async def handle_404(scope, receive, send): } -def main(scope, receive, send): - handler = routes.get(scope['path'], handle_404) - return handler(scope, receive, send) +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/granian/app_rsgi.py b/frameworks/Python/granian/app_rsgi.py index dc1eeba7e2c..b475137bb66 100644 --- a/frameworks/Python/granian/app_rsgi.py +++ b/frameworks/Python/granian/app_rsgi.py @@ -1,4 +1,3 @@ -import asyncio import os from operator import itemgetter @@ -10,6 +9,15 @@ 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 @@ -18,7 +26,10 @@ async def pg_setup(): password=os.getenv('PGPASS', 'benchmarkdbpass'), database='hello_world', host='tfb-database', - port=5432 + port=5432, + min_size=PG_POOL_SIZE, + max_size=PG_POOL_SIZE, + connection_class=NoResetConnection, ) @@ -37,8 +48,6 @@ async def pg_setup(): with Path('templates/fortune.html').open('r') as f: template = jinja2.Template(f.read()) -asyncio.get_event_loop().run_until_complete(pg_setup()) - def get_num_queries(scope): try: @@ -79,11 +88,9 @@ async def route_queries(scope, proto): worlds = [] async with pool.acquire() as connection: - statement = await connection.prepare(SQL_SELECT) - for row_id in row_ids: - number = await statement.fetchval(row_id) - worlds.append({'id': row_id, 'randomNumber': number}) + 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)] proto.response_bytes( 200, JSON_HEADERS, @@ -114,9 +121,7 @@ async def route_updates(scope, proto): worlds = [{'id': row_id, 'randomNumber': number} for row_id, number in updates] async with pool.acquire() as connection: - statement = await connection.prepare(SQL_SELECT) - for row_id, _ in updates: - await statement.fetchval(row_id) + await connection.executemany(SQL_SELECT, [(i[0],) for i in updates]) await connection.executemany(SQL_UPDATE, updates) proto.response_bytes( @@ -152,6 +157,13 @@ async def handle_404(scope, proto): } -def main(scope, proto): - handler = routes.get(scope.path, handle_404) - return handler(scope, proto) +class App: + def __rsgi_init__(self, loop): + loop.run_until_complete(pg_setup()) + + def __rsgi__(self, scope, proto): + handler = routes.get(scope.path, handle_404) + return handler(scope, proto) + + +main = App() diff --git a/frameworks/Python/granian/app_rsgi_nogil.py b/frameworks/Python/granian/app_rsgi_nogil.py new file mode 100644 index 00000000000..b87931f61b1 --- /dev/null +++ b/frameworks/Python/granian/app_rsgi_nogil.py @@ -0,0 +1,42 @@ +import json + +JSON_HEADERS = [('content-type', 'application/json')] +PLAINTEXT_HEADERS = [('content-type', 'text/plain; charset=utf-8')] + +# json_dumps = orjson.dumps +json_dumps = json.dumps + + +async def route_json(scope, proto): + proto.response_str( + 200, + JSON_HEADERS, + json_dumps({'message': 'Hello, world!'}) + ) + + +async def route_plaintext(scope, proto): + proto.response_bytes( + 200, + PLAINTEXT_HEADERS, + b'Hello, world!' + ) + + +async def handle_404(scope, proto): + proto.response_bytes( + 404, + PLAINTEXT_HEADERS, + b'Not found' + ) + + +routes = { + '/json': route_json, + '/plaintext': route_plaintext +} + + +def main(scope, proto): + handler = routes.get(scope.path, handle_404) + return handler(scope, proto) diff --git a/frameworks/Python/granian/benchmark_config.json b/frameworks/Python/granian/benchmark_config.json index 140075ee0a3..857d81e68ca 100644 --- a/frameworks/Python/granian/benchmark_config.json +++ b/frameworks/Python/granian/benchmark_config.json @@ -63,7 +63,7 @@ "notes": "", "versus": "uvicorn" }, - "wrk": { + "nogil": { "json_url": "/json", "plaintext_url": "/plaintext", "port": 8080, @@ -77,7 +77,7 @@ "webserver": "granian", "os": "Linux", "database_os": "Linux", - "display_name": "granian [rsgi wrk]", + "display_name": "granian [rsgi nogil]", "notes": "", "versus": "uvicorn" } diff --git a/frameworks/Python/granian/config.toml b/frameworks/Python/granian/config.toml index ade7eab9673..2338f0d4a48 100644 --- a/frameworks/Python/granian/config.toml +++ b/frameworks/Python/granian/config.toml @@ -48,7 +48,7 @@ platform = "None" webserver = "granian" versus = "uvicorn" -[wrk] +[nogil] urls.plaintext = "/plaintext" urls.json = "/json" approach = "Realistic" diff --git a/frameworks/Python/granian/granian-nogil.dockerfile b/frameworks/Python/granian/granian-nogil.dockerfile new file mode 100644 index 00000000000..5f0e4045f40 --- /dev/null +++ b/frameworks/Python/granian/granian-nogil.dockerfile @@ -0,0 +1,16 @@ +FROM ghcr.io/astral-sh/uv:debian-slim + +RUN uv python install 3.14t + +ENV UV_PYTHON=3.14t +ENV PYTHON_GIL=0 + +ADD ./ /granian +WORKDIR /granian + +RUN uv venv +RUN uv pip install -r requirements-nogil.txt + +EXPOSE 8080 + +CMD uv run python run_nogil.py rsgi st diff --git a/frameworks/Python/granian/granian-rsgi.dockerfile b/frameworks/Python/granian/granian-rsgi.dockerfile index d84b713044b..1eb5066dfeb 100644 --- a/frameworks/Python/granian/granian-rsgi.dockerfile +++ b/frameworks/Python/granian/granian-rsgi.dockerfile @@ -1,4 +1,4 @@ -FROM python:3.11-slim +FROM python:3.13-slim ADD ./ /granian @@ -8,4 +8,4 @@ RUN pip install -r /granian/requirements.txt EXPOSE 8080 -CMD python run.py rsgi runtime +CMD python run.py rsgi st diff --git a/frameworks/Python/granian/granian-wrk.dockerfile b/frameworks/Python/granian/granian-wrk.dockerfile deleted file mode 100644 index 2f56af92d53..00000000000 --- a/frameworks/Python/granian/granian-wrk.dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM python:3.11-slim - -ADD ./ /granian - -WORKDIR /granian - -RUN pip install -r /granian/requirements.txt - -EXPOSE 8080 - -CMD python run.py rsgi workers diff --git a/frameworks/Python/granian/granian-wsgi.dockerfile b/frameworks/Python/granian/granian-wsgi.dockerfile index f178eb4b618..366f274ff0c 100644 --- a/frameworks/Python/granian/granian-wsgi.dockerfile +++ b/frameworks/Python/granian/granian-wsgi.dockerfile @@ -1,4 +1,4 @@ -FROM python:3.11-slim +FROM python:3.13-slim ADD ./ /granian @@ -8,4 +8,4 @@ RUN pip install -r /granian/requirements.txt EXPOSE 8080 -CMD python run.py wsgi runtime +CMD python run.py wsgi mt diff --git a/frameworks/Python/granian/granian.dockerfile b/frameworks/Python/granian/granian.dockerfile index 883c433f3f0..139ba2300d8 100644 --- a/frameworks/Python/granian/granian.dockerfile +++ b/frameworks/Python/granian/granian.dockerfile @@ -1,4 +1,4 @@ -FROM python:3.11-slim +FROM python:3.13-slim ADD ./ /granian @@ -8,4 +8,4 @@ RUN pip install -r /granian/requirements.txt EXPOSE 8080 -CMD python run.py asgi runtime +CMD python run.py asgi st diff --git a/frameworks/Python/granian/requirements-nogil.txt b/frameworks/Python/granian/requirements-nogil.txt new file mode 100644 index 00000000000..c49d8ced726 --- /dev/null +++ b/frameworks/Python/granian/requirements-nogil.txt @@ -0,0 +1 @@ +granian[rloop]>=2.5.0,<2.6.0 diff --git a/frameworks/Python/granian/requirements.txt b/frameworks/Python/granian/requirements.txt index 601bdc3e401..8fc318454b4 100644 --- a/frameworks/Python/granian/requirements.txt +++ b/frameworks/Python/granian/requirements.txt @@ -1,4 +1,4 @@ -asyncpg==0.27.0 -granian>=0.7.0,<0.8.0 -jinja2==3.1.2 -orjson==3.9.10 +asyncpg==0.30.0 +granian[uvloop]>=2.5.0,<2.6.0 +jinja2==3.1.6 +orjson==3.11.3 diff --git a/frameworks/Python/granian/run.py b/frameworks/Python/granian/run.py index a81600ef9cd..d24d571e4a3 100644 --- a/frameworks/Python/granian/run.py +++ b/frameworks/Python/granian/run.py @@ -6,18 +6,26 @@ if __name__ == '__main__': interface = sys.argv[1] - threading_mode = sys.argv[2] + runtime_mode = sys.argv[2] workers = multiprocessing.cpu_count() - threads = 2 if threading_mode == "runtime" else 1 + + if interface == "rsgi": + #: leave 25% cpu to the Rust runtime + workers = round(workers * 0.75) + + blocking_threads = None + if interface == "wsgi": + #: we don't run any I/O in WSGI benches + blocking_threads = 1 Granian( f"app_{interface}:main", address="0.0.0.0", port=8080, workers=workers, - threading_mode=threading_mode, - threads=threads, - backlog=2048, + runtime_mode=runtime_mode, + blocking_threads=blocking_threads, + backlog=16384, interface=interface, http="1", websockets=False diff --git a/frameworks/Python/granian/run_nogil.py b/frameworks/Python/granian/run_nogil.py new file mode 100644 index 00000000000..b11779eea63 --- /dev/null +++ b/frameworks/Python/granian/run_nogil.py @@ -0,0 +1,32 @@ +import multiprocessing +import sys + +from granian import Granian + + +if __name__ == '__main__': + interface = sys.argv[1] + runtime_mode = sys.argv[2] + workers = multiprocessing.cpu_count() + + if interface == "rsgi": + #: leave 25% cpu to the Rust runtime + workers = round(workers * 0.75) + + blocking_threads = None + if interface == "wsgi": + #: we don't run any I/O in WSGI benches + blocking_threads = 1 + + Granian( + f"app_{interface}_nogil:main", + address="0.0.0.0", + port=8080, + workers=workers, + runtime_mode=runtime_mode, + blocking_threads=blocking_threads, + backlog=16384, + interface=interface, + http="1", + websockets=False + ).serve() diff --git a/frameworks/Python/heaven/requirements.txt b/frameworks/Python/heaven/requirements.txt index 3e8a09ee6f7..5546000791d 100644 --- a/frameworks/Python/heaven/requirements.txt +++ b/frameworks/Python/heaven/requirements.txt @@ -1,4 +1,4 @@ asyncpg==0.29.0 heaven==0.2.4 -orjson==3.9.10 -gunicorn==20.1.0 +orjson==3.9.15 +gunicorn==22.0.0 diff --git a/frameworks/Python/hug/app.py b/frameworks/Python/hug/app.py deleted file mode 100644 index 0ee6509add6..00000000000 --- a/frameworks/Python/hug/app.py +++ /dev/null @@ -1,29 +0,0 @@ -import hug - -from datetime import datetime - - -# Create decorators for mimetypes (JSON is default) -plaintext = hug.get(output=hug.output_format.text) -json = hug.get(output=hug.output_format.json) - - -# Create a directive to add necessary headers -@hug.response_middleware() -def set_required_headers(request, response, resource): - date_obj = datetime.now() - rfc_1123 = "%a, %d %b %Y %H:%M:%S GMT" - rfc_1123_date = date_obj.strftime(rfc_1123) - - headers = { "Server": "hug", "Date": rfc_1123_date } - - response.set_headers(headers) - - -@plaintext -@hug.get("/plaintext") -def plaintext(): - """Plaintext handler.""" - return "Hello, World!" - -app = hug.API(__name__).http.server() diff --git a/frameworks/Python/hug/benchmark_config.json b/frameworks/Python/hug/benchmark_config.json deleted file mode 100644 index b86b6f36db1..00000000000 --- a/frameworks/Python/hug/benchmark_config.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "framework": "hug", - "tests": [ - { - "default": { - "plaintext_url": "/plaintext", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "None", - "framework": "Hug", - "language": "Python", - "flavor": "Python3", - "orm": "Raw", - "platform": "Falcon", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "Hug", - "notes": "CPython 2", - "versus": "wsgi" - } - } - ] -} diff --git a/frameworks/Python/hug/config.toml b/frameworks/Python/hug/config.toml deleted file mode 100644 index 18bf06c490a..00000000000 --- a/frameworks/Python/hug/config.toml +++ /dev/null @@ -1,14 +0,0 @@ -[framework] -name = "hug" - -[main] -urls.plaintext = "/plaintext" -approach = "Realistic" -classification = "Micro" -database = "None" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "Falcon" -webserver = "None" -versus = "wsgi" diff --git a/frameworks/Python/hug/hug.dockerfile b/frameworks/Python/hug/hug.dockerfile deleted file mode 100644 index b385c993026..00000000000 --- a/frameworks/Python/hug/hug.dockerfile +++ /dev/null @@ -1,12 +0,0 @@ -FROM python:3.6.6-stretch - -WORKDIR /hug -COPY app.py app.py -COPY uwsgi.ini uwsgi.ini -COPY requirements.txt requirements.txt - -RUN pip3 install -r requirements.txt - -EXPOSE 8080 - -CMD ["uwsgi", "--ini", "uwsgi.ini"] diff --git a/frameworks/Python/hug/requirements.txt b/frameworks/Python/hug/requirements.txt deleted file mode 100644 index 7b366e79132..00000000000 --- a/frameworks/Python/hug/requirements.txt +++ /dev/null @@ -1,6 +0,0 @@ -Cython==0.28.5 -hug==2.3.2 -uWSGI==2.0.17.1 -greenlet==0.4.14 -gunicorn==19.9.0 -meinheld==0.6.1 diff --git a/frameworks/Python/hug/uwsgi.ini b/frameworks/Python/hug/uwsgi.ini deleted file mode 100644 index 15d7d5fa95f..00000000000 --- a/frameworks/Python/hug/uwsgi.ini +++ /dev/null @@ -1,13 +0,0 @@ -; These preferences specifically tuned for performance. - -[uwsgi] -http=:8080 -chdir=/hug -wsgi-file=/hug/app.py -callable=app -workers=%(%k * 2 + 1) -processes=%k -enable-threads=True -threads=1 -disable-logging=True -max-worker-lifetime=30 diff --git a/frameworks/Python/japronto/README.md b/frameworks/Python/japronto/README.md deleted file mode 100644 index e8cc702fac1..00000000000 --- a/frameworks/Python/japronto/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# Japronto Benchmark Test - -This is the Japronto portion of a [benchmarking tests suite](../../) -comparing a variety of web development platforms. - -The information below is specific to Japronto. 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 - -[Japronto](https://github.com/squeaky-pl/japronto) is a screaming-fast, scalable, -asynchronous Python 3.5+ HTTP toolkit. - -## Test Paths & Sources - -All of the test implementations are located within a single file ([app.py](app.py)). - -* [JSON Serialization](app.py): "/json" -* [Plaintext](app.py): "/plaintext" diff --git a/frameworks/Python/japronto/app.py b/frameworks/Python/japronto/app.py deleted file mode 100644 index 040de09a4be..00000000000 --- a/frameworks/Python/japronto/app.py +++ /dev/null @@ -1,78 +0,0 @@ -import os -import sys -import multiprocessing -from wsgiref.handlers import format_date_time -import japronto -import ujson as json -import random -import asyncio -import asyncpg - -db_pool = None - -async def db_setup(): - global db_pool - db_pool = await asyncpg.create_pool( - user = os.getenv('PGUSER', 'benchmarkdbuser'), - password = os.getenv('PGPASS', 'benchmarkdbpass'), - database = 'hello_world', - host = 'tfb-database', - port = 5432 - ) - -READ_ROW_SQL = 'SELECT "randomnumber", "id" FROM "world" WHERE id = $1' - - -def get_headers(): - return { - 'Server': 'Japronto/0.1.2', - 'Date': format_date_time(None), - } - -# ----------------------------------------------------------------------------------- - -def json_view(request): - return request.Response( - text = json.dumps( {'message': 'Hello, world!'} ), - mime_type = 'application/json', - headers = get_headers(), - ) - - -def plaintext_view(request): - return request.Response( - body = b'Hello, world!', - mime_type = 'text/plain', - headers = get_headers(), - ) - - -async def db_view(request): - global db_pool - row_id = random.randint(1, 10000) - async with db_pool.acquire() as connection: - number = await connection.fetchval(READ_ROW_SQL, row_id) - - text = json.dumps( {'id': row_id, 'randomNumber': number} ) - return request.Response(text = text, mime_type = 'application/json', headers = get_headers()) - -# ----------------------------------------------------------------------------------- - -app = japronto.Application() -app.router.add_route('/json', json_view, 'GET') -app.router.add_route('/plaintext', plaintext_view, 'GET') -#app.router.add_route('/db', db_view, 'GET') - -#asyncio.set_event_loop(app.loop) -#app.loop.run_until_complete(db_setup()) - -# ----------------------------------------------------------------------------------- - -if __name__ == '__main__': - _is_travis = os.environ.get('TRAVIS') == 'true' - - workers = int( multiprocessing.cpu_count() ) - if _is_travis: - workers = 2 - - app.run('0.0.0.0', 8080, worker_num = workers) diff --git a/frameworks/Python/japronto/app_postgres.py b/frameworks/Python/japronto/app_postgres.py deleted file mode 100644 index d68a92f026c..00000000000 --- a/frameworks/Python/japronto/app_postgres.py +++ /dev/null @@ -1,51 +0,0 @@ -import multiprocessing -from wsgiref.handlers import format_date_time -import random - -import japronto -import ujson as json - -from db import init_db, close_db - - -def get_headers(): - return { - 'Server': 'Japronto/0.1.1', - 'Date': format_date_time(None), - } - - -def json_view(request): - return request.Response( - text=json.dumps({'message': 'Hello, world!'}), - mime_type='application/json', - headers=get_headers(), - ) - - -def plaintext_view(request): - return request.Response( - body=b'Hello, world!', - mime_type='text/plain', - headers=get_headers(), - ) - - -async def db_view(request): - async with app.db_pool.acquire() as conn: - world = await conn.fetchrow("select id,randomnumber from world where id=%s" % random.randint(1, 10000)) - return request.Response( - text=json.dumps(dict(world)), - mime_type='application/json', headers=get_headers()) - - -app = japronto.Application() -app.on_startup.append(init_db) -app.on_cleanup.append(close_db) -app.router.add_route('/json', json_view, 'GET') -app.router.add_route('/plaintext', plaintext_view, 'GET') -app.router.add_route('/db', db_view, 'GET') - - -if __name__ == '__main__': - app.run('0.0.0.0', 8080, worker_num=multiprocessing.cpu_count()) diff --git a/frameworks/Python/japronto/benchmark_config.json b/frameworks/Python/japronto/benchmark_config.json deleted file mode 100644 index 21bb719516d..00000000000 --- a/frameworks/Python/japronto/benchmark_config.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "framework": "japronto", - "tests": [{ - "default": { - "json_url": "/json", - "plaintext_url": "/plaintext", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "framework": "japronto", - "language": "Python", - "flavor": "Python3", - "platform": "None", - "webserver": "None", - "os": "Linux", - "orm": "Raw", - "database_os": "Linux", - "database": "None", - "display_name": "Japronto", - "notes": "" - } - }] -} diff --git a/frameworks/Python/japronto/config.toml b/frameworks/Python/japronto/config.toml deleted file mode 100644 index 8b5d2cbd9ad..00000000000 --- a/frameworks/Python/japronto/config.toml +++ /dev/null @@ -1,15 +0,0 @@ -[framework] -name = "japronto" - -[main] -urls.plaintext = "/plaintext" -urls.json = "/json" -approach = "Realistic" -classification = "Micro" -database = "None" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "None" -webserver = "None" -versus = "None" diff --git a/frameworks/Python/japronto/db.py b/frameworks/Python/japronto/db.py deleted file mode 100644 index 2609377ff84..00000000000 --- a/frameworks/Python/japronto/db.py +++ /dev/null @@ -1,45 +0,0 @@ -import asyncio -from contextlib import asynccontextmanager -import asyncpg -import os - - -class Connection(asyncpg.Connection): - async def reset(self, *, timeout=None): - pass - - -class Pool: - def __init__(self, connect_url, max_size=10, connection_class=None): - self._connect_url = connect_url - self._connection_class = connection_class or Connection - self._queue = asyncio.LifoQueue(max_size) - - def __await__(self): - return self._async_init__().__await__() - - async def _async_init__(self): - for _ in range(self._queue.maxsize): - self._queue.put_nowait(await asyncpg.connect(self._connect_url, connection_class=self._connection_class)) - return self - - @asynccontextmanager - async def acquire(self): - conn = await self._queue.get() - try: - yield conn - finally: - self._queue.put_nowait(conn) - - async def close(self): - for _ in range(self._queue.maxsize): - conn = await self._queue.get() - await conn.close() - - -async def init_db(app): - app.db_pool = await Pool("postgresql://%s:%s@tfb-database:5432/hello_world" % (os.getenv("PGUSER", "benchmarkdbuser"), os.getenv("PSPASS", "benchmarkdbpass")), connection_class=asyncpg.Connection) - - -async def close_db(app): - await asyncio.wait_for(app.db_pool.close(), timeout=1) diff --git a/frameworks/Python/japronto/japronto-postgres.dockerfile b/frameworks/Python/japronto/japronto-postgres.dockerfile deleted file mode 100644 index d868e4b927c..00000000000 --- a/frameworks/Python/japronto/japronto-postgres.dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM python:3.9.7 - -ADD ./ /japronto - -WORKDIR /japronto - -RUN pip3 install -r /japronto/requirements_postgres.txt - -EXPOSE 8080 - -CMD python3 app_postgres.py diff --git a/frameworks/Python/japronto/japronto.dockerfile b/frameworks/Python/japronto/japronto.dockerfile deleted file mode 100644 index eb91bb3dfa1..00000000000 --- a/frameworks/Python/japronto/japronto.dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM python:3.8.12 - -ADD ./ /japronto - -WORKDIR /japronto - -RUN pip3 install -r /japronto/requirements.txt - -EXPOSE 8080 - -CMD python3 app.py diff --git a/frameworks/Python/japronto/requirements.txt b/frameworks/Python/japronto/requirements.txt deleted file mode 100644 index e3564875559..00000000000 --- a/frameworks/Python/japronto/requirements.txt +++ /dev/null @@ -1,4 +0,0 @@ -uvloop==0.17.0 -git+https://github.com/squeaky-pl/japronto.git#egg=japronto -asyncpg==0.27.0 -ujson==5.4.0 diff --git a/frameworks/Python/japronto/requirements_postgres.txt b/frameworks/Python/japronto/requirements_postgres.txt deleted file mode 100644 index 9b268878800..00000000000 --- a/frameworks/Python/japronto/requirements_postgres.txt +++ /dev/null @@ -1,3 +0,0 @@ -git+https://github.com/IterableTrucks/japronto.git@0d848d96dd010f6701729b14e6b8ec0330002b5c -asyncpg==0.25.0 -ujson==5.4.0 diff --git a/frameworks/Python/klein/benchmark_config.json b/frameworks/Python/klein/benchmark_config.json index e43ece59d8d..e00da480751 100644 --- a/frameworks/Python/klein/benchmark_config.json +++ b/frameworks/Python/klein/benchmark_config.json @@ -21,6 +21,7 @@ "os": "Linux", "database_os": "Linux", "display_name": "Klein", + "tags": ["broken"], "notes": "CPython 2.7" } }] diff --git a/frameworks/Python/litestar/.gitignore b/frameworks/Python/litestar/.gitignore new file mode 100644 index 00000000000..738a70f9240 --- /dev/null +++ b/frameworks/Python/litestar/.gitignore @@ -0,0 +1,244 @@ +### Python template +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/latest/usage/project/#working-with-version-control +.pdm.toml +.pdm-python +.pdm-build/ + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + +### PyCharm+all template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# AWS User-specific +.idea/**/aws.xml + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# SonarLint plugin +.idea/sonarlint/ + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +.ruff_cache/ \ No newline at end of file diff --git a/frameworks/Python/litestar/README.md b/frameworks/Python/litestar/README.md new file mode 100755 index 00000000000..c4b2b3e7ec8 --- /dev/null +++ b/frameworks/Python/litestar/README.md @@ -0,0 +1,37 @@ +# Litestar Benchmarking Test + +This is the Litestar portion of a [benchmarking tests suite](../../) +comparing a variety of web development platforms. + +The information below is specific to Litestar. 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 + +[**Litestar**](https://github.com/litestar-org/litestar) is a modern, fast (high-performance), web framework for building APIs with Python 3.6+. + +The key features are: + +* **Fast**: Very high performance, on par with **NodeJS** and **Go**. + +* **Fast to code**: Increase the speed to develop features by about 200% to 300% *. +* **Less bugs**: Reduce about 40% of human (developer) induced errors. * +* **Intuitive**: Great editor support. Completion everywhere. Less time debugging. +* **Easy**: Designed to be easy to use and learn. Less time reading docs. +* **Short**: Minimize code duplication. Multiple features from each parameter declaration. Less bugs. +* **Robust**: Get production-ready code. With automatic interactive documentation. +* **Standards-based**: Based on (and fully compatible with) the open standards for APIs: OpenAPI and JSON Schema. + +* estimation based on tests on an internal development team, building production applications. + +## Test Paths & Sources + +All of the test implementations are located within a single file ([app.py](app.py)). + + +## Resources + +* [Litestar source code on GitHub](https://github.com/litestar-org/litestar) +* [Litestar website - documentation](https://litestar.dev) diff --git a/frameworks/Python/litestar/app-socketify-asgi.py b/frameworks/Python/litestar/app-socketify-asgi.py new file mode 100755 index 00000000000..2e9de792826 --- /dev/null +++ b/frameworks/Python/litestar/app-socketify-asgi.py @@ -0,0 +1,49 @@ +import os +import multiprocessing +import logging + +import orjson +from litestar import Litestar, get, MediaType, Response +from socketify import ASGI + + +@get("/json") +async def json_serialization() -> Response: + return Response(content=orjson.dumps({"message": "Hello, world!"}), media_type=MediaType.JSON) + + +@get("/plaintext", media_type=MediaType.TEXT) +async def plaintext() -> bytes: + return b"Hello, world!" + + +app = Litestar( + route_handlers=[ + json_serialization, + plaintext, + ] +) + +_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 :) diff --git a/frameworks/Python/litestar/app.py b/frameworks/Python/litestar/app.py new file mode 100755 index 00000000000..6c5d0678ad9 --- /dev/null +++ b/frameworks/Python/litestar/app.py @@ -0,0 +1,152 @@ +import multiprocessing +import os +from contextlib import asynccontextmanager +from pathlib import Path +from random import randint, sample +from typing import Any + +import asyncpg +import orjson +from litestar import Litestar, MediaType, Request, get, Response +from litestar.contrib.jinja import JinjaTemplateEngine +from litestar.response import Template +from litestar.template import TemplateConfig + +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) + + +def get_num_queries(queries): + try: + query_count = int(queries) + except (ValueError, TypeError): + return 1 + + if query_count < 1: + return 1 + if query_count > 500: + return 500 + return query_count + + +connection_pool = None + + +async def setup_database(): + return await asyncpg.create_pool( + user=os.getenv("PGUSER", "benchmarkdbuser"), + password=os.getenv("PGPASS", "benchmarkdbpass"), + database="hello_world", + host="tfb-database", + port=5432, + min_size=MIN_POOL_SIZE, + max_size=MAX_POOL_SIZE, + ) + + +@asynccontextmanager +async def lifespan(app: Litestar): + # Set up the database connection pool + app.state.connection_pool = await setup_database() + yield + # Close the database connection pool + await app.state.connection_pool.close() + + +@get("/json") +async def json_serialization() -> Response: + return Response( + content=orjson.dumps({"message": "Hello, world!"}), + media_type=MediaType.JSON, + ) + + +@get("/db") +async def single_database_query() -> Response: + row_id = randint(1, 10000) + async with app.state.connection_pool.acquire() as connection: + number = await connection.fetchval(READ_ROW_SQL, row_id) + + return Response( + content=orjson.dumps({"id": row_id, "randomNumber": number}), + media_type=MediaType.JSON, + ) + + +@get("/queries") +async def multiple_database_queries(queries: Any = None) -> Response: + num_queries = get_num_queries(queries) + row_ids = sample(range(1, 10000), num_queries) + worlds = [] + + async with app.state.connection_pool.acquire() as connection: + statement = await connection.prepare(READ_ROW_SQL) + for row_id in row_ids: + number = await statement.fetchval(row_id) + worlds.append({"id": row_id, "randomNumber": number}) + + return Response( + content=orjson.dumps(worlds), + media_type=MediaType.JSON, + ) + + +@get("/fortunes", media_type=MediaType.HTML) +async def fortunes(request: Request) -> Template: + async with app.state.connection_pool.acquire() as connection: + fortunes = await connection.fetch("SELECT * FROM Fortune") + + fortunes.append(ADDITIONAL_ROW) + fortunes.sort(key=lambda row: row[1]) + return Template( + "fortune.html", + context={"fortunes": fortunes, "request": request}, + media_type=MediaType.HTML, + ) + + +@get("/updates") +async def database_updates(queries: Any = None) -> bytes: + num_queries = get_num_queries(queries) + # To avoid deadlock + ids = sorted(sample(range(1, 10000 + 1), num_queries)) + numbers = sorted(sample(range(1, 10000), num_queries)) + updates = list(zip(ids, numbers, strict=False)) + + worlds = [{"id": row_id, "randomNumber": number} for row_id, number in updates] + + async with app.state.connection_pool.acquire() as connection: + statement = await connection.prepare(READ_ROW_SQL) + for row_id, _ in updates: + await statement.fetchval(row_id) + await connection.executemany(WRITE_ROW_SQL, updates) + + return Response( + content=orjson.dumps(worlds), + media_type=MediaType.JSON, + ) + + +@get("/plaintext", media_type=MediaType.TEXT) +async def plaintext() -> bytes: + return b"Hello, world!" + + +app = Litestar( + lifespan=[lifespan], + template_config=TemplateConfig( + directory=Path("templates"), + engine=JinjaTemplateEngine, + ), + route_handlers=[ + json_serialization, + single_database_query, + multiple_database_queries, + fortunes, + database_updates, + plaintext, + ], +) diff --git a/frameworks/Python/litestar/app_orm.py b/frameworks/Python/litestar/app_orm.py new file mode 100755 index 00000000000..ab7f415450c --- /dev/null +++ b/frameworks/Python/litestar/app_orm.py @@ -0,0 +1,185 @@ +import logging +import multiprocessing +import os +from contextlib import asynccontextmanager +from operator import attrgetter +from pathlib import Path +from random import randint, sample +from typing import Any + +import orjson +from litestar import Litestar, MediaType, Request, get, Response +from litestar.contrib.jinja import JinjaTemplateEngine +from litestar.response import Template +from litestar.template import TemplateConfig +from sqlalchemy import Column, Integer, String, select +from sqlalchemy.ext.asyncio import async_sessionmaker, create_async_engine +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm.attributes import flag_modified + +logger = logging.getLogger(__name__) + +Base = declarative_base() + + +class World(Base): + __tablename__ = "world" + id = Column(Integer, primary_key=True) + randomnumber = Column(Integer) + + def __json__(self): + return {"id": self.id, "randomnumber": self.randomnumber} + + +sa_data = World.__table__ + + +class Fortune(Base): + __tablename__ = "fortune" + id = Column(Integer, primary_key=True) + message = Column(String) + + +sa_fortunes = Fortune.__table__ + +ADDITIONAL_FORTUNE = Fortune(id=0, message="Additional fortune added at request time.") +MAX_POOL_SIZE = 1000 // multiprocessing.cpu_count() + +sort_fortunes_key = attrgetter("message") + +template_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "templates") + + +async def setup_database(): + dsn = "postgresql+asyncpg://%s:%s@tfb-database:5432/hello_world" % ( + os.getenv("PGPASS", "benchmarkdbuser"), + os.getenv("PGPASS", "benchmarkdbpass"), + ) + + engine = create_async_engine( + dsn, + future=True, + pool_size=MAX_POOL_SIZE, + connect_args={ + "ssl": False # NEEDED FOR NGINX-UNIT OTHERWISE IT FAILS + }, + ) + return async_sessionmaker(engine) + + +@asynccontextmanager +async def lifespan(app: Litestar): + # Set up the database connection pool + app.state.db_session = await setup_database() + yield + # Close the database connection pool + await app.state.db_session().close() + + +def get_num_queries(queries): + try: + query_count = int(queries) + except (ValueError, TypeError): + return 1 + + if query_count < 1: + return 1 + if query_count > 500: + return 500 + return query_count + + +@get("/json") +async def json_serialization() -> Response: + return Response( + content=orjson.dumps({"message": "Hello, world!"}), + media_type=MediaType.JSON, + ) + + +@get("/db") +async def single_database_query() -> Response: + id_ = randint(1, 10000) + + async with app.state.db_session() as sess: + result = await sess.get(World, id_) + + return Response( + content=orjson.dumps(result.__json__()), + media_type=MediaType.JSON, + ) + + +@get("/queries") +async def multiple_database_queries(queries: Any = None) -> Response: + num_queries = get_num_queries(queries) + data = [] + + async with app.state.db_session() as sess: + for id_ in sample(range(1, 10001), num_queries): + result = await sess.get(World, id_) + data.append(result.__json__()) + + return Response( + content=orjson.dumps(data), + media_type=MediaType.JSON, + ) + + +@get("/fortunes", media_type=MediaType.HTML) +async def fortunes(request: Request) -> Template: + async with app.state.db_session() as sess: + ret = await sess.execute(select(Fortune.id, Fortune.message)) + data = ret.all() + + data.append(ADDITIONAL_FORTUNE) + data.sort(key=sort_fortunes_key) + + return Template( + "fortune.jinja", + context={"request": request, "fortunes": data}, + media_type=MediaType.HTML, + ) + + +@get("/updates") +async def database_updates(queries: Any = None) -> Response: + num_queries = get_num_queries(queries) + + ids = sorted(sample(range(1, 10000 + 1), num_queries)) + data = [] + async with app.state.db_session.begin() as sess: + for id_ in ids: + world = await sess.get(World, id_, populate_existing=True) + world.randomnumber = randint(1, 10000) + # force sqlalchemy to UPDATE entry even if the value has not changed + # doesn't make sense in a real application, added only for pass `tfb verify` + flag_modified(world, "randomnumber") + data.append(world.__json__()) + + return Response( + content=orjson.dumps(data), + media_type=MediaType.JSON, + ) + + +@get("/plaintext", media_type=MediaType.TEXT) +async def plaintext() -> bytes: + return b"Hello, world!" + + +app = Litestar( + template_config=TemplateConfig( + directory=Path("templates"), + engine=JinjaTemplateEngine, + ), + lifespan=[lifespan], + route_handlers=[ + json_serialization, + single_database_query, + multiple_database_queries, + fortunes, + database_updates, + plaintext, + ], +) diff --git a/frameworks/Python/litestar/benchmark_config.json b/frameworks/Python/litestar/benchmark_config.json new file mode 100755 index 00000000000..1f94fc49174 --- /dev/null +++ b/frameworks/Python/litestar/benchmark_config.json @@ -0,0 +1,186 @@ +{ + "framework": "litestar", + "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": "Micro", + "database": "Postgres", + "framework": "Litestar", + "language": "Python", + "flavor": "Python3", + "orm": "Raw", + "platform": "asyncio", + "webserver": "Gunicorn", + "os": "Linux", + "database_os": "Linux", + "display_name": "Litestar", + "notes": "", + "versus": "None" + }, + "socketify-asgi": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "Postgres", + "framework": "Litestar", + "language": "Python", + "flavor": "Python3", + "orm": "Raw", + "platform": "asyncio", + "webserver": "Socketify.py", + "os": "Linux", + "database_os": "Linux", + "display_name": "Litestar [Socketify.py ASGI]", + "notes": "", + "versus": "None" + }, + "gunicorn": { + "json_url": "/json", + "db_url": "/db", + "query_url": "/queries?queries=", + "update_url": "/updates?queries=", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "Postgres", + "framework": "Litestar", + "language": "Python", + "flavor": "Python3", + "orm": "Raw", + "platform": "asyncio", + "webserver": "Gunicorn", + "os": "Linux", + "database_os": "Linux", + "display_name": "Litestar-gunicorn", + "notes": "", + "versus": "None" + }, + "gunicorn-orm": { + "fortune_url": "/fortunes", + "db_url": "/db", + "query_url": "/queries?queries=", + "update_url": "/updates?queries=", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "Postgres", + "framework": "Litestar", + "language": "Python", + "flavor": "Python3", + "orm": "Full", + "platform": "asyncio", + "webserver": "Gunicorn", + "os": "Linux", + "database_os": "Linux", + "display_name": "Litestar-gunicorn-orm", + "notes": "", + "versus": "None" + }, + "granian": { + "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": "Micro", + "database": "Postgres", + "framework": "Litestar", + "language": "Python", + "flavor": "Python3", + "orm": "Raw", + "platform": "asyncio", + "webserver": "Granian", + "os": "Linux", + "database_os": "Linux", + "display_name": "Litestar-granian", + "notes": "", + "versus": "None" + }, + "granian-orm": { + "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": "Micro", + "database": "Postgres", + "framework": "Litestar", + "language": "Python", + "flavor": "Python3", + "orm": "Raw", + "platform": "asyncio", + "webserver": "Granian", + "os": "Linux", + "database_os": "Linux", + "display_name": "Litestar-granian-orm", + "notes": "", + "versus": "None" + }, + "nginx-unit": { + "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": "Micro", + "database": "Postgres", + "framework": "Litestar", + "language": "Python", + "flavor": "Python3", + "orm": "Raw", + "platform": "asyncio", + "webserver": "nginx-unit", + "os": "Linux", + "database_os": "Linux", + "display_name": "Litestar-nginx-unit", + "notes": "", + "versus": "None", + "tags": [ + "broken" + ] + }, + "uvicorn": { + "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": "Micro", + "database": "Postgres", + "framework": "Litestar", + "language": "Python", + "flavor": "Python3", + "orm": "Raw", + "platform": "asyncio", + "webserver": "Uvicorn", + "os": "Linux", + "database_os": "Linux", + "display_name": "Litestar-uvicorn", + "notes": "", + "versus": "None" + } + } + ] +} diff --git a/frameworks/Python/litestar/config.toml b/frameworks/Python/litestar/config.toml new file mode 100644 index 00000000000..7f9955e83d5 --- /dev/null +++ b/frameworks/Python/litestar/config.toml @@ -0,0 +1,184 @@ +[framework] +name = "litestar" + +[gunicorn] +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" + +[socketify-asgi-pypy] +urls.plaintext = "/plaintext" +urls.json = "/json" +approach = "Realistic" +classification = "Micro" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "None" +webserver = "Socketify.py" +versus = "None" + +[socketify-asgi] +urls.plaintext = "/plaintext" +urls.json = "/json" +approach = "Realistic" +classification = "Micro" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "Raw" +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" +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 = "Full" +platform = "None" +webserver = "Gunicorn" +versus = "None" + +[hypercorn] +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" + + +[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] +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" + + +[uvicorn] +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 = "uvicorn" +versus = "None" + +[uvicorn-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 = "uvicorn" +versus = "None" diff --git a/frameworks/Python/litestar/litestar-granian-orm.dockerfile b/frameworks/Python/litestar/litestar-granian-orm.dockerfile new file mode 100644 index 00000000000..72c989b5f42 --- /dev/null +++ b/frameworks/Python/litestar/litestar-granian-orm.dockerfile @@ -0,0 +1,20 @@ +FROM python:3.13 + +WORKDIR /litestar + +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-granian.txt ./ + +RUN pip3 install -r requirements.txt -r requirements-sqlalchemy.txt -r requirements-granian.txt + +COPY . ./ + +EXPOSE 8080 + +ENV CONNECTION=ORM + +CMD granian --interface asgi app:app --host '0.0.0.0' --port 8080 --workers $(nproc) diff --git a/frameworks/Python/litestar/litestar-granian.dockerfile b/frameworks/Python/litestar/litestar-granian.dockerfile new file mode 100644 index 00000000000..ae838eaedf6 --- /dev/null +++ b/frameworks/Python/litestar/litestar-granian.dockerfile @@ -0,0 +1,18 @@ +FROM python:3.13 + +WORKDIR /litestar + +RUN python -m venv /opt/venv +ENV PATH="/opt/venv/bin:$PATH" + +RUN pip3 install cython==3.0.12 + +COPY requirements.txt requirements-granian.txt ./ + +RUN pip3 install -r requirements.txt -r requirements-granian.txt + +COPY . ./ + +EXPOSE 8080 + +CMD granian --interface asgi app:app --host '0.0.0.0' --port 8080 --workers $(nproc) diff --git a/frameworks/Python/litestar/litestar-gunicorn-orm.dockerfile b/frameworks/Python/litestar/litestar-gunicorn-orm.dockerfile new file mode 100644 index 00000000000..a5c01176b32 --- /dev/null +++ b/frameworks/Python/litestar/litestar-gunicorn-orm.dockerfile @@ -0,0 +1,20 @@ +FROM python:3.13 + +WORKDIR /litestar + +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 ./ + +RUN pip3 install -r requirements.txt -r requirements-sqlalchemy.txt -r requirements-gunicorn.txt + +COPY . ./ + +EXPOSE 8080 + +ENV CONNECTION=ORM + +CMD gunicorn app_orm:app -k uvicorn_worker.UvicornWorker -c litestar_conf.py diff --git a/frameworks/Python/litestar/litestar-gunicorn.dockerfile b/frameworks/Python/litestar/litestar-gunicorn.dockerfile new file mode 100644 index 00000000000..6d3d793e6fc --- /dev/null +++ b/frameworks/Python/litestar/litestar-gunicorn.dockerfile @@ -0,0 +1,18 @@ +FROM python:3.13 + +WORKDIR /litestar + +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 ./ + +RUN pip3 install -r requirements.txt -r requirements-gunicorn.txt + +COPY . ./ + +EXPOSE 8080 + +CMD gunicorn app:app -k uvicorn_worker.UvicornWorker -c litestar_conf.py diff --git a/frameworks/Python/litestar/litestar-nginx-unit.dockerfile b/frameworks/Python/litestar/litestar-nginx-unit.dockerfile new file mode 100644 index 00000000000..b7b60b6f3d9 --- /dev/null +++ b/frameworks/Python/litestar/litestar-nginx-unit.dockerfile @@ -0,0 +1,20 @@ +FROM nginx/unit:1.29.1-python3.13 + +WORKDIR /litestar + +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/litestar/litestar-socketify-asgi.dockerfile b/frameworks/Python/litestar/litestar-socketify-asgi.dockerfile new file mode 100644 index 00000000000..0233ec1aebf --- /dev/null +++ b/frameworks/Python/litestar/litestar-socketify-asgi.dockerfile @@ -0,0 +1,19 @@ +FROM python:3.13-bullseye + +WORKDIR /litestar + +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 + +COPY requirements-socketify.txt ./ + +RUN pip3 install -r requirements-socketify.txt + +COPY . ./ + +EXPOSE 8080 + +CMD python ./app-socketify-asgi.py diff --git a/frameworks/Python/litestar/litestar-uvicorn.dockerfile b/frameworks/Python/litestar/litestar-uvicorn.dockerfile new file mode 100644 index 00000000000..bacb4961ba1 --- /dev/null +++ b/frameworks/Python/litestar/litestar-uvicorn.dockerfile @@ -0,0 +1,18 @@ +FROM python:3.13 + +WORKDIR /litestar + +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 + +COPY . ./ + +EXPOSE 8080 + +CMD uvicorn app:app --host 0.0.0.0 --port 8080 --workers $(nproc) --log-level error diff --git a/frameworks/Python/litestar/litestar.dockerfile b/frameworks/Python/litestar/litestar.dockerfile new file mode 100644 index 00000000000..6d3d793e6fc --- /dev/null +++ b/frameworks/Python/litestar/litestar.dockerfile @@ -0,0 +1,18 @@ +FROM python:3.13 + +WORKDIR /litestar + +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 ./ + +RUN pip3 install -r requirements.txt -r requirements-gunicorn.txt + +COPY . ./ + +EXPOSE 8080 + +CMD gunicorn app:app -k uvicorn_worker.UvicornWorker -c litestar_conf.py diff --git a/frameworks/Python/litestar/litestar_conf.py b/frameworks/Python/litestar/litestar_conf.py new file mode 100644 index 00000000000..c0f0af8f743 --- /dev/null +++ b/frameworks/Python/litestar/litestar_conf.py @@ -0,0 +1,12 @@ +import multiprocessing +import os + +_is_travis = os.environ.get("TRAVIS") == "true" + +workers = multiprocessing.cpu_count() + +bind = "0.0.0.0:8080" +keepalive = 120 +errorlog = "-" +pidfile = "/tmp/litestar.pid" +loglevel = "error" diff --git a/frameworks/Python/litestar/nginx-unit-config.sh b/frameworks/Python/litestar/nginx-unit-config.sh new file mode 100755 index 00000000000..3f947f13a90 --- /dev/null +++ b/frameworks/Python/litestar/nginx-unit-config.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash + +config='{' +config+=' "listeners": {' +config+=' "*:8080": {' +config+=' "pass": "applications/litestar"' +config+=' }' +config+=' },' +config+=' "applications": {' +config+=' "litestar": {' +config+=' "type": "python",' +config+=' "path": "/litestar",' +config+=' "home": "/opt/venv/",' +config+=' "protocol": "asgi",' +config+=' "module": "app",' +config+=' "callable": "app",' +config+=' "processes": '"$(nproc)"',' +config+=' }' +config+=' }', +config+=' "access_log": "/dev/null"' +config+='}' + +curl -X PUT \ + --data-binary "$config" \ + --unix-socket /var/run/control.unit.sock \ + http://localhost/config diff --git a/frameworks/Python/litestar/requirements-granian.txt b/frameworks/Python/litestar/requirements-granian.txt new file mode 100644 index 00000000000..946bfa8d0b1 --- /dev/null +++ b/frameworks/Python/litestar/requirements-granian.txt @@ -0,0 +1,2 @@ +granian==2.3.1 +litestar-granian==0.13.0 \ No newline at end of file diff --git a/frameworks/Python/litestar/requirements-gunicorn.txt b/frameworks/Python/litestar/requirements-gunicorn.txt new file mode 100644 index 00000000000..c95d2c0209a --- /dev/null +++ b/frameworks/Python/litestar/requirements-gunicorn.txt @@ -0,0 +1,2 @@ +gunicorn==23.0.0 +uvicorn-worker==0.3.0 diff --git a/frameworks/Python/litestar/requirements-socketify.txt b/frameworks/Python/litestar/requirements-socketify.txt new file mode 100644 index 00000000000..75fdf6fc3dd --- /dev/null +++ b/frameworks/Python/litestar/requirements-socketify.txt @@ -0,0 +1,3 @@ +orjson==3.10.16 +litestar==2.17.0 +git+https://github.com/cirospaciari/socketify.py.git@main#socketify diff --git a/frameworks/Python/litestar/requirements-sqlalchemy.txt b/frameworks/Python/litestar/requirements-sqlalchemy.txt new file mode 100644 index 00000000000..d2e7a36be45 --- /dev/null +++ b/frameworks/Python/litestar/requirements-sqlalchemy.txt @@ -0,0 +1,3 @@ +psycopg2==2.9.10 +SQLAlchemy==2.0.40 +litestar[sqlalchemy]==2.16.0 \ No newline at end of file diff --git a/frameworks/Python/litestar/requirements-uvicorn.txt b/frameworks/Python/litestar/requirements-uvicorn.txt new file mode 100644 index 00000000000..e9603a4a89c --- /dev/null +++ b/frameworks/Python/litestar/requirements-uvicorn.txt @@ -0,0 +1,3 @@ +uvicorn==0.34.2 +uvloop==0.21.0 +httptools==0.6.4 diff --git a/frameworks/Python/litestar/requirements.txt b/frameworks/Python/litestar/requirements.txt new file mode 100644 index 00000000000..f45f8fd344d --- /dev/null +++ b/frameworks/Python/litestar/requirements.txt @@ -0,0 +1,4 @@ +asyncpg==0.30.0 +litestar==2.17.0 +Jinja2==3.1.6 +orjson==3.10.18 \ No newline at end of file diff --git a/frameworks/Python/litestar/ruff.toml b/frameworks/Python/litestar/ruff.toml new file mode 100644 index 00000000000..adaca462881 --- /dev/null +++ b/frameworks/Python/litestar/ruff.toml @@ -0,0 +1,79 @@ +fix = true +line-length = 120 +src = ["evalai_backend", "tests"] +target-version = "py312" + +[format] +docstring-code-format = true +docstring-code-line-length = 120 +indent-style = "tab" +quote-style = "double" +skip-magic-trailing-comma = false + +[lint] +ignore = [ + "TID252", + "E501", + "S101", + "S102", + "S104", + "S324", + "EXE002", + "D100", + "D102", + "D203", # clash with formatter + "D206", # we use tabs + "D103", + "D104", + "D105", + "D106", + "D101", + "D107", + "D212", + "D211", + "PGH003", + "PGH004", + "N811", + "N804", + "N818", + "N806", + "N815", + "ARG001", + "ARG002", + "DTZ003", + "DTZ005", + "RSE102", + "SLF001", + "PLR", + "INP", + "TRY", + "SIM300", + "SIM114", + "DJ008", + "FIX002", + "S603", + "S607", + "TD002", + "TD003", + "W191", # We use tabs + "COM812", # missing trailing comma + "ISC001", # handled by formatter + "FBT001", + "FBT002", + "FBT003", + "ERA001", +] +select = [ + "ALL" +] + +[lint.flake8-annotations] +suppress-none-returning = true + +[lint.flake8-quotes] +docstring-quotes = "double" +inline-quotes = "double" +multiline-quotes = "double" + +[lint.isort] +combine-as-imports = true diff --git a/frameworks/Python/apidaora/templates/fortune.html b/frameworks/Python/litestar/templates/fortune.html similarity index 100% rename from frameworks/Python/apidaora/templates/fortune.html rename to frameworks/Python/litestar/templates/fortune.html diff --git a/frameworks/Python/litestar/templates/fortune.jinja b/frameworks/Python/litestar/templates/fortune.jinja new file mode 100644 index 00000000000..5126edffbf7 --- /dev/null +++ b/frameworks/Python/litestar/templates/fortune.jinja @@ -0,0 +1,10 @@ + + +Fortunes + + + +{% for fortune in fortunes %} +{% endfor %}
idmessage
{{ fortune.id }}{{ fortune.message|e }}
+ + diff --git a/frameworks/Python/microdot/README.md b/frameworks/Python/microdot/README.md index 9aefbcba3a3..c52da3793b9 100644 --- a/frameworks/Python/microdot/README.md +++ b/frameworks/Python/microdot/README.md @@ -8,20 +8,13 @@ Also note that there is additional information provided in the [Python README](. ### Test Source Code -* [JSON](app_sync.py#L60) -* [JSON-async](app_async.py#L60) -* [PLAINTEXT](app_sync.py#L102) -* [PLAINTEXT-async](app_async.py#L102) -* [DB](app_sync.py#L65) -* [DB-async](app_async.py#L65) -* [QUERY](app_sync.py#L73) -* [QUERY-async](app_async.py#L83) -* [CACHED QUERY](app_sync.py#L112) -* [CACHED_QUERY-async](app_async.py#L112) -* [UPDATE](app_sync.py#L89) -* [UPDATE-async](app_async.py#L89) -* [FORTUNES](app_sync.py#L80) -* [FORTUNES-async](app_async.py#L80) +* [JSON](app.py#L60) +* [PLAINTEXT](app.py#L102) +* [DB](app.py#L65) +* [QUERY](app.py#L73) +* [CACHED QUERY](app.py#L112) +* [UPDATE](app.py#L89) +* [FORTUNES](app.py#L80) ## Resources diff --git a/frameworks/Python/microdot/app.py b/frameworks/Python/microdot/app.py new file mode 100644 index 00000000000..a60c7edc98c --- /dev/null +++ b/frameworks/Python/microdot/app.py @@ -0,0 +1,117 @@ +#!/usr/bin/env python +import os +from random import randint, sample + +from alchemical.aio import Alchemical, Model +import sqlalchemy.orm as so +from asyncache import cached +from cachetools.keys import hashkey + +from microdot.asgi import Microdot +from microdot.jinja import Template + +app = Microdot() +Template.initialize('templates', enable_async=True) +db = Alchemical(os.environ.get('DATABASE_URL', 'sqlite:///')) + + +class World(Model): + __tablename__ = "world" + id: so.Mapped[int] = so.mapped_column(primary_key=True) + randomnumber: so.Mapped[int] + + def to_dict(self): + return {"id": self.id, "randomNumber": self.randomnumber} + + +class CachedWorld(Model): + __tablename__ = "cachedworld" + id: so.Mapped[int] = so.mapped_column(primary_key=True) + randomnumber: so.Mapped[int] + + def to_dict(self): + return {"id": self.id, "randomNumber": self.randomnumber} + + +class Fortune(Model): + __tablename__ = "fortune" + id: so.Mapped[int] = so.mapped_column(primary_key=True) + message: so.Mapped[str] + + +def get_num_queries(request, name="queries"): + try: + num_queries = request.args.get(name, 1, type=int) + except ValueError: + num_queries = 1 + if num_queries < 1: + return 1 + if num_queries > 500: + return 500 + return num_queries + + +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) + async with db.Session() as session: + world = await session.get(World, id) + return world.to_dict() + + +@app.route("/queries") +async def test_queries(request): + async with db.Session() as session: + worlds = [(await session.get(World, id)).to_dict() for id in generate_ids(get_num_queries(request))] + return worlds + + +@app.route("/fortunes") +async def test_fortunes(request): + async with db.Session() as session: + fortunes = list(await session.scalars(Fortune.select())) + fortunes.append(Fortune(id=0, message="Additional fortune added at request time.")) + fortunes.sort(key=lambda f: f.message) + return ( + await Template("fortunes.html").render_async(fortunes=fortunes), + {'Content-Type': 'text/html; charset=utf-8'}, + ) + + +@app.route("/updates") +async def test_updates(request): + worlds = [] + ids = generate_ids(get_num_queries(request)) + ids.sort() # to avoid deadlocks + async with db.begin() as session: + for id in ids: + world = await session.get(World, id) + world.randomnumber = (randint(1, 9999) + world.randomnumber - 1) % 10000 + 1 + worlds.append(world.to_dict()) + return worlds + + +@app.route("/plaintext") +async def test_plaintext(request): + return b"Hello, World!" + + +@cached(cache={}, key=lambda session, id: hashkey(id)) +async def get_cached_world(session, id): + return (await session.get(World, id)).to_dict() + + +@app.route("/cached-queries") +async def test_cached_queries(request): + async with db.Session() as session: + worlds = [await get_cached_world(session, id) for id in generate_ids(get_num_queries(request, 'count'))] + return worlds diff --git a/frameworks/Python/microdot/app_async.py b/frameworks/Python/microdot/app_async.py deleted file mode 100644 index 428491ce3d6..00000000000 --- a/frameworks/Python/microdot/app_async.py +++ /dev/null @@ -1,114 +0,0 @@ -#!/usr/bin/env python -from datetime import datetime -import os -from random import randint, sample - -from alchemical.aio import Alchemical -import sqlalchemy as sqla -from asyncache import cached -from cachetools.keys import hashkey - -from microdot_asgi import Microdot -from microdot_jinja import render_template - -app = Microdot() -db = Alchemical(os.environ['DATABASE_URL']) - - -class World(db.Model): - __tablename__ = "world" - id = sqla.Column(sqla.Integer, primary_key=True) - randomnumber = sqla.Column(sqla.Integer) - - def to_dict(self): - return {"id": self.id, "randomNumber": self.randomnumber} - - -class CachedWorld(db.Model): - __tablename__ = "cachedworld" - id = sqla.Column(sqla.Integer, primary_key=True) - randomnumber = sqla.Column(sqla.Integer) - - def to_dict(self): - return {"id": self.id, "randomNumber": self.randomnumber} - - -class Fortune(db.Model): - __tablename__ = "fortune" - id = sqla.Column(sqla.Integer, primary_key=True) - message = sqla.Column(sqla.String) - - -def get_num_queries(request, name="queries"): - try: - num_queries = request.args.get(name, 1, type=int) - except ValueError: - num_queries = 1 - if num_queries < 1: - return 1 - if num_queries > 500: - return 500 - return num_queries - - -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) - async with db.Session() as session: - world = await session.get(World, id) - return world.to_dict() - - -@app.route("/queries") -async def test_queries(request): - async with db.Session() as session: - worlds = [(await session.get(World, id)).to_dict() for id in generate_ids(get_num_queries(request))] - return worlds - - -@app.route("/fortunes") -async def test_fortunes(request): - async with db.Session() as session: - fortunes = list(await session.scalars(Fortune.select())) - fortunes.append(Fortune(id=0, message="Additional fortune added at request time.")) - fortunes.sort(key=lambda f: f.message) - return render_template("fortunes.html", fortunes=fortunes), {'Content-Type': 'text/html; charset=utf-8'} - - -@app.route("/updates") -async def test_updates(request): - worlds = [] - ids = generate_ids(get_num_queries(request)) - ids.sort() # to avoid deadlocks - async with db.begin() as session: - for id in ids: - world = await session.get(World, id) - world.randomnumber = (randint(1, 9999) + world.randomnumber - 1) % 10000 + 1 - worlds.append(world.to_dict()) - return worlds - - -@app.route("/plaintext") -async def test_plaintext(request): - return b"Hello, World!" - - -@cached(cache={}, key=lambda session, id: hashkey(id)) -async def get_cached_world(session, id): - return (await session.get(World, id)).to_dict() - - -@app.route("/cached-queries") -async def test_cached_queries(request): - async with db.Session() as session: - worlds = [await get_cached_world(session, id) for id in generate_ids(get_num_queries(request, 'count'))] - return worlds diff --git a/frameworks/Python/microdot/app_async_raw.py b/frameworks/Python/microdot/app_async_raw.py deleted file mode 100644 index d6368bc6826..00000000000 --- a/frameworks/Python/microdot/app_async_raw.py +++ /dev/null @@ -1,121 +0,0 @@ -#!/usr/bin/env python -from datetime import datetime -import os -from random import randint, sample - -import asyncpg -from asyncache import cached -from cachetools.keys import hashkey - -from microdot_asgi import Microdot -from microdot_jinja import render_template - -app = Microdot() -get_world_sql = 'SELECT id, randomnumber FROM world WHERE id = $1' -update_world_sql = 'UPDATE world SET randomnumber = $1 WHERE id = $2' -fortune_sql = 'SELECT * FROM fortune' -db = None - -async def asgi(scope, receive, send): - if scope['type'] == 'lifespan': - while True: - message = await receive() - if message['type'] == 'lifespan.startup': - global db, get_world_stmt, update_world_stmt, fortune_stmt - db = await asyncpg.create_pool(os.environ['DATABASE_URL']) - await send({'type': 'lifespan.startup.complete'}) - elif message['type'] == 'lifespan.shutdown': - db.close() - await send({'type': 'lifespan.shutdown.complete'}) - return - else: - return await app(scope, receive, send) - - -def get_num_queries(request, name="queries"): - try: - num_queries = request.args.get(name, 1, type=int) - except ValueError: - num_queries = 1 - if num_queries < 1: - return 1 - if num_queries > 500: - return 500 - return num_queries - - -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) - async with db.acquire() as conn: - result = await conn.fetchrow(get_world_sql, id) - world = {'id': result[0], 'randomNumber': result[1]} - return world - - -async def get_world(stmt, id): - result = await stmt.fetchrow(id) - return {'id': result[0], 'randomNumber': result[1]} - - -@app.route("/queries") -async def test_queries(request): - async with db.acquire() as conn: - stmt = await conn.prepare(get_world_sql) - worlds = [await get_world(stmt, id) for id in generate_ids(get_num_queries(request))] - return worlds - - -@app.route("/fortunes") -async def test_fortunes(request): - async with db.acquire() as conn: - fortunes = list(await conn.fetch(fortune_sql)) - fortunes.append((0, "Additional fortune added at request time.")) - fortunes.sort(key=lambda f: f[1]) - return render_template("fortunes_raw.html", fortunes=fortunes), {'Content-Type': 'text/html; charset=utf-8'} - - -@app.route("/updates") -async def test_updates(request): - worlds = [] - updated_worlds = [] - ids = generate_ids(get_num_queries(request)) - ids.sort() # to avoid deadlocks - async with db.acquire() as conn: - get_stmt = await conn.prepare(get_world_sql) - update_stmt = await conn.prepare(update_world_sql) - for id in ids: - world = await get_world(get_stmt, id) - new_value = randint(1, 10000) - updated_worlds.append((new_value, id)) - worlds.append({'id': id, 'randomNumber': new_value}) - await update_stmt.executemany(updated_worlds) - 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) - return {'id': result[0], 'randomNumber': result[1]} - - -@app.route("/cached-queries") -async def test_cached_queries(request): - async with db.acquire() as conn: - get_stmt = await conn.prepare(get_world_sql) - worlds = [await get_cached_world(get_stmt, id) for id in generate_ids(get_num_queries(request, 'count'))] - return worlds diff --git a/frameworks/Python/microdot/app_raw.py b/frameworks/Python/microdot/app_raw.py new file mode 100644 index 00000000000..9aa8a7ab362 --- /dev/null +++ b/frameworks/Python/microdot/app_raw.py @@ -0,0 +1,126 @@ +#!/usr/bin/env python +import os +from random import randint, sample + +import asyncpg +from asyncache import cached +from cachetools.keys import hashkey + +from microdot.asgi import Microdot +from microdot.jinja import Template + +app = Microdot() +Template.initialize('templates', enable_async=True) + +get_world_sql = 'SELECT id, randomnumber FROM world WHERE id = $1' +update_world_sql = 'UPDATE world SET randomnumber = $1 WHERE id = $2' +fortune_sql = 'SELECT * FROM fortune' +db = None + + +async def asgi(scope, receive, send): + if scope['type'] == 'lifespan': + while True: + message = await receive() + if message['type'] == 'lifespan.startup': + global db, get_world_stmt, update_world_stmt, fortune_stmt + db = await asyncpg.create_pool(os.environ['DATABASE_URL']) + await send({'type': 'lifespan.startup.complete'}) + elif message['type'] == 'lifespan.shutdown': + db.close() + await send({'type': 'lifespan.shutdown.complete'}) + return + else: + return await app(scope, receive, send) + + +def get_num_queries(request, name="queries"): + try: + num_queries = request.args.get(name, 1, type=int) + except ValueError: + num_queries = 1 + if num_queries < 1: + return 1 + if num_queries > 500: + return 500 + return num_queries + + +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) + async with db.acquire() as conn: + result = await conn.fetchrow(get_world_sql, id) + world = {'id': result[0], 'randomNumber': result[1]} + return world + + +async def get_world(stmt, id): + result = await stmt.fetchrow(id) + return {'id': result[0], 'randomNumber': result[1]} + + +@app.route("/queries") +async def test_queries(request): + async with db.acquire() as conn: + stmt = await conn.prepare(get_world_sql) + worlds = [await get_world(stmt, id) for id in generate_ids(get_num_queries(request))] + return worlds + + +@app.route("/fortunes") +async def test_fortunes(request): + async with db.acquire() as conn: + fortunes = list(await conn.fetch(fortune_sql)) + fortunes.append((0, "Additional fortune added at request time.")) + fortunes.sort(key=lambda f: f[1]) + return ( + await Template("fortunes_raw.html").render_async(fortunes=fortunes), + {'Content-Type': 'text/html; charset=utf-8'}, + ) + + +@app.route("/updates") +async def test_updates(request): + worlds = [] + updated_worlds = [] + ids = generate_ids(get_num_queries(request)) + ids.sort() # to avoid deadlocks + async with db.acquire() as conn: + get_stmt = await conn.prepare(get_world_sql) + update_stmt = await conn.prepare(update_world_sql) + for id in ids: + world = await get_world(get_stmt, id) + new_value = randint(1, 10000) + updated_worlds.append((new_value, id)) + worlds.append({'id': id, 'randomNumber': new_value}) + await update_stmt.executemany(updated_worlds) + 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) + return {'id': result[0], 'randomNumber': result[1]} + + +@app.route("/cached-queries") +async def test_cached_queries(request): + async with db.acquire() as conn: + get_stmt = await conn.prepare(get_world_sql) + worlds = [await get_cached_world(get_stmt, id) for id in generate_ids(get_num_queries(request, 'count'))] + return worlds diff --git a/frameworks/Python/microdot/app_sync.py b/frameworks/Python/microdot/app_sync.py deleted file mode 100644 index 546f4eb649b..00000000000 --- a/frameworks/Python/microdot/app_sync.py +++ /dev/null @@ -1,115 +0,0 @@ -#!/usr/bin/env python -from datetime import datetime -from functools import lru_cache -import os -from random import randint, sample - -from alchemical import Alchemical -import sqlalchemy as sqla -from cachetools import cached -from cachetools.keys import hashkey - -from microdot_wsgi import Microdot -from microdot_jinja import render_template - -app = Microdot() -db = Alchemical(os.environ['DATABASE_URL']) - - -class World(db.Model): - __tablename__ = "world" - id = sqla.Column(sqla.Integer, primary_key=True) - randomnumber = sqla.Column(sqla.Integer) - - def to_dict(self): - return {"id": self.id, "randomNumber": self.randomnumber} - - -class CachedWorld(db.Model): - __tablename__ = "cachedworld" - id = sqla.Column(sqla.Integer, primary_key=True) - randomnumber = sqla.Column(sqla.Integer) - - def to_dict(self): - return {"id": self.id, "randomNumber": self.randomnumber} - - -class Fortune(db.Model): - __tablename__ = "fortune" - id = sqla.Column(sqla.Integer, primary_key=True) - message = sqla.Column(sqla.String) - - -def get_num_queries(request, name="queries"): - try: - num_queries = request.args.get(name, 1, type=int) - except ValueError: - num_queries = 1 - if num_queries < 1: - return 1 - if num_queries > 500: - return 500 - return num_queries - - -def generate_ids(num_queries): - return sample(range(1, 10001), num_queries) - - -@app.route("/json") -def test_json(request): - return {"message": "Hello, World!"} - - -@app.route("/db") -def test_db(request): - id = randint(1, 10000) - with db.Session() as session: - world = session.get(World, id) - return world.to_dict() - - -@app.route("/queries") -def test_queries(request): - with db.Session() as session: - worlds = [session.get(World, id).to_dict() for id in generate_ids(get_num_queries(request))] - return worlds - - -@app.route("/fortunes") -def test_fortunes(request): - with db.Session() as session: - fortunes = list(session.scalars(Fortune.select())) - fortunes.append(Fortune(id=0, message="Additional fortune added at request time.")) - fortunes.sort(key=lambda f: f.message) - return render_template("fortunes.html", fortunes=fortunes), {'Content-Type': 'text/html; charset=utf-8'} - - -@app.route("/updates") -def test_updates(request): - worlds = [] - ids = generate_ids(get_num_queries(request)) - ids.sort() # to avoid deadlocks - with db.begin() as session: - for id in ids: - world = session.get(World, id) - world.randomnumber = (randint(1, 9999) + world.randomnumber - 1) % 10000 + 1 - worlds.append(world.to_dict()) - return worlds - - -@app.route("/plaintext") -def test_plaintext(request): - return b"Hello, World!" - - -@cached(cache={}, key=lambda session, id: hashkey(id)) -def get_cached_world(session, id): - return session.get(World, id).to_dict() - - -@app.route("/cached-queries") -def test_cached_queries(request): - with db.Session() as session: - worlds = [get_cached_world(session, id) for id in generate_ids(get_num_queries(request, 'count'))] - return worlds diff --git a/frameworks/Python/microdot/app_sync_raw.py b/frameworks/Python/microdot/app_sync_raw.py deleted file mode 100644 index 29edc250fae..00000000000 --- a/frameworks/Python/microdot/app_sync_raw.py +++ /dev/null @@ -1,112 +0,0 @@ -#!/usr/bin/env python -from datetime import datetime -from functools import lru_cache -import os -from random import randint, sample - -from microdot_wsgi import Microdot -from microdot_jinja import render_template -import psycopg2 -from psycopg2.extras import execute_batch -from cachetools import cached -from cachetools.keys import hashkey - -app = Microdot() -db = psycopg2.connect(os.environ['DATABASE_URL']) - -get_world_sql = 'SELECT id, randomnumber FROM world WHERE id = $1' -update_world_sql = 'UPDATE world SET randomnumber = $1 WHERE id = $2' -fortune_sql = 'SELECT * FROM fortune' -with db.cursor() as cur: - cur.execute('PREPARE get_world AS ' + get_world_sql) - cur.execute('PREPARE update_world AS ' + update_world_sql) - cur.execute('PREPARE fortune AS ' + fortune_sql) - - -def get_num_queries(request, name="queries"): - try: - num_queries = request.args.get(name, 1, type=int) - except ValueError: - num_queries = 1 - if num_queries < 1: - return 1 - if num_queries > 500: - return 500 - return num_queries - - -def generate_ids(num_queries): - return sample(range(1, 10001), num_queries) - - -@app.route("/json") -def test_json(request): - return {"message": "Hello, World!"} - - -@app.route("/db") -def test_db(request): - id = randint(1, 10000) - with db.cursor() as cur: - cur.execute('EXECUTE get_world (%s)', (id,)) - result = cur.fetchone() - world = {'id': result[0], 'randomNumber': result[1]} - return world - - -def get_world(cur, id): - cur.execute('EXECUTE get_world (%s)', (id,)) - result = cur.fetchone() - return {'id': result[0], 'randomNumber': result[1]} - - -@app.route("/queries") -def test_queries(request): - with db.cursor() as cur: - worlds = [get_world(cur, id) for id in generate_ids(get_num_queries(request))] - return worlds - - -@app.route("/fortunes") -def test_fortunes(request): - with db.cursor() as cur: - cur.execute('EXECUTE fortune') - fortunes = list(cur.fetchall()) - fortunes.append((0, 'Additional fortune added at request time.')) - fortunes.sort(key=lambda f: f[1]) - return render_template("fortunes_raw.html", fortunes=fortunes), {'Content-Type': 'text/html; charset=utf-8'} - - -@app.route("/updates") -def test_updates(request): - worlds = [] - updated_worlds = [] - with db.cursor() as cur: - for id in generate_ids(get_num_queries(request)): - cur.execute('EXECUTE get_world (%s)', (id,)) - result = cur.fetchone() - new_value = randint(1, 10000) - updated_worlds.append((new_value, result[0])) - worlds.append({'id': result[0], 'randomNumber': new_value}) - execute_batch(cur, 'EXECUTE update_world (%s, %s)', updated_worlds) - db.commit() - return worlds - - -@app.route("/plaintext") -def test_plaintext(request): - return b"Hello, World!" - - -@cached(cache={}, key=lambda cur, id: hashkey(id)) -def get_cached_world(cur, id): - cur.execute('EXECUTE get_world (%s)', (id,)) - result = cur.fetchone() - return {'id': result[0], 'randomNumber': result[1]} - - -@app.route("/cached-queries") -def test_cached_queries(request): - with db.cursor() as cur: - worlds = [get_cached_world(cur, id) for id in generate_ids(get_num_queries(request, 'count'))] - return worlds diff --git a/frameworks/Python/microdot/benchmark_config.json b/frameworks/Python/microdot/benchmark_config.json index d1c696c33ea..712e89b44b9 100644 --- a/frameworks/Python/microdot/benchmark_config.json +++ b/frameworks/Python/microdot/benchmark_config.json @@ -19,14 +19,14 @@ "flavor": "None", "orm": "Full", "platform": "None", - "webserver": "Gunicorn", + "webserver": "Uvicorn", "os": "Linux", "database_os": "Linux", - "display_name": "Microdot-WSGI", + "display_name": "Microdot", "notes": "", "versus": "None" }, - "async": { + "raw": { "json_url": "/json", "db_url": "/db", "query_url": "/queries?queries=", @@ -46,51 +46,7 @@ "webserver": "Uvicorn", "os": "Linux", "database_os": "Linux", - "display_name": "Microdot-ASGI", - "notes": "", - "versus": "None" - }, - "raw": { - "db_url": "/db", - "query_url": "/queries?queries=", - "fortune_url": "/fortunes", - "update_url": "/updates?queries=", - "cached_query_url": "/cached-queries?count=", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "postgres", - "framework": "Microdot", - "language": "Python", - "flavor": "None", - "orm": "Raw", - "platform": "None", - "webserver": "Gunicorn", - "os": "Linux", - "database_os": "Linux", - "display_name": "Microdot-WSGI-Raw", - "notes": "", - "versus": "None" - }, - "async-raw": { - "db_url": "/db", - "query_url": "/queries?queries=", - "fortune_url": "/fortunes", - "update_url": "/updates?queries=", - "cached_query_url": "/cached-queries?count=", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "postgres", - "framework": "Microdot", - "language": "Python", - "flavor": "None", - "orm": "Raw", - "platform": "None", - "webserver": "Uvicorn", - "os": "Linux", - "database_os": "Linux", - "display_name": "Microdot-ASGI-Raw", + "display_name": "Microdot-Raw", "notes": "", "versus": "None" } diff --git a/frameworks/Python/microdot/gunicorn_conf.py b/frameworks/Python/microdot/gunicorn_conf.py deleted file mode 100644 index 525911bf39e..00000000000 --- a/frameworks/Python/microdot/gunicorn_conf.py +++ /dev/null @@ -1,15 +0,0 @@ -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() * 4) -if _is_travis: - workers = 2 - -bind = "0.0.0.0:8080" -keepalive = 120 -errorlog = "-" -pidfile = "gunicorn.pid" diff --git a/frameworks/Python/microdot/microdot-async-raw.dockerfile b/frameworks/Python/microdot/microdot-async-raw.dockerfile deleted file mode 100644 index d238d7a909a..00000000000 --- a/frameworks/Python/microdot/microdot-async-raw.dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -FROM python:3.11-buster - -RUN apt-get update -RUN apt-get install libpq-dev python3-dev -y -ADD ./requirements.txt /microdot/requirements.txt -RUN pip3 install -r /microdot/requirements.txt -ADD ./ /microdot -WORKDIR /microdot - -ENV PYTHONUNBUFFERED 1 -ENV DATABASE_URL postgresql://benchmarkdbuser:benchmarkdbpass@tfb-database:5432/hello_world - -EXPOSE 8080 - -CMD gunicorn app_async_raw:asgi -c uvicorn_conf.py diff --git a/frameworks/Python/microdot/microdot-async.dockerfile b/frameworks/Python/microdot/microdot-async.dockerfile deleted file mode 100644 index 87f96776066..00000000000 --- a/frameworks/Python/microdot/microdot-async.dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -FROM python:3.11-buster - -RUN apt-get update -RUN apt-get install libpq-dev python3-dev -y -ADD ./requirements.txt /microdot/requirements.txt -RUN pip3 install -r /microdot/requirements.txt -ADD ./ /microdot -WORKDIR /microdot - -ENV PYTHONUNBUFFERED 1 -ENV DATABASE_URL postgresql://benchmarkdbuser:benchmarkdbpass@tfb-database:5432/hello_world - -EXPOSE 8080 - -CMD gunicorn app_async:app -c uvicorn_conf.py diff --git a/frameworks/Python/microdot/microdot-raw.dockerfile b/frameworks/Python/microdot/microdot-raw.dockerfile index 6d14a41e20d..e5501998e14 100644 --- a/frameworks/Python/microdot/microdot-raw.dockerfile +++ b/frameworks/Python/microdot/microdot-raw.dockerfile @@ -1,4 +1,4 @@ -FROM python:3.11-buster +FROM python:3.12-slim RUN apt-get update RUN apt-get install libpq-dev python3-dev -y @@ -8,8 +8,8 @@ ADD ./ /microdot WORKDIR /microdot ENV PYTHONUNBUFFERED 1 -ENV DATABASE_URL "host=tfb-database port=5432 user=benchmarkdbuser password=benchmarkdbpass dbname=hello_world" +ENV DATABASE_URL postgresql://benchmarkdbuser:benchmarkdbpass@tfb-database:5432/hello_world EXPOSE 8080 -CMD gunicorn app_sync_raw:app -c gunicorn_conf.py +CMD gunicorn app_raw:asgi -c uvicorn_conf.py diff --git a/frameworks/Python/microdot/microdot.dockerfile b/frameworks/Python/microdot/microdot.dockerfile index 01db2e263b1..a47b8e74026 100644 --- a/frameworks/Python/microdot/microdot.dockerfile +++ b/frameworks/Python/microdot/microdot.dockerfile @@ -1,4 +1,4 @@ -FROM python:3.11-buster +FROM python:3.12-slim RUN apt-get update RUN apt-get install libpq-dev python3-dev -y @@ -12,4 +12,4 @@ ENV DATABASE_URL postgresql://benchmarkdbuser:benchmarkdbpass@tfb-database:5432/ EXPOSE 8080 -CMD gunicorn app_sync:app -c gunicorn_conf.py +CMD gunicorn app:app -c uvicorn_conf.py diff --git a/frameworks/Python/microdot/requirements.txt b/frameworks/Python/microdot/requirements.txt index 05a4c8c3f2c..2bb6d533047 100644 --- a/frameworks/Python/microdot/requirements.txt +++ b/frameworks/Python/microdot/requirements.txt @@ -5,8 +5,9 @@ asyncpg jinja2 cachetools asyncache +orjson alchemical -microdot<2 +microdot>=2.3.1 gunicorn uvicorn[standard] diff --git a/frameworks/Python/microdot/uvicorn_conf.py b/frameworks/Python/microdot/uvicorn_conf.py index 9faf6f02064..5f410a49eb3 100644 --- a/frameworks/Python/microdot/uvicorn_conf.py +++ b/frameworks/Python/microdot/uvicorn_conf.py @@ -1,6 +1,5 @@ import multiprocessing import os -import sys _is_travis = os.environ.get("TRAVIS") == "true" diff --git a/frameworks/Python/morepath/README.md b/frameworks/Python/morepath/README.md deleted file mode 100644 index 3d0066a6f32..00000000000 --- a/frameworks/Python/morepath/README.md +++ /dev/null @@ -1,50 +0,0 @@ -# [Morepath](http://morepath.readthedocs.io/) Benchmark Test - -The information below is specific to Morepath. For further guidance, -review the [documentation](https://github.com/TechEmpower/FrameworkBenchmarks/wiki). -Also note that there is additional information that's provided in -the [Python README](../). - -This is the Python Morepath portion of a [benchmarking tests suite](../../) -comparing a variety of frameworks. - -All test implementations are located within ([./app](app)). - -## Description - -Morepath with [PonyOrm](https://docs.ponyorm.com/) using PostgreSQL for -database access. - -### Database - -PostgreSQL (with PonyORM). - -### Server - -gunicorn + meinheld on CPython - -## 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?queries=20 - -### Test 4: Fortunes (Template rendering) - - http://localhost:8080/fortunes - -### Test 5: Update Query - - http://localhost:8080/updates?queries=20 - -### Test 6: Plaintext - - http://localhost:8080/plaintext diff --git a/frameworks/Python/morepath/app/__init__.py b/frameworks/Python/morepath/app/__init__.py deleted file mode 100644 index b601c11a64a..00000000000 --- a/frameworks/Python/morepath/app/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# flake8: noqa - -from app.app import App diff --git a/frameworks/Python/morepath/app/app.py b/frameworks/Python/morepath/app/app.py deleted file mode 100644 index 7b43a7baf51..00000000000 --- a/frameworks/Python/morepath/app/app.py +++ /dev/null @@ -1,11 +0,0 @@ -from more.pony import PonyApp -from more.jinja2 import Jinja2App - - -class App(PonyApp, Jinja2App): - pass - - -@App.template_directory() -def get_template_directory(): - return 'templates' diff --git a/frameworks/Python/morepath/app/collection.py b/frameworks/Python/morepath/app/collection.py deleted file mode 100644 index 8ab02a095f8..00000000000 --- a/frameworks/Python/morepath/app/collection.py +++ /dev/null @@ -1,6 +0,0 @@ -from .model import Fortune - - -class FortuneCollection(object): - def query(self): - return Fortune.select() diff --git a/frameworks/Python/morepath/app/model.py b/frameworks/Python/morepath/app/model.py deleted file mode 100644 index 9cd7bc8ed49..00000000000 --- a/frameworks/Python/morepath/app/model.py +++ /dev/null @@ -1,29 +0,0 @@ -from pony.orm import Database, Optional - -db = Database() - - -class Json(): - pass - - -class World(db.Entity): - randomnumber = Optional(int) - - -class WorldQueries(): - def __init__(self, queries): - self.queries = queries - - -class Fortune(db.Entity): - message = Optional(str) - - -class WorldUpdates(): - def __init__(self, queries): - self.queries = queries - - -class Plaintext(): - pass diff --git a/frameworks/Python/morepath/app/path.py b/frameworks/Python/morepath/app/path.py deleted file mode 100644 index 05d1dc442e1..00000000000 --- a/frameworks/Python/morepath/app/path.py +++ /dev/null @@ -1,35 +0,0 @@ -from random import randint - -from .app import App -from .model import Json, World, WorldQueries, WorldUpdates, Plaintext -from .collection import FortuneCollection - - -@App.path(model=Json, path='json') -def get_json(): - return Json() - - -@App.path(model=World, path='db') -def get_random_world(): - return World[randint(1, 10000)] - - -@App.path(model=WorldQueries, path='queries') -def get_queries(queries): - return WorldQueries(queries) - - -@App.path(model=FortuneCollection, path='fortunes') -def get_fortunes(): - return FortuneCollection() - - -@App.path(model=WorldUpdates, path='updates') -def get_updates(queries): - return WorldUpdates(queries) - - -@App.path(model=Plaintext, path='plaintext') -def get_plaintext(): - return Plaintext() diff --git a/frameworks/Python/morepath/app/run.py b/frameworks/Python/morepath/app/run.py deleted file mode 100644 index 82336adbb79..00000000000 --- a/frameworks/Python/morepath/app/run.py +++ /dev/null @@ -1,31 +0,0 @@ -import os - -import morepath - -from app import App -from .model import db - - -def setup_db(): - DBHOST = 'tfb-database' - - db.bind( - 'postgres', - user='benchmarkdbuser', - password='benchmarkdbpass', - host=DBHOST, - database='hello_world' - ) - db.generate_mapping(create_tables=True) - - -def wsgi_factory(): # pragma: no cover - morepath.autoscan() - - App.commit() - setup_db() - - return App() - - -application = wsgi_factory() # pragma: no cover diff --git a/frameworks/Python/morepath/app/templates/fortune.jinja2 b/frameworks/Python/morepath/app/templates/fortune.jinja2 deleted file mode 100644 index e2c33c3c4af..00000000000 --- a/frameworks/Python/morepath/app/templates/fortune.jinja2 +++ /dev/null @@ -1,21 +0,0 @@ - - - - -Fortunes - - - - - - - -{% for fortune in fortunes %} - - - - -{% endfor %} -
idmessage
{{ fortune.id }}{{ fortune.message|escape }}
- - diff --git a/frameworks/Python/morepath/app/tests/test_app.py b/frameworks/Python/morepath/app/tests/test_app.py deleted file mode 100644 index 63f94e5c818..00000000000 --- a/frameworks/Python/morepath/app/tests/test_app.py +++ /dev/null @@ -1,259 +0,0 @@ -from webtest import TestApp as Client -import morepath - -import app -from app import App - - -def setup_module(module): - morepath.scan(app) - morepath.commit(App) - - -def test_json(): - """/json""" - app = App() - c = Client(app) - - response = c.get('/json', status=200) - assert response.headerlist == [ - ('Content-Type', 'application/json'), - ('Content-Length', '27') - ] - assert response.json == {"message": "Hello, World!"} - - -def test_db(): - """/db""" - app = App() - c = Client(app) - - response = c.get('/db', status=200) - assert response.content_type == 'application/json' - assert 'id' in response.json - assert 'randomNumber' in response.json - assert 1 <= response.json['id'] <= 10000 - assert 1 <= response.json['randomNumber'] <= 10000 - - -def test_queries(): - """/queries?queries=""" - app = App() - c = Client(app) - - response = c.get('/queries?queries=', status=200) - assert response.content_type == 'application/json' - assert len(response.json) == 1 - - -def test_queries_foo(): - """/queries?queries=foo""" - app = App() - c = Client(app) - - response = c.get('/queries?queries=foo', status=200) - assert response.content_type == 'application/json' - assert len(response.json) == 1 - - -def test_queries_0(): - """/queries?queries=0""" - app = App() - c = Client(app) - - response = c.get('/queries?queries=0', status=200) - assert response.content_type == 'application/json' - assert len(response.json) == 1 - - -def test_queries_999(): - """/queries?queries=999""" - app = App() - c = Client(app) - - response = c.get('/queries?queries=999', status=200) - assert response.content_type == 'application/json' - assert len(response.json) == 500 - - -def test_queries_10(): - """/queries?queries=10""" - app = App() - c = Client(app) - - response = c.get('/queries?queries=10', status=200) - assert response.content_type == 'application/json' - assert len(response.json) == 10 - - obj_list = response.json - for obj in obj_list: - assert 'id' in obj - assert 'randomNumber' in obj - assert 1 <= obj['id'] <= 10000 - assert 1 <= obj['randomNumber'] <= 10000 - - -def test_fortunes(): - """/fortunes""" - app = App() - c = Client(app) - - response = c.get('/fortunes', status=200) - assert response.headerlist == [ - ('Content-Type', 'text/html; charset=UTF-8'), - ('Content-Length', '1304') - ] - assert response.text == fortunes - - -def test_updates(): - """/updates?queries=""" - app = App() - c = Client(app) - - response = c.get('/updates?queries=', status=200) - assert response.content_type == 'application/json' - assert len(response.json) == 1 - - -def test_updates_foo(): - """/updates?queries=foo""" - app = App() - c = Client(app) - - response = c.get('/updates?queries=foo', status=200) - assert response.content_type == 'application/json' - assert len(response.json) == 1 - - -def test_updates_0(): - """/updates?queries=0""" - app = App() - c = Client(app) - - response = c.get('/updates?queries=0', status=200) - assert response.content_type == 'application/json' - assert len(response.json) == 1 - - -def test_updates_999(): - """/updates?queries=999""" - app = App() - c = Client(app) - - response = c.get('/updates?queries=999', status=200) - assert response.content_type == 'application/json' - assert len(response.json) == 500 - - -def test_updates_10(): - """/updates?queries=10""" - app = App() - c = Client(app) - - response = c.get('/updates?queries=10', status=200) - assert response.content_type == 'application/json' - assert len(response.json) == 10 - - obj_list = response.json - for obj in obj_list: - assert 'id' in obj - assert 'randomNumber' in obj - assert 1 <= obj['id'] <= 10000 - assert 1 <= obj['randomNumber'] <= 10000 - - -def test_plaintext(): - """/plaintext""" - app = App() - c = Client(app) - - response = c.get('/plaintext', status=200) - assert response.headerlist == [ - ('Content-Type', 'text/plain; charset=UTF-8'), - ('Content-Length', '13') - ] - assert response.text == 'Hello, World!' - - -fortunes = """ - - - -Fortunes - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
idmessage
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.
8A list is only as strong as its weakest link. — Donald Knuth
0Additional fortune added at request time.
3After enough decimal places, nobody gives a damn.
7Any program that runs right is obsolete.
10Computers make very fast, very accurate mistakes.
6Emacs is a nice operating system, but I prefer UNIX. — Tom Christaensen
9Feature: A bug with seniority.
1fortune: No such file or directory
12フレームワークのベンチマーク
- -""" diff --git a/frameworks/Python/morepath/app/view.py b/frameworks/Python/morepath/app/view.py deleted file mode 100644 index c518784a93d..00000000000 --- a/frameworks/Python/morepath/app/view.py +++ /dev/null @@ -1,79 +0,0 @@ -from random import randint - -from .app import App -from .model import Json, World, WorldQueries, WorldUpdates, Plaintext -from .collection import FortuneCollection - - -@App.json(model=Json) -def test_1(self, request): - """Test 1: JSON serialization""" - return {'message': 'Hello, World!'} - - -@App.json(model=World) -def test_2(self, request): - """Test 2: Single database query""" - return {'id': self.id, 'randomNumber': self.randomnumber} - - -@App.json(model=WorldQueries) -def test_3(self, request): - """Test 3: Multiple database queries""" - try: - queries = int(self.queries) - except ValueError: - queries = 1 - else: - if queries < 1: - queries = 1 - elif queries > 500: - queries = 500 - - result = [] - - for id_ in [randint(1, 10000) for _ in range(queries)]: - result.append({'id': id_, 'randomNumber': World[id_].randomnumber}) - - return result - - -@App.html(model=FortuneCollection, template='fortune.jinja2') -def test_4(self, request): - """Test 4: Fortunes""" - fortunes = [f.to_dict() for f in self.query()] - fortunes.append({ - 'id': 0, - 'message': 'Additional fortune added at request time.' - }) - - return {'fortunes': sorted(fortunes, key=lambda x: x['message'])} - - -@App.json(model=WorldUpdates) -def test_5(self, request): - """Test 5: Database updates""" - try: - queries = int(self.queries) - except ValueError: - queries = 1 - else: - if queries < 1: - queries = 1 - elif queries > 500: - queries = 500 - - result = [] - - for id_ in sorted(randint(1, 10000) for _ in range(queries)): - randomNumber = randint(1, 10000) - World[id_].randomnumber = randomNumber - result.append({'id': id_, 'randomNumber': randomNumber}) - - return result - - -@App.view(model=Plaintext) -def test_6(self, request): - """Test 6: Plaintext""" - return 'Hello, World!' diff --git a/frameworks/Python/morepath/benchmark_config.json b/frameworks/Python/morepath/benchmark_config.json deleted file mode 100644 index 43f1b3200d4..00000000000 --- a/frameworks/Python/morepath/benchmark_config.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "framework": "morepath", - "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": "morepath", - "language": "Python", - "flavor": "Python3", - "orm": "Full", - "platform": "Meinheld", - "webserver": "gunicorn", - "os": "Linux", - "database_os": "Linux", - "display_name": "Morepath", - "notes": "uses Morepath with PonyORM for database access" - } - }] -} diff --git a/frameworks/Python/morepath/config.toml b/frameworks/Python/morepath/config.toml deleted file mode 100644 index af46ef2250a..00000000000 --- a/frameworks/Python/morepath/config.toml +++ /dev/null @@ -1,19 +0,0 @@ -[framework] -name = "morepath" - -[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 = "Full" -platform = "Meinheld" -webserver = "gunicorn" -versus = "None" diff --git a/frameworks/Python/morepath/gunicorn_conf.py b/frameworks/Python/morepath/gunicorn_conf.py deleted file mode 100644 index bab6df83a9e..00000000000 --- a/frameworks/Python/morepath/gunicorn_conf.py +++ /dev/null @@ -1,14 +0,0 @@ -import multiprocessing -import os - -if os.environ.get('TRAVIS') == 'true': - workers = 2 -else: - workers = multiprocessing.cpu_count() * 3 - -bind = '0.0.0.0:8080' -keepalive = 120 -errorlog = '-' -pidfile = 'gunicorn.pid' - -worker_class = "meinheld.gmeinheld.MeinheldWorker" diff --git a/frameworks/Python/morepath/morepath.dockerfile b/frameworks/Python/morepath/morepath.dockerfile deleted file mode 100644 index a0fee3578cd..00000000000 --- a/frameworks/Python/morepath/morepath.dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM python:3.6.6-stretch - -ADD ./ /japronto - -WORKDIR /japronto - -RUN pip3 install -r /japronto/requirements.txt - -EXPOSE 8080 - -CMD gunicorn app.run -c gunicorn_conf.py diff --git a/frameworks/Python/morepath/requirements.txt b/frameworks/Python/morepath/requirements.txt deleted file mode 100644 index 68dc3474f06..00000000000 --- a/frameworks/Python/morepath/requirements.txt +++ /dev/null @@ -1,17 +0,0 @@ -dectate==0.13 -greenlet==0.4.14 -gunicorn==19.9.0 -importscan==0.1 -Jinja2==2.11.3 -MarkupSafe==1.0 -meinheld==0.6.1 -more.jinja2==0.2 -more.pony==0.1 -morepath==0.18.1 -pony==0.7.1 -psycopg2==2.7.5 -reg==0.11 -repoze.lru==0.6 -WebOb==1.7.2 - --e . diff --git a/frameworks/Python/morepath/setup.py b/frameworks/Python/morepath/setup.py deleted file mode 100644 index d712f4e8c87..00000000000 --- a/frameworks/Python/morepath/setup.py +++ /dev/null @@ -1,41 +0,0 @@ -# -*- coding: utf-8 -*- - -from setuptools import setup, find_packages - -setup( - name='frameworkbenchmarks', - version='0.0', - description='FrameworkBenchmarks', - author='', - author_email='', - url='', - packages=find_packages(), - include_package_data=True, - zip_safe=False, - platforms='any', - install_requires=[ - 'more.pony', - 'psycopg2', - 'more.jinja2', - 'gunicorn', - 'meinheld', - ], - extras_require=dict( - test=[ - 'pytest >= 2.9.1', - 'WebTest >= 2.0.14', - 'pytest-cov', - ] - ), - entry_points=dict( - morepath=[ - 'scan = app', - ], - ), - classifiers=[ - 'Programming Language :: Python', - 'Framework :: Morepath', - 'Topic :: Internet :: WWW/HTTP', - 'Topic :: Internet :: WWW/HTTP :: WSGI :: Application', - ] -) diff --git a/frameworks/Python/mrhttp/README.md b/frameworks/Python/mrhttp/README.md new file mode 100644 index 00000000000..ab294b9a94c --- /dev/null +++ b/frameworks/Python/mrhttp/README.md @@ -0,0 +1,20 @@ +# MrHTTP Benchmark Test + +This is the MrHTTP portion of a [benchmarking tests suite](../../) +comparing a variety of web development platforms. + +The information below is specific to MrHTTP. 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 + +[MrHTTP](https://github.com/MarkReedZ/mrhttp) is an asynchronous web framework for python 3.5+ written in C that has hit 8.5 million requests per second. + +## Test Paths & Sources + +All of the test implementations are located within a single file ([app.py](app.py)). + +* [JSON Serialization](app.py): "/json" +* [Plaintext](app.py): "/plaintext" diff --git a/frameworks/Python/mrhttp/app.py b/frameworks/Python/mrhttp/app.py new file mode 100644 index 00000000000..2e91f309f25 --- /dev/null +++ b/frameworks/Python/mrhttp/app.py @@ -0,0 +1,18 @@ + +import multiprocessing +import mrhttp +import mrjson as json + +app = mrhttp.Application() + +@app.route('/json', _type="json") +def j(r): + return json.dumps({'message': 'Hello, world!'}) + +@app.route('/plaintext', _type="text", options=['cache']) +def p(r): + return "Hello, world!" + + +app.run('0.0.0.0', 8080, cores=multiprocessing.cpu_count()) + diff --git a/frameworks/Python/mrhttp/benchmark_config.json b/frameworks/Python/mrhttp/benchmark_config.json new file mode 100644 index 00000000000..8303a252e1f --- /dev/null +++ b/frameworks/Python/mrhttp/benchmark_config.json @@ -0,0 +1,23 @@ +{ + "framework": "mrhttp", + "tests": [{ + "default": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "framework": "mrhttp", + "language": "Python", + "flavor": "Python3", + "platform": "None", + "webserver": "None", + "os": "Linux", + "orm": "Raw", + "database_os": "Linux", + "database": "None", + "display_name": "MrHTTP", + "notes": "" + } + }] +} diff --git a/frameworks/Python/mrhttp/config.toml b/frameworks/Python/mrhttp/config.toml new file mode 100644 index 00000000000..f9c36bcfa78 --- /dev/null +++ b/frameworks/Python/mrhttp/config.toml @@ -0,0 +1,15 @@ +[framework] +name = "mrhttp" + +[main] +urls.plaintext = "/plaintext" +urls.json = "/json" +approach = "Realistic" +classification = "Micro" +database = "None" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "None" +webserver = "None" +versus = "None" diff --git a/frameworks/Python/mrhttp/mrhttp.dockerfile b/frameworks/Python/mrhttp/mrhttp.dockerfile new file mode 100644 index 00000000000..a8cb1e5b201 --- /dev/null +++ b/frameworks/Python/mrhttp/mrhttp.dockerfile @@ -0,0 +1,13 @@ + +FROM python:3.8.12 + +ADD ./ /mrhttp + +WORKDIR /mrhttp + +RUN pip3 install -r /mrhttp/requirements.txt + +EXPOSE 8080 + +CMD python3 app.py + diff --git a/frameworks/Python/mrhttp/requirements.txt b/frameworks/Python/mrhttp/requirements.txt new file mode 100644 index 00000000000..047961f9463 --- /dev/null +++ b/frameworks/Python/mrhttp/requirements.txt @@ -0,0 +1,6 @@ +asyncpg==0.25.0 +mrjson==1.4 +ujson==5.4.0 +mrpacker==1.5 +mrhttp==0.12 +uvloop==0.19.0 diff --git a/frameworks/Python/starlite/.dockerignore b/frameworks/Python/openrun/.dockerignore similarity index 100% rename from frameworks/Python/starlite/.dockerignore rename to frameworks/Python/openrun/.dockerignore diff --git a/frameworks/Python/openrun/README.md b/frameworks/Python/openrun/README.md new file mode 100755 index 00000000000..cee6a1a0dd9 --- /dev/null +++ b/frameworks/Python/openrun/README.md @@ -0,0 +1,11 @@ +# Introduction + +[OpenRun](https://github.com/openrundev/openrun) is a platform for developing and deploying internal tools. + +OpenRun is implemented in Go. OpenRun apps are written in [Starlark](https://starlark-lang.org/). Starlark is a thread-safe language with Python syntax, designed for embedding. OpenRun uses the [Starlark Go](https://github.com/google/starlark-go) implementation. Since apps are developed using a python like syntax, the benchmark is added under the Python category. + +# Benchmarking + +The JSON and plaintext tests are implemented. OpenRun supports SQLite database only currently, so the database tests are not implemented. + +The Dockerfile starts the OpenRun server and creates a single app which implements the benchmark apis (app.star). diff --git a/frameworks/Python/openrun/app.star b/frameworks/Python/openrun/app.star new file mode 100644 index 00000000000..017235a9da9 --- /dev/null +++ b/frameworks/Python/openrun/app.star @@ -0,0 +1,12 @@ +def json_no_args(): + return {'message': 'Hello, world!'} + +def text_no_args(): + return 'Hello, world!' + +app = ace.app("testapp", + routes = [ + ace.api("/json", type=ace.JSON, handler=json_no_args), + ace.api("/plaintext", type=ace.TEXT, handler=text_no_args) + ] +) diff --git a/frameworks/Python/openrun/benchmark_config.json b/frameworks/Python/openrun/benchmark_config.json new file mode 100755 index 00000000000..88edd90bdc9 --- /dev/null +++ b/frameworks/Python/openrun/benchmark_config.json @@ -0,0 +1,23 @@ +{ + "framework": "openrun", + "tests": [ + { + "default": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "framework": "OpenRun", + "language": "python", + "flavor": "Starlark", + "platform": "None", + "webserver": "OpenRun", + "os": "Linux", + "display_name": "OpenRun", + "notes": "", + "versus": "None" + } + } + ] +} diff --git a/frameworks/Python/openrun/openrun.dockerfile b/frameworks/Python/openrun/openrun.dockerfile new file mode 100644 index 00000000000..f0de014b790 --- /dev/null +++ b/frameworks/Python/openrun/openrun.dockerfile @@ -0,0 +1,11 @@ +FROM python:3.11 +WORKDIR /openrun/ + +RUN curl -L https://openrun.dev/install.sh | bash +ENV OPENRUN_HOME="/root/openrun" +ENV PATH="/root/openrun/bin:$PATH" + +COPY . . + +EXPOSE 8080 +CMD /openrun/run.sh diff --git a/frameworks/Python/openrun/run.sh b/frameworks/Python/openrun/run.sh new file mode 100755 index 00000000000..2e6961527db --- /dev/null +++ b/frameworks/Python/openrun/run.sh @@ -0,0 +1,26 @@ +#!/bin/sh +cd /root + +cat < /root/openrun/openrun.toml +[logging] +console = false +file = false +access_logging = false +level = "WARN" + +[http] +host = "" +port = 8080 + +[system] +enable_compression = false + +[app_config] +cors.allow_origin = "" +EOF + + +openrun server start & +sleep 2 +openrun app create --auth=none --approve /openrun / +tail -f /dev/null diff --git a/frameworks/Python/panther/README.md b/frameworks/Python/panther/README.md new file mode 100644 index 00000000000..f57bc888b7e --- /dev/null +++ b/frameworks/Python/panther/README.md @@ -0,0 +1,36 @@ +# Panther Benchmark Test + +This is the Panther portion of a [benchmarking tests suite](../../) +comparing a variety of web development platforms. + +The information below is specific to Panther. 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 + +[Panther](https://pantherpy.github.io/) Is A Fast & Friendly Web Framework For Building Async APIs With Python 3.10+ +

+ logo +

+ + +## Implementation + +All tests are implemented in a single file ([app.py](app.py)). + +* [JSON](app.py): "/json" +* [DB](app.py): "/db" +* [QUERY](app.py): "/queries?=#"* +* [FORTUNES](app.py): "/fortunes" +* [UPDATE](app.py): "/updates?queries=#"* +* [Plaintext](app.py): "/plaintext" + +*Replace # with an actual number. + +## Resources + +* GitHub -> [GitHub.com/AliRn76/Panther](https://github.com/AliRn76/Panther) +* Documentation -> [PantherPy.GitHub.io](https://pantherpy.github.io) +* PyPI -> [PyPI.org/project/Panther](https://pypi.org/project/panther) diff --git a/frameworks/Python/panther/app.py b/frameworks/Python/panther/app.py new file mode 100644 index 00000000000..4a257bc02e7 --- /dev/null +++ b/frameworks/Python/panther/app.py @@ -0,0 +1,115 @@ +import multiprocessing +from random import randint, sample + +import asyncpg +import jinja2 +from panther import Panther +from panther.app import API +from panther.events import Event +from panther.request import Request +from panther.response import Response, PlainTextResponse, HTMLResponse + +cpu_count = multiprocessing.cpu_count() +MAX_POOL_SIZE = 1000 // cpu_count +MIN_POOL_SIZE = max(MAX_POOL_SIZE // 2, 1) + +connection_pool = None + +fortune_template = jinja2.Environment( + loader=jinja2.FileSystemLoader('templates'), + autoescape=True +).get_template('fortune.html') + + +@Event.startup +async def on_startup(): + global connection_pool + connection_pool = await asyncpg.create_pool( + user='benchmarkdbuser', + password='benchmarkdbpass', + database='hello_world', + host='tfb-database', + port=5432, + min_size=MIN_POOL_SIZE, + max_size=MAX_POOL_SIZE, + ) + + +@Event.shutdown +async def on_shutdown(): + await connection_pool.close() + + +@API() +def json_serialization(): + return Response(data={'message': 'Hello, world!'}) + + +@API() +async def single_database_query(): + row_id = randint(1, 10000) + async with connection_pool.acquire() as connection: + number = await connection.fetchval('SELECT id, randomnumber FROM world WHERE id = $1', row_id) + return Response(data={'id': row_id, 'randomNumber': number}) + + +@API() +async def multiple_database_queries(request: Request): + try: + count = int(request.query_params.get('queries', 1)) + except (ValueError, TypeError): + count = 1 + row_ids = sample(range(1, 10000), min(max(count, 1), 500)) + async with connection_pool.acquire() as connection: + statement = await connection.prepare('SELECT id, randomnumber FROM world WHERE id = $1') + worlds = [{'id': i, 'randomNumber': await statement.fetchval(i)} for i in row_ids] + return Response(data=worlds) + + +@API() +async def fortunes(): + async with connection_pool.acquire() as connection: + fortune_records = await connection.fetch('SELECT * FROM Fortune') + fortune_records = [(row['id'], row['message']) for row in fortune_records] + fortune_records.append((0, 'Additional fortune added at request time.')) + fortune_records.sort(key=lambda row: row[1]) + data = fortune_template.render(fortunes=fortune_records) + return HTMLResponse(data=data) + + +@API() +async def database_updates(request: Request): + try: + count = int(request.query_params.get('queries', 1)) + except (ValueError, TypeError): + count = 1 + num_queries = min(max(count, 1), 500) + + 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 connection_pool.acquire() as connection: + statement = await connection.prepare('SELECT id, randomnumber FROM world WHERE id = $1') + for _, row_id in updates: + await statement.fetchval(row_id) + await connection.executemany('UPDATE world SET randomnumber = $1 WHERE id = $2', updates) + return Response(data=worlds) + + +@API() +def plaintext(): + return PlainTextResponse(b'Hello, world!') + + +url_routing = { + 'json': json_serialization, + 'db': single_database_query, + 'queries': multiple_database_queries, + 'fortunes': fortunes, + 'updates': database_updates, + 'plaintext': plaintext, +} + +app = Panther(__name__, configs=__name__, urls=url_routing) diff --git a/frameworks/Python/panther/benchmark_config.json b/frameworks/Python/panther/benchmark_config.json new file mode 100644 index 00000000000..3de0b7a0974 --- /dev/null +++ b/frameworks/Python/panther/benchmark_config.json @@ -0,0 +1,28 @@ +{ + "framework": "panther", + "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": "Micro", + "framework": "panther", + "language": "Python", + "flavor": "Python3", + "platform": "ASGI", + "webserver": "Uvicorn", + "os": "Linux", + "orm": "Raw", + "database_os": "Linux", + "database": "Postgres", + "display_name": "Panther", + "versus": "None", + "notes": "" + } + }] +} diff --git a/frameworks/Python/panther/config.toml b/frameworks/Python/panther/config.toml new file mode 100644 index 00000000000..f556e171a19 --- /dev/null +++ b/frameworks/Python/panther/config.toml @@ -0,0 +1,19 @@ +[framework] +name = "panther" + +[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 = "ASGI" +webserver = "Uvicorn" +versus = "None" diff --git a/frameworks/Python/panther/panther.dockerfile b/frameworks/Python/panther/panther.dockerfile new file mode 100644 index 00000000000..1ed09ea2374 --- /dev/null +++ b/frameworks/Python/panther/panther.dockerfile @@ -0,0 +1,16 @@ +FROM python:3.12 AS builder +WORKDIR /panther +RUN python -m venv /opt/venv +RUN pip install --no-cache-dir uv +COPY requirements.txt . +RUN /usr/local/bin/uv pip install -r requirements.txt --python /opt/venv/bin/python + +FROM python:3.12-slim AS production +ENV PYTHONUNBUFFERED=1 +ENV PATH="/opt/venv/bin:$PATH" +COPY --from=builder /opt/venv /opt/venv +WORKDIR /panther +COPY . /panther + +EXPOSE 8080 +CMD gunicorn app:app -k uvicorn.workers.UvicornWorker -c panther_conf.py diff --git a/frameworks/Python/panther/panther_conf.py b/frameworks/Python/panther/panther_conf.py new file mode 100644 index 00000000000..f2176beb091 --- /dev/null +++ b/frameworks/Python/panther/panther_conf.py @@ -0,0 +1,14 @@ +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/panther.pid' +loglevel = 'error' diff --git a/frameworks/Python/panther/requirements.txt b/frameworks/Python/panther/requirements.txt new file mode 100644 index 00000000000..730b0ed72f8 --- /dev/null +++ b/frameworks/Python/panther/requirements.txt @@ -0,0 +1,6 @@ +panther==5.0.2 +cython==3.1.2 +asyncpg==0.30.0 +gunicorn==23.0.0 +uvloop==0.21.0 +uvicorn==0.27.0 \ No newline at end of file diff --git a/frameworks/Python/panther/templates/fortune.html b/frameworks/Python/panther/templates/fortune.html new file mode 100644 index 00000000000..d9c26bfa96a --- /dev/null +++ b/frameworks/Python/panther/templates/fortune.html @@ -0,0 +1,14 @@ + + + + Fortunes + + + + + {% for fortune in fortunes %} + + {% endfor %} +
idmessage
{{ fortune[0] }}{{ fortune[1]|e }}
+ + diff --git a/frameworks/Python/pyramid/requirements.txt b/frameworks/Python/pyramid/requirements.txt index 9a4521e4b5a..d9cd315c6e3 100644 --- a/frameworks/Python/pyramid/requirements.txt +++ b/frameworks/Python/pyramid/requirements.txt @@ -8,12 +8,14 @@ chameleon==3.9.1 # via pyramid-chameleon greenlet==1.1.2 # via sqlalchemy -gunicorn==20.1.0 +gunicorn==22.0.0 # via -r requirements.in hupper==1.10.3 # via pyramid -orjson==3.6.5 +orjson==3.9.15 # via -r requirements.in +packaging==24.0 + # via gunicorn pastedeploy==2.1.1 # via plaster-pastedeploy plaster==1.0 @@ -38,9 +40,9 @@ venusian==3.0.0 # via pyramid webob==1.8.7 # via pyramid -zope.deprecation==4.4.0 +zope-deprecation==4.4.0 # via pyramid -zope.interface==5.4.0 +zope-interface==5.4.0 # via pyramid # The following packages are considered to be unsafe in a requirements file: diff --git a/frameworks/Python/quart/requirements-uvicorn.txt b/frameworks/Python/quart/requirements-uvicorn.txt index 8518917c668..cb62fac6b78 100644 --- a/frameworks/Python/quart/requirements-uvicorn.txt +++ b/frameworks/Python/quart/requirements-uvicorn.txt @@ -1,7 +1,7 @@ anyio==3.6.1 -gunicorn==20.1.0 +gunicorn==22.0.0 httptools==0.4.0 -idna==3.3 +idna==3.7 python-dotenv==0.20.0 PyYAML==6.0 sniffio==1.3.0 diff --git a/frameworks/Python/quart/requirements.txt b/frameworks/Python/quart/requirements.txt index 7bb0976e5a0..063f2131e0f 100644 --- a/frameworks/Python/quart/requirements.txt +++ b/frameworks/Python/quart/requirements.txt @@ -2,17 +2,17 @@ aiofiles==0.8.0 asyncpg==0.26.0 blinker==1.5 click==8.1.3 -h11==0.13.0 +h11==0.16.0 h2==4.1.0 hpack==4.0.0 hypercorn==0.14.2 hyperframe==6.0.1 itsdangerous==2.1.2 -Jinja2==3.1.2 +Jinja2==3.1.4 MarkupSafe==2.1.1 priority==2.0.0 quart==0.18.0 toml==0.10.2 uvloop==0.16.0 -Werkzeug==2.2.3 +Werkzeug==2.3.8 wsproto==1.2.0 diff --git a/frameworks/Python/responder/requirements.txt b/frameworks/Python/responder/requirements.txt index 12b381c6b2f..a16d601e4a8 100644 --- a/frameworks/Python/responder/requirements.txt +++ b/frameworks/Python/responder/requirements.txt @@ -1,6 +1,6 @@ asyncpg==0.21.0 -gunicorn==20.0.4 -Jinja2==2.11.3 +gunicorn==22.0.0 +Jinja2==3.1.4 ujson==2.0.3 uvloop==0.17.0 httptools==0.5.0 diff --git a/frameworks/Python/robyn/app-const.py b/frameworks/Python/robyn/app-const.py index f6cce721132..ceec8488829 100755 --- a/frameworks/Python/robyn/app-const.py +++ b/frameworks/Python/robyn/app-const.py @@ -1,7 +1,7 @@ import multiprocessing import os -from robyn import Robyn +from robyn import Response, Robyn from robyn.argument_parser import Config @@ -9,7 +9,7 @@ class SpecialConfig(Config): def __init__(self): super().__init__() self.workers = 2 - self.processes = (os.cpu_count() * 2) + 1 + self.processes = ( os.cpu_count() * 2 ) + 1 self.log_level = "WARN" @@ -21,8 +21,13 @@ def plaintext() -> str: return "Hello, world!" +@app.get("/json", const=True) +def json() -> dict: + return { + "message": "Hello, world!" + } + + if __name__ == "__main__": app.add_response_header("Server", "Robyn") - app.add_response_header("Content-Type", "text/plain") - - app.start(url="0.0.0.0", port=8080) + app.start(host="0.0.0.0", port=8080) diff --git a/frameworks/Python/robyn/app.py b/frameworks/Python/robyn/app.py index 5e8aae14d81..bbbb037868a 100755 --- a/frameworks/Python/robyn/app.py +++ b/frameworks/Python/robyn/app.py @@ -1,7 +1,7 @@ import multiprocessing import os -from robyn import Robyn +from robyn import Response, Robyn from robyn.argument_parser import Config @@ -9,7 +9,7 @@ class SpecialConfig(Config): def __init__(self): super().__init__() self.workers = 2 - self.processes = (os.cpu_count() * 2) + 1 + self.processes = ( os.cpu_count() * 2 ) + 1 self.log_level = "WARN" @@ -21,8 +21,12 @@ def plaintext() -> str: return "Hello, world!" -if __name__ == "__main__": - app.add_response_header("Server", "Robyn") - app.add_response_header("Content-Type", "text/plain") +@app.get("/json") +def json() -> dict: + return { + "message": "Hello, world!" + } - app.start(url="0.0.0.0", port=8080) +if __name__ == "__main__": + app.add_response_header("Server", "Roby1n") + app.start(host="0.0.0.0", port=8080) diff --git a/frameworks/Python/robyn/benchmark_config.json b/frameworks/Python/robyn/benchmark_config.json index 16a462b0768..46cd72fe4c6 100755 --- a/frameworks/Python/robyn/benchmark_config.json +++ b/frameworks/Python/robyn/benchmark_config.json @@ -3,6 +3,7 @@ "tests": [ { "default": { + "json_url": "/json", "plaintext_url": "/plaintext", "port": 8080, "approach": "Realistic", @@ -19,6 +20,7 @@ "versus": "None" }, "const": { + "json_url": "/json", "plaintext_url": "/plaintext", "port": 8080, "approach": "Realistic", @@ -36,4 +38,5 @@ } } ] -} \ No newline at end of file +} + diff --git a/frameworks/Python/robyn/config.toml b/frameworks/Python/robyn/config.toml index b4bcd32194f..5fcc7591d68 100644 --- a/frameworks/Python/robyn/config.toml +++ b/frameworks/Python/robyn/config.toml @@ -3,6 +3,7 @@ name = "Robyn" [main] urls.plaintext = "/plaintext" +urls.json = "/json" approach = "Realistic" classification = "Micro" os = "Linux" @@ -13,6 +14,7 @@ versus = "None" [const] urls.plaintext = "/plaintext" +urls.json = "/json" approach = "Realistic" classification = "Micro" os = "Linux" diff --git a/frameworks/Python/robyn/requirements-const.txt b/frameworks/Python/robyn/requirements-const.txt index 49ff1ae519f..484d4b7704f 100644 --- a/frameworks/Python/robyn/requirements-const.txt +++ b/frameworks/Python/robyn/requirements-const.txt @@ -1,2 +1,2 @@ -uvloop==0.17.0 -robyn==0.37.0 +uvloop==0.19.0 +robyn==0.62.0 diff --git a/frameworks/Python/robyn/requirements.txt b/frameworks/Python/robyn/requirements.txt index 49ff1ae519f..484d4b7704f 100644 --- a/frameworks/Python/robyn/requirements.txt +++ b/frameworks/Python/robyn/requirements.txt @@ -1,2 +1,2 @@ -uvloop==0.17.0 -robyn==0.37.0 +uvloop==0.19.0 +robyn==0.62.0 diff --git a/frameworks/Python/robyn/robyn-const.dockerfile b/frameworks/Python/robyn/robyn-const.dockerfile index ab65d8de834..9429ff37376 100644 --- a/frameworks/Python/robyn/robyn-const.dockerfile +++ b/frameworks/Python/robyn/robyn-const.dockerfile @@ -1,4 +1,4 @@ -FROM python:3.11 +FROM python:3.12 ADD ./ /robyn @@ -8,4 +8,4 @@ RUN pip3 install -r /robyn/requirements-const.txt EXPOSE 8080 -CMD ["python", "app-const.py", "--log-level", "warn"]] +CMD ["python", "app-const.py", "--log-level", "warn"] diff --git a/frameworks/Python/robyn/robyn.dockerfile b/frameworks/Python/robyn/robyn.dockerfile index 5d0ecc64845..bc42b5be462 100644 --- a/frameworks/Python/robyn/robyn.dockerfile +++ b/frameworks/Python/robyn/robyn.dockerfile @@ -1,4 +1,4 @@ -FROM python:3.9 +FROM python:3.12 ADD ./ /robyn diff --git a/frameworks/Python/routerling/README.md b/frameworks/Python/routerling/README.md deleted file mode 100755 index 2e4cb9faa5a..00000000000 --- a/frameworks/Python/routerling/README.md +++ /dev/null @@ -1,22 +0,0 @@ -# Routerling Benchmarking Test - -This is the Routerling portion of a [benchmarking tests suite](../../) -comparing a variety of web development platforms. - -The information below is specific to Routerling. 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 - -[Routerling](https://github.com/rayattack/pyrouterling) is a lightweight ASGI framework. - -## Test Paths & Sources - -All of the test implementations are located within a single file ([app.py](app.py)). - -## Resources - -* [Routerling on GitHub](https://github.com/rayattack/pyrouterling) -* [ASGI specification](https://asgi.readthedocs.io/en/latest/) diff --git a/frameworks/Python/routerling/app.py b/frameworks/Python/routerling/app.py deleted file mode 100644 index 291d5da2653..00000000000 --- a/frameworks/Python/routerling/app.py +++ /dev/null @@ -1,170 +0,0 @@ -import asyncio -import asyncpg -import jinja2 -import os -import ujson -from random import randint -from operator import itemgetter -from urllib.parse import parse_qs - -from routerling import Router - - -router = Router() - - -async def 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 - ) - - -CONTENT_TYPE = 'Content-Type' -JSON = 'application/json' - -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.'] - - -pool = None -key = itemgetter(1) -json_dumps = ujson.dumps -template = None -path = os.path.join('templates', 'fortune.html') -with open(path, 'r') as template_file: - template_text = template_file.read() - template = jinja2.Template(template_text) - -loop = asyncio.get_event_loop() -loop.run_until_complete(setup()) - - -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 json_serialization(r, w, c): - """ - Test type 1: JSON Serialization - """ - content = json_dumps({'message': 'Hello, world!'}) - w.headers = CONTENT_TYPE, JSON - w.body = content - - -async def single_database_query(r, w, c): - """ - Test type 2: Single database object - """ - row_id = randint(1, 10000) - connection = await pool.acquire() - try: - number = await connection.fetchval(READ_ROW_SQL, row_id) - world = {'id': row_id, 'randomNumber': number} - finally: - await pool.release(connection) - - content = json_dumps(world).encode('utf-8') - w.headers = CONTENT_TYPE, JSON - w.body = content - - -async def multiple_database_queries(r, w, c): - """ - Test type 3: Multiple database queries - """ - num_queries = get_num_queries(r._scope) - row_ids = [randint(1, 10000) for _ in range(num_queries)] - worlds = [] - - connection = await pool.acquire() - try: - statement = await connection.prepare(READ_ROW_SQL) - for row_id in row_ids: - number = await statement.fetchval(row_id) - worlds.append({'id': row_id, 'randomNumber': number}) - finally: - await pool.release(connection) - - content = json_dumps(worlds).encode('utf-8') - w.headers = CONTENT_TYPE, JSON - w.body = content - - -async def fortunes(r, w, c): - """ - Test type 4: Fortunes - """ - connection = await pool.acquire() - try: - fortunes = await connection.fetch('SELECT * FROM Fortune') - finally: - await pool.release(connection) - - fortunes.append(ADDITIONAL_ROW) - fortunes.sort(key=key) - content = template.render(fortunes=fortunes).encode('utf-8') - w.headers = CONTENT_TYPE, 'text/html; charset=utf-8' - w.body = content - - -async def database_updates(r, w, c): - """ - Test type 5: Database updates - """ - num_queries = get_num_queries(r._scope) - updates = [(randint(1, 10000), randint(1, 10000)) for _ in range(num_queries)] - worlds = [{'id': row_id, 'randomNumber': number} for row_id, number in updates] - - connection = await pool.acquire() - try: - statement = await connection.prepare(READ_ROW_SQL) - for row_id, _ in updates: - await statement.fetchval(row_id) - await connection.executemany(WRITE_ROW_SQL, updates) - finally: - await pool.release(connection) - - content = json_dumps(worlds).encode('utf-8') - w.headers = CONTENT_TYPE, JSON - w.body = content - - -async def plaintext(r, w, c): - """ - Test type 6: Plaintext - """ - content = 'Hello, world!' - w.headers = CONTENT_TYPE, 'text/plain; charset=utf-8' - w.body = content - - -async def handle_404(r, w, c): - content = b'Not found' - w.headers = CONTENT_TYPE, b'text/plain; charset=utf-8' - w.body = content - - - -router.HTTP('/json', json_serialization) -router.HTTP('/db', single_database_query) -router.HTTP('/queries', multiple_database_queries) -router.HTTP('/fortunes', fortunes) -router.HTTP('/updates', database_updates) -router.HTTP('/plaintext', plaintext) diff --git a/frameworks/Python/routerling/benchmark_config.json b/frameworks/Python/routerling/benchmark_config.json deleted file mode 100755 index 7ec9ca2895e..00000000000 --- a/frameworks/Python/routerling/benchmark_config.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "framework": "routerling", - "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", - "framework": "uvicorn", - "language": "Python", - "flavor": "Python3", - "platform": "None", - "webserver": "None", - "os": "Linux", - "orm": "Raw", - "database_os": "Linux", - "database": "Postgres", - "display_name": "routerling", - "notes": "" - } - }] -} diff --git a/frameworks/Python/routerling/config.toml b/frameworks/Python/routerling/config.toml deleted file mode 100644 index daf63bdbf08..00000000000 --- a/frameworks/Python/routerling/config.toml +++ /dev/null @@ -1,19 +0,0 @@ -[framework] -name = "routerling" - -[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 = "None" -versus = "None" \ No newline at end of file diff --git a/frameworks/Python/routerling/requirements.txt b/frameworks/Python/routerling/requirements.txt deleted file mode 100644 index 7b68e45f102..00000000000 --- a/frameworks/Python/routerling/requirements.txt +++ /dev/null @@ -1,11 +0,0 @@ -asgiref==3.4.1 -asyncpg==0.24.0 -click==8.0.1 -gunicorn==20.1.0 -h11==0.12.0 -Jinja2==3.0.1 -MarkupSafe==2.0.1 -routerling==0.3.1 -ujson==5.4.0 -uvloop==0.16.0 -uvicorn==0.14.0 diff --git a/frameworks/Python/routerling/routerling.dockerfile b/frameworks/Python/routerling/routerling.dockerfile deleted file mode 100644 index e46173e71e9..00000000000 --- a/frameworks/Python/routerling/routerling.dockerfile +++ /dev/null @@ -1,17 +0,0 @@ -FROM python:3.8 - -WORKDIR /routerling - -RUN pip3 install cython==0.29.13 - -ADD requirements.txt /routerling/ - -RUN pip3 install -r /routerling/requirements.txt - -ADD templates/fortune.html /routerling/templates/ - -ADD settings.py app.py /routerling/ - -EXPOSE 8080 - -CMD gunicorn app:router -k uvicorn.workers.UvicornWorker -c settings.py \ No newline at end of file diff --git a/frameworks/Python/routerling/settings.py b/frameworks/Python/routerling/settings.py deleted file mode 100644 index 295745226cd..00000000000 --- a/frameworks/Python/routerling/settings.py +++ /dev/null @@ -1,14 +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/routerling.pid' -loglevel = 'error' diff --git a/frameworks/Python/routerling/templates/fortune.html b/frameworks/Python/routerling/templates/fortune.html deleted file mode 100644 index 244205144fd..00000000000 --- a/frameworks/Python/routerling/templates/fortune.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - Fortunes - - - - - - - {% for fortune in fortunes %} - - - - {% endfor %} -
idmessage
{{ fortune[0] }}{{ fortune[1]|e }}
- - \ No newline at end of file diff --git a/frameworks/Python/sanic/app.py b/frameworks/Python/sanic/app.py index 47b374ce9a3..4070503205d 100644 --- a/frameworks/Python/sanic/app.py +++ b/frameworks/Python/sanic/app.py @@ -11,6 +11,8 @@ import sanic from sanic import response +from orjson import dumps + logger = getLogger(__name__) @@ -41,23 +43,26 @@ def get_num_queries(queries): return query_count -connection_pool = None sort_fortunes_key = itemgetter(1) template = load_fortunes_template() -app = sanic.Sanic(name=__name__) +app = sanic.Sanic(name=__name__, dumps=dumps) @app.listener('before_server_start') async def setup_database(app, loop): - global connection_pool - connection_pool = await asyncpg.create_pool( - user=os.getenv('PGUSER', 'benchmarkdbuser'), - password=os.getenv('PGPASS', 'benchmarkdbpass'), - database='hello_world', - host='tfb-database', - port=5432 - ) + app.ctx.pool = await asyncpg.create_pool( + user=os.getenv('PGUSER', 'benchmarkdbuser'), + password=os.getenv('PGPASS', 'benchmarkdbpass'), + database='hello_world', + host='tfb-database', + port=5432 + ) + + +@app.listener('after_server_stop') +async def close_database(app, loop): + app.ctx.pool.close() @app.get('/json') @@ -69,7 +74,7 @@ def json_view(request): async def single_database_query_view(request): row_id = randint(1, 10000) - async with connection_pool.acquire() as connection: + async with request.app.ctx.pool.acquire() as connection: number = await connection.fetchval(READ_ROW_SQL, row_id) return response.json( @@ -84,7 +89,7 @@ async def multiple_database_queries_view(request): row_ids = sample(range(1, 10000), num_queries) worlds = [] - async with connection_pool.acquire() as connection: + async with request.app.ctx.pool.acquire() as connection: statement = await connection.prepare(READ_ROW_SQL) for row_id in row_ids: number = await statement.fetchval(row_id) @@ -100,7 +105,7 @@ async def multiple_database_queries_view(request): @app.get('/fortunes') async def fortunes_view(request): - async with connection_pool.acquire() as connection: + async with request.app.ctx.pool.acquire() as connection: fortunes = await connection.fetch('SELECT * FROM Fortune') fortunes.append(ADDITIONAL_ROW) @@ -112,22 +117,21 @@ async def fortunes_view(request): @app.get('/updates') async def database_updates_view(request): - worlds = [] - updates = set() queries = request.args.get('queries', 1) + num_queries = get_num_queries(queries) + # To avoid deadlock + ids = sorted(sample(range(1, 10000 + 1), num_queries)) + numbers = sorted(sample(range(1, 10000), num_queries)) + updates = list(zip(ids, numbers)) - async with connection_pool.acquire() as connection: - statement = await connection.prepare(READ_ROW_SQL_TO_UPDATE) - - for row_id in sample(range(1, 10000), get_num_queries(queries)): - record = await statement.fetchrow(row_id) - world = dict( - id=record['id'], randomNumber=record['randomnumber'] - ) - world['randomNumber'] = randint(1, 10000) - worlds.append(world) - updates.add((world['id'], world['randomNumber'])) + worlds = [ + {"id": row_id, "randomNumber": number} for row_id, number in updates + ] + async with request.app.ctx.pool.acquire() as connection: + statement = await connection.prepare(READ_ROW_SQL) + for row_id, _ in updates: + await statement.fetchval(row_id) await connection.executemany(WRITE_ROW_SQL, updates) return response.json(worlds, headers=get_headers()) diff --git a/frameworks/Python/sanic/benchmark_config.json b/frameworks/Python/sanic/benchmark_config.json index b1bdd529d60..b3c6799b42b 100644 --- a/frameworks/Python/sanic/benchmark_config.json +++ b/frameworks/Python/sanic/benchmark_config.json @@ -23,8 +23,7 @@ "database_os": "Linux", "display_name": "Sanic", "notes": "", - "versus": "None", - "tags": ["broken"] + "versus": "None" } } ] diff --git a/frameworks/Python/sanic/requirements.txt b/frameworks/Python/sanic/requirements.txt index 36f8d2c8246..ff8b4afd8a9 100644 --- a/frameworks/Python/sanic/requirements.txt +++ b/frameworks/Python/sanic/requirements.txt @@ -1,4 +1,5 @@ -asyncpg==0.25.0 -Jinja2==3.1.2 -sanic==22.6.1 -uvloop==0.16.0 +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 diff --git a/frameworks/Python/sanic/sanic.dockerfile b/frameworks/Python/sanic/sanic.dockerfile index 9619237ed21..d12ebcb391a 100644 --- a/frameworks/Python/sanic/sanic.dockerfile +++ b/frameworks/Python/sanic/sanic.dockerfile @@ -1,8 +1,8 @@ -FROM python:3.8 +FROM python:3.12 ADD ./requirements.txt /sanic/requirements.txt -RUN pip3 install cython==0.29.13 && \ +RUN pip3 install cython==3.0.11 && \ pip3 install -r /sanic/requirements.txt ADD ./ /sanic diff --git a/frameworks/Python/starlette/requirements.txt b/frameworks/Python/starlette/requirements.txt index ec1b4acc589..7a06852153f 100644 --- a/frameworks/Python/starlette/requirements.txt +++ b/frameworks/Python/starlette/requirements.txt @@ -1,11 +1,11 @@ asyncpg==0.26.0 -gunicorn==20.1.0 +gunicorn==23.0.0 httptools==0.5.0 -idna==3.3 -Jinja2==3.1.2 +idna==3.7 +Jinja2==3.1.4 MarkupSafe==2.1.1 python-dotenv==0.20.0 PyYAML==6.0 -starlette==0.27.0 +starlette==0.49.1 uvicorn==0.20.0 uvloop==0.17.0 diff --git a/frameworks/Python/starlite/README.md b/frameworks/Python/starlite/README.md deleted file mode 100755 index 0d1452fc99a..00000000000 --- a/frameworks/Python/starlite/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# Starlite Benchmarking Test - -This is the Starlite portion of a [benchmarking tests suite](../../) -comparing a variety of web development platforms. - -The information below is specific to Starlite. 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# Starlite - -Starlite is a powerful, performant, flexible and opinionated ASGI framework, -offering first class typing support and a full [Pydantic](https://github.com/samuelcolvin/pydantic) -integration. - -Check out the [documentation 📚](https://starlite-api.github.io/starlite/). diff --git a/frameworks/Python/starlite/app.py b/frameworks/Python/starlite/app.py deleted file mode 100755 index 09a4ffa56f5..00000000000 --- a/frameworks/Python/starlite/app.py +++ /dev/null @@ -1,121 +0,0 @@ -import asyncio -import os -from operator import itemgetter -from random import randint, sample -from typing import Any - -import uvloop -from asyncpg import create_pool -from jinja2 import Template -from starlite import MediaType, Starlite, get - -asyncio.set_event_loop_policy(uvloop.EventLoopPolicy()) -connection_pool: Any = None - - -async def init_connection_pool() -> None: - global connection_pool - connection_pool = await create_pool( - user=os.getenv('PGUSER', 'benchmarkdbuser'), - password=os.getenv('PGPASS', 'benchmarkdbpass'), - database='hello_world', - host='tfb-database', - port=5432 - ) - - -def normalize_queries(value: str | None) -> int: - queries = int(value) if value and value.isnumeric() else 1 - if queries > 500: - return 500 - if queries < 1: - return 1 - return queries - - -def load_fortunes_template() -> "Template": - path = os.path.join('templates', 'fortune.html') - with open(path, 'r') as template_file: - template_text = template_file.read() - return Template(template_text) - - -fortune_template = load_fortunes_template() - - -@get(path='/json') -def json_serialization() -> dict[str, str]: - return {'message': 'Hello, world!'} - - -@get(path='/db') -async def single_database_query() -> dict[str, int]: - row_id = randint(1, 10000) - async with connection_pool.acquire() as connection: - number = await connection.fetchval( - 'SELECT "randomnumber", "id" FROM "world" WHERE id = $1', - row_id - ) - - return {'id': row_id, 'randomNumber': number} - - -@get(path='/queries') -async def multiple_database_queries(queries: None | str = None) -> list[dict[str, int]]: - row_ids = sample(range(1, 10000), normalize_queries(queries)) - worlds = [] - - async with connection_pool.acquire() as connection: - statement = await connection.prepare('SELECT "randomnumber", "id" FROM "world" WHERE id = $1') - for row_id in row_ids: - number = await statement.fetchval(row_id) - worlds.append({'id': row_id, 'randomNumber': number}) - - return worlds - - -@get(path='/fortunes', media_type=MediaType.HTML) -async def render_fortunes_template() -> str: - async with connection_pool.acquire() as connection: - fortunes = await connection.fetch('SELECT * FROM Fortune') - - fortunes.append([0, 'Additional fortune added at request time.']) - fortunes.sort(key=itemgetter(1)) - return fortune_template.render(fortunes=fortunes) - - -@get(path='/updates') -async def database_updates(queries: None | str = None) -> list[dict[str, int]]: - num_queries = normalize_queries(queries) - updates = list(zip(sorted(sample(range(1, 10000 + 1), num_queries)), sample(range(1, 10000), num_queries))) - - worlds = [ - {"id": row_id, "randomNumber": number} for row_id, number in updates - ] - - async with connection_pool.acquire() as connection: - statement = await connection.prepare('SELECT "id", "randomnumber" FROM "world" WHERE id = $1') - for row_id, _ in updates: - await statement.fetchval(row_id) - await connection.executemany('UPDATE "world" SET "randomnumber"=$1 WHERE id=$2', updates) - - return worlds - - -@get(path='/plaintext', media_type=MediaType.TEXT) -def plaintext() -> bytes: - return b'Hello, world!' - - -app = Starlite( - route_handlers=[ - database_updates, - json_serialization, - multiple_database_queries, - plaintext, - render_fortunes_template, - single_database_query, - ], - on_startup=[init_connection_pool], - openapi_config=None, -) diff --git a/frameworks/Python/starlite/benchmark_config.json b/frameworks/Python/starlite/benchmark_config.json deleted file mode 100755 index cdceafff5e4..00000000000 --- a/frameworks/Python/starlite/benchmark_config.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "framework": "starlite", - "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": "Micro", - "database": "Postgres", - "framework": "Starlite", - "language": "Python", - "flavor": "Python3", - "orm": "Raw", - "platform": "None", - "webserver": "Uvicorn", - "os": "Linux", - "database_os": "Linux", - "display_name": "Starlite", - "notes": "", - "versus": "None" - } - } - ] -} diff --git a/frameworks/Python/starlite/config.toml b/frameworks/Python/starlite/config.toml deleted file mode 100644 index 3aa7c3cec44..00000000000 --- a/frameworks/Python/starlite/config.toml +++ /dev/null @@ -1,19 +0,0 @@ -[framework] -name = "starlite" - -[uvicorn] -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 = "Uvicorn" -versus = "None" diff --git a/frameworks/Python/starlite/requirements.txt b/frameworks/Python/starlite/requirements.txt deleted file mode 100644 index d8312c6df61..00000000000 --- a/frameworks/Python/starlite/requirements.txt +++ /dev/null @@ -1,5 +0,0 @@ -asyncpg>=0.27.0 -jinja2>=3.1.2 -starlite>=1.51.0 -uvicorn[standard]>=0.20.0 -uvloop>=0.17.0 \ No newline at end of file diff --git a/frameworks/Python/starlite/starlite.dockerfile b/frameworks/Python/starlite/starlite.dockerfile deleted file mode 100644 index f51c232e4cc..00000000000 --- a/frameworks/Python/starlite/starlite.dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM python:3.11 -WORKDIR /starlite/ - -RUN python -m venv /opt/venv -ENV PATH="/opt/venv/bin:$PATH" - -COPY . . - -RUN pip install --upgrade pip \ - && pip install cython==0.29.33 \ - && pip install -r /starlite/requirements.txt - -EXPOSE 8080 -CMD uvicorn app:app --host 0.0.0.0 --port 8080 --workers $(nproc) --log-level error --loop uvloop diff --git a/frameworks/Python/starlite/templates/fortune.html b/frameworks/Python/starlite/templates/fortune.html deleted file mode 100644 index 2e62ac5f7a0..00000000000 --- a/frameworks/Python/starlite/templates/fortune.html +++ /dev/null @@ -1,17 +0,0 @@ - - -Fortunes - - - - - - - {% for fortune in fortunes %} - - - - - {% endfor %}
idmessage
{{ fortune[0] }}{{ fortune[1]|e }}
- - diff --git a/frameworks/Python/turbogears/benchmark_config.json b/frameworks/Python/turbogears/benchmark_config.json index cfd4c3efda7..162dbb38e64 100644 --- a/frameworks/Python/turbogears/benchmark_config.json +++ b/frameworks/Python/turbogears/benchmark_config.json @@ -21,6 +21,7 @@ "os": "Linux", "database_os": "Linux", "display_name": "TurboGears", + "tags": ["broken"], "notes": "CPython 2.7" } }] diff --git a/frameworks/Python/turbogears/requirements.txt b/frameworks/Python/turbogears/requirements.txt index c3d5ccc9d7d..58499e541b2 100644 --- a/frameworks/Python/turbogears/requirements.txt +++ b/frameworks/Python/turbogears/requirements.txt @@ -3,8 +3,8 @@ tg.devtools==2.3.8 SQLAlchemy==1.3.0 zope.sqlalchemy==0.7.6 mysqlclient==1.3.7 -jinja2==2.11.3 +jinja2==3.1.6 gunicorn==19.9.0 -meinheld==0.6.1 +meinheld==1.0.2 greenlet==0.4.14 diff --git a/frameworks/Python/uvicorn/requirements.txt b/frameworks/Python/uvicorn/requirements.txt index b75fdec808c..8b3843c6cb6 100644 --- a/frameworks/Python/uvicorn/requirements.txt +++ b/frameworks/Python/uvicorn/requirements.txt @@ -1,7 +1,7 @@ asyncpg==0.28.0 -gunicorn==20.1.0 +gunicorn==22.0.0 httptools==0.6.0 -Jinja2==3.1.2 +Jinja2==3.1.4 ujson==5.8.0 uvloop==0.17.0 uvicorn==0.22.0 diff --git a/frameworks/Python/vibora/README.md b/frameworks/Python/vibora/README.md deleted file mode 100644 index 647792661a2..00000000000 --- a/frameworks/Python/vibora/README.md +++ /dev/null @@ -1,46 +0,0 @@ -# [Vibora](https://github.com/vibora-io/vibora) Benchmark Test - -The information below is specific to Vibora. For further guidance, -review the [documentation](https://github.com/TechEmpower/FrameworkBenchmarks/wiki). -Also note that there is additional information that's provided in -the [Python README](../). - -This is the Python Vibora portion of a [benchmarking tests suite](../../) -comparing a variety of frameworks. - -All test implementations are located within a single file -([app.py](app.py)). - -## Description - -Vibora, Vibora + psycopg2 - -### Database - -Postgres - -## Test URLs -### JSON Encoding - -http://localhost:8080/json - -### Single Row Random Query - -http://localhost:8080/db - -### Plaintext - -http://localhost:8080/plaintext - - - -The following tests cannot be currently run due to an issue with the framework -[Details Here] = https://github.com/vibora-io/vibora/issues/223 - -### Update random rows - -http://localhost:8080/updates/?queries= - -### Variable Row Query Test - -http://localhost:8080/db?queries= diff --git a/frameworks/Python/vibora/app.py b/frameworks/Python/vibora/app.py deleted file mode 100644 index 243aa4365e1..00000000000 --- a/frameworks/Python/vibora/app.py +++ /dev/null @@ -1,115 +0,0 @@ -import multiprocessing -import os -from random import randint -from operator import itemgetter - -from vibora import Vibora, Request, JsonResponse, Response -from vibora.hooks import Events - -from db import Pool -DEFAULT_POOL_SIZE = 1000//multiprocessing.cpu_count() - -READ_ROW_SQL = 'SELECT * FROM "world" WHERE id={0}' -WRITE_ROW_SQL = 'UPDATE "world" SET "randomnumber"={0} WHERE id={1} RETURNING id, randomNumber' -READ_ALL_FORTUNES = 'SELECT * FROM "fortune"' -ADDITIONAL_ROW = [0, 'Additional fortune added at request time.'] -sort_fortunes_key = itemgetter(1) - -app = Vibora(template_dirs=['templates']) - - -@app.handle(Events.BEFORE_SERVER_START) -async def init_db(app: Vibora): - app.components.add(await Pool("postgresql://%s:%s@%s:5432/%s" % (os.getenv("PGUSER", "benchmarkdbuser"), os.getenv("PSPASS", "benchmarkdbpass"), os.getenv("PGADDR", "tfb-database"), os.getenv("PGDB", "hello_world")), max_size=int(os.getenv("PGPOOLSIZE", DEFAULT_POOL_SIZE)))) - - -@app.handle(Events.BEFORE_SERVER_STOP) -async def close_db(app: Vibora): - await asyncio.wait_for(app.components.get(Pool).close(), timeout=10) - - -def getQueriesTotal(params): - try: - queries = params['queries'][0] - query_count = int(queries) - except: - return 1 - - if query_count < 1: - return 1 - if query_count > 500: - return 500 - return query_count - - -async def fetchWorld(pool): - async with pool.acquire() as conn: - return await conn.fetchrow(READ_ROW_SQL.format(randint(1, 10000))) - - -async def updateWorld(world_id, pool): - async with pool.acquire() as conn: - return await conn.fetchrow(WRITE_ROW_SQL.format(randint(1, 10000), world_id)) - - -async def fetchMultipleWorlds(total, pool): - worlds = [] - for x in range(total): - res = await fetchWorld(pool) - worlds.append({'id': res[0], 'randomNumber': res[1]}) - return worlds - - -async def updateMultipleWorlds(total, pool): - worlds = [] - for x in range(total): - res = await fetchWorld(pool) - updated = await updateWorld(res[0], pool) - worlds.append({'id': updated[0], 'randomNumber': updated[1]}) - return worlds - - -async def fetchFortunes(pool): - async with pool.acquire() as conn: - return await conn.fetch(READ_ALL_FORTUNES) - - -@app.route('/fortunes') -async def fortunes(pool: Pool): - fortunes = await fetchFortunes(pool) - fortunes.append(ADDITIONAL_ROW) - fortunes.sort(key=sort_fortunes_key) - return await app.render('index.html', fortunes=fortunes) - - -@app.route('/db') -async def single_query(request: Request, pool: Pool): - res = await fetchWorld(pool) - return JsonResponse({'id': res[0], 'randomNumber': res[1]}, headers={'Server': 'Vibora'}) - - -@app.route('/plaintext') -async def plaintext(): - return Response(b'Hello, World!', headers={'Server': 'Vibora', 'Content-Type': 'text/plain'}) - - -@app.route('/json') -async def json(): - return JsonResponse({'message': 'Hello, World!'}, headers={'Server': 'Vibora'}) - - -@app.route('/queries') -async def multiple_queries(request: Request, pool: Pool): - total_queries = getQueriesTotal(request.args) - worlds = await fetchMultipleWorlds(total_queries, pool) - return JsonResponse(worlds, headers={'Server': 'Vibora', 'Content-Type': 'application/json', 'Content-Length': str(total_queries)}) - - -@app.route('/updates') -async def update_queries(request: Request, pool: Pool): - total_queries = getQueriesTotal(request.args) - worlds = await updateMultipleWorlds(total_queries, pool) - return JsonResponse(worlds, headers={'Server': 'Vibora', 'Content-Type': 'application/json', 'Content-Length': str(total_queries)}) - -if __name__ == '__main__': - app.run(host="0.0.0.0", port=8000, workers=multiprocessing.cpu_count()) diff --git a/frameworks/Python/vibora/benchmark_config.json b/frameworks/Python/vibora/benchmark_config.json deleted file mode 100644 index 3876196498a..00000000000 --- a/frameworks/Python/vibora/benchmark_config.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "framework": "vibora", - "tests": [{ - "default": { - "json_url": "/json", - "plaintext_url": "/plaintext", - "db_url": "/db", - "port": 8000, - "approach": "Realistic", - "classification": "Platform", - "framework": "vibora", - "language": "Python", - "flavor": "Python3", - "platform": "None", - "webserver": "None", - "os": "Linux", - "orm": "Full", - "database_os": "Linux", - "database": "Postgres", - "display_name": "Vibora", - "notes": "" - } - }] -} diff --git a/frameworks/Python/vibora/config.toml b/frameworks/Python/vibora/config.toml deleted file mode 100644 index 03952ecdb41..00000000000 --- a/frameworks/Python/vibora/config.toml +++ /dev/null @@ -1,16 +0,0 @@ -[framework] -name = "vibora" - -[main] -urls.plaintext = "/plaintext" -urls.json = "/json" -urls.db = "/db" -approach = "Realistic" -classification = "Platform" -database = "Postgres" -database_os = "Linux" -os = "Linux" -orm = "Full" -platform = "None" -webserver = "None" -versus = "None" diff --git a/frameworks/Python/vibora/db.py b/frameworks/Python/vibora/db.py deleted file mode 100644 index 2f3fe5560e2..00000000000 --- a/frameworks/Python/vibora/db.py +++ /dev/null @@ -1,36 +0,0 @@ -import asyncio -from contextlib import asynccontextmanager -import asyncpg - - -class Connection(asyncpg.Connection): - async def reset(self, *, timeout=None): - pass - - -class Pool: - def __init__(self, connect_url, max_size=10, connection_class=None): - self._connect_url = connect_url - self._connection_class = connection_class or Connection - self._queue = asyncio.LifoQueue(max_size) - - def __await__(self): - return self._async_init__().__await__() - - async def _async_init__(self): - for _ in range(self._queue.maxsize): - self._queue.put_nowait(await asyncpg.connect(self._connect_url, connection_class=self._connection_class)) - return self - - @asynccontextmanager - async def acquire(self): - conn = await self._queue.get() - try: - yield conn - finally: - self._queue.put_nowait(conn) - - async def close(self): - for _ in range(self._queue.maxsize): - conn = await self._queue.get() - await conn.close() diff --git a/frameworks/Python/vibora/requirements.txt b/frameworks/Python/vibora/requirements.txt deleted file mode 100644 index 88fbcd0ba4b..00000000000 --- a/frameworks/Python/vibora/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -asyncpg==0.26.0 -git+https://github.com/IterableTrucks/vibora.git@a24bbf417a84df3a25f7e8901613a1c50ccfe63f#egg=vibora[fast] diff --git a/frameworks/Python/vibora/templates/index.html b/frameworks/Python/vibora/templates/index.html deleted file mode 100644 index 55c472c8ee1..00000000000 --- a/frameworks/Python/vibora/templates/index.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - Fortunes - - - - - - - - {% for fortune in fortunes %} - - - - - {% endfor %} -
idmessage
{{ fortune[0] }}{{ fortune[1] }}
- - \ No newline at end of file diff --git a/frameworks/Python/vibora/vibora.dockerfile b/frameworks/Python/vibora/vibora.dockerfile deleted file mode 100644 index 5a2685d5ec5..00000000000 --- a/frameworks/Python/vibora/vibora.dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM python:3.10.6 - -ADD ./ /vibora - -WORKDIR /vibora - -RUN pip3 install -r /vibora/requirements.txt - -EXPOSE 8000 - -CMD ["python3", "app.py"] diff --git a/frameworks/Python/web2py/benchmark_config.json b/frameworks/Python/web2py/benchmark_config.json index d1349f5633e..c8bf7c94bf0 100644 --- a/frameworks/Python/web2py/benchmark_config.json +++ b/frameworks/Python/web2py/benchmark_config.json @@ -22,6 +22,7 @@ "database_os": "Linux", "display_name": "web2py-standard", "notes": "CPython 2.7", + "tags": ["broken"], "versus": "wsgi" }, "optimized": { @@ -44,6 +45,7 @@ "database_os": "Linux", "display_name": "web2py-optimized", "notes": "CPython 2.7", + "tags": ["broken"], "versus": "wsgi" } }] diff --git a/frameworks/Python/web2py/requirements.txt b/frameworks/Python/web2py/requirements.txt index ffff87771f6..968f12b799f 100644 --- a/frameworks/Python/web2py/requirements.txt +++ b/frameworks/Python/web2py/requirements.txt @@ -1,4 +1,4 @@ mysqlclient==1.3.12 gunicorn==19.7.1 -meinheld==0.6.1 +meinheld==1.0.2 greenlet==0.4.14 diff --git a/frameworks/Python/weppy/README.md b/frameworks/Python/weppy/README.md deleted file mode 100644 index 9292402d79f..00000000000 --- a/frameworks/Python/weppy/README.md +++ /dev/null @@ -1,33 +0,0 @@ -# weppy Benchmark Test (ported from Flask example) - -This is the weppy portion of a [benchmarking tests suite](../../) -comparing a variety of web development platforms. - -The information below is specific to weppy. For further guidance, -review the [documentation](https://github.com/TechEmpower/FrameworkBenchmarks/wiki). -Also note that there is additional information provided in -the [Python README](../). - -[weppy](http://weppy.org/) is a fullstack Python 2/3 web framework. -This test uses the included ORM and templating system, and gunicorn+meinheld for the application server on CPtyhon and Tornado on pypy. - -## Test Paths & Source - -* [JSON Serialization](app.py): "/json" -* [Single Database Query](app.py): "/db" -* [Multiple Database Queries](app.py): "queries?queries=#" -* [Fortunes](app.py): "/fortunes" -* [Database Updates](app.py): "updates?queries=#" -* [Plaintext](app.py): "/plaintext" - -*Replace # with an actual number. - -### Resources - -* [weppy Source Code](https://github.com/gi0baro/weppy) -* [weppy Documentation](http://weppy.org/docs) - -### Community - -* [weppy (weppy-talk) Google Group](https://groups.google.com/forum/#!forum/weppy-talk) - diff --git a/frameworks/Python/weppy/app.py b/frameworks/Python/weppy/app.py deleted file mode 100644 index 23a461d8340..00000000000 --- a/frameworks/Python/weppy/app.py +++ /dev/null @@ -1,128 +0,0 @@ -import sys -from functools import partial -from random import randint -from weppy import App, Pipe, request, response -from weppy.orm import Database, Model, Field, rowmethod -from weppy.tools import service -from email.utils import formatdate - -_is_pypy = hasattr(sys, 'pypy_version_info') -if sys.version_info[0] == 3: - xrange = range - -DBHOSTNAME = 'tfb-database' - -app = App(__name__) - - -class World(Model): - tablename = "world" - randomnumber = Field.int() - - @rowmethod('serialize') - def _serialize(self, row): - return {'id': row.id, 'randomNumber': row.randomnumber} - - -class Fortune(Model): - tablename = "fortune" - message = Field.string() - - @rowmethod('serialize') - def _serialize(self, row): - return {'id': row.id, 'message': row.message} - - -class DateHeaderPipe(Pipe): - def open(self): - response.headers["Date"] = formatdate(timeval=None, localtime=False, usegmt=True) - - -app.config.handle_static = False -app.config.db.adapter = 'postgres:psycopg2' \ - if not _is_pypy else 'postgres:pg8000' -app.config.db.host = DBHOSTNAME -app.config.db.user = 'benchmarkdbuser' -app.config.db.password = 'benchmarkdbpass' -app.config.db.database = 'hello_world' -app.config.db.pool_size = 100 - -app.pipeline = [DateHeaderPipe()] - -db = Database(app, auto_migrate=False) -db.define_models(World, Fortune) - - -@app.route() -@service.json -def json(): - return {'message': 'Hello, World!'} - - -@app.route("/db", pipeline=[db.pipe]) -@service.json -def get_random_world(): - return World.get(randint(1, 10000)).serialize() - - -def get_qparam(): - try: - rv = int(request.query_params.queries) - if rv < 1: - rv = 1 - if rv > 500: - rv = 500 - except: - rv = 1 - return rv - - -@app.route("/queries", pipeline=[db.pipe]) -@service.json -def get_random_worlds(): - num_queries = get_qparam() - worlds = [ - World.get(randint(1, 10000)).serialize() for _ in xrange(num_queries)] - return worlds - - -@app.route(pipeline=[db.pipe]) -def fortunes(): - fortunes = Fortune.all().select() - fortunes.append( - Fortune.new(id=0, message="Additional fortune added at request time.")) - fortunes.sort(lambda m: m.message) - return {'fortunes': fortunes} - - -@app.route(pipeline=[db.pipe]) -@service.json -def updates(): - num_queries = get_qparam() - worlds = [] - rp = partial(randint, 1, 10000) - ids = [rp() for _ in xrange(num_queries)] - ids.sort() # To avoid deadlock - for id in ids: - world = World.get(id) - world.update_record(randomnumber=rp()) - worlds.append(world.serialize()) - return worlds - - -@app.route() -def plaintext(): - response.headers["Content-Type"] = "text/plain" - return 'Hello, World!' - - -try: - import meinheld - meinheld.server.set_access_logger(None) - meinheld.set_keepalive(120) -except ImportError: - pass - -# entry point for debugging -if __name__ == "__main__": - app.run(debug=True) diff --git a/frameworks/Python/weppy/benchmark_config.json b/frameworks/Python/weppy/benchmark_config.json deleted file mode 100644 index 3b989c719dc..00000000000 --- a/frameworks/Python/weppy/benchmark_config.json +++ /dev/null @@ -1,97 +0,0 @@ -{ - "framework": "weppy", - "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": "Postgres", - "framework": "weppy", - "language": "Python", - "orm": "Full", - "platform": "Meinheld", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "weppy-Py2", - "notes": "CPython 2.7", - "versus": "wsgi", - "tags": ["broken"] - }, - "py3": { - "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": "Postgres", - "framework": "weppy", - "language": "Python", - "orm": "Full", - "platform": "Meinheld", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "weppy-Py3", - "notes": "CPython 3.6", - "versus": "wsgi" - }, - "pypy2": { - "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": "Postgres", - "framework": "weppy", - "language": "Python", - "flavor": "PyPy2", - "orm": "Full", - "platform": "Tornado", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "weppy-PyPy2", - "notes": "PyPy2", - "versus": "wsgi", - "tags": ["broken"] - }, - "nginx-uwsgi": { - "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": "Postgres", - "framework": "weppy", - "language": "Python", - "orm": "Full", - "platform": "uWSGI", - "webserver": "nginx", - "os": "Linux", - "database_os": "Linux", - "display_name": "weppy-nginx-uWSGI", - "notes": "CPython 3.6", - "versus": "wsgi", - "tags": ["broken"] - } - }] -} diff --git a/frameworks/Python/weppy/config.toml b/frameworks/Python/weppy/config.toml deleted file mode 100644 index baceb6e8747..00000000000 --- a/frameworks/Python/weppy/config.toml +++ /dev/null @@ -1,70 +0,0 @@ -[framework] -name = "weppy" - -[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 = "Full" -platform = "Meinheld" -webserver = "None" -versus = "wsgi" - -[py3] -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 = "Full" -platform = "Meinheld" -webserver = "None" -versus = "wsgi" - -[nginx-uwsgi] -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 = "Full" -platform = "uWSGI" -webserver = "nginx" -versus = "wsgi" - -[pypy2] -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 = "Full" -platform = "Tornado" -webserver = "None" -versus = "wsgi" diff --git a/frameworks/Python/weppy/gunicorn_conf.py b/frameworks/Python/weppy/gunicorn_conf.py deleted file mode 100644 index 817008b6d65..00000000000 --- a/frameworks/Python/weppy/gunicorn_conf.py +++ /dev/null @@ -1,26 +0,0 @@ -import multiprocessing -import os -import sys - -_is_pypy = hasattr(sys, 'pypy_version_info') -_is_travis = os.environ.get('TRAVIS') == 'true' - -workers = multiprocessing.cpu_count() * 3 -if _is_travis: - workers = 2 - -bind = "0.0.0.0:8080" -keepalive = 120 -errorlog = '-' -pidfile = 'gunicorn.pid' - -if _is_pypy: - worker_class = "tornado" -else: - worker_class = "meinheld.gmeinheld.MeinheldWorker" - - def post_fork(server, worker): - # Disable access log. - # (Until https://github.com/mopemope/meinheld/pull/42 is released) - import meinheld.server - meinheld.server.set_access_logger(None) diff --git a/frameworks/Python/weppy/nginx.conf b/frameworks/Python/weppy/nginx.conf deleted file mode 100644 index 38c0c61341c..00000000000 --- a/frameworks/Python/weppy/nginx.conf +++ /dev/null @@ -1,48 +0,0 @@ -# This file is based on /usr/local/nginx/conf/nginx.conf.default. - -# One worker process per core -error_log stderr error; - -events { - # This needed to be increased because the nginx error log said so. - # http://nginx.org/en/docs/ngx_core_module.html#worker_connections - worker_connections 65535; - multi_accept on; -} - -http { - default_type application/octet-stream; - client_body_temp_path /tmp; - - # turn off request logging for performance - access_log off; - - # I think these only options affect static file serving - sendfile on; - tcp_nopush on; - - # Allow many HTTP Keep-Alive requests in a single TCP connection before - # closing it (the default is 100). This will minimize the total number - # of TCP connections opened/closed. The problem is that this may cause - # some worker processes to be handling too connections relative to the - # other workers based on an initial imbalance, so this is disabled for - # now. -# keepalive_requests 1000; - - #keepalive_timeout 0; - keepalive_timeout 65; - - server { - # For information on deferred, see: - # http://nginx.org/en/docs/http/ngx_http_core_module.html#listen - # http://www.techrepublic.com/article/take-advantage-of-tcp-ip-options-to-optimize-data-transmission/ - # The backlog argument to listen() is set to match net.ipv4.tcp_max_syn_backlog and net.core.somaxconn - listen 8080 default_server deferred reuseport backlog=65535; - server_name localhost; - - location / { - uwsgi_pass unix:/var/tmp/uwsgi.sock; - include /usr/local/nginx/conf/uwsgi_params; - } - } -} diff --git a/frameworks/Python/weppy/requirements-pypy.txt b/frameworks/Python/weppy/requirements-pypy.txt deleted file mode 100644 index e56b1b00d5f..00000000000 --- a/frameworks/Python/weppy/requirements-pypy.txt +++ /dev/null @@ -1,4 +0,0 @@ -pg8000==1.10.6 -weppy==1.3 -gunicorn==19.9.0 -tornado==6.3.3 diff --git a/frameworks/Python/weppy/requirements.txt b/frameworks/Python/weppy/requirements.txt deleted file mode 100644 index 9e0c789e3ba..00000000000 --- a/frameworks/Python/weppy/requirements.txt +++ /dev/null @@ -1,6 +0,0 @@ -psycopg2==2.7.5 -weppy==1.3 -gunicorn==19.9.0 -meinheld==0.6.1 -uwsgi==2.0.22 -greenlet==0.4.14 diff --git a/frameworks/Python/weppy/templates/fortunes.html b/frameworks/Python/weppy/templates/fortunes.html deleted file mode 100644 index 07d84854bcc..00000000000 --- a/frameworks/Python/weppy/templates/fortunes.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - Fortunes - - - - - - - - {{for fortune in fortunes:}} - - - - - {{pass}} -
idmessage
{{=fortune.id}}{{=fortune.message}}
- - diff --git a/frameworks/Python/weppy/uwsgi.ini b/frameworks/Python/weppy/uwsgi.ini deleted file mode 100644 index 5c9f5b80227..00000000000 --- a/frameworks/Python/weppy/uwsgi.ini +++ /dev/null @@ -1,19 +0,0 @@ -[uwsgi] -master -; Increase listen queue used for nginx connecting to uWSGI. This matches -; net.ipv4.tcp_max_syn_backlog and net.core.somaxconn. -listen = 16384 -; for performance -disable-logging -; use UNIX sockets instead of TCP loopback for performance -socket = /var/tmp/uwsgi.sock -; allow nginx to access the UNIX socket -chmod-socket = 666 -; Avoid thundering herd problem http://uwsgi-docs.readthedocs.org/en/latest/articles/SerializingAccept.html . -; This is currently disabled because when I tried it with flask, it caused a -; 20% performance hit. The CPU cores could not be saturated with thunder-lock. -; I'm not yet sure the full story, so this is presently disabled. Also, -; disabling this caused bottle to get ~13% faster. -;thunder-lock -; used by uwsgi_stop.ini -pidfile = /var/tmp/uwsgi.pid diff --git a/frameworks/Python/weppy/weppy-nginx-uwsgi.dockerfile b/frameworks/Python/weppy/weppy-nginx-uwsgi.dockerfile deleted file mode 100644 index e29f5447c0d..00000000000 --- a/frameworks/Python/weppy/weppy-nginx-uwsgi.dockerfile +++ /dev/null @@ -1,19 +0,0 @@ -FROM python:3.6.6-stretch - -RUN curl -s http://nginx.org/keys/nginx_signing.key | apt-key add - -RUN echo "deb http://nginx.org/packages/debian/ stretch nginx" >> /etc/apt/sources.list -RUN echo "deb-src http://nginx.org/packages/debian/ stretch nginx" >> /etc/apt/sources.list - -RUN apt-get update -yqq && apt-get install -yqq nginx - -ADD ./ /weppy - -WORKDIR /weppy - -RUN pip install -r /weppy/requirements.txt - -RUN sed -i 's|include .*/conf/uwsgi_params;|include /etc/nginx/uwsgi_params;|g' /weppy/nginx.conf - -EXPOSE 8080 - -CMD nginx -c /weppy/nginx.conf && uwsgi --ini /weppy/uwsgi.ini --processes $(nproc) --wsgi app:app diff --git a/frameworks/Python/weppy/weppy-py3.dockerfile b/frameworks/Python/weppy/weppy-py3.dockerfile deleted file mode 100644 index 4591004350d..00000000000 --- a/frameworks/Python/weppy/weppy-py3.dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM python:3.6.6-stretch - -ADD ./ /weppy - -WORKDIR /weppy - -RUN pip3 install -r /weppy/requirements.txt - -EXPOSE 8080 - -CMD gunicorn app:app -c gunicorn_conf.py diff --git a/frameworks/Python/weppy/weppy-pypy2.dockerfile b/frameworks/Python/weppy/weppy-pypy2.dockerfile deleted file mode 100644 index 7c5a6a14abf..00000000000 --- a/frameworks/Python/weppy/weppy-pypy2.dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM pypy:2-5.10 - -ADD ./ /weppy - -WORKDIR /weppy - -RUN pip install -r /weppy/requirements-pypy.txt - -EXPOSE 8080 - -CMD gunicorn app:app -c gunicorn_conf.py diff --git a/frameworks/Python/weppy/weppy.dockerfile b/frameworks/Python/weppy/weppy.dockerfile deleted file mode 100644 index 5f840729f96..00000000000 --- a/frameworks/Python/weppy/weppy.dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM python:2.7.15-stretch - -ADD ./ /weppy - -WORKDIR /weppy - -RUN pip install -r /weppy/requirements.txt - -EXPOSE 8080 - -CMD gunicorn app:app -c gunicorn_conf.py diff --git a/frameworks/Python/wsgi/requirements.txt b/frameworks/Python/wsgi/requirements.txt index 8c35857d83b..9ba0b97b7b6 100644 --- a/frameworks/Python/wsgi/requirements.txt +++ b/frameworks/Python/wsgi/requirements.txt @@ -1,4 +1,4 @@ ujson==1.35 gunicorn==19.9.0 -meinheld==0.6.1 +meinheld==1.0.2 greenlet==0.4.14 diff --git a/frameworks/Python/xpresso/README.md b/frameworks/Python/xpresso/README.md deleted file mode 100755 index 1a66fe57feb..00000000000 --- a/frameworks/Python/xpresso/README.md +++ /dev/null @@ -1,25 +0,0 @@ -# Xpresso Benchmarking Test - -This is the Xpresso portion of a [benchmarking tests suite](../../) comparing a variety of web development platforms. - -The information below is specific to Xpresso. -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 - -[Xpresso] is a high performance Python web framework built on top of [Starlette], [Pydantic] and [di] with a focus on composability, flexibility and minimal but well defined library APIs. - -## Test Paths & Sources - -All of the test implementations are located within a single file ([main.py](main.py)). - -## Resources - -* [Xpresso source code on GitHub](https://github.com/adriangb/xpresso) -* [Xpresso website - documentation](https://xpresso-api.dev) - -[Xpresso]: https://github.com/adriangb/xpresso -[Starlette]: https://github.com/encode/starlette -[Pydantic]: https://github.com/samuelcolvin/pydantic/ -[di]: https://github.com/adriangb/di diff --git a/frameworks/Python/xpresso/benchmark_config.json b/frameworks/Python/xpresso/benchmark_config.json deleted file mode 100755 index dcc76e906a7..00000000000 --- a/frameworks/Python/xpresso/benchmark_config.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "framework": "xpresso", - "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": "Micro", - "database": "Postgres", - "framework": "Xpresso", - "language": "Python", - "flavor": "Python3", - "orm": "Raw", - "platform": "None", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "Xpresso", - "notes": "", - "versus": "None" - } - } - ] -} diff --git a/frameworks/Python/xpresso/config.toml b/frameworks/Python/xpresso/config.toml deleted file mode 100644 index fe4a990a539..00000000000 --- a/frameworks/Python/xpresso/config.toml +++ /dev/null @@ -1,19 +0,0 @@ -[framework] -name = "xpresso" - -[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/Python/xpresso/main.py b/frameworks/Python/xpresso/main.py deleted file mode 100755 index 0862fe51c7a..00000000000 --- a/frameworks/Python/xpresso/main.py +++ /dev/null @@ -1,158 +0,0 @@ -import multiprocessing -import os -import pathlib -from operator import itemgetter -from random import randint, sample -from typing import Annotated, AsyncIterable, Optional - -import asyncpg # type: ignore -import jinja2 # type: ignore -import uvicorn # type: ignore -from pydantic import BaseModel, Field -from starlette.responses import HTMLResponse, PlainTextResponse -from xpresso import App, Depends, Path, Response, FromQuery - -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) - -app_dir = pathlib.Path(__file__).parent -with (app_dir / "templates" / "fortune.html").open() as template_file: - template = jinja2.Template(template_file.read()) - - -async def get_db_pool() -> AsyncIterable[asyncpg.Pool]: - async with asyncpg.create_pool( # type: ignore - user=os.getenv('PGUSER', 'benchmarkdbuser'), - password=os.getenv('PGPASS', 'benchmarkdbpass'), - database=os.getenv('PGDB', 'hello_world'), - host=os.getenv('PGHOST', 'tfb-database'), - port=5432, - ) as pool: - yield pool - - -DBPool = Annotated[asyncpg.Pool, Depends(get_db_pool, scope="app")] - - -def get_num_queries(queries: Optional[str]) -> int: - if not queries: - return 1 - try: - queries_num = int(queries) - except (ValueError, TypeError): - return 1 - if queries_num < 1: - return 1 - if queries_num > 500: - return 500 - return queries_num - - - -class Greeting(BaseModel): - message: str - - -def json_serialization() -> Greeting: - return Greeting(message="Hello, world!") - - -def plaintext() -> Response: - return PlainTextResponse(b"Hello, world!") - - -class QueryResult(BaseModel): - id: int - randomNumber: int - - -async def single_database_query(pool: DBPool) -> QueryResult: - row_id = randint(1, 10000) - - connection: "asyncpg.Connection" - async with pool.acquire() as connection: # type: ignore - number: int = await connection.fetchval(READ_ROW_SQL, row_id) # type: ignore - - return QueryResult.construct(id=row_id, randomNumber=number) - - -QueryCount = Annotated[str, Field(gt=0, le=500)] - - -async def multiple_database_queries( - pool: DBPool, - queries: FromQuery[str | None] = None, -) -> list[QueryResult]: - num_queries = get_num_queries(queries) - row_ids = sample(range(1, 10000), num_queries) - - connection: "asyncpg.Connection" - async with pool.acquire() as connection: # type: ignore - statement = await connection.prepare(READ_ROW_SQL) # type: ignore - return [ - QueryResult.construct( - id=row_id, - randomNumber=await statement.fetchval(row_id), # type: ignore - ) - for row_id in row_ids - ] - - -async def fortunes(pool: DBPool) -> Response: - connection: "asyncpg.Connection" - async with pool.acquire() as connection: # type: ignore - fortunes: "list[tuple[int, str]]" = await connection.fetch("SELECT * FROM Fortune") # type: ignore - - fortunes.append(ADDITIONAL_ROW) - fortunes.sort(key=sort_fortunes_key) - content = template.render(fortunes=fortunes) # type: ignore - return HTMLResponse(content) - - -async def database_updates( - pool: DBPool, - queries: FromQuery[str | None] = None, -) -> list[QueryResult]: - num_queries = get_num_queries(queries) - - updates = [(row_id, randint(1, 10000)) for row_id in sample(range(1, 10000), num_queries)] - - async with pool.acquire() as connection: - statement = await connection.prepare(READ_ROW_SQL) - for row_id, _ in updates: - await statement.fetchval(row_id) - await connection.executemany(WRITE_ROW_SQL, updates) # type: ignore - - return [QueryResult.construct(id=row_id, randomNumber=number) for row_id, number in updates] - - -routes = ( - Path("/json", get=json_serialization), - Path("/plaintext", get=plaintext), - Path("/db", get=single_database_query), - Path("/queries", get=multiple_database_queries), - Path("/fortunes", get=fortunes), - Path("/updates", get=database_updates), -) - - -app = App(routes=routes) - - -if __name__ == "__main__": - workers = multiprocessing.cpu_count() - if os.environ.get("TRAVIS") == "true": - workers = 2 - uvicorn.run( # type: ignore - "main:app", - host="0.0.0.0", - port=8080, - workers=workers, - log_level="error", - loop="uvloop", - http="httptools", - ) diff --git a/frameworks/Python/xpresso/requirements.txt b/frameworks/Python/xpresso/requirements.txt deleted file mode 100644 index e9e6af671f9..00000000000 --- a/frameworks/Python/xpresso/requirements.txt +++ /dev/null @@ -1,7 +0,0 @@ -asyncpg==0.27.0 -Jinja2==2.11.3 -markupsafe==2.0.1 -httptools==0.5.0 -uvloop==0.17.0 -uvicorn==0.20.0 -xpresso==0.46.0 diff --git a/frameworks/Python/xpresso/templates/fortune.html b/frameworks/Python/xpresso/templates/fortune.html deleted file mode 100644 index 1c90834285d..00000000000 --- a/frameworks/Python/xpresso/templates/fortune.html +++ /dev/null @@ -1,10 +0,0 @@ - - -Fortunes - - - -{% for fortune in fortunes %} -{% endfor %}
idmessage
{{ fortune[0] }}{{ fortune[1]|e }}
- - diff --git a/frameworks/Python/xpresso/xpresso.dockerfile b/frameworks/Python/xpresso/xpresso.dockerfile deleted file mode 100644 index f0aba7a9005..00000000000 --- a/frameworks/Python/xpresso/xpresso.dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM python:3.10 - -RUN mkdir /xpresso -WORKDIR /xpresso - -COPY ./requirements.txt /xpresso/ - -RUN pip install --no-cache-dir -r /xpresso/requirements.txt - -COPY ./ /xpresso/ - -EXPOSE 8080 - -CMD ["python", "main.py"] diff --git a/frameworks/Racket/racket/racket.dockerfile b/frameworks/Racket/racket/racket.dockerfile index f5d975e077d..58448b4c541 100644 --- a/frameworks/Racket/racket/racket.dockerfile +++ b/frameworks/Racket/racket/racket.dockerfile @@ -11,7 +11,7 @@ RUN echo 'APT::Get::Install-Recommends "false";' > /etc/apt/apt.conf.d/00-genera FROM debian AS racket -ARG RACKET_VERSION=8.9 +ARG RACKET_VERSION=8.18 RUN apt-get update -q \ && apt-get install --no-install-recommends -q -y \ diff --git a/frameworks/Ruby/agoo/.ruby-gemset b/frameworks/Ruby/agoo/.ruby-gemset deleted file mode 100644 index 92fc86eb583..00000000000 --- a/frameworks/Ruby/agoo/.ruby-gemset +++ /dev/null @@ -1 +0,0 @@ -agoo diff --git a/frameworks/Ruby/agoo/.ruby-version b/frameworks/Ruby/agoo/.ruby-version deleted file mode 100644 index 4560fb912c0..00000000000 --- a/frameworks/Ruby/agoo/.ruby-version +++ /dev/null @@ -1 +0,0 @@ -ruby-2.6.3 diff --git a/frameworks/Ruby/agoo/Gemfile.lock b/frameworks/Ruby/agoo/Gemfile.lock index daf0ea3b35d..7f05c4040ea 100644 --- a/frameworks/Ruby/agoo/Gemfile.lock +++ b/frameworks/Ruby/agoo/Gemfile.lock @@ -1,14 +1,20 @@ GEM remote: https://rubygems.org/ specs: - agoo (2.8.3) - connection_pool (2.2.2) - oj (3.7.12) - pg (1.1.4) - rack (2.0.7) + agoo (2.15.13) + bigdecimal (3.1.9) + connection_pool (2.5.0) + oj (3.16.10) + bigdecimal (>= 3.0) + ostruct (>= 0.2) + ostruct (0.6.1) + pg (1.6.2) + pg (1.6.2-x86_64-linux) + rack (3.2.0) PLATFORMS ruby + x86_64-linux DEPENDENCIES agoo @@ -18,4 +24,4 @@ DEPENDENCIES rack BUNDLED WITH - 1.17.2 + 2.7.0 diff --git a/frameworks/Ruby/agoo/agoo.dockerfile b/frameworks/Ruby/agoo/agoo.dockerfile index cbd64cb1f69..548fb50341b 100644 --- a/frameworks/Ruby/agoo/agoo.dockerfile +++ b/frameworks/Ruby/agoo/agoo.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:3.3-rc +FROM ruby:3.5-rc RUN apt-get update -q \ && apt-get install --no-install-recommends -q -y \ @@ -6,14 +6,20 @@ RUN apt-get update -q \ libpq-dev \ && rm -rf /var/lib/apt/lists/* +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 + WORKDIR /rack -COPY Gemfile app.rb ./ +COPY Gemfile* app.rb ./ RUN bundle install --jobs=4 EXPOSE 8080 -ENV RUBY_YJIT_ENABLE=1 CMD AGOO_WORKER_COUNT=$(nproc) ruby app.rb diff --git a/frameworks/Ruby/agoo/app.rb b/frameworks/Ruby/agoo/app.rb index f2c2c9f3301..2c8e64bc9a9 100644 --- a/frameworks/Ruby/agoo/app.rb +++ b/frameworks/Ruby/agoo/app.rb @@ -6,36 +6,48 @@ require 'pg' require 'rack' -$pool = ConnectionPool.new(size: 256, timeout: 5) do - PG::Connection.new({ - dbname: 'hello_world', - host: 'tfb-database', - user: 'benchmarkdbuser', - password: 'benchmarkdbpass' - }) - end +$pool = ConnectionPool.new(size: 1, timeout: 5) do + conn = PG::Connection.new({ + dbname: 'hello_world', + host: 'tfb-database', + user: 'benchmarkdbuser', + password: 'benchmarkdbpass' + }) + conn.set_error_verbosity(PG::PQERRORS_VERBOSE) + conn.prepare('select_world', 'SELECT * FROM world WHERE id = $1') + conn.prepare('select_fortune', 'SELECT id, message FROM fortune') + conn +end + +QUERY_RANGE = (1..10_000).freeze +ALL_IDS = QUERY_RANGE.to_a +QUERIES_MIN = 1 +QUERIES_MAX = 500 + +CONTENT_TYPE = 'Content-Type' +DATE = 'Date' +SERVER = 'Server' +SERVER_STRING = 'Agoo' + +JSON_TYPE = 'application/json' +HTML_TYPE = 'text/html; charset=utf-8' +PLAINTEXT_TYPE = 'text/plain' + class BaseHandler def self.extract_queries_param(request = nil) queries = Rack::Utils.parse_query(request['QUERY_STRING'])['queries'].to_i rescue 1 - return 1 if queries < 1 - return 500 if queries > 500 - - queries + queries.clamp(QUERIES_MIN, QUERIES_MAX) end def self.get_one_random_number - 1 + Random.rand(10000) + Random.rand(QUERY_RANGE) end def self.get_one_record(id = get_one_random_number) $pool.with do |conn| - conn.exec_params(<<-SQL, [id]).first - - SELECT * FROM world WHERE id = $1 - - SQL + conn.exec_prepared('select_world', [id]).first end end @@ -43,9 +55,9 @@ def self.html_response(str = '') [ 200, { - 'Content-Type' => 'text/html; charset=utf-8', - 'Date' => Time.now.utc.httpdate, - 'Server' => 'Agoo' + CONTENT_TYPE => HTML_TYPE, + DATE => Time.now.httpdate, + SERVER => SERVER_STRING }, [str] ] @@ -55,9 +67,9 @@ def self.json_response(obj = {}) [ 200, { - 'Content-Type' => 'application/json', - 'Date' => Time.now.utc.httpdate, - 'Server' => 'Agoo' + CONTENT_TYPE => JSON_TYPE, + DATE => Time.now.httpdate, + SERVER => SERVER_STRING }, [Oj.dump(obj, { :mode => :strict })] ] @@ -67,9 +79,9 @@ def self.plain_response(str = '') [ 200, { - 'Content-Type' => 'text/plain', - 'Date' => Time.now.utc.httpdate, - 'Server' => 'Agoo' + CONTENT_TYPE => PLAINTEXT_TYPE, + DATE => Time.now.httpdate, + SERVER => SERVER_STRING }, [str] ] @@ -102,20 +114,17 @@ def self.call(_req) end end + class FortunesHandler < BaseHandler def self.call(_req) f_1 = $pool.with do |conn| - conn.exec(<<-SQL) - - SELECT id, message FROM fortune - - SQL - end + conn.exec_prepared('select_fortune', []) + end 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'] }#{ Rack::Utils.escape_html(f['message']) }" }. + map { |f| "#{ f['id'] }#{ ERB::Escape.html_escape(f['message']) }" }. join html_response(<<-HTML) @@ -140,12 +149,10 @@ def self.call(_req) class QueriesHandler < BaseHandler def self.call(req) - records = - [].tap do|r| - (extract_queries_param req).times do - r << get_one_record() - end - end + queries = extract_queries_param req + records = ALL_IDS.sample(queries).map do |id| + get_one_record(id) + end json_response(records) end @@ -153,20 +160,18 @@ def self.call(req) class UpdatesHandler < BaseHandler def self.call(req) - records = - [].tap do|r| - (extract_queries_param req).times do - r << get_one_record() - end - end - - updated_records = - records.map { |r| r['randomnumber'] = get_one_random_number; r } + queries = extract_queries_param req + records = ALL_IDS.sample(queries).sort.map do |id| + world = get_one_record(id) + world['randomnumber'] = get_one_random_number + world + end sql_values = - updated_records. - map { |r| "(#{ r['id'] }, #{ r['randomnumber'] })"}. - join(', ') + records. + map { |r| + "(#{ r['id'] }, #{ r['randomnumber'] })" + }.join(', ') $pool.with do |conn| conn.exec(<<-SQL) @@ -179,26 +184,25 @@ def self.call(req) SQL end - json_response(updated_records) + json_response(records) end end Agoo::Log.configure({ - classic: true, - colorize: true, - console: true, - dir: '', - states: { - DEBUG: false, - INFO: false, - - connect: false, - eval: false, - push: false, - request: false, - response: false - } - }) + classic: true, + colorize: true, + console: true, + dir: '', + states: { + DEBUG: false, + INFO: false, + connect: false, + eval: false, + push: false, + request: false, + response: false + } +}) worker_count = 4 worker_count = ENV['AGOO_WORKER_COUNT'].to_i if ENV.key?('AGOO_WORKER_COUNT') diff --git a/frameworks/Ruby/agoo/benchmark_config.json b/frameworks/Ruby/agoo/benchmark_config.json index a4042facee3..29c8106d1e2 100644 --- a/frameworks/Ruby/agoo/benchmark_config.json +++ b/frameworks/Ruby/agoo/benchmark_config.json @@ -19,7 +19,7 @@ "webserver": "Agoo", "os": "Linux", "database_os": "Linux", - "display_name": "rack-agoo-mri", + "display_name": "rack [agoo]", "notes": "" } }] diff --git a/frameworks/Ruby/grape/Gemfile b/frameworks/Ruby/grape/Gemfile index 380df952afe..89f6c86a84e 100644 --- a/frameworks/Ruby/grape/Gemfile +++ b/frameworks/Ruby/grape/Gemfile @@ -1,10 +1,8 @@ -source 'http://rubygems.org' +source 'https://rubygems.org' -gem 'mysql2', '0.5.4' +gem 'mysql2', '0.5.6' gem 'unicorn', '6.1.0' -gem 'puma', '5.6.4' -gem 'activerecord', '7.0.3', :require => 'active_record' -gem 'activerecord-import', '1.4.0' -gem 'grape', '1.6.2' -gem 'rack', '2.2.3.1' -gem 'json', '2.6.2' +gem 'puma', '~> 7.1' +gem 'activerecord', '~> 8.0.0', :require => 'active_record' +gem 'grape', '2.1.1' +gem 'json', '~> 2.9' diff --git a/frameworks/Ruby/grape/Gemfile.lock b/frameworks/Ruby/grape/Gemfile.lock new file mode 100644 index 00000000000..a1053906658 --- /dev/null +++ b/frameworks/Ruby/grape/Gemfile.lock @@ -0,0 +1,93 @@ +GEM + remote: https://rubygems.org/ + specs: + activemodel (8.0.1) + activesupport (= 8.0.1) + activerecord (8.0.1) + activemodel (= 8.0.1) + activesupport (= 8.0.1) + timeout (>= 0.4.0) + activesupport (8.0.1) + base64 + benchmark (>= 0.3) + bigdecimal + concurrent-ruby (~> 1.0, >= 1.3.1) + connection_pool (>= 2.2.5) + drb + i18n (>= 1.6, < 2) + 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) + dry-core (1.1.0) + concurrent-ruby (~> 1.0) + logger + zeitwerk (~> 2.6) + dry-inflector (1.2.0) + dry-logic (1.6.0) + bigdecimal + concurrent-ruby (~> 1.0) + dry-core (~> 1.1) + zeitwerk (~> 2.6) + dry-types (1.8.2) + 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) + dry-types (>= 1.1) + mustermann-grape (~> 1.1.0) + rack (>= 2) + zeitwerk + i18n (1.14.7) + concurrent-ruby (~> 1.0) + json (2.11.3) + kgio (2.11.4) + logger (1.6.6) + minitest (5.25.4) + mustermann (3.0.3) + 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.0) + rack (3.2.3) + raindrops (0.20.1) + ruby2_keywords (0.0.5) + securerandom (0.4.1) + timeout (0.4.3) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) + unicorn (6.1.0) + kgio (~> 2.6) + raindrops (~> 0.7) + uri (1.0.3) + zeitwerk (2.7.2) + +PLATFORMS + ruby + x86_64-darwin-23 + x86_64-linux + +DEPENDENCIES + activerecord (~> 8.0.0) + grape (= 2.1.1) + json (~> 2.9) + mysql2 (= 0.5.6) + puma (~> 7.1) + unicorn (= 6.1.0) + +BUNDLED WITH + 2.7.0 diff --git a/frameworks/Ruby/grape/README.md b/frameworks/Ruby/grape/README.md index a6cc29080a3..87f4e3f1c2a 100644 --- a/frameworks/Ruby/grape/README.md +++ b/frameworks/Ruby/grape/README.md @@ -11,11 +11,10 @@ comparing a variety of web servers. ## Infrastructure Software Versions The tests were run with: -* [Ruby 3.3-rc1](http://www.ruby-lang.org/) -* [Grape 1.6.2](http://www.ruby-grape.org/) -* [Rack 2.2.3.1](https://rack.github.io/) +* [Ruby 3.4](http://www.ruby-lang.org/) +* [Grape 2.0.0](http://www.ruby-grape.org/) * [Unicorn 6.1.0](https://yhbt.net/unicorn/) -* [Puma 5.6.4](https://puma.io/) +* [Puma 6.4](https://puma.io/) ## Paths & Source for Tests diff --git a/frameworks/Ruby/grape/benchmark_config.json b/frameworks/Ruby/grape/benchmark_config.json index f0afa34bc72..70e233c3cf6 100644 --- a/frameworks/Ruby/grape/benchmark_config.json +++ b/frameworks/Ruby/grape/benchmark_config.json @@ -18,7 +18,7 @@ "webserver": "Puma", "os": "Linux", "database_os": "Linux", - "display_name": "grape-puma-mri", + "display_name": "grape [puma]", "notes": "", "versus": "rack-puma-mri" }, @@ -39,7 +39,7 @@ "webserver": "Unicorn", "os": "Linux", "database_os": "Linux", - "display_name": "grape-unicorn-mri", + "display_name": "grape [unicorn]", "notes": "", "versus": "rack-unicorn-mri" } diff --git a/frameworks/Ruby/grape/config.ru b/frameworks/Ruby/grape/config.ru index 7ea5bc40e14..65396539b64 100644 --- a/frameworks/Ruby/grape/config.ru +++ b/frameworks/Ruby/grape/config.ru @@ -1,8 +1,11 @@ require 'erb' require 'active_record' require 'yaml' +require_relative 'config/auto_tune' MAX_PK = 10_000 +ID_RANGE = (1..MAX_PK).freeze +ALL_IDS = ID_RANGE.to_a QUERIES_MIN = 1 QUERIES_MAX = 500 @@ -32,12 +35,11 @@ module Acme end class DatabaseQueries < Grape::API + logger nil helpers do def bounded_queries queries = params[:queries].to_i - return QUERIES_MIN if queries < QUERIES_MIN - return QUERIES_MAX if queries > QUERIES_MAX - queries + queries.clamp(QUERIES_MIN, QUERIES_MAX) end # Return a random number between 1 and MAX_PK @@ -47,27 +49,27 @@ module Acme end get '/db' do - ActiveRecord::Base.connection_pool.with_connection do + ActiveRecord::Base.with_connection do World.find(rand1).attributes end end get '/query' do - ActiveRecord::Base.connection_pool.with_connection do - Array.new(bounded_queries) do - World.find(rand1) + 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.connection_pool.with_connection do - Array.new(bounded_queries) do - world = World.find(rand1) + 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(randomNumber: new_value) + world.update_columns(randomNumber: new_value) world end end @@ -76,9 +78,10 @@ module Acme class API < Grape::API before do - header 'Date', Time.now.httpdate + header 'Date', Time.now.httpdate if defined?(Puma) header 'Server', 'WebServer' end + logger nil content_type :json, 'application/json' format :json diff --git a/frameworks/Ruby/grape/config/database.yml b/frameworks/Ruby/grape/config/database.yml index f69080e07bd..9be8d7d851a 100644 --- a/frameworks/Ruby/grape/config/database.yml +++ b/frameworks/Ruby/grape/config/database.yml @@ -5,5 +5,5 @@ production: database: hello_world username: benchmarkdbuser password: benchmarkdbpass - pool: 512 + pool: 3 timeout: 5000 diff --git a/frameworks/Ruby/grape/config/puma.rb b/frameworks/Ruby/grape/config/puma.rb index efde35cd784..a489e1af89d 100644 --- a/frameworks/Ruby/grape/config/puma.rb +++ b/frameworks/Ruby/grape/config/puma.rb @@ -1,10 +1,10 @@ require_relative 'auto_tune' # FWBM only... use the puma_auto_tune gem in production! -num_workers, num_threads = auto_tune +_, num_threads = auto_tune + +threads num_threads -workers num_workers -threads num_threads, num_threads # Use the `preload_app!` method when specifying a `workers` number. # This directive tells Puma to first boot the application and load code # before forking the application. This takes advantage of Copy On Write diff --git a/frameworks/Ruby/grape/config/unicorn.rb b/frameworks/Ruby/grape/config/unicorn.rb index 972e803e685..697d61d8016 100644 --- a/frameworks/Ruby/grape/config/unicorn.rb +++ b/frameworks/Ruby/grape/config/unicorn.rb @@ -1,6 +1,8 @@ require_relative 'auto_tune' -worker_processes, = auto_tune +num_workers, = auto_tune +worker_processes num_workers + listen "/tmp/unicorn.sock", :backlog => 4096 preload_app true diff --git a/frameworks/Ruby/grape/grape-unicorn.dockerfile b/frameworks/Ruby/grape/grape-unicorn.dockerfile index b7d800649ba..a20de1c8e3f 100644 --- a/frameworks/Ruby/grape/grape-unicorn.dockerfile +++ b/frameworks/Ruby/grape/grape-unicorn.dockerfile @@ -1,14 +1,19 @@ -FROM ruby:3.3-rc +FROM ruby:3.5-rc 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 apt-get update -yqq && apt-get install -yqq nginx ADD ./ /grape WORKDIR /grape -RUN bundle install --jobs=4 --gemfile=/grape/Gemfile --path=/grape/grape/bundle +RUN bundle install --jobs=4 --gemfile=/grape/Gemfile EXPOSE 8080 diff --git a/frameworks/Ruby/grape/grape.dockerfile b/frameworks/Ruby/grape/grape.dockerfile index 76b45401ac9..3108a40dc55 100644 --- a/frameworks/Ruby/grape/grape.dockerfile +++ b/frameworks/Ruby/grape/grape.dockerfile @@ -1,13 +1,19 @@ -FROM ruby:3.3-rc +FROM ruby:3.5-rc 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 ./ /grape WORKDIR /grape -RUN bundle install --jobs=4 --gemfile=/grape/Gemfile --path=/grape/grape/bundle +RUN bundle install --jobs=4 --gemfile=/grape/Gemfile +ENV WEB_CONCURRENCY=auto EXPOSE 8080 CMD bundle exec puma -C config/puma.rb -b tcp://0.0.0.0:8080 -e production diff --git a/frameworks/Ruby/h2o_mruby/h2o_mruby.dockerfile b/frameworks/Ruby/h2o_mruby/h2o_mruby.dockerfile index 9b7c57be690..aaf6a6eaa96 100644 --- a/frameworks/Ruby/h2o_mruby/h2o_mruby.dockerfile +++ b/frameworks/Ruby/h2o_mruby/h2o_mruby.dockerfile @@ -1,26 +1,28 @@ -ARG UBUNTU_VERSION=22.04 +ARG UBUNTU_VERSION=25.10 ARG H2O_PREFIX=/opt/h2o -FROM "ubuntu:${UBUNTU_VERSION}" AS compile +FROM "buildpack-deps:${UBUNTU_VERSION}" AS compile -ARG H2O_VERSION=13ba727ad12dfb2338165d2bcfb2136457e33c8a +ARG H2O_VERSION=3b9b6a53cac8bcc6a25fb28df81ad295fc5f9402 ARG DEBIAN_FRONTEND=noninteractive ARG H2O_PREFIX WORKDIR /tmp/h2o-build -RUN apt-get -yqq update && \ - apt-get -yqq install \ +RUN apt-get install \ + --no-install-recommends \ + -qqUy \ cmake \ curl \ g++ \ libbrotli-dev \ libcap-dev \ libssl-dev \ - libtool \ + liburing-dev \ libuv1-dev \ libwslay-dev \ libz-dev \ + make \ ninja-build \ pkg-config \ ruby \ @@ -29,10 +31,8 @@ RUN apt-get -yqq update && \ tar --strip-components=1 -xz && \ cmake \ -B build \ - -DCMAKE_AR=/usr/bin/gcc-ar \ - -DCMAKE_C_FLAGS="-flto -march=native -mtune=native" \ + -DCMAKE_C_FLAGS="-flto=auto -march=native -mtune=native" \ -DCMAKE_INSTALL_PREFIX="${H2O_PREFIX}" \ - -DCMAKE_RANLIB=/usr/bin/gcc-ranlib \ -DWITH_MRUBY=on \ -G Ninja \ -S . && \ @@ -41,6 +41,8 @@ RUN apt-get -yqq update && \ FROM "ubuntu:${UBUNTU_VERSION}" +ARG DEBIAN_FRONTEND=noninteractive +RUN apt-get install --no-install-recommends -qqUy liburing2 ARG H2O_PREFIX COPY --from=compile "${H2O_PREFIX}/bin/h2o" "${H2O_PREFIX}/bin/" COPY --from=compile "${H2O_PREFIX}/share" "${H2O_PREFIX}/share/" diff --git a/frameworks/Ruby/hanami/.env b/frameworks/Ruby/hanami/.env new file mode 100644 index 00000000000..c28bf215c1f --- /dev/null +++ b/frameworks/Ruby/hanami/.env @@ -0,0 +1,3 @@ +HANAMI_ENV=production +HANAMI_PORT=8080 +DATABASE_URL=postgres://benchmarkdbuser:benchmarkdbpass@tfb-database:5432/hello_world diff --git a/frameworks/Ruby/hanami/Gemfile b/frameworks/Ruby/hanami/Gemfile index d1d45e22f87..956ff09ad32 100644 --- a/frameworks/Ruby/hanami/Gemfile +++ b/frameworks/Ruby/hanami/Gemfile @@ -2,10 +2,12 @@ source "https://rubygems.org" -gem "hanami", "~> 2.0" -gem "hanami-router", "~> 2.0" -gem "hanami-controller", "~> 2.0" -gem "hanami-validations", "~> 2.0" +gem "hanami", "~> 2.2" +gem "hanami-router", "~> 2.2" +gem "hanami-controller", "~> 2.2" +gem "hanami-db", "~> 2.2" +gem "hanami-validations", "~> 2.2" +gem "hanami-view", "~> 2.2" gem "dry-types", "~> 1.0", ">= 1.6.1" gem "puma" @@ -14,3 +16,4 @@ gem "rake" gem "rom", "~> 5.3" gem "rom-sql", "~> 3.6" gem "pg" +gem "ostruct" # required for Ruby 3.5 diff --git a/frameworks/Ruby/hanami/Gemfile.lock b/frameworks/Ruby/hanami/Gemfile.lock new file mode 100644 index 00000000000..853de823128 --- /dev/null +++ b/frameworks/Ruby/hanami/Gemfile.lock @@ -0,0 +1,183 @@ +GEM + remote: https://rubygems.org/ + specs: + bigdecimal (3.1.9) + concurrent-ruby (1.3.5) + dry-auto_inject (1.1.0) + dry-core (~> 1.1) + zeitwerk (~> 2.6) + dry-cli (1.2.0) + dry-configurable (1.3.0) + dry-core (~> 1.1) + zeitwerk (~> 2.6) + dry-core (1.1.0) + concurrent-ruby (~> 1.0) + logger + zeitwerk (~> 2.6) + dry-events (1.1.0) + concurrent-ruby (~> 1.0) + dry-core (~> 1.1) + dry-files (1.1.0) + dry-inflector (1.2.0) + dry-initializer (3.2.0) + dry-logger (1.0.4) + dry-logic (1.6.0) + bigdecimal + concurrent-ruby (~> 1.0) + dry-core (~> 1.1) + zeitwerk (~> 2.6) + dry-monitor (1.0.1) + dry-configurable (~> 1.0, < 2) + dry-core (~> 1.0, < 2) + dry-events (~> 1.0, < 2) + dry-schema (1.14.1) + concurrent-ruby (~> 1.0) + dry-configurable (~> 1.0, >= 1.0.1) + dry-core (~> 1.1) + dry-initializer (~> 3.2) + dry-logic (~> 1.5) + dry-types (~> 1.8) + zeitwerk (~> 2.6) + dry-struct (1.8.0) + dry-core (~> 1.1) + dry-types (~> 1.8, >= 1.8.2) + ice_nine (~> 0.11) + zeitwerk (~> 2.6) + dry-system (1.2.2) + dry-auto_inject (~> 1.1) + dry-configurable (~> 1.3) + dry-core (~> 1.1) + dry-inflector (~> 1.1) + dry-transformer (1.0.1) + zeitwerk (~> 2.6) + dry-types (1.8.2) + bigdecimal (~> 3.0) + concurrent-ruby (~> 1.0) + dry-core (~> 1.0) + dry-inflector (~> 1.0) + dry-logic (~> 1.4) + zeitwerk (~> 2.6) + dry-validation (1.11.1) + concurrent-ruby (~> 1.0) + dry-core (~> 1.1) + dry-initializer (~> 3.2) + dry-schema (~> 1.14) + zeitwerk (~> 2.6) + hanami (2.2.1) + bundler (>= 1.16, < 3) + dry-configurable (~> 1.0, >= 1.2.0, < 2) + dry-core (~> 1.0, < 2) + dry-inflector (~> 1.0, >= 1.1.0, < 2) + dry-logger (~> 1.0, < 2) + dry-monitor (~> 1.0, >= 1.0.1, < 2) + dry-system (~> 1.1) + hanami-cli (~> 2.2.1) + hanami-utils (~> 2.2) + json (>= 2.7.2) + zeitwerk (~> 2.6) + hanami-cli (2.2.1) + bundler (~> 2.1) + dry-cli (~> 1.0, >= 1.1.0) + dry-files (~> 1.0, >= 1.0.2, < 2) + dry-inflector (~> 1.0, < 2) + rake (~> 13.0) + zeitwerk (~> 2.6) + hanami-controller (2.2.0) + dry-configurable (~> 1.0, < 2) + dry-core (~> 1.0) + hanami-utils (~> 2.2) + rack (~> 2.0) + zeitwerk (~> 2.6) + hanami-db (2.2.1) + rom (~> 5.4, >= 5.4.1) + rom-sql (~> 3.7) + zeitwerk (~> 2.6) + hanami-router (2.2.0) + mustermann (~> 3.0) + mustermann-contrib (~> 3.0) + rack (~> 2.0) + hanami-utils (2.2.0) + concurrent-ruby (~> 1.0) + dry-core (~> 1.0, < 2) + dry-transformer (~> 1.0, < 2) + hanami-validations (2.2.0) + dry-validation (>= 1.10, < 2) + hanami-view (2.2.1) + dry-configurable (~> 1.0) + dry-core (~> 1.0) + dry-inflector (~> 1.0, < 2) + temple (~> 0.10.0, >= 0.10.2) + tilt (~> 2.3) + zeitwerk (~> 2.6) + hansi (0.2.1) + ice_nine (0.11.2) + json (2.11.3) + logger (1.6.6) + 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) + puma (6.6.0) + nio4r (~> 2.0) + rack (2.2.19) + rake (13.2.1) + rom (5.4.2) + rom-changeset (~> 5.4) + rom-core (~> 5.4) + rom-repository (~> 5.4, >= 5.4.2) + rom-changeset (5.4.0) + dry-core (~> 1.0) + rom-core (~> 5.4) + transproc (~> 1.1) + rom-core (5.4.0) + concurrent-ruby (~> 1.1) + dry-configurable (~> 1.0) + dry-core (~> 1.0) + dry-inflector (~> 1.0) + dry-initializer (~> 3.2) + dry-struct (~> 1.0) + dry-types (~> 1.6) + transproc (~> 1.1) + rom-repository (5.4.2) + dry-core (~> 1.0) + dry-initializer (~> 3.2) + rom-core (~> 5.4) + rom-sql (3.7.0) + dry-core (~> 1.1) + dry-types (~> 1.8) + rom (~> 5.4) + sequel (>= 4.49) + ruby2_keywords (0.0.5) + sequel (5.90.0) + bigdecimal + temple (0.10.3) + tilt (2.6.0) + transproc (1.1.1) + zeitwerk (2.7.2) + +PLATFORMS + ruby + x86_64-darwin-23 + x86_64-linux + +DEPENDENCIES + dry-types (~> 1.0, >= 1.6.1) + hanami (~> 2.2) + hanami-controller (~> 2.2) + hanami-db (~> 2.2) + hanami-router (~> 2.2) + hanami-validations (~> 2.2) + hanami-view (~> 2.2) + ostruct + pg + puma + rake + rom (~> 5.3) + rom-sql (~> 3.6) + +BUNDLED WITH + 2.7.0 diff --git a/frameworks/Ruby/hanami/Procfile.dev b/frameworks/Ruby/hanami/Procfile.dev new file mode 100644 index 00000000000..04e92a10dc1 --- /dev/null +++ b/frameworks/Ruby/hanami/Procfile.dev @@ -0,0 +1,2 @@ +web: bundle exec hanami server +# assets: bundle exec hanami assets watch diff --git a/frameworks/Ruby/hanami/app/action.rb b/frameworks/Ruby/hanami/app/action.rb index 0771adb9298..8ef93e34f4a 100644 --- a/frameworks/Ruby/hanami/app/action.rb +++ b/frameworks/Ruby/hanami/app/action.rb @@ -5,5 +5,13 @@ module HelloWorld class Action < Hanami::Action + before :set_headers + + private + + def set_headers(*, response) + response.headers['Server'] = 'hanami' + response.headers['Date'] = Time.now.httpdate + end end end diff --git a/frameworks/Ruby/hanami/app/actions/db/index.rb b/frameworks/Ruby/hanami/app/actions/db/index.rb index 3751a8d0621..e5efcc2f414 100644 --- a/frameworks/Ruby/hanami/app/actions/db/index.rb +++ b/frameworks/Ruby/hanami/app/actions/db/index.rb @@ -2,17 +2,16 @@ module HelloWorld module Actions - module Db + module DB class Index < HelloWorld::Action QUERY_RANGE = 1..10_000 # range of IDs in the Fortune DB - include Deps["persistence.rom"] + + include Deps["repos.world_repo"] def handle(*, response) - world = rom.relations[:World].where(id: random_id).one - response.headers['Server'] = 'hanami' - response.headers['Date'] = Time.now.httpdate + world = world_repo.find(random_id) response.format = :json - response.body = world.to_json + response.body = world.to_h.to_json end def random_id diff --git a/frameworks/Ruby/hanami/app/actions/fortunes/index.rb b/frameworks/Ruby/hanami/app/actions/fortunes/index.rb new file mode 100644 index 00000000000..4d6bbbba502 --- /dev/null +++ b/frameworks/Ruby/hanami/app/actions/fortunes/index.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +module HelloWorld + module Actions + module Fortunes + class Index < HelloWorld::Action + def handle(*, response) + end + end + end + end +end diff --git a/frameworks/Ruby/hanami/app/actions/json/index.rb b/frameworks/Ruby/hanami/app/actions/json/index.rb deleted file mode 100644 index a49b641cb7c..00000000000 --- a/frameworks/Ruby/hanami/app/actions/json/index.rb +++ /dev/null @@ -1,16 +0,0 @@ -# frozen_string_literal: true - -module HelloWorld - module Actions - module JSON - class Index < HelloWorld::Action - def handle(*, response) - response.headers['Server'] = 'hanami' - response.headers['Date'] = Time.now.httpdate - response.format = :json - response.body = { 'message' => 'Hello, World!' }.to_json - end - end - end - end -end diff --git a/frameworks/Ruby/hanami/app/actions/plaintext/index.rb b/frameworks/Ruby/hanami/app/actions/plaintext/index.rb deleted file mode 100644 index 62523769a66..00000000000 --- a/frameworks/Ruby/hanami/app/actions/plaintext/index.rb +++ /dev/null @@ -1,15 +0,0 @@ -# frozen_string_literal: true - -module HelloWorld - module Actions - module Plaintext - class Index < HelloWorld::Action - def handle(*, response) - response.headers['Server'] = 'hanami' - response.headers['Date'] = Time.now.httpdate - response.body = 'Hello, World!' - end - end - end - end -end diff --git a/frameworks/Ruby/hanami/app/actions/queries/index.rb b/frameworks/Ruby/hanami/app/actions/queries/index.rb new file mode 100644 index 00000000000..d20dfc2df3a --- /dev/null +++ b/frameworks/Ruby/hanami/app/actions/queries/index.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +module HelloWorld + module Actions + module Queries + class Index < HelloWorld::Action + QUERY_RANGE = 1..10_000 # 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 + + include Deps["repos.world_repo"] + + def handle(request, response) + worlds = ALL_IDS.sample(queries(request)).map do |id| + world_repo.find(id) + end + response.format = :json + response.body = worlds.map(&:to_h).to_json + end + + private + + def queries(request) + request.params[:queries].to_i.clamp(MIN_QUERIES, MAX_QUERIES) + end + end + end + end +end diff --git a/frameworks/Ruby/hanami/app/actions/updates/index.rb b/frameworks/Ruby/hanami/app/actions/updates/index.rb new file mode 100644 index 00000000000..3e68be733be --- /dev/null +++ b/frameworks/Ruby/hanami/app/actions/updates/index.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +module HelloWorld + module Actions + module Updates + class Index < HelloWorld::Action + QUERY_RANGE = 1..10_000 # 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 + + include Deps["repos.world_repo"] + + def handle(request, response) + worlds = ALL_IDS.sample(queries(request)).map do |id| + world_repo.update_random_number(id) + end + response.format = :json + response.body = worlds.to_json + end + + private + + def queries(request) + request.params[:queries].to_i.clamp(MIN_QUERIES, MAX_QUERIES) + end + + def random_id + Random.rand(QUERY_RANGE) + end + end + end + end +end diff --git a/frameworks/Ruby/hanami/app/db/relation.rb b/frameworks/Ruby/hanami/app/db/relation.rb new file mode 100644 index 00000000000..9ff3c56789f --- /dev/null +++ b/frameworks/Ruby/hanami/app/db/relation.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +require "hanami/db/relation" + +module HelloWorld + module DB + class Relation < Hanami::DB::Relation + end + end +end diff --git a/frameworks/Ruby/hanami/app/db/repo.rb b/frameworks/Ruby/hanami/app/db/repo.rb new file mode 100644 index 00000000000..586c7af94d0 --- /dev/null +++ b/frameworks/Ruby/hanami/app/db/repo.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +require "hanami/db/repo" + +module HelloWorld + module DB + class Repo < Hanami::DB::Repo + end + end +end diff --git a/frameworks/Ruby/hanami/app/db/struct.rb b/frameworks/Ruby/hanami/app/db/struct.rb new file mode 100644 index 00000000000..5484ea7c357 --- /dev/null +++ b/frameworks/Ruby/hanami/app/db/struct.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +require "hanami/db/struct" + +module HelloWorld + module DB + class Struct < Hanami::DB::Struct + end + end +end diff --git a/frameworks/PHP/lumen/database/migrations/.gitkeep b/frameworks/Ruby/hanami/app/relations/.keep similarity index 100% rename from frameworks/PHP/lumen/database/migrations/.gitkeep rename to frameworks/Ruby/hanami/app/relations/.keep diff --git a/frameworks/Ruby/hanami/app/relations/fortunes.rb b/frameworks/Ruby/hanami/app/relations/fortunes.rb new file mode 100644 index 00000000000..d35a05575f1 --- /dev/null +++ b/frameworks/Ruby/hanami/app/relations/fortunes.rb @@ -0,0 +1,7 @@ +module HelloWorld + module Relations + class Fortunes < HelloWorld::DB::Relation + schema :Fortune, infer: true, as: :fortunes + end + end +end diff --git a/frameworks/Ruby/hanami/app/relations/worlds.rb b/frameworks/Ruby/hanami/app/relations/worlds.rb new file mode 100644 index 00000000000..54d982fa9bf --- /dev/null +++ b/frameworks/Ruby/hanami/app/relations/worlds.rb @@ -0,0 +1,7 @@ +module HelloWorld + module Relations + class Worlds < HelloWorld::DB::Relation + schema :World, infer: true, as: :worlds + end + end +end diff --git a/frameworks/PHP/lumen/resources/views/.gitkeep b/frameworks/Ruby/hanami/app/repos/.keep similarity index 100% rename from frameworks/PHP/lumen/resources/views/.gitkeep rename to frameworks/Ruby/hanami/app/repos/.keep diff --git a/frameworks/Ruby/hanami/app/repos/fortune_repo.rb b/frameworks/Ruby/hanami/app/repos/fortune_repo.rb new file mode 100644 index 00000000000..c356c615e91 --- /dev/null +++ b/frameworks/Ruby/hanami/app/repos/fortune_repo.rb @@ -0,0 +1,11 @@ +module HelloWorld + module Repos + class FortuneRepo < HelloWorld::DB::Repo + def all + results = fortunes.to_a.map(&:to_h) + results << { id: 0, message: 'Additional fortune added at request time.' } + results.sort_by! { |fortune| fortune[:message] } + end + end + end +end diff --git a/frameworks/Ruby/hanami/app/repos/world_repo.rb b/frameworks/Ruby/hanami/app/repos/world_repo.rb new file mode 100644 index 00000000000..42a5c6f8a7c --- /dev/null +++ b/frameworks/Ruby/hanami/app/repos/world_repo.rb @@ -0,0 +1,26 @@ +module HelloWorld + module Repos + class WorldRepo < HelloWorld::DB::Repo + QUERY_RANGE = 1..10_000 # range of IDs in the Fortune DB + + def find(id) + worlds.by_pk(id).one + end + + def update_random_number(id) + world = find(id) + world_hash = world.to_h + new_value = random_id + new_value = random_id while new_value == world_hash[:randomnumber] + worlds.where(id: id).update({ randomnumber: new_value }) + world_hash + end + + private + + def random_id + Random.rand(QUERY_RANGE) + end + end + end +end diff --git a/frameworks/Python/async-worker/src/__init__.py b/frameworks/Ruby/hanami/app/structs/.keep similarity index 100% rename from frameworks/Python/async-worker/src/__init__.py rename to frameworks/Ruby/hanami/app/structs/.keep diff --git a/frameworks/Ruby/hanami/app/templates/fortunes/index.html.erb b/frameworks/Ruby/hanami/app/templates/fortunes/index.html.erb new file mode 100644 index 00000000000..eacad31aca9 --- /dev/null +++ b/frameworks/Ruby/hanami/app/templates/fortunes/index.html.erb @@ -0,0 +1,12 @@ + + + + + + <% fortunes.each do |fortune| %> + + + + + <% end %> +
idmessage
<%= fortune[:id] %><%= fortune[:message] %>
diff --git a/frameworks/Ruby/hanami/app/templates/layouts/app.html.erb b/frameworks/Ruby/hanami/app/templates/layouts/app.html.erb new file mode 100644 index 00000000000..2c125c136fd --- /dev/null +++ b/frameworks/Ruby/hanami/app/templates/layouts/app.html.erb @@ -0,0 +1,9 @@ + + + + Fortunes + + + <%= yield %> + + diff --git a/frameworks/Ruby/hanami/app/view.rb b/frameworks/Ruby/hanami/app/view.rb new file mode 100644 index 00000000000..d0a4d76065d --- /dev/null +++ b/frameworks/Ruby/hanami/app/view.rb @@ -0,0 +1,9 @@ +# auto_register: false +# frozen_string_literal: true + +require "hanami/view" + +module HelloWorld + class View < Hanami::View + end +end diff --git a/frameworks/Ruby/hanami/app/views/fortunes/index.rb b/frameworks/Ruby/hanami/app/views/fortunes/index.rb new file mode 100644 index 00000000000..5eb7d500305 --- /dev/null +++ b/frameworks/Ruby/hanami/app/views/fortunes/index.rb @@ -0,0 +1,14 @@ +module HelloWorld + module Views + module Fortunes + class Index < HelloWorld::View + + include Deps["repos.fortune_repo"] + + expose :fortunes do + fortune_repo.all + end + end + end + end +end diff --git a/frameworks/Ruby/hanami/benchmark_config.json b/frameworks/Ruby/hanami/benchmark_config.json index d5ee774c13f..1a081210b16 100644 --- a/frameworks/Ruby/hanami/benchmark_config.json +++ b/frameworks/Ruby/hanami/benchmark_config.json @@ -2,8 +2,11 @@ "framework": "hanami", "tests": [{ "default": { - "db_url": "/db", "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/Ruby/hanami/config/providers/persistence.rb b/frameworks/Ruby/hanami/config/providers/persistence.rb deleted file mode 100644 index 28234177e29..00000000000 --- a/frameworks/Ruby/hanami/config/providers/persistence.rb +++ /dev/null @@ -1,30 +0,0 @@ -Hanami.app.register_provider :persistence, namespace: true do - prepare do - require "rom" - - require_relative '../auto_tune' - num_workers, num_threads = auto_tune - - opts = {} - - if (threads = num_threads) > 1 - opts[:max_connections] = (2 * Math.log(threads)).floor - opts[:pool_timeout] = 10 - end - config = ROM::Configuration.new(:sql, target["settings"].database_url, opts) - - register "config", config - register "db", config.gateways[:default].connection - end - - start do - config = target["persistence.config"] - - config.auto_registration( - target.root.join("lib/hello_world/persistence"), - namespace: "HelloWorld::Persistence" - ) - - register "rom", ROM.container(config) - end -end diff --git a/frameworks/Ruby/hanami/config/puma.rb b/frameworks/Ruby/hanami/config/puma.rb index b360cf8a278..a2be144a827 100644 --- a/frameworks/Ruby/hanami/config/puma.rb +++ b/frameworks/Ruby/hanami/config/puma.rb @@ -1,11 +1,5 @@ # frozen_string_literal: true -require_relative 'auto_tune' - -# FWBM only... use the puma_auto_tune gem in production! -num_workers, num_threads = auto_tune - -workers num_workers -threads num_threads, num_threads +threads 3, 3 port ENV.fetch("HANAMI_PORT", 2300) environment ENV.fetch("HANAMI_ENV", "development") diff --git a/frameworks/Ruby/hanami/config/routes.rb b/frameworks/Ruby/hanami/config/routes.rb index 77ea9582b13..b57e5af753f 100644 --- a/frameworks/Ruby/hanami/config/routes.rb +++ b/frameworks/Ruby/hanami/config/routes.rb @@ -2,8 +2,27 @@ module HelloWorld class Routes < Hanami::Routes + get "/json", to: ->(env) do + [200, + { + 'Server' => 'Rails', + 'Content-Type' => 'application/json', + 'Date' => Time.now.httpdate, + }, + [{ 'message' => 'Hello, World!' }.to_json]] + end get "/db", to: "db.index" - get "/json", to: "json.index" - get "/plaintext", to: "plaintext.index" + get "/queries", to: "queries.index" + get "/fortunes", to: "fortunes.index" + get "/updates", to: "updates.index" + get "/plaintext", to: ->(env) do + [200, + { + 'Server' => 'Hanami', + 'Content-Type' => 'text/plain', + 'Date' => Time.now.httpdate + }, + ['Hello, World!']] + end end end diff --git a/frameworks/Ruby/hanami/hanami.dockerfile b/frameworks/Ruby/hanami/hanami.dockerfile index 2230a6d4675..172d55b4946 100644 --- a/frameworks/Ruby/hanami/hanami.dockerfile +++ b/frameworks/Ruby/hanami/hanami.dockerfile @@ -1,16 +1,19 @@ -FROM ruby:3.3-rc +FROM ruby:3.5-rc -ENV BUNDLE_FORCE_RUBY_PLATFORM=true ENV RUBY_YJIT_ENABLE=1 +ENV WEB_CONCURRENCY=auto -WORKDIR /hanami +# Use Jemalloc +RUN apt-get update && \ + apt-get install -y --no-install-recommends libjemalloc2 +ENV LD_PRELOAD=libjemalloc.so.2 -COPY Gemfile ./ +ADD ./ /hanami +WORKDIR /hanami +ENV BUNDLE_FORCE_RUBY_PLATFORM=true RUN bundle install --jobs=8 -COPY . . - EXPOSE 8080 ENV HANAMI_ENV=production diff --git a/frameworks/Ruby/hanami/lib/hello_world/persistence/relations/world.rb b/frameworks/Ruby/hanami/lib/hello_world/persistence/relations/world.rb deleted file mode 100644 index 2039d0481c9..00000000000 --- a/frameworks/Ruby/hanami/lib/hello_world/persistence/relations/world.rb +++ /dev/null @@ -1,9 +0,0 @@ -module HelloWorld - module Persistence - module Relations - class World < ROM::Relation[:sql] - schema(:World, infer: true) - end - end - end -end diff --git a/frameworks/Ruby/padrino/Gemfile b/frameworks/Ruby/padrino/Gemfile index 18cff716d85..8ccd7f58765 100644 --- a/frameworks/Ruby/padrino/Gemfile +++ b/frameworks/Ruby/padrino/Gemfile @@ -1,10 +1,13 @@ -source 'http://rubygems.org' +source 'https://rubygems.org' + +gem 'mysql2', '> 0.5' +gem 'json' +gem 'activerecord', '>= 7.1', :require => 'active_record' -gem 'mysql2', '~> 0.4' -gem "unicorn", '~> 6.1' -gem 'puma', '~> 6.4' -gem 'json', '~> 2.0' gem 'slim', '2.0.3' -gem 'dm-mysql-adapter', '1.2.0' -gem 'dm-core', '1.2.1' -gem 'padrino', '0.15.3' +gem 'padrino', git: 'https://github.com/padrino/padrino-framework.git' +gem 'rack' + +group :iodine, optional: true do + gem "iodine", "~> 0.7", require: false +end diff --git a/frameworks/Ruby/padrino/Gemfile.lock b/frameworks/Ruby/padrino/Gemfile.lock new file mode 100644 index 00000000000..3636648c76e --- /dev/null +++ b/frameworks/Ruby/padrino/Gemfile.lock @@ -0,0 +1,141 @@ +GIT + remote: https://github.com/padrino/padrino-framework.git + revision: 9a38042351c9f5768231e94abca87bb1592cdcfa + specs: + padrino (0.16.0.pre3) + padrino-admin (= 0.16.0.pre3) + padrino-cache (= 0.16.0.pre3) + padrino-core (= 0.16.0.pre3) + padrino-gen (= 0.16.0.pre3) + padrino-helpers (= 0.16.0.pre3) + padrino-mailer (= 0.16.0.pre3) + padrino-support (= 0.16.0.pre3) + padrino-admin (0.16.0.pre3) + padrino-core (= 0.16.0.pre3) + padrino-helpers (= 0.16.0.pre3) + padrino-cache (0.16.0.pre3) + moneta (~> 1.6) + padrino-core (= 0.16.0.pre3) + padrino-helpers (= 0.16.0.pre3) + padrino-core (0.16.0.pre3) + padrino-support (= 0.16.0.pre3) + rackup (~> 2.1) + sinatra (~> 4) + thor (~> 1.0) + padrino-gen (0.16.0.pre3) + bundler (>= 1.0, < 3) + padrino-core (= 0.16.0.pre3) + padrino-helpers (0.16.0.pre3) + i18n (>= 0.6.7, < 2) + padrino-support (= 0.16.0.pre3) + tilt (>= 1.4.1, < 3) + padrino-mailer (0.16.0.pre3) + mail (~> 2.5) + mime-types (< 4) + padrino-core (= 0.16.0.pre3) + padrino-support (0.16.0.pre3) + +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) + timeout (>= 0.4.0) + activesupport (8.0.2) + base64 + benchmark (>= 0.3) + bigdecimal + concurrent-ruby (~> 1.0, >= 1.3.1) + connection_pool (>= 2.2.5) + drb + i18n (>= 1.6, < 2) + 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) + date (3.4.1) + drb (2.2.1) + i18n (1.14.7) + concurrent-ruby (~> 1.0) + iodine (0.7.58) + json (2.11.3) + logger (1.6.6) + mail (2.8.1) + mini_mime (>= 0.1.1) + net-imap + net-pop + net-smtp + mime-types (3.6.1) + logger + mime-types-data (~> 3.2015) + mime-types-data (3.2025.0318) + mini_mime (1.1.5) + minitest (5.25.5) + moneta (1.6.0) + mustermann (3.0.3) + ruby2_keywords (~> 0.0.1) + mysql2 (0.5.6) + net-imap (0.5.6) + date + net-protocol + net-pop (0.1.2) + net-protocol + net-protocol (0.2.2) + timeout + net-smtp (0.5.1) + net-protocol + rack (3.1.18) + rack-protection (4.1.1) + base64 (>= 0.1.0) + logger (>= 1.6.0) + rack (>= 3.0.0, < 4) + rack-session (2.1.0) + base64 (>= 0.1.0) + rack (>= 3.0.0) + rackup (2.2.1) + rack (>= 3) + ruby2_keywords (0.0.5) + securerandom (0.4.1) + sinatra (4.1.1) + logger (>= 1.6.0) + mustermann (~> 3.0) + rack (>= 3.0.0, < 4) + rack-protection (= 4.1.1) + rack-session (>= 2.0.0, < 3) + tilt (~> 2.0) + slim (2.0.3) + temple (~> 0.6.6) + tilt (>= 1.3.3, < 2.1) + temple (0.6.10) + thor (1.3.2) + tilt (2.0.11) + timeout (0.4.3) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) + uri (1.0.3) + +PLATFORMS + ruby + x86_64-darwin-23 + x86_64-linux + +DEPENDENCIES + activerecord (>= 7.1) + iodine (~> 0.7) + json + mysql2 (> 0.5) + padrino! + rack + slim (= 2.0.3) + +BUNDLED WITH + 2.7.0 diff --git a/frameworks/Ruby/padrino/README.md b/frameworks/Ruby/padrino/README.md index c0c1e7601fe..9d11b9ef5a4 100644 --- a/frameworks/Ruby/padrino/README.md +++ b/frameworks/Ruby/padrino/README.md @@ -11,14 +11,9 @@ comparing a variety of web servers. ## Infrastructure Software Versions The tests were run with: -* [Ruby 2.0.0-p0](http://www.ruby-lang.org/) -* [JRuby 1.7.8](http://jruby.org/) -* [Rubinius 2.2.10](http://rubini.us/) +* [Ruby 3.5](http://www.ruby-lang.org/) * [Padrino 0.12.3](http://www.padrinorb.com/) -* [Rack 1.5.2](http://rack.github.com/) -* [Unicorn 4.8.3](http://unicorn.bogomips.org/) -* [Puma 3.9](http://puma.io/) -* [Thin 1.6.2](http://code.macournoyer.com/thin/) +* [Iodine](https://github.com/boazsegev/iodine) ## Paths & Source for Tests diff --git a/frameworks/Ruby/padrino/app/app.rb b/frameworks/Ruby/padrino/app/app.rb index 1b991b42dca..fca3a95a649 100644 --- a/frameworks/Ruby/padrino/app/app.rb +++ b/frameworks/Ruby/padrino/app/app.rb @@ -14,11 +14,16 @@ class App < Padrino::Application # # You can customize caching store engines: # - # set :cache, Padrino::Cache::Store::Memcache.new(::Memcached.new('127.0.0.1:11211', :exception_retry_limit => 1)) - # set :cache, Padrino::Cache::Store::Memcache.new(::Dalli::Client.new('127.0.0.1:11211', :exception_retry_limit => 1)) - # set :cache, Padrino::Cache::Store::Redis.new(::Redis.new(:host => '127.0.0.1', :port => 6379, :db => 0)) - # set :cache, Padrino::Cache::Store::Memory.new(50) - # set :cache, Padrino::Cache::Store::File.new(Padrino.root('tmp', app_name.to_s, 'cache')) # default choice + # set :cache, Padrino::Cache.new(:LRUHash) # Keeps cached values in memory + # set :cache, Padrino::Cache.new(:Memcached) # Uses default server at localhost + # set :cache, Padrino::Cache.new(:Memcached, :server => '127.0.0.1:11211', :exception_retry_limit => 1) + # set :cache, Padrino::Cache.new(:Memcached, :backend => memcached_or_dalli_instance) + # set :cache, Padrino::Cache.new(:Redis) # Uses default server at localhost + # set :cache, Padrino::Cache.new(:Redis, :host => '127.0.0.1', :port => 6379, :db => 0) + # set :cache, Padrino::Cache.new(:Redis, :backend => redis_instance) + # set :cache, Padrino::Cache.new(:Mongo) # Uses default server at localhost + # set :cache, Padrino::Cache.new(:Mongo, :backend => mongo_client_instance) + # set :cache, Padrino::Cache.new(:File, :dir => Padrino.root('tmp', app_name.to_s, 'cache')) # default choice # ## @@ -27,13 +32,13 @@ class App < Padrino::Application # set :raise_errors, true # Raise exceptions (will stop application) (default for test) # set :dump_errors, true # Exception backtraces are written to STDERR (default for production/development) # set :show_exceptions, true # Shows a stack trace in browser (default for development) - # set :logging, true # Logging in STDOUT for development and file for production (default only for development) + set :logging, false # Logging in STDOUT for development and file for production (default only for development) # set :public_folder, 'foo/bar' # Location for static assets (default root/public) # set :reload, false # Reload application files (default in development) # set :default_builder, 'foo' # Set a custom form builder (default 'StandardFormBuilder') # set :locale_path, 'bar' # Set path for I18n translations (default your_apps_root_path/locale) - # disable :sessions # Disabled sessions by default (enable if needed) - # disable :flash # Disables sinatra-flash (enabled by default if Sinatra::Flash is defined) + disable :sessions # Disabled sessions by default (enable if needed) + disable :flash # Disables sinatra-flash (enabled by default if Sinatra::Flash is defined) # layout :my_layout # Layout can be in views/layouts/foo.ext or views/foo.ext (default :application) # @@ -53,8 +58,8 @@ class App < Padrino::Application # render 'errors/404' # end # - # error 505 do - # render 'errors/505' + # error 500 do + # render 'errors/500' # end # end diff --git a/frameworks/Ruby/padrino/app/controllers.rb b/frameworks/Ruby/padrino/app/controllers.rb index 119d2f45f20..e5a200c7f2c 100644 --- a/frameworks/Ruby/padrino/app/controllers.rb +++ b/frameworks/Ruby/padrino/app/controllers.rb @@ -1,63 +1,61 @@ +QUERY_RANGE = (1..10_000).freeze +ALL_IDS = QUERY_RANGE.to_a + HelloWorld::App.controllers do + + after do + response['Server'] = 'padrino' + end + get '/json', :provides => [:json] do - response.headers['Server'] = 'padrino' - response.headers['Date'] = Time.now.httpdate {message: "Hello, World!"}.to_json end get '/db', :provides => [:json] do - response.headers['Server'] = 'padrino' - response.headers['Date'] = Time.now.httpdate - id = Random.rand(10000) + 1 - World.get(id).attributes.to_json + world = ActiveRecord::Base.with_connection do + World.find(rand1).attributes + end + world.to_json end get '/queries', :provides => [:json] do - response.headers['Server'] = 'padrino' - response.headers['Date'] = Time.now.httpdate - queries = params['queries'].to_i - queries = 1 if queries < 1 - queries = 500 if queries > 500 - - results = (1..queries).map do - World.get(Random.rand(10000) + 1).attributes - end.to_json + worlds = ActiveRecord::Base.with_connection do + ALL_IDS.sample(bounded_queries).map do |id| + World.find(id).attributes + end + end + worlds.to_json end get '/fortunes' do - response.headers['Server'] = 'padrino' - response.headers['Date'] = Time.now.httpdate - @fortunes = Fortune.all - @fortunes << Fortune.new(:id => 0, :message => "Additional fortune added at request time.") - @fortunes = @fortunes.sort_by { |x| x.message } + @fortunes = Fortune.all.to_a + @fortunes << Fortune.new( + id: 0, + message: "Additional fortune added at request time." + ) + @fortunes = @fortunes.sort_by(&:message) render 'fortunes', layout: "layout" end get '/updates', :provides => [:json] do - response.headers['Server'] = 'padrino' - response.headers['Date'] = Time.now.httpdate - queries = params['queries'].to_i - queries = 1 if queries < 1 - queries = 500 if queries > 500 - - worlds = (1..queries).map do - # get a random row from the database, which we know has 10000 - # rows with ids 1 - 10000 - world = World.get(Random.rand(10000) + 1) - world.update(:randomNumber => Random.rand(10000) + 1) - world.attributes + worlds = [] + ActiveRecord::Base.with_connection do + worlds = ALL_IDS.sample(bounded_queries).map do |id| + world = World.find(id) + new_value = rand1 + new_value = rand1 while new_value == world.randomNumber + world.randomNumber = new_value + world + end + World.upsert_all(worlds) end worlds.to_json end get '/plaintext' do - response.headers['Server'] = 'padrino' - response.headers['Date'] = Time.now.httpdate content_type 'text/plain' "Hello, World!" end - end - diff --git a/frameworks/Ruby/padrino/app/helpers.rb b/frameworks/Ruby/padrino/app/helpers.rb index 16774801dff..523fb246f77 100644 --- a/frameworks/Ruby/padrino/app/helpers.rb +++ b/frameworks/Ruby/padrino/app/helpers.rb @@ -1,7 +1,16 @@ # Helper methods defined here can be accessed in any controller or view in the application +MAX_PK = 10_000 +QUERIES_MIN = 1 +QUERIES_MAX = 500 + HelloWorld::App.helpers do - # def simple_helper_method - # ... - # end + def rand1 + rand(MAX_PK) + 1 + end + + def bounded_queries + queries = params[:queries].to_i + queries.clamp(QUERIES_MIN, QUERIES_MAX) + end end diff --git a/frameworks/Ruby/padrino/benchmark_config.json b/frameworks/Ruby/padrino/benchmark_config.json index db352531224..0eaf86be1d9 100644 --- a/frameworks/Ruby/padrino/benchmark_config.json +++ b/frameworks/Ruby/padrino/benchmark_config.json @@ -3,10 +3,10 @@ "tests": [{ "default": { "json_url": "/json", - "db_url": "/db", - "query_url": "/queries?queries=", + "db_url": "/db", + "query_url": "/queries?queries=", "fortune_url": "/fortunes", - "update_url": "/updates?queries=", + "update_url": "/updates?queries=", "plaintext_url": "/plaintext", "port": 8080, "approach": "Realistic", @@ -16,34 +16,12 @@ "language": "Ruby", "orm": "Full", "platform": "Rack", - "webserver": "Puma", + "webserver": "Iodine", "os": "Linux", "database_os": "Linux", - "display_name": "padrino-puma-mri", + "display_name": "padrino", "notes": "", - "versus": "rack-puma-mri" - }, - "unicorn": { - "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": "padrino", - "language": "Ruby", - "orm": "Full", - "platform": "Rack", - "webserver": "Unicorn", - "os": "Linux", - "database_os": "Linux", - "display_name": "padrino-unicorn", - "notes": "", - "versus": "rack-unicorn" + "versus": "rack-iodine" } }] } diff --git a/frameworks/Ruby/padrino/config.toml b/frameworks/Ruby/padrino/config.toml index 795c2789614..e5103e75fa5 100644 --- a/frameworks/Ruby/padrino/config.toml +++ b/frameworks/Ruby/padrino/config.toml @@ -15,22 +15,5 @@ database_os = "Linux" os = "Linux" orm = "Full" platform = "Rack" -webserver = "Puma" -versus = "rack-puma-mri" - -[unicorn] -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 = "MySQL" -database_os = "Linux" -os = "Linux" -orm = "Full" -platform = "Rack" -webserver = "Unicorn" -versus = "rack-unicorn" +webserver = "Iodine" +versus = "rack-iodine" diff --git a/frameworks/Ruby/padrino/config/apps.rb b/frameworks/Ruby/padrino/config/apps.rb index 4b36a36b656..2956874c751 100644 --- a/frameworks/Ruby/padrino/config/apps.rb +++ b/frameworks/Ruby/padrino/config/apps.rb @@ -28,8 +28,8 @@ Padrino.configure_apps do # enable :sessions set :session_secret, 'b941cbcb2d647360c0d1fb3c54a7039ed4f71cc0b7785d2aac689cc37d7757b7' - set :protection, true - set :protect_from_csrf, true + set :protection, false + set :protect_from_csrf, false end # Mounts the core application for this project diff --git a/frameworks/Ruby/padrino/config/auto_tune.rb b/frameworks/Ruby/padrino/config/auto_tune.rb index 4544231b9d2..54ae1e08731 100644 --- a/frameworks/Ruby/padrino/config/auto_tune.rb +++ b/frameworks/Ruby/padrino/config/auto_tune.rb @@ -9,7 +9,7 @@ MIN_WORKERS = 2 MAX_WORKERS_PER_VCPU = 1.25 # virtual/logical MIN_THREADS_PER_WORKER = 1 -MAX_THREADS = Integer(ENV['MAX_CONCURRENCY'] || 8) +MAX_THREADS = Integer(ENV['MAX_CONCURRENCY'] || 256) def meminfo(arg) File.open('/proc/meminfo') do |f| diff --git a/frameworks/Ruby/padrino/config/boot.rb b/frameworks/Ruby/padrino/config/boot.rb index 0706fc35e87..6e01f2ed030 100644 --- a/frameworks/Ruby/padrino/config/boot.rb +++ b/frameworks/Ruby/padrino/config/boot.rb @@ -39,7 +39,6 @@ # Add your after (RE)load hooks here # Padrino.after_load do - DataMapper.finalize end Padrino.load! diff --git a/frameworks/Ruby/padrino/config/database.rb b/frameworks/Ruby/padrino/config/database.rb index b87a47f1d19..c4bf9d564d2 100644 --- a/frameworks/Ruby/padrino/config/database.rb +++ b/frameworks/Ruby/padrino/config/database.rb @@ -1,17 +1,27 @@ -## -# A MySQL connection: -# DataMapper.setup(:default, 'mysql://user:password@localhost/the_database_name') -# -# # A Postgres connection: -# DataMapper.setup(:default, 'postgres://user:password@localhost/the_database_name') -# -# # A Sqlite3 connection -# DataMapper.setup(:default, "sqlite3://" + Padrino.root('db', "development.db")) -# +Bundler.require('mysql') +opts = { + adapter: 'mysql2', + username: 'benchmarkdbuser', + password: 'benchmarkdbpass', + host: 'tfb-database', + database: 'hello_world' +} -DataMapper.logger = logger -DataMapper::Property::String.length(255) +# Determine threading/thread pool size and timeout +# TODO: ActiveRecord doesn't have a single-threaded mode? +opts[:pool] = 512 +opts[:checkout_timeout] = 5 -case Padrino.env - when :production then DataMapper.setup(:default, "mysql://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world") -end + +# Setup our logger +ActiveRecord::Base.logger = logger + +# Use ISO 8601 format for JSON serialized times and dates. +ActiveSupport.use_standard_json_time_format = true + +# Don't escape HTML entities in JSON, leave that for the #json_escape helper +# if you're including raw JSON in an HTML page. +ActiveSupport.escape_html_entities_in_json = false + +# Now we can establish connection with our db. +ActiveRecord::Base.establish_connection(opts) diff --git a/frameworks/Ruby/padrino/config/puma.rb b/frameworks/Ruby/padrino/config/puma.rb deleted file mode 100644 index 8a42642fd61..00000000000 --- a/frameworks/Ruby/padrino/config/puma.rb +++ /dev/null @@ -1,9 +0,0 @@ -require_relative 'auto_tune' - -num_workers, num_threads = auto_tune - -workers num_workers -threads num_threads, num_threads - -environment 'production' -bind 'tcp://0.0.0.0:8080' diff --git a/frameworks/Ruby/padrino/config/unicorn.rb b/frameworks/Ruby/padrino/config/unicorn.rb deleted file mode 100644 index 9ca3171328b..00000000000 --- a/frameworks/Ruby/padrino/config/unicorn.rb +++ /dev/null @@ -1,15 +0,0 @@ -require_relative 'auto_tune' - -num_workers, = auto_tune - -worker_processes num_workers -listen "/tmp/.sock", :backlog => 4096 - -preload_app true -GC.respond_to?(:copy_on_write_friendly=) and GC.copy_on_write_friendly = true - -before_fork do |server, worker| -end - -after_fork do |server, worker| -end diff --git a/frameworks/Ruby/padrino/models/fortune.rb b/frameworks/Ruby/padrino/models/fortune.rb index 98e91d0f9c5..61151fa4848 100644 --- a/frameworks/Ruby/padrino/models/fortune.rb +++ b/frameworks/Ruby/padrino/models/fortune.rb @@ -1,9 +1,3 @@ -class Fortune - include DataMapper::Resource - - storage_names[:default] = 'Fortune' - - # property , - property :id, Serial - property :message, String +class Fortune < ActiveRecord::Base + self.table_name = name end diff --git a/frameworks/Ruby/padrino/models/world.rb b/frameworks/Ruby/padrino/models/world.rb index 9d093ade56d..9e7b8d16fb7 100644 --- a/frameworks/Ruby/padrino/models/world.rb +++ b/frameworks/Ruby/padrino/models/world.rb @@ -1,9 +1,16 @@ -class World - include DataMapper::Resource +class World < ActiveRecord::Base + self.table_name = name - storage_names[:default] = 'World' + alias_attribute(:randomNumber, :randomnumber) \ + if connection.adapter_name.downcase.start_with?('postgres') - # property , - property :id, Serial - property :randomNumber, Integer, field: 'randomNumber' + 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-unicorn.dockerfile b/frameworks/Ruby/padrino/padrino-unicorn.dockerfile deleted file mode 100644 index 2ca282ab180..00000000000 --- a/frameworks/Ruby/padrino/padrino-unicorn.dockerfile +++ /dev/null @@ -1,19 +0,0 @@ -FROM ruby:3.0 - -WORKDIR /padrino -COPY app app -COPY config config -COPY models models -COPY .components .components -COPY config.ru config.ru -COPY Gemfile Gemfile -COPY Rakefile Rakefile - -RUN bundle install --jobs=4 --gemfile=/padrino/Gemfile --path=/padrino/padrino/bundle - -RUN apt-get update -yqq && apt-get install -yqq nginx - -EXPOSE 8080 - -CMD nginx -c /padrino/config/nginx.conf && \ - bundle exec unicorn -E production -c config/unicorn.rb diff --git a/frameworks/Ruby/padrino/padrino.dockerfile b/frameworks/Ruby/padrino/padrino.dockerfile index 66605e2457d..57fe29b1034 100644 --- a/frameworks/Ruby/padrino/padrino.dockerfile +++ b/frameworks/Ruby/padrino/padrino.dockerfile @@ -1,4 +1,4 @@ -FROM ruby:3.0 +FROM ruby:3.4 WORKDIR /padrino COPY app app @@ -7,10 +7,15 @@ COPY models models COPY .components .components COPY config.ru config.ru COPY Gemfile Gemfile +COPY Gemfile.lock Gemfile.lock COPY Rakefile Rakefile -RUN bundle install --jobs=4 --gemfile=/padrino/Gemfile --path=/padrino/padrino/bundle +RUN bundle config set with 'iodine' +RUN bundle install --jobs=4 --gemfile=/padrino/Gemfile EXPOSE 8080 -CMD ["bundle", "exec", "puma", "-C", "config/puma.rb", "-w", "8", "--preload"] +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) diff --git a/frameworks/Ruby/rack-app/Gemfile b/frameworks/Ruby/rack-app/Gemfile new file mode 100644 index 00000000000..2ad03adfb21 --- /dev/null +++ b/frameworks/Ruby/rack-app/Gemfile @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +source 'https://rubygems.org' + +gem 'rack-app' +gem 'rack-app-front_end' +gem 'iodine', '~> 0.7', platforms: %i[ruby windows] +gem 'irb' # for Ruby 3.5 +gem 'logger' # for Ruby 3.5 +gem 'json', '~> 2.10' +gem 'pg', '~> 1.5' +gem 'sequel', '~> 5.0' +gem 'sequel_pg', '~> 1.6', require: false diff --git a/frameworks/Ruby/rack-app/Gemfile.lock b/frameworks/Ruby/rack-app/Gemfile.lock new file mode 100644 index 00000000000..7da89e051ce --- /dev/null +++ b/frameworks/Ruby/rack-app/Gemfile.lock @@ -0,0 +1,51 @@ +GEM + remote: https://rubygems.org/ + specs: + concurrent-ruby (1.3.5) + date (3.5.0) + erb (5.1.3) + io-console (0.8.1) + irb (1.15.3) + pp (>= 0.6.0) + rdoc (>= 4.0.0) + reline (>= 0.4.2) + json (2.15.2) + logger (1.7.0) + nio4r (2.7.5) + pp (0.6.3) + prettyprint + prettyprint (0.2.0) + psych (5.2.6) + date + stringio + puma (7.1.0) + nio4r (~> 2.0) + rack (3.2.4) + rack-app (11.0.2) + rack (>= 3.0.0) + rackup + rackup (2.2.1) + rack (>= 3) + rdoc (6.15.1) + erb + psych (>= 4.0.0) + tsort + reline (0.6.2) + io-console (~> 0.5) + stringio (3.1.7) + tsort (0.2.0) + +PLATFORMS + arm64-darwin-24 + ruby + +DEPENDENCIES + concurrent-ruby + irb + json (~> 2.10) + logger + puma (~> 7.1) + rack-app + +BUNDLED WITH + 2.7.2 diff --git a/frameworks/Ruby/rack-app/README.md b/frameworks/Ruby/rack-app/README.md new file mode 100644 index 00000000000..585c970919e --- /dev/null +++ b/frameworks/Ruby/rack-app/README.md @@ -0,0 +1,44 @@ +# Rack-app Benchmarking Test + +rack-app is a minimalist web framework that focuses on simplicity and +maintainability. The framework is meant to be used by seasoned web developers. + +https://github.com/rack-app/rack-app + +### Test Type Implementation Source Code + +* [JSON Serialization](app.rb): "/json" +* [Single Database Query](app.rb): "/db" +* [Multiple Database Queries](app.rb): "/db?queries={#}" +* [Fortunes](app.rb): "/fortune" +* [Plaintext](app.rb): "/plaintext" + +## Important Libraries + +The tests were run with: + +* [Sequel](https://rubygems.org/gems/sequel) +* [PG](https://rubygems.org/gems/pg) + +## Test URLs + +### JSON + +http://localhost:8080/json + +### PLAINTEXT + +http://localhost:8080/plaintext + +### DB + +http://localhost:8080/db + +### QUERY + +http://localhost:8080/queries?queries= + +### FORTUNES + +http://localhost:8080/fortunes + diff --git a/frameworks/Ruby/rack-app/app.rb b/frameworks/Ruby/rack-app/app.rb new file mode 100644 index 00000000000..e5310fc012d --- /dev/null +++ b/frameworks/Ruby/rack-app/app.rb @@ -0,0 +1,76 @@ +# frozen_string_literal: true + +require 'rack/app' +require 'rack/app/front_end' +require 'json' + +class App < Rack::App + MAX_PK = 10_000 + ID_RANGE = (1..10_000).freeze + ALL_IDS = ID_RANGE.to_a + QUERIES_MIN = 1 + QUERIES_MAX = 500 + JSON_TYPE = 'application/json' + HTML_TYPE = 'text/html; charset=utf-8' + PLAINTEXT_TYPE = 'text/plain' + + apply_extensions :front_end + + helpers do + def fortunes + fortunes = Fortune.all + fortunes << Fortune.new( + id: 0, + message: "Additional fortune added at request time." + ) + fortunes.sort_by!(&:message) + end + end + + get '/json' do + set_headers(JSON_TYPE) + { message: 'Hello, World!' }.to_json + end + + get '/db' do + set_headers(JSON_TYPE) + World.with_pk(rand1).values.to_json + end + + get '/queries' do + set_headers(JSON_TYPE) + ids = ALL_IDS.sample(bounded_queries) + DB.synchronize do + ids.map do |id| + World.with_pk(id).values + end + end.to_json + end + + get '/fortunes' do + set_headers(HTML_TYPE) + render 'fortunes.html.erb' + end + + get '/plaintext' do + set_headers(PLAINTEXT_TYPE) + 'Hello, World!' + end + + private + + # Return a random number between 1 and MAX_PK + def rand1 + rand(MAX_PK).succ + end + + def bounded_queries + queries = params['queries'].to_i + queries.clamp(QUERIES_MIN, QUERIES_MAX) + end + + def set_headers(content_type) + response.headers[::Rack::CONTENT_TYPE] = content_type + response.headers['Server'] = 'rack-app' + end +end diff --git a/frameworks/Ruby/rack-app/app/fortunes.html.erb b/frameworks/Ruby/rack-app/app/fortunes.html.erb new file mode 100644 index 00000000000..56c5c540270 --- /dev/null +++ b/frameworks/Ruby/rack-app/app/fortunes.html.erb @@ -0,0 +1,12 @@ + + + Fortunes + + + + <% fortunes.each do |record| %> + + <% end %> +
idmessage
<%= record.id %><%= ERB::Escape.html_escape(record.message) %>
+ + diff --git a/frameworks/Ruby/rack-app/benchmark_config.json b/frameworks/Ruby/rack-app/benchmark_config.json new file mode 100644 index 00000000000..d25acd9a641 --- /dev/null +++ b/frameworks/Ruby/rack-app/benchmark_config.json @@ -0,0 +1,27 @@ +{ + "framework": "rack-app", + "tests": [ + { + "default": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "db_url": "/db", + "query_url": "/queries?queries=", + "fortune_url": "/fortunes", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "orm": "Full", + "database": "Postgres", + "framework": "rack-app", + "language": "Ruby", + "platform": "Mri", + "webserver": "Iodine", + "os": "Linux", + "database_os": "Linux", + "display_name": "rack-app", + "notes": "" + } + } + ] +} diff --git a/frameworks/Ruby/rack-app/boot.rb b/frameworks/Ruby/rack-app/boot.rb new file mode 100644 index 00000000000..7711f76a0a1 --- /dev/null +++ b/frameworks/Ruby/rack-app/boot.rb @@ -0,0 +1,68 @@ +# 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 new file mode 100644 index 00000000000..27540c2f4ee --- /dev/null +++ b/frameworks/Ruby/rack-app/config.ru @@ -0,0 +1,5 @@ +# frozen_string_literal: true +require_relative 'boot' +require_relative 'app' + +run App diff --git a/frameworks/Ruby/hanami/config/auto_tune.rb b/frameworks/Ruby/rack-app/config/auto_tune.rb similarity index 92% rename from frameworks/Ruby/hanami/config/auto_tune.rb rename to frameworks/Ruby/rack-app/config/auto_tune.rb index 476ed1a45bd..1e075f56911 100644 --- a/frameworks/Ruby/hanami/config/auto_tune.rb +++ b/frameworks/Ruby/rack-app/config/auto_tune.rb @@ -7,7 +7,7 @@ # 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) +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 diff --git a/frameworks/Ruby/rack-app/config/puma.rb b/frameworks/Ruby/rack-app/config/puma.rb new file mode 100644 index 00000000000..1b6d05d8ac0 --- /dev/null +++ b/frameworks/Ruby/rack-app/config/puma.rb @@ -0,0 +1,10 @@ +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/rack-app.dockerfile b/frameworks/Ruby/rack-app/rack-app.dockerfile new file mode 100644 index 00000000000..2b24fcab8bd --- /dev/null +++ b/frameworks/Ruby/rack-app/rack-app.dockerfile @@ -0,0 +1,21 @@ +FROM ruby:3.5-rc + +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 + +WORKDIR /rack-app + +COPY Gemfile* ./ + +ENV BUNDLE_FORCE_RUBY_PLATFORM=true +RUN bundle install --jobs=8 + +COPY . . + +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/rack-sequel/Gemfile b/frameworks/Ruby/rack-sequel/Gemfile index 83d341118d0..fa1f161147d 100644 --- a/frameworks/Ruby/rack-sequel/Gemfile +++ b/frameworks/Ruby/rack-sequel/Gemfile @@ -1,19 +1,19 @@ source 'https://rubygems.org' -gem 'json', '~> 2.0' -gem 'passenger', '~> 5.1', :platforms=>[:ruby, :mswin], :require=>false -gem 'puma', '~> 6.4', :require=>false +gem 'json', '~> 2.8' gem 'sequel', '~> 5.0' -gem 'rack', '2.0.8' -gem 'unicorn', '~> 5.2', :platforms=>[:ruby, :mswin], :require=>false +gem 'rack', '~> 3.1' +gem "concurrent-ruby" -group :mysql do - gem 'jdbc-mysql', '~> 5.1', :platforms=>:jruby, :require=>'jdbc/mysql' - gem 'mysql2', '~> 0.4', :platforms=>[:ruby, :mswin] +group :mysql, optional: true do + gem 'trilogy', '~> 2.9', platforms: [:ruby, :windows] end -group :postgresql do - gem 'jdbc-postgres', '~> 9.4', :platforms=>:jruby, :require=>'jdbc/postgres' - gem 'pg', '~> 0.19', :platforms=>[:ruby, :mswin] - gem 'sequel_pg', '~> 1.6', :platforms=>:ruby, :require=>false +group :postgresql, optional: true do + gem 'pg', '~> 1.5', platforms: [:ruby, :windows] + gem 'sequel_pg', '~> 1.6', platforms: :ruby, 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 new file mode 100644 index 00000000000..25aedc6282a --- /dev/null +++ b/frameworks/Ruby/rack-sequel/Gemfile.lock @@ -0,0 +1,37 @@ +GEM + remote: https://rubygems.org/ + specs: + bigdecimal (3.3.1) + concurrent-ruby (1.3.5) + json (2.13.2) + 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) + nio4r (~> 2.0) + rack (3.2.0) + sequel (5.97.0) + bigdecimal + sequel_pg (1.17.2) + pg (>= 0.18.0, != 1.2.0) + sequel (>= 4.38.0) + trilogy (2.9.0) + +PLATFORMS + ruby + x86_64-darwin-22 + x86_64-linux + +DEPENDENCIES + concurrent-ruby + json (~> 2.8) + pg (~> 1.5) + puma (~> 7.0) + rack (~> 3.1) + sequel (~> 5.0) + sequel_pg (~> 1.6) + trilogy (~> 2.9) + +BUNDLED WITH + 2.7.0 diff --git a/frameworks/Ruby/rack-sequel/README.md b/frameworks/Ruby/rack-sequel/README.md index 1aa39b2b4a2..3639fca8cc6 100644 --- a/frameworks/Ruby/rack-sequel/README.md +++ b/frameworks/Ruby/rack-sequel/README.md @@ -12,13 +12,9 @@ a variety of web platforms. The tests will be run with: -* [Ruby 2.4](http://www.ruby-lang.org) -* [JRuby 9.1](http://jruby.org) -* [Rubinius 3](https://rubinius.com)\* -* [Puma 3](http://puma.io) -* [Passenger 5](https://www.phusionpassenger.com) -* [Unicorn 5](https://bogomips.org/unicorn/) -* [Rack 2](http://rack.rubyforge.org) +* [Ruby 3.4](http://www.ruby-lang.org) +* [Puma 7](http://puma.io) +* [Rack 3](http://rack.rubyforge.org) * [Sequel 5](http://sequel.jeremyevans.net) * [MySQL 5.5](https://www.mysql.com) * [Postgres 9.3](https://www.postgresql.org) diff --git a/frameworks/Ruby/rack-sequel/benchmark_config.json b/frameworks/Ruby/rack-sequel/benchmark_config.json index a298e84d371..15763639c4c 100644 --- a/frameworks/Ruby/rack-sequel/benchmark_config.json +++ b/frameworks/Ruby/rack-sequel/benchmark_config.json @@ -3,24 +3,22 @@ "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", + "approach": "Realistic", "classification": "Micro", "database": "MySQL", - "framework": "rack-sequel", + "framework": "rack", "language": "Ruby", "orm": "Micro", "platform": "Rack", "webserver": "Puma", "os": "Linux", "database_os": "Linux", - "display_name": "rack-sequel-puma-mri", + "display_name": "rack-sequel [puma, mysql]", "versus": "rack-puma-mri", "notes": "" }, @@ -30,101 +28,17 @@ "fortune_url": "/fortunes", "update_url": "/updates?queries=", "port": 8080, - "approach": "Stripped", + "approach": "Realistic", "classification": "Micro", "database": "Postgres", - "framework": "rack-sequel", + "framework": "rack", "language": "Ruby", "orm": "Micro", "platform": "Rack", "webserver": "Puma", "os": "Linux", "database_os": "Linux", - "display_name": "rack-sequel-postgres-puma-mri", - "versus": null, - "notes": "" - }, - "passenger-mri": { - "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": "Micro", - "database": "MySQL", - "framework": "rack-sequel", - "language": "Ruby", - "orm": "Micro", - "platform": "Rack", - "webserver": "Passenger", - "os": "Linux", - "database_os": "Linux", - "display_name": "rack-sequel-passenger-mri", - "versus": null, - "notes": "" - }, - "postgres-passenger-mri": { - "db_url": "/db", - "query_url": "/queries?queries=", - "fortune_url": "/fortunes", - "update_url": "/updates?queries=", - "port": 8080, - "approach": "Stripped", - "classification": "Micro", - "database": "Postgres", - "framework": "rack-sequel", - "language": "Ruby", - "orm": "Micro", - "platform": "Rack", - "webserver": "Passenger", - "os": "Linux", - "database_os": "Linux", - "display_name": "rack-sequel-postgres-passenger-mri", - "versus": null, - "notes": "" - }, - "unicorn-mri": { - "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": "Micro", - "database": "MySQL", - "framework": "rack-sequel", - "language": "Ruby", - "orm": "Micro", - "platform": "Rack", - "webserver": "Unicorn", - "os": "Linux", - "database_os": "Linux", - "display_name": "rack-sequel-unicorn-mri", - "versus": "rack-unicorn", - "notes": "" - }, - "postgres-unicorn-mri": { - "db_url": "/db", - "query_url": "/queries?queries=", - "fortune_url": "/fortunes", - "update_url": "/updates?queries=", - "port": 8080, - "approach": "Stripped", - "classification": "Micro", - "database": "Postgres", - "framework": "rack-sequel", - "language": "Ruby", - "orm": "Micro", - "platform": "Rack", - "webserver": "Unicorn", - "os": "Linux", - "database_os": "Linux", - "display_name": "rack-sequel-postgres-unicorn-mri", + "display_name": "rack-sequel [puma, postgres]", "versus": null, "notes": "" } diff --git a/frameworks/Ruby/rack-sequel/benchmark_config.rb b/frameworks/Ruby/rack-sequel/benchmark_config.rb deleted file mode 100644 index 5aa58997825..00000000000 --- a/frameworks/Ruby/rack-sequel/benchmark_config.rb +++ /dev/null @@ -1,8 +0,0 @@ -# frozen_string_literal: true - -require 'json' -require 'yaml' - -yaml = YAML.load(ARGF.read) -yaml["tests"][0].delete_if { |_, v| v["disabled"] } -puts JSON.pretty_generate(yaml) diff --git a/frameworks/Ruby/rack-sequel/benchmark_config.yaml b/frameworks/Ruby/rack-sequel/benchmark_config.yaml deleted file mode 100644 index 16ae74080e5..00000000000 --- a/frameworks/Ruby/rack-sequel/benchmark_config.yaml +++ /dev/null @@ -1,69 +0,0 @@ ---- -framework: rack-sequel -tests: - - default: &default - setup_file: run_mri_puma - 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: Micro - database: MySQL - framework: rack-sequel - language: Ruby - orm: Micro - platform: Rack - webserver: Puma - os: Linux - database_os: Linux - display_name: rack-sequel-puma-mri - versus: rack-puma-mri - notes: "" - postgres: - <<: *default - database: Postgres - display_name: rack-sequel-postgres-puma-mri - versus: ~ - puma-jruby: - <<: *default - setup_file: run_jruby_puma - display_name: rack-sequel-puma-jruby - versus: rack-puma-jruby - disabled: true - postgres-puma-jruby: - <<: *default - setup_file: run_jruby_puma - database: Postgres - display_name: rack-sequel-postgres-puma-jruby - versus: ~ - disabled: true - passenger-mri: - <<: *default - setup_file: run_mri_passenger - webserver: Passenger - display_name: rack-sequel-passenger-mri - versus: ~ - postgres-passenger-mri: - <<: *default - setup_file: run_mri_passenger - database: Postgres - webserver: Passenger - display_name: rack-sequel-postgres-passenger-mri - versus: ~ - unicorn-mri: - <<: *default - setup_file: run_mri_unicorn - webserver: Unicorn - display_name: rack-sequel-unicorn-mri - versus: rack-unicorn - postgres-unicorn-mri: - <<: *default - setup_file: run_mri_unicorn - database: Postgres - webserver: Unicorn - display_name: rack-sequel-postgres-unicorn-mri - versus: ~ diff --git a/frameworks/Ruby/rack-sequel/boot.rb b/frameworks/Ruby/rack-sequel/boot.rb index e012694c06a..9c06a7f981f 100644 --- a/frameworks/Ruby/rack-sequel/boot.rb +++ b/frameworks/Ruby/rack-sequel/boot.rb @@ -1,54 +1,39 @@ # frozen_string_literal: true require 'bundler/setup' -require 'time' -MAX_PK = 10_000 -QUERIES_MIN = 1 -QUERIES_MAX = 500 SEQUEL_NO_ASSOCIATIONS = true -SERVER_STRING = - if defined?(PhusionPassenger) - [ - PhusionPassenger::SharedConstants::SERVER_TOKEN_NAME, - PhusionPassenger::VERSION_STRING - ].join('/').freeze - elsif defined?(Puma) - Puma::Const::PUMA_SERVER_STRING - elsif defined?(Unicorn) - Unicorn::HttpParser::DEFAULTS['SERVER_SOFTWARE'] - end - Bundler.require(:default) # Load core modules def connect(dbtype) Bundler.require(dbtype) # Load database-specific modules - adapters = { - :mysql=>{ :jruby=>'jdbc:mysql', :mri=>'mysql2' }, - :postgresql=>{ :jruby=>'jdbc:postgresql', :mri=>'postgres' } - } - 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?(JRUBY_VERSION) - opts[:max_connections] = (2 * Math.log(Integer(ENV.fetch('MAX_CONCURRENCY')))).floor - opts[:pool_timeout] = 10 - elsif defined?(Puma) && (threads = Puma.cli_config.options.fetch(:max_threads)) > 1 - opts[:max_connections] = (2 * Math.log(threads)).floor + if defined?(Puma) && (threads = Puma.cli_config.options.fetch(:max_threads)) > 1 + opts[:max_connections] = threads opts[:pool_timeout] = 10 else - Sequel.single_threaded = true + opts[:max_connections] = 512 end Sequel.connect \ '%{adapter}://%{host}/%{database}?user=%{user}&password=%{password}' % { - :adapter=>adapters.fetch(dbtype).fetch(defined?(JRUBY_VERSION) ? :jruby : :mri), - :host=>'tfb-database', - :database=>'hello_world', - :user=>'benchmarkdbuser', - :password=>'benchmarkdbpass' + adapter: adapter, + host: 'tfb-database', + database: 'hello_world', + user: 'benchmarkdbuser', + password: 'benchmarkdbpass' }, opts end @@ -57,6 +42,21 @@ def connect(dbtype) # 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) diff --git a/frameworks/Ruby/rack-sequel/config.ru b/frameworks/Ruby/rack-sequel/config.ru index ff84c719d0f..8fceb7c06fc 100644 --- a/frameworks/Ruby/rack-sequel/config.ru +++ b/frameworks/Ruby/rack-sequel/config.ru @@ -1,5 +1,4 @@ require_relative 'boot' require_relative 'hello_world' use Rack::ContentLength -use Rack::Chunked run HelloWorld.new diff --git a/frameworks/Ruby/rack-sequel/config.toml b/frameworks/Ruby/rack-sequel/config.toml index 96a74c4a105..3888d522682 100644 --- a/frameworks/Ruby/rack-sequel/config.toml +++ b/frameworks/Ruby/rack-sequel/config.toml @@ -34,71 +34,3 @@ orm = "Micro" platform = "Rack" webserver = "Puma" versus = "rack-puma-mri" - -[postgres-passenger-mri] -urls.plaintext = "/plaintext" -urls.json = "/json" -urls.db = "/db" -urls.query = "/queries?queries=" -urls.update = "/updates?queries=" -urls.fortune = "/fortunes" -approach = "Stripped" -classification = "Micro" -database = "Postgres" -database_os = "Linux" -os = "Linux" -orm = "Micro" -platform = "Rack" -webserver = "Passenger" -versus = "None" - -[postgres-unicorn-mri] -urls.plaintext = "/plaintext" -urls.json = "/json" -urls.db = "/db" -urls.query = "/queries?queries=" -urls.update = "/updates?queries=" -urls.fortune = "/fortunes" -approach = "Stripped" -classification = "Micro" -database = "Postgres" -database_os = "Linux" -os = "Linux" -orm = "Micro" -platform = "Rack" -webserver = "Unicorn" -versus = "None" - -[passenger-mri] -urls.plaintext = "/plaintext" -urls.json = "/json" -urls.db = "/db" -urls.query = "/queries?queries=" -urls.update = "/updates?queries=" -urls.fortune = "/fortunes" -approach = "Stripped" -classification = "Micro" -database = "MySQL" -database_os = "Linux" -os = "Linux" -orm = "Micro" -platform = "Rack" -webserver = "Passenger" -versus = "None" - -[unicorn-mri] -urls.plaintext = "/plaintext" -urls.json = "/json" -urls.db = "/db" -urls.query = "/queries?queries=" -urls.update = "/updates?queries=" -urls.fortune = "/fortunes" -approach = "Stripped" -classification = "Micro" -database = "MySQL" -database_os = "Linux" -os = "Linux" -orm = "Micro" -platform = "Rack" -webserver = "Unicorn" -versus = "rack-unicorn" diff --git a/frameworks/Ruby/rack-sequel/config/mri_puma.rb b/frameworks/Ruby/rack-sequel/config/mri_puma.rb index 95b855bafd3..d70db95a94f 100644 --- a/frameworks/Ruby/rack-sequel/config/mri_puma.rb +++ b/frameworks/Ruby/rack-sequel/config/mri_puma.rb @@ -1,7 +1,10 @@ require_relative 'auto_tune' # FWBM only... use the puma_auto_tune gem in production! -num_workers, num_threads = auto_tune +_, num_threads = auto_tune -workers num_workers threads num_threads, num_threads + +before_fork do + Sequel::DATABASES.each(&:disconnect) +end diff --git a/frameworks/Ruby/rack-sequel/config/mri_unicorn.rb b/frameworks/Ruby/rack-sequel/config/mri_unicorn.rb deleted file mode 100644 index c9a0c55083e..00000000000 --- a/frameworks/Ruby/rack-sequel/config/mri_unicorn.rb +++ /dev/null @@ -1,6 +0,0 @@ -require_relative 'auto_tune' - -# FWBM only... -num_workers, = auto_tune - -worker_processes num_workers diff --git a/frameworks/Ruby/rack-sequel/hello_world.rb b/frameworks/Ruby/rack-sequel/hello_world.rb index 8ecb1c75fca..9b496788da6 100644 --- a/frameworks/Ruby/rack-sequel/hello_world.rb +++ b/frameworks/Ruby/rack-sequel/hello_world.rb @@ -1,20 +1,27 @@ # frozen_string_literal: true +require 'time' # Our Rack application to be executed by rackup class HelloWorld - DEFAULT_HEADERS = {}.tap do |h| - h['Server'] = SERVER_STRING if SERVER_STRING - - h.freeze - end + MAX_PK = 10_000 + ID_RANGE = (1..10_000).freeze + 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' + DATE = 'Date' + SERVER = 'Server' + SERVER_STRING = "Rack" def bounded_queries(env) params = Rack::Utils.parse_query(env['QUERY_STRING']) queries = params['queries'].to_i - return QUERIES_MIN if queries < QUERIES_MIN - return QUERIES_MAX if queries > QUERIES_MAX - queries + queries.clamp(QUERIES_MIN, QUERIES_MAX) end # Return a random number between 1 and MAX_PK @@ -22,17 +29,15 @@ def rand1 rand(MAX_PK).succ end - WORLD_BY_ID = World.naked.where(:id=>:$id).prepare(:first, :world_by_id) - WORLD_UPDATE = World.where(:id=>:$id).prepare(:update, :world_update, :randomnumber=>:$randomnumber) - def db - WORLD_BY_ID.(:id=>rand1) + World.with_pk(rand1).values end def queries(env) + ids = ALL_IDS.sample(bounded_queries(env)) DB.synchronize do - Array.new(bounded_queries(env)) do - WORLD_BY_ID.(:id=>rand1) + ids.map do |id| + World.with_pk(id).values end end end @@ -40,8 +45,8 @@ def queries(env) def fortunes fortunes = Fortune.all fortunes << Fortune.new( - :id=>0, - :message=>'Additional fortune added at request time.' + id: 0, + message: 'Additional fortune added at request time.' ) fortunes.sort_by!(&:message) @@ -65,7 +70,7 @@ def fortunes html << <<~"HTML" #{fortune.id} - #{Rack::Utils.escape_html(fortune.message)} + #{ERB::Escape.html_escape(fortune.message)} HTML end @@ -79,45 +84,69 @@ def fortunes end def updates(env) + worlds = [] + ids = ALL_IDS.sample(bounded_queries(env)) DB.synchronize do - Array.new(bounded_queries(env)) do - world = WORLD_BY_ID.(:id=>rand1) - WORLD_UPDATE.(:id=>world[:id], :randomnumber=>(world[:randomnumber] = rand1)) - world - end + worlds = + ids.map do |id| + world = World.with_pk(id) + new_value = rand1 + new_value = rand1 while new_value == world.randomnumber + world.randomnumber = new_value + world + end + World.batch_update(worlds) end + worlds.map!(&:values) end def call(env) - content_type, *body = - case env['PATH_INFO'] - when '/json' - # Test type 1: JSON serialization - ['application/json', JSON.fast_generate(:message=>'Hello, World!')] - when '/db' - # Test type 2: Single database query - ['application/json', JSON.fast_generate(db)] - when '/queries' - # Test type 3: Multiple database queries - ['application/json', JSON.fast_generate(queries(env))] - when '/fortunes' - # Test type 4: Fortunes - ['text/html; charset=utf-8', fortunes] - when '/updates' - # Test type 5: Database updates - ['application/json', JSON.fast_generate(updates(env))] - when '/plaintext' - # Test type 6: Plaintext - ['text/plain', 'Hello, World!'] - end + case env['PATH_INFO'] + when '/json' + # Test type 1: JSON serialization + respond JSON_TYPE, { message: 'Hello, World!' }.to_json + when '/db' + # Test type 2: Single database query + respond JSON_TYPE, db.to_json + when '/queries' + # Test type 3: Multiple database queries + respond JSON_TYPE, queries(env).to_json + when '/fortunes' + # Test type 4: Fortunes + respond HTML_TYPE, fortunes + when '/updates' + # Test type 5: Database updates + respond JSON_TYPE, updates(env).to_json + when '/plaintext' + # Test type 6: Plaintext + respond PLAINTEXT_TYPE, 'Hello, World!' + end + end + + private + def respond(content_type, body) [ 200, - DEFAULT_HEADERS.merge( - 'Content-Type'=>content_type, - 'Date'=>Time.now.httpdate - ), - body + headers(content_type, body), + [body] ] end + + if defined?(Puma) + def headers(content_type, _) + { + CONTENT_TYPE => content_type, + SERVER => SERVER_STRING, + DATE => Time.now.utc.httpdate + } + end + else + def headers(content_type, _) + { + CONTENT_TYPE => content_type, + SERVER => SERVER_STRING + } + end + end end diff --git a/frameworks/Ruby/rack-sequel/rack-sequel-passenger-mri.dockerfile b/frameworks/Ruby/rack-sequel/rack-sequel-passenger-mri.dockerfile deleted file mode 100644 index 1264a3d67e7..00000000000 --- a/frameworks/Ruby/rack-sequel/rack-sequel-passenger-mri.dockerfile +++ /dev/null @@ -1,22 +0,0 @@ -FROM ruby:3.3-rc - -ADD ./ /rack-sequel - -WORKDIR /rack-sequel - -RUN bundle install --jobs=4 --gemfile=/rack-sequel/Gemfile --path=/rack-sequel/rack-sequel/bundle - -# TODO: https://github.com/phusion/passenger/issues/1916 -ENV _PASSENGER_FORCE_HTTP_SESSION=true -ENV DBTYPE=mysql -ENV RUBY_YJIT_ENABLE=1 - -RUN ruby -r /rack-sequel/config/auto_tune -e 'puts auto_tune.first' > instances - -EXPOSE 8080 - -CMD bundle exec passenger start --log-level 1 \ - --engine builtin --disable-turbocaching --disable-security-update-check \ - --spawn-method direct --max-pool-size $(cat instances) --min-instances $(cat instances) --max-request-queue-size 1024 \ - --address 0.0.0.0 --port 8080 --environment production - diff --git a/frameworks/Ruby/rack-sequel/rack-sequel-postgres-passenger-mri.dockerfile b/frameworks/Ruby/rack-sequel/rack-sequel-postgres-passenger-mri.dockerfile deleted file mode 100644 index f4cec089ff8..00000000000 --- a/frameworks/Ruby/rack-sequel/rack-sequel-postgres-passenger-mri.dockerfile +++ /dev/null @@ -1,21 +0,0 @@ -FROM ruby:3.3-rc - -ADD ./ /rack-sequel - -WORKDIR /rack-sequel - -RUN bundle install --jobs=4 --gemfile=/rack-sequel/Gemfile --path=/rack-sequel/rack-sequel/bundle - -# TODO: https://github.com/phusion/passenger/issues/1916 -ENV _PASSENGER_FORCE_HTTP_SESSION=true -ENV DBTYPE=postgresql -ENV RUBY_YJIT_ENABLE=1 - -RUN ruby -r /rack-sequel/config/auto_tune -e 'puts auto_tune.first' > instances - -EXPOSE 8080 - -CMD bundle exec passenger start --log-level 1 \ - --engine builtin --disable-turbocaching --disable-security-update-check \ - --spawn-method direct --max-pool-size $(cat instances) --min-instances $(cat instances) --max-request-queue-size 1024 \ - --address 0.0.0.0 --port 8080 --environment production diff --git a/frameworks/Ruby/rack-sequel/rack-sequel-postgres-unicorn-mri.dockerfile b/frameworks/Ruby/rack-sequel/rack-sequel-postgres-unicorn-mri.dockerfile deleted file mode 100644 index b702ee0cc8b..00000000000 --- a/frameworks/Ruby/rack-sequel/rack-sequel-postgres-unicorn-mri.dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM ruby:3.3-rc - -ADD ./ /rack-sequel - -WORKDIR /rack-sequel - -RUN bundle install --jobs=4 --gemfile=/rack-sequel/Gemfile --path=/rack-sequel/rack-sequel/bundle - -ENV DBTYPE=postgresql -ENV RUBY_YJIT_ENABLE=1 - -EXPOSE 8080 - -CMD bundle exec unicorn -c config/mri_unicorn.rb -o 0.0.0.0 -p 8080 -E production diff --git a/frameworks/Ruby/rack-sequel/rack-sequel-postgres.dockerfile b/frameworks/Ruby/rack-sequel/rack-sequel-postgres.dockerfile index 490dce8730e..65728878595 100644 --- a/frameworks/Ruby/rack-sequel/rack-sequel-postgres.dockerfile +++ b/frameworks/Ruby/rack-sequel/rack-sequel-postgres.dockerfile @@ -1,14 +1,22 @@ -FROM ruby:3.3-rc +FROM ruby:3.5-rc ADD ./ /rack-sequel WORKDIR /rack-sequel -RUN bundle install --jobs=4 --gemfile=/rack-sequel/Gemfile --path=/rack-sequel/rack-sequel/bundle +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 puma' +RUN bundle install --jobs=4 --gemfile=/rack-sequel/Gemfile ENV DBTYPE=postgresql -ENV RUBY_YJIT_ENABLE=1 +ENV WEB_CONCURRENCY=auto EXPOSE 8080 CMD bundle exec puma -C config/mri_puma.rb -b tcp://0.0.0.0:8080 -e production diff --git a/frameworks/Ruby/rack-sequel/rack-sequel-unicorn-mri.dockerfile b/frameworks/Ruby/rack-sequel/rack-sequel-unicorn-mri.dockerfile deleted file mode 100644 index 3e03ab1d14a..00000000000 --- a/frameworks/Ruby/rack-sequel/rack-sequel-unicorn-mri.dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM ruby:3.3-rc - -ADD ./ /rack-sequel - -WORKDIR /rack-sequel - -RUN bundle install --jobs=4 --gemfile=/rack-sequel/Gemfile --path=/rack-sequel/rack-sequel/bundle - -ENV DBTYPE=mysql -ENV RUBY_YJIT_ENABLE=1 - -EXPOSE 8080 - -CMD bundle exec unicorn -c config/mri_unicorn.rb -o 0.0.0.0 -p 8080 -E production diff --git a/frameworks/Ruby/rack-sequel/rack-sequel.dockerfile b/frameworks/Ruby/rack-sequel/rack-sequel.dockerfile index 9da494ae34a..a7e0c901daa 100644 --- a/frameworks/Ruby/rack-sequel/rack-sequel.dockerfile +++ b/frameworks/Ruby/rack-sequel/rack-sequel.dockerfile @@ -1,14 +1,22 @@ -FROM ruby:3.3-rc +FROM ruby:3.5-rc ADD ./ /rack-sequel WORKDIR /rack-sequel -RUN bundle install --jobs=4 --gemfile=/rack-sequel/Gemfile --path=/rack-sequel/rack-sequel/bundle +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 puma' +RUN bundle install --jobs=4 --gemfile=/rack-sequel/Gemfile ENV DBTYPE=mysql -ENV RUBY_YJIT_ENABLE=1 +ENV WEB_CONCURRENCY=auto EXPOSE 8080 CMD bundle exec puma -C config/mri_puma.rb -b tcp://0.0.0.0:8080 -e production diff --git a/frameworks/Ruby/rack/Gemfile b/frameworks/Ruby/rack/Gemfile index d92ca804595..0512085a64f 100644 --- a/frameworks/Ruby/rack/Gemfile +++ b/frameworks/Ruby/rack/Gemfile @@ -2,20 +2,44 @@ source 'https://rubygems.org' -gem 'rack', '~>3.0' -gem 'connection_pool', '~>2.4' -gem 'falcon', '~>0.42', platforms: %i[ruby mswin] +# Show platform so we can set in the Gemfile +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.6', platforms: :jruby -gem 'oj', '~> 3.14', platforms: %i[ruby mswin] -gem 'pg', '~>1.5', platforms: %i[ruby mswin] -gem 'puma', '~> 6.3' +gem 'json', '~> 2.10' +gem 'pg', '~> 1.5', platforms: %i[ruby windows] gem 'sequel' -gem 'sequel_pg', platforms: %i[ruby mswin] +gem 'sequel_pg', platforms: %i[ruby windows] gem 'tzinfo-data', '1.2023.3' -gem 'unicorn', '~> 6.1', platforms: %i[ruby mswin], require: false -group :development do +group :falcon, optional: true do + gem 'falcon', '~> 0.47', platforms: %i[ruby windows] +end + +group :iodine, optional: true do + gem 'iodine', '~> 0.7', platforms: %i[ruby windows] +end + +group :itsi, optional: true do + gem 'itsi' +end + +group :passenger, optional: true do + gem 'logger' # required by passenger on Ruby 3.5 + gem 'passenger', '~> 6.1', platforms: [:ruby, :windows], require: false +end + +group :pitchfork, optional: true do + gem 'pitchfork', '~> 0.17' +end + +group :puma, optional: true do + gem 'puma', '~> 7.1' +end + +group :development, optional: true do gem 'rack-test' - gem 'rubocop', platforms: %i[ruby mswin] + gem 'rubocop', platforms: %i[ruby windows] end diff --git a/frameworks/Ruby/rack/Gemfile.lock b/frameworks/Ruby/rack/Gemfile.lock index a6c921d3e6c..4030d1e1ecb 100644 --- a/frameworks/Ruby/rack/Gemfile.lock +++ b/frameworks/Ruby/rack/Gemfile.lock @@ -2,130 +2,177 @@ GEM remote: https://rubygems.org/ specs: ast (2.4.2) - async (2.5.0) - console (~> 1.10) - io-event (~> 1.1) - timers (~> 4.1) - async-container (0.16.12) - async - async-io - async-http (0.60.1) - async (>= 1.25) - async-io (>= 1.28) - async-pool (>= 0.2) - protocol-http (~> 0.24.0) - protocol-http1 (~> 0.15.0) - protocol-http2 (~> 0.15.0) - traces (>= 0.8.0) - async-http-cache (0.4.3) + async (2.23.0) + console (~> 1.29) + fiber-annotation + io-event (~> 1.9) + metrics (~> 0.12) + traces (~> 0.15) + async-container (0.24.0) + async (~> 2.22) + async-container-supervisor (0.5.1) + async-container (~> 0.22) + async-service + io-endpoint + memory-leak (~> 0.5) + async-http (0.87.0) + async (>= 2.10.2) + async-pool (~> 0.9) + io-endpoint (~> 0.14) + io-stream (~> 0.6) + metrics (~> 0.12) + protocol-http (~> 0.49) + protocol-http1 (~> 0.30) + protocol-http2 (~> 0.22) + traces (~> 0.10) + async-http-cache (0.4.5) async-http (~> 0.56) - async-io (1.34.3) - async - async-pool (0.4.0) + async-pool (0.10.3) async (>= 1.25) - build-environment (1.13.0) - concurrent-ruby (1.2.2) - connection_pool (2.4.0) - console (1.16.2) - fiber-local - falcon (0.42.3) + async-service (0.13.0) + async + async-container (~> 0.16) + bigdecimal (3.1.9) + concurrent-ruby (1.3.5) + connection_pool (2.5.0) + console (1.30.0) + fiber-annotation + fiber-local (~> 1.1) + json + falcon (0.51.1) async - async-container (~> 0.16.0) - async-http (~> 0.57) - async-http-cache (~> 0.4.0) - async-io (~> 1.22) - build-environment (~> 1.13) + async-container (~> 0.20) + async-container-supervisor (~> 0.5.0) + async-http (~> 0.75) + async-http-cache (~> 0.4) + async-service (~> 0.10) bundler localhost (~> 1.1) openssl (~> 3.0) - process-metrics (~> 0.2.0) - protocol-rack (~> 0.1) - samovar (~> 2.1) - fiber-local (1.0.0) - io-event (1.1.7) - json (2.6.3) - kgio (2.11.4) - localhost (1.1.10) + protocol-http (~> 0.31) + protocol-rack (~> 0.7) + samovar (~> 2.3) + fiber-annotation (0.2.0) + fiber-local (1.1.0) + fiber-storage + fiber-storage (1.0.0) + io-endpoint (0.15.2) + io-event (1.9.0) + io-stream (0.6.1) + iodine (0.7.58) + itsi (0.2.18) + itsi-scheduler (~> 0.2.18) + itsi-server (~> 0.2.18) + itsi-scheduler (0.2.18) + rb_sys (~> 0.9.91) + itsi-server (0.2.18) + json (~> 2) + prism (~> 1.4) + rack (>= 1.6) + rb_sys (~> 0.9.91) + json (2.13.2) + language_server-protocol (3.17.0.4) + lint_roller (1.1.0) + localhost (1.3.1) + logger (1.6.6) mapping (1.1.1) - nio4r (2.5.9) - oj (3.14.2) - openssl (3.1.0) - parallel (1.23.0) - parser (3.2.2.1) + memory-leak (0.5.2) + metrics (0.12.2) + nio4r (2.7.4) + openssl (3.3.0) + parallel (1.26.3) + parser (3.3.7.1) ast (~> 2.4.1) - pg (1.5.3) - process-metrics (0.2.1) - console (~> 1.8) - samovar (~> 2.1) - protocol-hpack (1.4.2) - protocol-http (0.24.7) - protocol-http1 (0.15.1) + racc + passenger (6.1.0) + 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) + pitchfork (0.17.0) + logger + rack (>= 2.0) + prism (1.4.0) + protocol-hpack (1.5.1) + protocol-http (0.54.0) + protocol-http1 (0.35.2) protocol-http (~> 0.22) - protocol-http2 (0.15.1) + protocol-http2 (0.22.1) protocol-hpack (~> 1.4) - protocol-http (~> 0.18) - protocol-rack (0.2.4) - protocol-http (~> 0.23) + protocol-http (~> 0.47) + protocol-rack (0.11.2) + protocol-http (~> 0.43) rack (>= 1.0) - puma (6.3.1) + puma (7.1.0) nio4r (~> 2.0) - rack (3.0.7) - rack-test (2.1.0) + racc (1.8.1) + rack (3.2.2) + rack-test (2.2.0) rack (>= 1.3) + rackup (2.2.1) + rack (>= 3) rainbow (3.1.1) - raindrops (0.20.1) - regexp_parser (2.8.0) - rexml (3.2.5) - rubocop (1.51.0) + rake (13.3.0) + rake-compiler-dock (1.9.1) + rb_sys (0.9.117) + rake-compiler-dock (= 1.9.1) + regexp_parser (2.10.0) + rubocop (1.73.2) json (~> 2.3) + language_server-protocol (~> 3.17.0.2) + lint_roller (~> 1.1.0) parallel (~> 1.10) - parser (>= 3.2.0.0) + parser (>= 3.3.0.2) rainbow (>= 2.2.2, < 4.0) - regexp_parser (>= 1.8, < 3.0) - rexml (>= 3.2.5, < 4.0) - rubocop-ast (>= 1.28.0, < 2.0) + regexp_parser (>= 2.9.3, < 3.0) + rubocop-ast (>= 1.38.0, < 2.0) ruby-progressbar (~> 1.7) - unicode-display_width (>= 2.4.0, < 3.0) - rubocop-ast (1.28.1) - parser (>= 3.2.1.0) + unicode-display_width (>= 2.4.0, < 4.0) + rubocop-ast (1.38.1) + parser (>= 3.3.1.0) ruby-progressbar (1.13.0) - samovar (2.1.4) + samovar (2.3.0) console (~> 1.0) mapping (~> 1.0) - sequel (5.68.0) + sequel (5.90.0) + bigdecimal sequel_pg (1.17.1) pg (>= 0.18.0, != 1.2.0) sequel (>= 4.38.0) - timers (4.3.5) - traces (0.9.1) + traces (0.15.2) tzinfo (2.0.6) concurrent-ruby (~> 1.0) tzinfo-data (1.2023.3) tzinfo (>= 1.0.0) - unicode-display_width (2.4.2) - unicorn (6.1.0) - kgio (~> 2.6) - raindrops (~> 0.7) + unicode-display_width (3.1.4) + unicode-emoji (~> 4.0, >= 4.0.4) + unicode-emoji (4.0.4) PLATFORMS - x86_64-darwin-20 + arm64-darwin-24 + x86_64-darwin-23 x86_64-linux DEPENDENCIES connection_pool (~> 2.4) - falcon (~> 0.42) + falcon (~> 0.47) + iodine (~> 0.7) + itsi jdbc-postgres (~> 42.2) - json (~> 2.6) - oj (~> 3.14) + json (~> 2.10) + logger + passenger (~> 6.1) pg (~> 1.5) - puma (~> 6.3) + pitchfork (~> 0.17) + puma (~> 7.1) rack (~> 3.0) rack-test rubocop sequel sequel_pg tzinfo-data (= 1.2023.3) - unicorn (~> 6.1) BUNDLED WITH - 2.4.10 + 2.7.0 diff --git a/frameworks/Ruby/rack/README.md b/frameworks/Ruby/rack/README.md index 7bc67727fba..4dd0a7d3954 100644 --- a/frameworks/Ruby/rack/README.md +++ b/frameworks/Ruby/rack/README.md @@ -11,14 +11,16 @@ comparing a variety of web servers. ## Infrastructure Software Versions The tests were run with: -* [Ruby 3.2](http://www.ruby-lang.org/) +* [Ruby 3.4](http://www.ruby-lang.org/) * [JRuby 9.4](http://jruby.org/) -* [Rack 3.0.7](http://rack.github.com/) -* [Unicorn 6.1.0](http://unicorn.bogomips.org/) -* [Puma 6.2.1](http://puma.io/) -* [Falcon 0.42.3](https://github.com/socketry/falcon) -* [Sequel 5.68.0](https://sequel.jeremyevans.net/) - +* [Rack 3](http://rack.github.com/) +* [Falcon](https://github.com/socketry/falcon) +* [Iodine](https://github.com/boazsegev/iodine) +* [Itsi](https://github.com/wouterken/itsi) +* [Passenger](https://github.com/phusion/passenger) +* [Pitchfork](https://github.com/Shopify/pitchfork) +* [Puma](http://puma.io/) +* [Sequel 5](https://sequel.jeremyevans.net/) ## Paths & Source for Tests diff --git a/frameworks/Ruby/rack/benchmark_config.json b/frameworks/Ruby/rack/benchmark_config.json index 8e2f5884387..031e00dc5e9 100644 --- a/frameworks/Ruby/rack/benchmark_config.json +++ b/frameworks/Ruby/rack/benchmark_config.json @@ -10,8 +10,8 @@ "fortune_url": "/fortunes", "update_url": "/updates?queries=", "port": 8080, - "approach": "Stripped", - "classification": "Micro", + "approach": "Realistic", + "classification": "Platform", "orm": "raw", "database": "Postgres", "framework": "rack", @@ -20,10 +20,10 @@ "webserver": "Puma", "os": "Linux", "database_os": "Linux", - "display_name": "rack-puma-mri-sequel-raw", + "display_name": "rack [puma]", "notes": "" }, - "unicorn": { + "iodine": { "json_url": "/json", "plaintext_url": "/plaintext", "db_url": "/db", @@ -31,17 +31,17 @@ "fortune_url": "/fortunes", "update_url": "/updates?queries=", "port": 8080, - "approach": "Stripped", - "classification": "Micro", + "approach": "Realistic", + "classification": "Platform", "orm": "raw", "database": "Postgres", "framework": "rack", "language": "Ruby", "platform": "Mri", - "webserver": "Unicorn", + "webserver": "Iodine", "os": "Linux", "database_os": "Linux", - "display_name": "rack-unicorn-mri-sequel-raw", + "display_name": "rack [iodine]", "notes": "" }, "falcon": { @@ -52,8 +52,8 @@ "fortune_url": "/fortunes", "update_url": "/updates?queries=", "port": 8080, - "approach": "Stripped", - "classification": "Micro", + "approach": "Realistic", + "classification": "Platform", "orm": "raw", "database": "Postgres", "framework": "rack", @@ -62,7 +62,28 @@ "webserver": "Falcon", "os": "Linux", "database_os": "Linux", - "display_name": "rack-falcon-mri-sequel-raw", + "display_name": "rack [falcon]", + "notes": "" + }, + "itsi": { + "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": "Itsi", + "os": "Linux", + "database_os": "Linux", + "display_name": "rack [itsi]", "notes": "" }, "jruby": { @@ -73,8 +94,8 @@ "fortune_url": "/fortunes", "update_url": "/updates?queries=", "port": 8080, - "approach": "Stripped", - "classification": "Micro", + "approach": "Realistic", + "classification": "Platform", "orm": "raw", "database": "Postgres", "framework": "rack", @@ -83,7 +104,49 @@ "webserver": "Puma", "os": "Linux", "database_os": "Linux", - "display_name": "rack-puma-jruby-sequel-raw", + "display_name": "rack [jruby, puma]", + "notes": "" + }, + "passenger": { + "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": "Passenger", + "os": "Linux", + "database_os": "Linux", + "display_name": "rack [passenger]", + "notes": "" + }, + "pitchfork": { + "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 [pitchfork]", "notes": "" } } diff --git a/frameworks/Ruby/rack/config/auto_tune.rb b/frameworks/Ruby/rack/config/auto_tune.rb old mode 100755 new mode 100644 index 476ed1a45bd..1e075f56911 --- a/frameworks/Ruby/rack/config/auto_tune.rb +++ b/frameworks/Ruby/rack/config/auto_tune.rb @@ -7,7 +7,7 @@ # 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) +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 diff --git a/frameworks/Ruby/rack/config/itsi.rb b/frameworks/Ruby/rack/config/itsi.rb new file mode 100644 index 00000000000..d0dd0992dc1 --- /dev/null +++ b/frameworks/Ruby/rack/config/itsi.rb @@ -0,0 +1,13 @@ +require_relative 'auto_tune' + +rackup_file './config.ru' + +ruby_thread_request_backlog_size 10_000 + +preload false + +num_workers, num_threads = auto_tune + +workers num_workers +threads num_threads +fiber_scheduler false diff --git a/frameworks/Ruby/rack-sequel/config/java_tune.sh b/frameworks/Ruby/rack/config/java_tune.sh similarity index 100% rename from frameworks/Ruby/rack-sequel/config/java_tune.sh rename to frameworks/Ruby/rack/config/java_tune.sh diff --git a/frameworks/Ruby/padrino/config/nginx.conf b/frameworks/Ruby/rack/config/nginx.conf similarity index 100% rename from frameworks/Ruby/padrino/config/nginx.conf rename to frameworks/Ruby/rack/config/nginx.conf diff --git a/frameworks/Ruby/rack/config/pitchfork.rb b/frameworks/Ruby/rack/config/pitchfork.rb new file mode 100644 index 00000000000..9cf3d92dfbe --- /dev/null +++ b/frameworks/Ruby/rack/config/pitchfork.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require_relative 'auto_tune' +require 'sequel' +num_workers, = auto_tune + +worker_processes num_workers + +before_fork do |_server| + Sequel::DATABASES.each(&:disconnect) +end + +listen "/tmp/.sock", :backlog => 4096 diff --git a/frameworks/Ruby/rack/config/puma.rb b/frameworks/Ruby/rack/config/puma.rb index 83118c34761..5f6c878f757 100644 --- a/frameworks/Ruby/rack/config/puma.rb +++ b/frameworks/Ruby/rack/config/puma.rb @@ -1,32 +1,17 @@ -# frozen_string_literal: true - require_relative 'auto_tune' -require 'etc' -require 'sequel' # FWBM only... use the puma_auto_tune gem in production! num_workers, num_threads = auto_tune - -before_fork do - Sequel::DATABASES.each(&:disconnect) -end - if RUBY_PLATFORM == 'java' num_threads = 512 num_workers = 0 end -workers num_workers -threads num_threads, num_threads - # Use the `preload_app!` method when specifying a `workers` number. - # This directive tells Puma to first boot the application and load code - # before forking the application. This takes advantage of Copy On Write - # process behavior so workers use less memory. - # - preload_app! - - - - +threads num_threads +if num_workers > 0 + before_fork do + Sequel::DATABASES.each(&:disconnect) + end +end diff --git a/frameworks/Ruby/rack/config/unicorn.rb b/frameworks/Ruby/rack/config/unicorn.rb deleted file mode 100644 index ecfc229e586..00000000000 --- a/frameworks/Ruby/rack/config/unicorn.rb +++ /dev/null @@ -1,11 +0,0 @@ -# frozen_string_literal: true - -require_relative 'auto_tune' -require 'sequel' -num_workers, = auto_tune - -worker_processes num_workers - -before_fork do |_server, _worker| - Sequel::DATABASES.each(&:disconnect) -end diff --git a/frameworks/Ruby/rack/falcon.rb b/frameworks/Ruby/rack/falcon.rb old mode 100755 new mode 100644 diff --git a/frameworks/Ruby/rack/hello_world.rb b/frameworks/Ruby/rack/hello_world.rb index d6886797fc0..2a806461fa2 100644 --- a/frameworks/Ruby/rack/hello_world.rb +++ b/frameworks/Ruby/rack/hello_world.rb @@ -5,13 +5,12 @@ require_relative 'pg_db' require_relative 'config/auto_tune' require 'rack' +require 'json' +require 'erb' if RUBY_PLATFORM == 'java' - require 'json' DEFAULT_DATABASE_URL = 'jdbc:postgresql://tfb-database/hello_world?user=benchmarkdbuser&password=benchmarkdbpass' else - require 'oj' - Oj.mimic_JSON DEFAULT_DATABASE_URL = 'postgresql://tfb-database/hello_world?user=benchmarkdbuser&password=benchmarkdbpass' end @@ -27,17 +26,7 @@ class HelloWorld PLAINTEXT_TYPE = 'text/plain' DATE = 'Date' SERVER = 'Server' - SERVER_STRING = if defined?(PhusionPassenger) - 'Passenger' - elsif defined?(Puma) - Puma::Const::PUMA_SERVER_STRING - elsif defined?(Unicorn) - 'Unicorn' - elsif defined?(Falcon) - 'Falcon' - else - ' Ruby Rack' - end + SERVER_STRING = 'Rack' TEMPLATE_PREFIX = ' @@ -54,24 +43,18 @@ class HelloWorld ' def initialize - # auto_tune - max_connections = 512 + if defined?(Puma) && (threads = Puma.cli_config.options.fetch(:max_threads)) > 1 + max_connections = 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 respond(content_type, body = '') - [ - 200, - { - CONTENT_TYPE => content_type, - DATE => Time.now.utc.httpdate, - SERVER => SERVER_STRING, - CONTENT_LENGTH => body.bytesize.to_s - }, - [body] - ] - end - def fortunes fortunes = @db.select_fortunes fortunes << { id: 0, message: 'Additional fortune added at request time.' } @@ -80,7 +63,7 @@ def fortunes buffer << TEMPLATE_PREFIX fortunes.each do |item| - buffer << "#{item[:id]}#{Rack::Utils.escape_html(item[:message])}" + buffer << "#{item[:id]}#{ERB::Escape.html_escape(item[:message])}" end buffer << TEMPLATE_POSTFIX end @@ -112,4 +95,31 @@ def call(env) respond PLAINTEXT_TYPE, 'Hello, World!' end end + + private + + def respond(content_type, body) + [ + 200, + headers(content_type, body), + [body] + ] + end + + if defined?(Falcon) || defined?(Puma) + def headers(content_type, _) + { + CONTENT_TYPE => content_type, + SERVER => SERVER_STRING, + DATE => Time.now.utc.httpdate + } + end + else + def headers(content_type, _) + { + CONTENT_TYPE => content_type, + SERVER => SERVER_STRING + } + end + end end diff --git a/frameworks/Ruby/rack/pg_db.rb b/frameworks/Ruby/rack/pg_db.rb index deeb149f0ad..51a38cadc85 100644 --- a/frameworks/Ruby/rack/pg_db.rb +++ b/frameworks/Ruby/rack/pg_db.rb @@ -18,12 +18,8 @@ class PgDb attr_reader :connection def initialize(connection_string = nil, max_connections = 512) - @connection = Sequel.connect(connection_string, max_connections: max_connections, sql_log_level: :warning) - if defined?(Falcon) - Sequel.extension :fiber_concurrency if defined?(Falcon) - else - @connection.extension :async_thread_pool - end + @connection = Sequel.connect(connection_string, max_connections: max_connections) + Sequel.extension :fiber_concurrency if defined?(Falcon) prepare_statements end @@ -32,65 +28,41 @@ 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 - @world_select.call(id: random_id)[0] + select_world(random_id) end def select_world(id) - @world_select.call(id: id)[0] + @world_select.call(id: id).first end def validate_count(count) count = count.to_i - if count < MIN_QUERIES - MIN_QUERIES - elsif count > MAX_QUERIES - MAX_QUERIES - else - count - end + count.clamp(MIN_QUERIES, MAX_QUERIES) end def select_promises(count) count = validate_count(count) - promises = [] - count.times do + ALL_IDS.sample(count).map do |id| @connection.synchronize do - promises << @connection['SELECT id, randomNumber FROM World WHERE id = ?', random_id].async.first + @connection['SELECT id, randomNumber FROM World WHERE id = ?', id].async.first end end - promises - end - - def select_random_numbers(count) - count = validate_count(count) - results = [] - count.times do - results << @world_random_select.call(randomvalue: random_id, id: random_id)[0] - end - results end def select_worlds(count) count = validate_count(count) - results = [] - count.times do - results << @world_select.call(id: random_id)[0] + ALL_IDS.sample(count).map do |id| + @world_select.call(id: id).first end - results end def select_worlds_async(count) promises = select_promises(count) - results = [] - promises.each do |p| - results << p.to_hash - end - results + promises.map(&:to_hash) end def update_worlds(count, async = false) @@ -99,8 +71,7 @@ def update_worlds(count, async = false) else select_worlds(count) end - #values = [] - ids=[] + ids = [] sql = String.new("UPDATE world SET randomnumber = CASE id ") results.each do |r| r[:randomnumber] = random_id @@ -111,6 +82,7 @@ def update_worlds(count, async = false) @connection[sql].update results end + def select_fortunes @fortune_select.call end diff --git a/frameworks/Ruby/rack/rack-falcon.dockerfile b/frameworks/Ruby/rack/rack-falcon.dockerfile index b8e5d330cc5..608fb7a39a9 100644 --- a/frameworks/Ruby/rack/rack-falcon.dockerfile +++ b/frameworks/Ruby/rack/rack-falcon.dockerfile @@ -1,13 +1,18 @@ -FROM ruby:3.3-rc +FROM ruby:3.5-rc -ENV BUNDLE_FORCE_RUBY_PLATFORM=true 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 + WORKDIR /rack -COPY Gemfile ./ +COPY Gemfile* ./ -RUN bundle config set without 'development test' +ENV BUNDLE_FORCE_RUBY_PLATFORM=true +RUN bundle config set with 'falcon' RUN bundle install --jobs=8 COPY . . diff --git a/frameworks/Ruby/rack/rack-iodine.dockerfile b/frameworks/Ruby/rack/rack-iodine.dockerfile new file mode 100644 index 00000000000..0c4f7aafc6d --- /dev/null +++ b/frameworks/Ruby/rack/rack-iodine.dockerfile @@ -0,0 +1,22 @@ +FROM ruby:3.5-rc + +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 + +WORKDIR /rack + +COPY Gemfile* ./ + +ENV BUNDLE_FORCE_RUBY_PLATFORM=true +RUN bundle config set with 'iodine' +RUN bundle install --jobs=8 + +COPY . . + +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/rack/rack-itsi.dockerfile b/frameworks/Ruby/rack/rack-itsi.dockerfile new file mode 100644 index 00000000000..952ac7ccdad --- /dev/null +++ b/frameworks/Ruby/rack/rack-itsi.dockerfile @@ -0,0 +1,24 @@ +FROM ruby:3.5-rc + +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 apt-get install -y build-essential libclang-dev + +WORKDIR /rack + +COPY Gemfile* ./ + +ENV BUNDLE_FORCE_RUBY_PLATFORM=true +RUN bundle config set with 'itsi' +RUN bundle install --jobs=8 + +COPY . . + +EXPOSE 8080 + +CMD bundle exec itsi start -C config/itsi.rb --bind "http://tfb-server:8080" diff --git a/frameworks/Ruby/rack/rack-jruby.dockerfile b/frameworks/Ruby/rack/rack-jruby.dockerfile index 7bf4b329af1..062547508ca 100644 --- a/frameworks/Ruby/rack/rack-jruby.dockerfile +++ b/frameworks/Ruby/rack/rack-jruby.dockerfile @@ -1,16 +1,18 @@ -FROM jruby:9.4-jdk17 +FROM jruby:10.0 RUN apt-get update -y && apt-get install netbase -y WORKDIR /rack -COPY Gemfile ./ +COPY Gemfile* ./ -RUN bundle config set without 'development test' +RUN bundle config set with 'puma' RUN bundle install --jobs=8 COPY . . EXPOSE 8080 +CMD config/java_tune.sh + CMD bundle exec puma -C config/puma.rb -b tcp://0.0.0.0:8080 -e production diff --git a/frameworks/Ruby/rack/rack-passenger.dockerfile b/frameworks/Ruby/rack/rack-passenger.dockerfile new file mode 100644 index 00000000000..bde26ea58bc --- /dev/null +++ b/frameworks/Ruby/rack/rack-passenger.dockerfile @@ -0,0 +1,31 @@ +FROM ruby:3.5-rc + +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 + +WORKDIR /rack + +COPY Gemfile* ./ + +ENV BUNDLE_FORCE_RUBY_PLATFORM=true +RUN bundle config set with 'passenger' +RUN bundle install --jobs=8 + +COPY . . + +# TODO: https://github.com/phusion/passenger/issues/1916 +ENV _PASSENGER_FORCE_HTTP_SESSION=true + +RUN ruby config/auto_tune.rb | grep -Eo '[0-9]+' | head -n 1 > instances + +EXPOSE 8080 + +CMD bundle exec passenger start --log-level 1 \ + --engine builtin --disable-turbocaching --disable-security-update-check \ + --spawn-method direct --max-pool-size $(cat instances) --min-instances $(cat instances) --max-request-queue-size 1024 \ + --address 0.0.0.0 --port 8080 --environment production + diff --git a/frameworks/Ruby/rack/rack-pitchfork.dockerfile b/frameworks/Ruby/rack/rack-pitchfork.dockerfile new file mode 100644 index 00000000000..bebaf61bcb4 --- /dev/null +++ b/frameworks/Ruby/rack/rack-pitchfork.dockerfile @@ -0,0 +1,25 @@ +FROM ruby:3.5-rc + +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 apt-get install -yqq nginx + +WORKDIR /rack + +COPY Gemfile* ./ + +ENV BUNDLE_FORCE_RUBY_PLATFORM=true +RUN bundle config set with 'pitchfork' +RUN bundle install --jobs=8 + +COPY . . + +EXPOSE 8080 + +CMD nginx -c /rack/config/nginx.conf && \ + bundle exec pitchfork -c config/pitchfork.rb -E production diff --git a/frameworks/Ruby/rack/rack-unicorn.dockerfile b/frameworks/Ruby/rack/rack-unicorn.dockerfile deleted file mode 100644 index 917295345ae..00000000000 --- a/frameworks/Ruby/rack/rack-unicorn.dockerfile +++ /dev/null @@ -1,21 +0,0 @@ -FROM ruby:3.3-rc - -#RUN apt-get update -yqq && apt-get install -yqq nginx - -ENV BUNDLE_FORCE_RUBY_PLATFORM=true -ENV RUBY_YJIT_ENABLE=1 - -WORKDIR /rack - -COPY Gemfile ./ - -RUN bundle config set without 'development test' -RUN bundle install --jobs=8 - -COPY . . - -EXPOSE 8080 - -#CMD nginx -c /rack/config/nginx.conf && bundle exec unicorn -E production -c config/unicorn.rb - -CMD bundle exec unicorn -c config/unicorn.rb -o 0.0.0.0 -p 8080 -E production diff --git a/frameworks/Ruby/rack/rack.dockerfile b/frameworks/Ruby/rack/rack.dockerfile index 5819b3288ed..ce1c639ea11 100644 --- a/frameworks/Ruby/rack/rack.dockerfile +++ b/frameworks/Ruby/rack/rack.dockerfile @@ -1,18 +1,24 @@ -FROM ruby:3.3-rc +FROM ruby:3.5-rc -ENV BUNDLE_FORCE_RUBY_PLATFORM=true ENV RUBY_YJIT_ENABLE=1 +ENV RUBY_THREAD_TIMESLICE=10 + +# Use Jemalloc +RUN apt-get update && \ + apt-get install -y --no-install-recommends libjemalloc2 +ENV LD_PRELOAD=libjemalloc.so.2 WORKDIR /rack -COPY Gemfile ./ +COPY Gemfile* ./ -RUN bundle config set without 'development test' +ENV BUNDLE_FORCE_RUBY_PLATFORM=true +RUN bundle config set with 'puma' RUN bundle install --jobs=8 COPY . . EXPOSE 8080 +ENV WEB_CONCURRENCY=auto CMD bundle exec puma -C config/puma.rb -b tcp://0.0.0.0:8080 -e production - diff --git a/frameworks/Ruby/rage-sequel/Gemfile b/frameworks/Ruby/rage-sequel/Gemfile new file mode 100644 index 00000000000..c3d6bfb0968 --- /dev/null +++ b/frameworks/Ruby/rage-sequel/Gemfile @@ -0,0 +1,8 @@ +source "https://rubygems.org" + +gem "rage-rb", "~> 1.10" + +gem "pg", "~> 1.0" +gem 'sequel', '~> 5.0' +gem 'sequel_pg', '~> 1.6', platforms: :ruby, require: false +gem 'logger' # required for ruby 3.5 diff --git a/frameworks/Ruby/rage-sequel/Gemfile.lock b/frameworks/Ruby/rage-sequel/Gemfile.lock new file mode 100644 index 00000000000..566a7025400 --- /dev/null +++ b/frameworks/Ruby/rage-sequel/Gemfile.lock @@ -0,0 +1,40 @@ +GEM + remote: https://rubygems.org/ + specs: + bigdecimal (3.3.1) + logger (1.7.0) + pg (1.6.2) + pg (1.6.2-x86_64-darwin) + rack (2.2.20) + rack-test (2.2.0) + rack (>= 1.3) + rage-iodine (4.0.0) + rage-rb (1.11.0) + rack (~> 2.0) + rack-test (~> 2.1) + rage-iodine (~> 4.0) + rake (>= 12.0) + thor (~> 1.0) + zeitwerk (~> 2.6) + rake (13.2.1) + sequel (5.97.0) + bigdecimal + sequel_pg (1.17.2) + pg (>= 0.18.0, != 1.2.0) + sequel (>= 4.38.0) + thor (1.3.2) + zeitwerk (2.7.2) + +PLATFORMS + ruby + x86_64-darwin-20 + +DEPENDENCIES + logger + pg (~> 1.0) + rage-rb (~> 1.10) + sequel (~> 5.0) + sequel_pg (~> 1.6) + +BUNDLED WITH + 2.7.0 diff --git a/frameworks/Ruby/rage-sequel/README.md b/frameworks/Ruby/rage-sequel/README.md new file mode 100755 index 00000000000..d299d0834ba --- /dev/null +++ b/frameworks/Ruby/rage-sequel/README.md @@ -0,0 +1,47 @@ +# Rage Benchmarking Test + +Rage is a fast web framework compatible with Rails. It uses an event-driven architecture and implements a lightweight, cooperative concurrency model based on Ruby Fibers. + +https://github.com/rage-rb/rage + +### Test Type Implementation Source Code + +* [JSON](app/controllers/benchmarks_controller.rb) +* [PLAINTEXT](app/controllers/benchmarks_controller.rb) +* [DB](app/controllers/benchmarks_controller.rb) +* [QUERY](app/controllers/benchmarks_controller.rb) +* [UPDATE](app/controllers/benchmarks_controller.rb) +* [FORTUNES](app/controllers/benchmarks_controller.rb) + +## Important Libraries + +The tests were run with: + +* [Sequel](https://rubygems.org/gems/sequel) +* [PG](https://rubygems.org/gems/pg) + +## Test URLs + +### JSON + +http://localhost:8080/json + +### PLAINTEXT + +http://localhost:8080/plaintext + +### DB + +http://localhost:8080/db + +### QUERY + +http://localhost:8080/queries?queries= + +### UPDATE + +http://localhost:8080/updates?queries= + +### FORTUNES + +http://localhost:8080/fortunes diff --git a/frameworks/Ruby/rage-sequel/Rakefile b/frameworks/Ruby/rage-sequel/Rakefile new file mode 100644 index 00000000000..046f1fcbd8d --- /dev/null +++ b/frameworks/Ruby/rage-sequel/Rakefile @@ -0,0 +1 @@ +require_relative "config/application" diff --git a/frameworks/Ruby/rage-sequel/app/controllers/application_controller.rb b/frameworks/Ruby/rage-sequel/app/controllers/application_controller.rb new file mode 100644 index 00000000000..c3238c52392 --- /dev/null +++ b/frameworks/Ruby/rage-sequel/app/controllers/application_controller.rb @@ -0,0 +1,2 @@ +class ApplicationController < RageController::API +end diff --git a/frameworks/Ruby/rage-sequel/app/controllers/benchmarks_controller.rb b/frameworks/Ruby/rage-sequel/app/controllers/benchmarks_controller.rb new file mode 100644 index 00000000000..4765293093d --- /dev/null +++ b/frameworks/Ruby/rage-sequel/app/controllers/benchmarks_controller.rb @@ -0,0 +1,73 @@ +# frozen_string_literal: true + +class BenchmarksController < ApplicationController + ALL_DB_IDS = (1..10_000).to_a + FORTUNES_TEMPLATE = ERB.new(Rage.root.join("app/views/fortunes.html.erb").read) + + before_action do + headers["server"] = "rage" + end + + def db + render json: World.with_pk(random_id).values + end + + def queries + ids = requested_ids + worlds = DB.synchronize do + ids.map do |id| + World.with_pk(id) + end + end + + render json: worlds.map!(&:values) + end + + def fortunes + records = Fortune.all + + records << Fortune.new(id: 0, message: "Additional fortune added at request time.") + records.sort_by!(&:message) + + render plain: FORTUNES_TEMPLATE.result(binding) + headers["content-type"] = "text/html; charset=utf-8" + end + + def updates + worlds = nil + ids = requested_ids + + DB.synchronize do + worlds = ids.map do |id| + world = World.with_pk(id) + new_value = random_id + new_value = random_id while new_value == world.randomnumber + world.randomnumber = new_value + + world + end + + World.batch_update(worlds) + end + + render json: worlds.map!(&:values) + end + + private + + def requested_ids + num = params[:queries].to_i + + if num > 500 + num = 500 + elsif num < 1 + num = 1 + end + + ALL_DB_IDS.sample(num) + end + + def random_id + Random.rand(9_999) + 1 + end +end diff --git a/frameworks/Ruby/rage-sequel/app/views/fortunes.html.erb b/frameworks/Ruby/rage-sequel/app/views/fortunes.html.erb new file mode 100644 index 00000000000..f524ee8b8a5 --- /dev/null +++ b/frameworks/Ruby/rage-sequel/app/views/fortunes.html.erb @@ -0,0 +1,12 @@ + + + Fortunes + + + + <% records.each do |record| %> + + <% end %> +
idmessage
<%= record.id %><%= ERB::Escape.html_escape(record.message) %>
+ + diff --git a/frameworks/Ruby/rage-sequel/benchmark_config.json b/frameworks/Ruby/rage-sequel/benchmark_config.json new file mode 100755 index 00000000000..4cbe6d248f4 --- /dev/null +++ b/frameworks/Ruby/rage-sequel/benchmark_config.json @@ -0,0 +1,28 @@ +{ + "framework": "rage-sequel", + "tests": [ + { + "default": { + "db_url": "/db", + "query_url": "/queries?queries=", + "fortune_url": "/fortunes", + "update_url": "/updates?queries=", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "postgres", + "framework": "Rage", + "language": "Ruby", + "flavor": "None", + "orm": "Full", + "platform": "Rack", + "webserver": "Rage-Iodine", + "os": "Linux", + "database_os": "Linux", + "display_name": "Rage-Sequel", + "notes": "", + "versus": "None" + } + } + ] +} diff --git a/frameworks/Ruby/rage-sequel/config.ru b/frameworks/Ruby/rage-sequel/config.ru new file mode 100644 index 00000000000..049a1ad509d --- /dev/null +++ b/frameworks/Ruby/rage-sequel/config.ru @@ -0,0 +1,3 @@ +require_relative "config/application" + +run Rage.application diff --git a/frameworks/Ruby/rage-sequel/config/application.rb b/frameworks/Ruby/rage-sequel/config/application.rb new file mode 100644 index 00000000000..9af142340b3 --- /dev/null +++ b/frameworks/Ruby/rage-sequel/config/application.rb @@ -0,0 +1,14 @@ +require "bundler/setup" +require "rage" +Bundler.require(*Rage.groups) + +require "rage/all" + +Rage.configure do + # use this to add settings that are constant across all environments +end + +require "erb" +require "cgi" + +require "rage/setup" diff --git a/frameworks/Ruby/rage-sequel/config/environments/development.rb b/frameworks/Ruby/rage-sequel/config/environments/development.rb new file mode 100644 index 00000000000..35d9e7ae7d6 --- /dev/null +++ b/frameworks/Ruby/rage-sequel/config/environments/development.rb @@ -0,0 +1,4 @@ +Rage.configure do + config.server.workers_count = -1 + config.logger = Rage::Logger.new(STDOUT) +end diff --git a/frameworks/Ruby/rage-sequel/config/environments/production.rb b/frameworks/Ruby/rage-sequel/config/environments/production.rb new file mode 100644 index 00000000000..0189c7742fa --- /dev/null +++ b/frameworks/Ruby/rage-sequel/config/environments/production.rb @@ -0,0 +1,3 @@ +Rage.configure do + config.logger = nil +end diff --git a/frameworks/Ruby/rage-sequel/config/initializers/sequel.rb b/frameworks/Ruby/rage-sequel/config/initializers/sequel.rb new file mode 100644 index 00000000000..273694b7b15 --- /dev/null +++ b/frameworks/Ruby/rage-sequel/config/initializers/sequel.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +SEQUEL_NO_ASSOCIATIONS = true +Sequel.extension :fiber_concurrency + +# Determine thread pool size and timeout +opts = { + max_connections: 512, + pool_timeout: 10 +} + +DB = Sequel.connect \ + '%{adapter}://%{host}/%{database}?user=%{user}&password=%{password}' % { + :adapter=>'postgres', + :host=>'tfb-database', + :database=>'hello_world', + :user=>'benchmarkdbuser', + :password=>'benchmarkdbpass' + }, opts + +# Define ORM models +class World < Sequel::Model(:World) + 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/rage-sequel/config/routes.rb b/frameworks/Ruby/rage-sequel/config/routes.rb new file mode 100644 index 00000000000..c03b04a7f52 --- /dev/null +++ b/frameworks/Ruby/rage-sequel/config/routes.rb @@ -0,0 +1,8 @@ +Rage.routes.draw do + root to: ->(env) { [200, {}, "It works!"] } + + get "db", to: "benchmarks#db" + get "queries", to: "benchmarks#queries" + get "fortunes", to: "benchmarks#fortunes" + get "updates", to: "benchmarks#updates" +end diff --git a/frameworks/Python/crax/hello/__init__.py b/frameworks/Ruby/rage-sequel/lib/.keep similarity index 100% rename from frameworks/Python/crax/hello/__init__.py rename to frameworks/Ruby/rage-sequel/lib/.keep diff --git a/frameworks/Ruby/rage-sequel/rage-sequel.dockerfile b/frameworks/Ruby/rage-sequel/rage-sequel.dockerfile new file mode 100644 index 00000000000..41bfd349920 --- /dev/null +++ b/frameworks/Ruby/rage-sequel/rage-sequel.dockerfile @@ -0,0 +1,13 @@ +FROM ruby:3.5-rc + +EXPOSE 8080 +WORKDIR /rage-sequel + +COPY Gemfile* /rage-sequel/ +RUN bundle install --jobs=8 +COPY . /rage-sequel + +ENV RUBY_YJIT_ENABLE=1 +ENV BUNDLE_FORCE_RUBY_PLATFORM=true + +CMD bundle exec rage s -b 0.0.0.0 -p 8080 -e production diff --git a/frameworks/Ruby/rage/Gemfile b/frameworks/Ruby/rage/Gemfile new file mode 100644 index 00000000000..ad9ccba5aa8 --- /dev/null +++ b/frameworks/Ruby/rage/Gemfile @@ -0,0 +1,13 @@ +source "https://rubygems.org" + +gem "rage-rb", "~> 1.10" + +gem "pg", "~> 1.0" +gem "activerecord", "~> 8.0.0", require: "active_record" + +# Build JSON APIs with ease +# gem "alba" + +# Get 50% to 150% boost when parsing JSON. +# Rage will automatically use FastJsonparser if it is available. +# gem "fast_jsonparser" diff --git a/frameworks/Ruby/rage/Gemfile.lock b/frameworks/Ruby/rage/Gemfile.lock new file mode 100644 index 00000000000..d5d524b3192 --- /dev/null +++ b/frameworks/Ruby/rage/Gemfile.lock @@ -0,0 +1,65 @@ +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) + timeout (>= 0.4.0) + activesupport (8.0.2) + base64 + benchmark (>= 0.3) + bigdecimal + concurrent-ruby (~> 1.0, >= 1.3.1) + connection_pool (>= 2.2.5) + drb + i18n (>= 1.6, < 2) + 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) + concurrent-ruby (~> 1.0) + logger (1.7.0) + minitest (5.25.5) + pg (1.6.2) + pg (1.6.2-x86_64-darwin) + rack (2.2.18) + rack-test (2.2.0) + rack (>= 1.3) + rage-iodine (4.0.0) + rage-rb (1.11.0) + rack (~> 2.0) + rack-test (~> 2.1) + rage-iodine (~> 4.0) + rake (>= 12.0) + thor (~> 1.0) + zeitwerk (~> 2.6) + rake (13.2.1) + securerandom (0.4.1) + thor (1.3.2) + timeout (0.4.3) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) + uri (1.0.3) + zeitwerk (2.7.1) + +PLATFORMS + ruby + x86_64-darwin-23 + +DEPENDENCIES + activerecord (~> 8.0.0) + pg (~> 1.0) + rage-rb (~> 1.10) + +BUNDLED WITH + 2.7.0 diff --git a/frameworks/Ruby/rage/README.md b/frameworks/Ruby/rage/README.md new file mode 100755 index 00000000000..05e005bd363 --- /dev/null +++ b/frameworks/Ruby/rage/README.md @@ -0,0 +1,47 @@ +# Rage Benchmarking Test + +Rage is a fast web framework compatible with Rails. It uses an event-driven architecture and implements a lightweight, cooperative concurrency model based on Ruby Fibers. + +https://github.com/rage-rb/rage + +### Test Type Implementation Source Code + +* [JSON](app/controllers/benchmarks_controller.rb) +* [PLAINTEXT](app/controllers/benchmarks_controller.rb) +* [DB](app/controllers/benchmarks_controller.rb) +* [QUERY](app/controllers/benchmarks_controller.rb) +* [UPDATE](app/controllers/benchmarks_controller.rb) +* [FORTUNES](app/controllers/benchmarks_controller.rb) + +## Important Libraries + +The tests were run with: + +* [ActiveRecord](https://rubygems.org/gems/activerecord) +* [PG](https://rubygems.org/gems/pg) + +## Test URLs + +### JSON + +http://localhost:8080/json + +### PLAINTEXT + +http://localhost:8080/plaintext + +### DB + +http://localhost:8080/db + +### QUERY + +http://localhost:8080/queries?queries= + +### UPDATE + +http://localhost:8080/updates?queries= + +### FORTUNES + +http://localhost:8080/fortunes diff --git a/frameworks/Ruby/rage/Rakefile b/frameworks/Ruby/rage/Rakefile new file mode 100644 index 00000000000..046f1fcbd8d --- /dev/null +++ b/frameworks/Ruby/rage/Rakefile @@ -0,0 +1 @@ +require_relative "config/application" diff --git a/frameworks/Ruby/rage/app/controllers/application_controller.rb b/frameworks/Ruby/rage/app/controllers/application_controller.rb new file mode 100644 index 00000000000..c3238c52392 --- /dev/null +++ b/frameworks/Ruby/rage/app/controllers/application_controller.rb @@ -0,0 +1,2 @@ +class ApplicationController < RageController::API +end diff --git a/frameworks/Ruby/rage/app/controllers/benchmarks_controller.rb b/frameworks/Ruby/rage/app/controllers/benchmarks_controller.rb new file mode 100644 index 00000000000..884356e58c1 --- /dev/null +++ b/frameworks/Ruby/rage/app/controllers/benchmarks_controller.rb @@ -0,0 +1,77 @@ +# frozen_string_literal: true + +class BenchmarksController < ApplicationController + ALL_DB_IDS = (1..10_000).to_a + FORTUNES_TEMPLATE = ERB.new(Rage.root.join("app/views/fortunes.html.erb").read) + + before_action do + headers["server"] = "rage" + end + + def json + render json: { message: "Hello, World!" } + end + + def plaintext + render plain: "Hello, World!" + end + + def db + render json: World.find(random_id) + end + + def queries + records = requested_ids.map do |id| + World.find(id) + end + + render json: records + end + + def fortunes + records = Fortune.pluck(:id, :message).map! { |id, message| { id:, message: } } + + records << Fortune.new(id: 0, message: "Additional fortune added at request time.") + records.sort_by! { |record| record[:message] } + + render plain: FORTUNES_TEMPLATE.result(binding) + headers["content-type"] = "text/html; charset=utf-8" + end + + def updates + records = requested_ids.map do |id| + World.find(id) + end + + updates = records.map do |record| + new_value = random_id + new_value = random_id until new_value != record.randomNumber + + record.randomNumber = new_value + + { id: record.id, randomnumber: new_value } + end + + World.upsert_all(updates.sort_by! { |u| u[:id] }) + + render json: records + end + + private + + def requested_ids + num = params[:queries].to_i + + if num > 500 + num = 500 + elsif num < 1 + num = 1 + end + + ALL_DB_IDS.sample(num) + end + + def random_id + Random.rand(9_999) + 1 + end +end diff --git a/frameworks/Ruby/rage/app/models/application_record.rb b/frameworks/Ruby/rage/app/models/application_record.rb new file mode 100644 index 00000000000..b63caeb8a5c --- /dev/null +++ b/frameworks/Ruby/rage/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/frameworks/Ruby/rage/app/models/fortune.rb b/frameworks/Ruby/rage/app/models/fortune.rb new file mode 100644 index 00000000000..0080d6363c4 --- /dev/null +++ b/frameworks/Ruby/rage/app/models/fortune.rb @@ -0,0 +1,3 @@ +class Fortune < ApplicationRecord + self.table_name = "Fortune" +end diff --git a/frameworks/Ruby/rage/app/models/world.rb b/frameworks/Ruby/rage/app/models/world.rb new file mode 100644 index 00000000000..836783137c6 --- /dev/null +++ b/frameworks/Ruby/rage/app/models/world.rb @@ -0,0 +1,5 @@ +class World < ApplicationRecord + self.table_name = "World" + + alias_attribute(:randomNumber, :randomnumber) +end diff --git a/frameworks/Ruby/rage/app/views/fortunes.html.erb b/frameworks/Ruby/rage/app/views/fortunes.html.erb new file mode 100644 index 00000000000..565e143803b --- /dev/null +++ b/frameworks/Ruby/rage/app/views/fortunes.html.erb @@ -0,0 +1,12 @@ + + + Fortunes + + + + <% records.each do |record| %> + + <% end %> +
idmessage
<%= record[:id] %><%= ERB::Escape.html_escape(record[:message]) %>
+ + diff --git a/frameworks/Ruby/rage/benchmark_config.json b/frameworks/Ruby/rage/benchmark_config.json new file mode 100755 index 00000000000..04d51d3ca3b --- /dev/null +++ b/frameworks/Ruby/rage/benchmark_config.json @@ -0,0 +1,30 @@ +{ + "framework": "rage", + "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": "Micro", + "database": "postgres", + "framework": "Rage", + "language": "Ruby", + "flavor": "None", + "orm": "Full", + "platform": "Rack", + "webserver": "Rage-Iodine", + "os": "Linux", + "database_os": "Linux", + "display_name": "Rage", + "notes": "", + "versus": "None" + } + } + ] +} diff --git a/frameworks/Ruby/rage/config.ru b/frameworks/Ruby/rage/config.ru new file mode 100644 index 00000000000..049a1ad509d --- /dev/null +++ b/frameworks/Ruby/rage/config.ru @@ -0,0 +1,3 @@ +require_relative "config/application" + +run Rage.application diff --git a/frameworks/Ruby/rage/config/application.rb b/frameworks/Ruby/rage/config/application.rb new file mode 100644 index 00000000000..9af142340b3 --- /dev/null +++ b/frameworks/Ruby/rage/config/application.rb @@ -0,0 +1,14 @@ +require "bundler/setup" +require "rage" +Bundler.require(*Rage.groups) + +require "rage/all" + +Rage.configure do + # use this to add settings that are constant across all environments +end + +require "erb" +require "cgi" + +require "rage/setup" diff --git a/frameworks/Ruby/rage/config/environments/development.rb b/frameworks/Ruby/rage/config/environments/development.rb new file mode 100644 index 00000000000..ba6e1d01423 --- /dev/null +++ b/frameworks/Ruby/rage/config/environments/development.rb @@ -0,0 +1,4 @@ +Rage.configure do + config.server.workers_count = -1 + config.logger = ActiveRecord::Base.logger = Rage::Logger.new(STDOUT) +end diff --git a/frameworks/Ruby/rage/config/environments/production.rb b/frameworks/Ruby/rage/config/environments/production.rb new file mode 100644 index 00000000000..0189c7742fa --- /dev/null +++ b/frameworks/Ruby/rage/config/environments/production.rb @@ -0,0 +1,3 @@ +Rage.configure do + config.logger = nil +end diff --git a/frameworks/Ruby/rage/config/initializers/activerecord.rb b/frameworks/Ruby/rage/config/initializers/activerecord.rb new file mode 100644 index 00000000000..34a3b019a66 --- /dev/null +++ b/frameworks/Ruby/rage/config/initializers/activerecord.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +require "etc" + +pool_size = (2 * Math.log(256 / Etc.nprocessors)).floor +puts "ActiveRecord pool size: #{pool_size}" + +ENV["DATABASE_URL"]="postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world?pool=#{pool_size}&reaping_frequency=0" diff --git a/frameworks/Ruby/rage/config/routes.rb b/frameworks/Ruby/rage/config/routes.rb new file mode 100644 index 00000000000..98def92a7e7 --- /dev/null +++ b/frameworks/Ruby/rage/config/routes.rb @@ -0,0 +1,10 @@ +Rage.routes.draw do + root to: ->(env) { [200, {}, "It works!"] } + + get "json", to: "benchmarks#json" + get "plaintext", to: "benchmarks#plaintext" + get "db", to: "benchmarks#db" + get "queries", to: "benchmarks#queries" + get "fortunes", to: "benchmarks#fortunes" + get "updates", to: "benchmarks#updates" +end diff --git a/frameworks/Python/hug/README.md b/frameworks/Ruby/rage/lib/.keep similarity index 100% rename from frameworks/Python/hug/README.md rename to frameworks/Ruby/rage/lib/.keep diff --git a/frameworks/Ruby/rage/rage.dockerfile b/frameworks/Ruby/rage/rage.dockerfile new file mode 100644 index 00000000000..e73bb58f8c9 --- /dev/null +++ b/frameworks/Ruby/rage/rage.dockerfile @@ -0,0 +1,13 @@ +FROM ruby:3.5-rc + +EXPOSE 8080 +WORKDIR /rage + +COPY Gemfile* /rage/ +RUN bundle install --jobs=8 +COPY . /rage + +ENV RUBY_YJIT_ENABLE=1 +ENV BUNDLE_FORCE_RUBY_PLATFORM=true + +CMD bundle exec rage s -b 0.0.0.0 -p 8080 -e production diff --git a/frameworks/Ruby/rails/.ruby-version b/frameworks/Ruby/rails/.ruby-version index fd2a01863fd..15a27998172 100644 --- a/frameworks/Ruby/rails/.ruby-version +++ b/frameworks/Ruby/rails/.ruby-version @@ -1 +1 @@ -3.1.0 +3.3.0 diff --git a/frameworks/Ruby/rails/Gemfile b/frameworks/Ruby/rails/Gemfile index 04b3343f6c4..ec48c009fcb 100644 --- a/frameworks/Ruby/rails/Gemfile +++ b/frameworks/Ruby/rails/Gemfile @@ -1,11 +1,29 @@ -ruby '~> 3.2' - source 'https://rubygems.org' -gem 'trilogy', group: :mysql -gem 'oj', '~> 3.16' -gem 'pg', '1.5.4', group: :postgresql -gem 'puma', '~> 6.4' -gem 'rails', '~> 7.1.0' +gem 'rails', '~> 8.1.0' gem 'redis', '~> 5.0' gem 'tzinfo-data' + +group :mysql, optional: true do + gem 'trilogy', '~> 2.8.1' +end + +group :postgresql, optional: true do + gem 'pg', '~> 1.5' +end + +group :iodine, optional: true do + gem 'iodine', '~> 0.7', require: false +end + +group :falcon, optional: true do + gem 'falcon', '~> 0.47', require: false +end + +group :puma, optional: true do + gem 'puma', '~> 7.1', require: false +end + +group :pitchfork, optional: true do + gem 'pitchfork', '~> 0.17' +end diff --git a/frameworks/Ruby/rails/Gemfile.lock b/frameworks/Ruby/rails/Gemfile.lock index b14e081c818..5b86a8d2e48 100644 --- a/frameworks/Ruby/rails/Gemfile.lock +++ b/frameworks/Ruby/rails/Gemfile.lock @@ -1,211 +1,318 @@ GEM remote: https://rubygems.org/ specs: - actioncable (7.1.0) - actionpack (= 7.1.0) - activesupport (= 7.1.0) + action_text-trix (2.1.15) + railties + actioncable (8.1.0) + actionpack (= 8.1.0) + activesupport (= 8.1.0) nio4r (~> 2.0) websocket-driver (>= 0.6.1) zeitwerk (~> 2.6) - actionmailbox (7.1.0) - actionpack (= 7.1.0) - activejob (= 7.1.0) - activerecord (= 7.1.0) - activestorage (= 7.1.0) - activesupport (= 7.1.0) - mail (>= 2.7.1) - net-imap - net-pop - net-smtp - actionmailer (7.1.0) - actionpack (= 7.1.0) - actionview (= 7.1.0) - activejob (= 7.1.0) - activesupport (= 7.1.0) - mail (~> 2.5, >= 2.5.4) - net-imap - net-pop - net-smtp + actionmailbox (8.1.0) + actionpack (= 8.1.0) + activejob (= 8.1.0) + activerecord (= 8.1.0) + activestorage (= 8.1.0) + activesupport (= 8.1.0) + mail (>= 2.8.0) + actionmailer (8.1.0) + actionpack (= 8.1.0) + actionview (= 8.1.0) + activejob (= 8.1.0) + activesupport (= 8.1.0) + mail (>= 2.8.0) rails-dom-testing (~> 2.2) - actionpack (7.1.0) - actionview (= 7.1.0) - activesupport (= 7.1.0) + actionpack (8.1.0) + actionview (= 8.1.0) + activesupport (= 8.1.0) nokogiri (>= 1.8.5) rack (>= 2.2.4) rack-session (>= 1.0.1) rack-test (>= 0.6.3) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) - actiontext (7.1.0) - actionpack (= 7.1.0) - activerecord (= 7.1.0) - activestorage (= 7.1.0) - activesupport (= 7.1.0) + useragent (~> 0.16) + actiontext (8.1.0) + action_text-trix (~> 2.1.15) + actionpack (= 8.1.0) + activerecord (= 8.1.0) + activestorage (= 8.1.0) + activesupport (= 8.1.0) globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (7.1.0) - activesupport (= 7.1.0) + actionview (8.1.0) + activesupport (= 8.1.0) builder (~> 3.1) erubi (~> 1.11) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) - activejob (7.1.0) - activesupport (= 7.1.0) + activejob (8.1.0) + activesupport (= 8.1.0) globalid (>= 0.3.6) - activemodel (7.1.0) - activesupport (= 7.1.0) - activerecord (7.1.0) - activemodel (= 7.1.0) - activesupport (= 7.1.0) + activemodel (8.1.0) + activesupport (= 8.1.0) + activerecord (8.1.0) + activemodel (= 8.1.0) + activesupport (= 8.1.0) timeout (>= 0.4.0) - activestorage (7.1.0) - actionpack (= 7.1.0) - activejob (= 7.1.0) - activerecord (= 7.1.0) - activesupport (= 7.1.0) + activestorage (8.1.0) + actionpack (= 8.1.0) + activejob (= 8.1.0) + activerecord (= 8.1.0) + activesupport (= 8.1.0) marcel (~> 1.0) - activesupport (7.1.0) + activesupport (8.1.0) base64 bigdecimal - concurrent-ruby (~> 1.0, >= 1.0.2) + 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) - mutex_m - tzinfo (~> 2.0) - base64 (0.1.1) - bigdecimal (3.1.4) - builder (3.2.4) - concurrent-ruby (1.1.10) - connection_pool (2.4.1) + securerandom (>= 0.3) + tzinfo (~> 2.0, >= 2.0.5) + uri (>= 0.13.1) + async (2.34.0) + console (~> 1.29) + fiber-annotation + io-event (~> 1.11) + metrics (~> 0.12) + traces (~> 0.18) + async-container (0.27.7) + async (~> 2.22) + async-container-supervisor (0.8.0) + async-service + io-endpoint + memory (~> 0.7) + memory-leak (~> 0.5) + process-metrics + async-http (0.92.1) + 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-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 (>= 2.0) + async-service (0.14.4) + async + async-container (~> 0.16) + string-format (~> 0.2) + bake (0.24.1) + bigdecimal + samovar (~> 2.1) + base64 (0.3.0) + bigdecimal (3.3.1) + builder (3.3.0) + concurrent-ruby (1.3.5) + connection_pool (2.5.4) + console (1.34.2) + fiber-annotation + fiber-local (~> 1.1) + json crass (1.0.6) - date (3.3.3) - drb (2.1.1) - ruby2_keywords - erubi (1.12.0) - globalid (1.2.1) + date (3.4.1) + drb (2.2.3) + erb (5.1.3) + erubi (1.13.1) + falcon (0.52.4) + async + async-container (~> 0.20) + async-container-supervisor (~> 0.6) + async-http (~> 0.75) + async-http-cache (~> 0.4) + async-service (~> 0.10) + bundler + localhost (~> 1.1) + openssl (~> 3.0) + protocol-http (~> 0.31) + protocol-rack (~> 0.7) + samovar (~> 2.3) + fiber-annotation (0.2.0) + fiber-local (1.1.0) + fiber-storage + fiber-storage (1.0.1) + globalid (1.3.0) activesupport (>= 6.1) - i18n (1.14.1) + i18n (1.14.7) concurrent-ruby (~> 1.0) - io-console (0.6.0) - irb (1.8.1) - rdoc - reline (>= 0.3.8) - loofah (2.21.3) + io-console (0.8.1) + io-endpoint (0.15.2) + io-event (1.14.0) + io-stream (0.11.0) + iodine (0.7.58) + irb (1.15.2) + pp (>= 0.6.0) + rdoc (>= 4.0.0) + reline (>= 0.4.2) + json (2.15.2) + localhost (1.6.0) + logger (1.7.0) + loofah (2.24.1) crass (~> 1.0.2) nokogiri (>= 1.12.0) - mail (2.8.1) + mail (2.9.0) + logger mini_mime (>= 0.1.1) net-imap net-pop net-smtp - marcel (1.0.2) + mapping (1.1.3) + marcel (1.1.0) + memory (0.7.1) + bake (~> 0.15) + console + msgpack + memory-leak (0.7.0) + metrics (0.15.0) mini_mime (1.1.5) - mini_portile2 (2.8.4) - minitest (5.20.0) - mutex_m (0.1.2) - net-imap (0.4.0) + mini_portile2 (2.8.9) + minitest (5.26.0) + msgpack (1.8.0) + net-imap (0.5.12) date net-protocol net-pop (0.1.2) net-protocol - net-protocol (0.2.1) + net-protocol (0.2.2) timeout - net-smtp (0.4.0) + net-smtp (0.5.1) net-protocol - nio4r (2.5.9) - nokogiri (1.15.4) + nio4r (2.7.4) + nokogiri (1.18.10) mini_portile2 (~> 2.8.2) racc (~> 1.4) - nokogiri (1.15.4-arm64-darwin) + nokogiri (1.18.10-x86_64-darwin) racc (~> 1.4) - nokogiri (1.15.4-x86_64-linux) + nokogiri (1.18.10-x86_64-linux-gnu) racc (~> 1.4) - oj (3.16.1) - pg (1.5.4) - psych (5.1.0) + openssl (3.3.2) + pg (1.5.9) + pitchfork (0.17.0) + logger + rack (>= 2.0) + pp (0.6.3) + prettyprint + prettyprint (0.2.0) + process-metrics (0.6.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-hpack (~> 1.4) + protocol-http (~> 0.47) + protocol-rack (0.16.0) + io-stream (>= 0.10) + protocol-http (~> 0.43) + rack (>= 1.0) + protocol-url (0.4.0) + psych (5.2.6) + date stringio - puma (6.4.0) + puma (7.1.0) nio4r (~> 2.0) - racc (1.7.1) - rack (3.0.8) - rack-session (2.0.0) + racc (1.8.1) + rack (3.2.3) + rack-session (2.1.1) + base64 (>= 0.1.0) rack (>= 3.0.0) - rack-test (2.1.0) + rack-test (2.2.0) rack (>= 1.3) - rackup (2.1.0) + rackup (2.2.1) rack (>= 3) - webrick (~> 1.8) - rails (7.1.0) - actioncable (= 7.1.0) - actionmailbox (= 7.1.0) - actionmailer (= 7.1.0) - actionpack (= 7.1.0) - actiontext (= 7.1.0) - actionview (= 7.1.0) - activejob (= 7.1.0) - activemodel (= 7.1.0) - activerecord (= 7.1.0) - activestorage (= 7.1.0) - activesupport (= 7.1.0) + 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) bundler (>= 1.15.0) - railties (= 7.1.0) - rails-dom-testing (2.2.0) + railties (= 8.1.0) + rails-dom-testing (2.3.0) activesupport (>= 5.0.0) minitest nokogiri (>= 1.6) - rails-html-sanitizer (1.6.0) + rails-html-sanitizer (1.6.2) loofah (~> 2.21) - nokogiri (~> 1.14) - railties (7.1.0) - actionpack (= 7.1.0) - activesupport (= 7.1.0) - irb + 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) + irb (~> 1.13) rackup (>= 1.0.0) rake (>= 12.2) thor (~> 1.0, >= 1.2.2) + tsort (>= 0.2) zeitwerk (~> 2.6) - rake (13.0.6) - rdoc (6.5.0) + rake (13.3.0) + rdoc (6.15.0) + erb psych (>= 4.0.0) - redis (5.0.7) - redis-client (>= 0.9.0) - redis-client (0.17.0) + tsort + redis (5.4.0) + redis-client (>= 0.22.0) + redis-client (0.24.0) connection_pool - reline (0.3.9) + reline (0.6.2) io-console (~> 0.5) - ruby2_keywords (0.0.5) - stringio (3.0.8) - thor (1.2.2) - timeout (0.4.0) - trilogy (2.6.0) - tzinfo (2.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) + traces (0.18.2) + trilogy (2.8.1) + tsort (0.2.0) + tzinfo (2.0.6) concurrent-ruby (~> 1.0) - tzinfo-data (1.2021.5) + tzinfo-data (1.2025.1) tzinfo (>= 1.0.0) - webrick (1.8.1) - websocket-driver (0.7.6) + uri (1.0.4) + useragent (0.16.11) + websocket-driver (0.8.0) + base64 websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) - zeitwerk (2.6.12) + zeitwerk (2.7.3) PLATFORMS - arm64-darwin-20 ruby + x86_64-darwin-22 x86_64-linux DEPENDENCIES - oj (~> 3.16) - pg (= 1.5.4) - puma (~> 6.4) - rails (~> 7.1.0) + falcon (~> 0.47) + iodine (~> 0.7) + pg (~> 1.5) + pitchfork (~> 0.17) + puma (~> 7.1) + rails (~> 8.1.0) redis (~> 5.0) - trilogy + trilogy (~> 2.8.1) tzinfo-data -RUBY VERSION - ruby 3.2.2p53 - BUNDLED WITH - 2.3.3 + 2.7.0 diff --git a/frameworks/Ruby/rails/README.md b/frameworks/Ruby/rails/README.md index 6699e544d72..fff40abd584 100644 --- a/frameworks/Ruby/rails/README.md +++ b/frameworks/Ruby/rails/README.md @@ -12,9 +12,12 @@ comparing a variety of web platforms. The tests were run with: -- [Ruby 3.2.2](http://www.ruby-lang.org/) -- [Rails 7.0.8](http://rubyonrails.org/) +- [Ruby 3.4](http://www.ruby-lang.org/) +- [Rails 8.0](http://rubyonrails.org/) - [Puma 6.4](http://puma.io/) +- [Iodine](https://github.com/boazsegev/iodine) +- [Falcon](https://github.com/socketry/falcon) +- [Pitchfork](https://github.com/Shopify/pitchfork) - [MySQL](https://dev.mysql.com/) - [PostgreSQL](https://www.postgresql.org/) - [Redis 6](https://redis.io) diff --git a/frameworks/Ruby/rails/app/controllers/application_controller.rb b/frameworks/Ruby/rails/app/controllers/application_controller.rb index 02f927caed7..7944f9f993a 100644 --- a/frameworks/Ruby/rails/app/controllers/application_controller.rb +++ b/frameworks/Ruby/rails/app/controllers/application_controller.rb @@ -1,11 +1,4 @@ # frozen_string_literal: true class ApplicationController < ActionController::Base - before_action :add_header - - private - - def add_header - response.set_header('Date', Time.now.httpdate) - end end diff --git a/frameworks/Ruby/rails/app/controllers/application_controller_metal.rb b/frameworks/Ruby/rails/app/controllers/application_controller_metal.rb deleted file mode 100644 index b26d9c470cd..00000000000 --- a/frameworks/Ruby/rails/app/controllers/application_controller_metal.rb +++ /dev/null @@ -1,8 +0,0 @@ -# frozen_string_literal: true - -class ApplicationControllerMetal < ActionController::Metal - def add_headers - response.set_header('Server', 'rails') - response.set_header('Date', Time.now.httpdate) - end -end diff --git a/frameworks/Ruby/rails/app/controllers/concerns/date_header.rb b/frameworks/Ruby/rails/app/controllers/concerns/date_header.rb new file mode 100644 index 00000000000..d314038144c --- /dev/null +++ b/frameworks/Ruby/rails/app/controllers/concerns/date_header.rb @@ -0,0 +1,15 @@ +module DateHeader + extend ActiveSupport::Concern + + included do + if defined?(Agoo) || defined?(Falcon) || defined?(Puma) + before_action :add_header + end + end + + private + + def add_header + response.set_header('Date', Time.now.httpdate) + end +end diff --git a/frameworks/Ruby/rails/app/controllers/fortunes_controller.rb b/frameworks/Ruby/rails/app/controllers/fortunes_controller.rb new file mode 100644 index 00000000000..0f937aff039 --- /dev/null +++ b/frameworks/Ruby/rails/app/controllers/fortunes_controller.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +class FortunesController < ApplicationController + include DateHeader + + def index + @fortunes = Fortune.all.to_a + @fortunes << Fortune.new(id: 0, message: 'Additional fortune added at request time.') + @fortunes.sort_by!(&:message) + render :fortune + 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 cb533d57a37..526d850e94c 100644 --- a/frameworks/Ruby/rails/app/controllers/hello_world_controller.rb +++ b/frameworks/Ruby/rails/app/controllers/hello_world_controller.rb @@ -1,13 +1,15 @@ # frozen_string_literal: true -class HelloWorldController < ApplicationController +class HelloWorldController < ActionController::API + include DateHeader + QUERY_RANGE = 1..10_000 # 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 def db - render json: World.find(random_id) + render json: World.find(random_id).attributes end def query @@ -19,27 +21,22 @@ def query end def cached_query - items = Rails.cache.fetch_multi(*ALL_IDS.sample(query_count)) do |id| - World.find(id).as_json + keys = ALL_IDS.sample(query_count).map { "world_#{_1}" } + items = Rails.cache.fetch_multi(*keys) do |id| + raise "Could not find World with id: #{id} in cache" end render json: items.values end - def fortune - @fortunes = Fortune.all.to_a - @fortunes << Fortune.new(id: 0, message: 'Additional fortune added at request time.') - @fortunes.sort_by!(&:message) - end - def update - worlds = Array.new(query_count) do - world = World.find(random_id) + worlds = ALL_IDS.sample(query_count).map do |id| + world = World.find(id) new_value = random_id new_value = random_id until new_value != world.randomNumber - world.update_columns(randomNumber: new_value) - world + { id: id, randomNumber: new_value } end + World.upsert_all(worlds.sort_by!{_1[:id]}) render json: worlds end @@ -48,10 +45,7 @@ def update def query_count queries = params[:queries].to_i - return MIN_QUERIES if queries < MIN_QUERIES - return MAX_QUERIES if queries > MAX_QUERIES - - queries + queries.clamp(MIN_QUERIES, MAX_QUERIES) end def random_id diff --git a/frameworks/Ruby/rails/app/controllers/json_controller.rb b/frameworks/Ruby/rails/app/controllers/json_controller.rb deleted file mode 100644 index e7234f692f3..00000000000 --- a/frameworks/Ruby/rails/app/controllers/json_controller.rb +++ /dev/null @@ -1,9 +0,0 @@ -# frozen_string_literal: true - -class JsonController < ApplicationControllerMetal - def index - add_headers - self.content_type = 'application/json' - self.response_body = Oj.dump({ 'message' => 'Hello, World!' }) - end -end diff --git a/frameworks/Ruby/rails/app/controllers/plaintext_controller.rb b/frameworks/Ruby/rails/app/controllers/plaintext_controller.rb deleted file mode 100644 index 1afe3639c4d..00000000000 --- a/frameworks/Ruby/rails/app/controllers/plaintext_controller.rb +++ /dev/null @@ -1,9 +0,0 @@ -# frozen_string_literal: true - -class PlaintextController < ApplicationControllerMetal - def index - add_headers - self.content_type = 'text/plain' - self.response_body = 'Hello, World!' - end -end diff --git a/frameworks/Ruby/rails/app/models/world.rb b/frameworks/Ruby/rails/app/models/world.rb index 278501c05f4..bc1c8e9311b 100644 --- a/frameworks/Ruby/rails/app/models/world.rb +++ b/frameworks/Ruby/rails/app/models/world.rb @@ -3,4 +3,14 @@ class World < ApplicationRecord 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 diff --git a/frameworks/Ruby/rails/app/views/hello_world/fortune.html.erb b/frameworks/Ruby/rails/app/views/fortunes/fortune.html.erb similarity index 100% rename from frameworks/Ruby/rails/app/views/hello_world/fortune.html.erb rename to frameworks/Ruby/rails/app/views/fortunes/fortune.html.erb diff --git a/frameworks/Ruby/rails/benchmark_config.json b/frameworks/Ruby/rails/benchmark_config.json index 7e309e25450..5f86a525145 100644 --- a/frameworks/Ruby/rails/benchmark_config.json +++ b/frameworks/Ruby/rails/benchmark_config.json @@ -20,7 +20,7 @@ "webserver": "Puma", "os": "Linux", "database_os": "Linux", - "display_name": "rails-postgresql", + "display_name": "rails [puma, postgres]", "notes": "", "versus": "" }, @@ -41,9 +41,78 @@ "webserver": "Puma", "os": "Linux", "database_os": "Linux", - "display_name": "rails-mysql", + "display_name": "rails [puma, mysql]", "notes": "", "versus": "rack-puma-mri" + }, + "falcon": { + "db_url": "/db", + "json_url": "/json", + "query_url": "/queries?queries=", + "fortune_url": "/fortunes", + "update_url": "/updates?queries=", + "plaintext_url": "/plaintext", + "cached_query_url": "/cached?queries=", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "database": "Postgres", + "framework": "rails", + "language": "Ruby", + "orm": "Full", + "platform": "Rack", + "webserver": "Falcon", + "os": "Linux", + "database_os": "Linux", + "display_name": "rails [falcon]", + "notes": "", + "versus": "rack-falcon-mri-sequel-raw" + }, + "iodine": { + "db_url": "/db", + "json_url": "/json", + "query_url": "/queries?queries=", + "fortune_url": "/fortunes", + "update_url": "/updates?queries=", + "plaintext_url": "/plaintext", + "cached_query_url": "/cached?queries=", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "database": "Postgres", + "framework": "rails", + "language": "Ruby", + "orm": "Full", + "platform": "Rack", + "webserver": "Iodine", + "os": "Linux", + "database_os": "Linux", + "display_name": "rails [iodine]", + "notes": "", + "versus": "rack-iodine-mri-sequel-raw" + }, + "pitchfork": { + "db_url": "/db", + "json_url": "/json", + "query_url": "/queries?queries=", + "fortune_url": "/fortunes", + "update_url": "/updates?queries=", + "plaintext_url": "/plaintext", + "cached_query_url": "/cached?queries=", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "database": "Postgres", + "framework": "rails", + "language": "Ruby", + "orm": "Full", + "platform": "Rack", + "webserver": "Pitchfork", + "os": "Linux", + "database_os": "Linux", + "display_name": "rails [pitchfork]", + "notes": "", + "versus": "rack-pitchfork-mri-sequel-raw" } }] } diff --git a/frameworks/Ruby/rails/config/agoo.rb b/frameworks/Ruby/rails/config/agoo.rb new file mode 100644 index 00000000000..e69de29bb2d diff --git a/frameworks/Ruby/rails/config/application.rb b/frameworks/Ruby/rails/config/application.rb index 2cca7e95baa..19ca9a41572 100644 --- a/frameworks/Ruby/rails/config/application.rb +++ b/frameworks/Ruby/rails/config/application.rb @@ -8,9 +8,10 @@ # require "active_storage/engine" require "action_controller/railtie" # require "action_mailer/railtie" +# require "action_mailbox/engine" +# require "action_text/engine" require "action_view/railtie" # require "action_cable/engine" -# require "sprockets/railtie" # require "rails/test_unit/railtie" # Require the gems listed in Gemfile, including any gems @@ -20,36 +21,37 @@ module Hello class Application < Rails::Application # Initialize configuration defaults for originally generated Rails version. - config.load_defaults 7.1 + config.load_defaults Rails::VERSION::STRING.to_f - # Settings in config/environments/* take precedence over those specified here. - # Application configuration can go into files in config/initializers - # -- all .rb files in that directory are automatically loaded after loading - # the framework and any gems in your application. + # Please, add to the `ignore` list any other `lib` subdirectories that do + # not contain `.rb` files, or that should not be reloaded or eager loaded. + # Common ones are `templates`, `generators`, or `middleware`, for example. + config.autoload_lib(ignore: %w[assets tasks]) - config.action_dispatch.default_headers.merge!('Server' => 'WebServer') + # Only use headers required by TechEmpower. + config.action_dispatch.default_headers = {'Server' => 'Rails'} - config.middleware.delete ActionDispatch::HostAuthorization - config.middleware.delete Rack::Sendfile - config.middleware.delete ActionDispatch::Static + config.api_only = true + + config.middleware.delete ActionDispatch::Callbacks + config.middleware.delete ActionDispatch::DebugExceptions config.middleware.delete ActionDispatch::Executor - config.middleware.delete Rack::Runtime - config.middleware.delete Rack::MethodOverride - config.middleware.delete ActionDispatch::RequestId config.middleware.delete ActionDispatch::RemoteIp - config.middleware.delete Rails::Rack::Logger + config.middleware.delete ActionDispatch::RequestId config.middleware.delete ActionDispatch::ShowExceptions - config.middleware.delete ActionDispatch::DebugExceptions - config.middleware.delete ActionDispatch::ActionableExceptions - config.middleware.delete ActionDispatch::Reloader - config.middleware.delete ActiveRecord::Migration::CheckPending - config.middleware.delete ActionDispatch::Cookies - config.middleware.delete ActionDispatch::Session::CookieStore - config.middleware.delete ActionDispatch::Flash - config.middleware.delete ActionDispatch::ContentSecurityPolicy::Middleware - config.middleware.delete ActionDispatch::PermissionsPolicy::Middleware - config.middleware.delete Rack::Head config.middleware.delete Rack::ConditionalGet config.middleware.delete Rack::ETag + config.middleware.delete Rack::Head + config.middleware.delete Rack::Runtime + config.middleware.delete Rack::Sendfile + config.middleware.delete Rails::Rack::Logger + + config.active_support.isolation_level = :fiber if defined?(Falcon) + + config.to_prepare do + HelloWorldController::ALL_IDS.each do |id| + Rails.cache.write("world_#{id}", World.find(id).as_json, expires_in: 1.day) + end + end end end diff --git a/frameworks/Ruby/rails/config/database.yml b/frameworks/Ruby/rails/config/database.yml index ae7de0910d7..e4f159e0f72 100644 --- a/frameworks/Ruby/rails/config/database.yml +++ b/frameworks/Ruby/rails/config/database.yml @@ -5,7 +5,7 @@ default: &default password: benchmarkdbpass host: tfb-database timeout: 5000 - pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 3 } %> development: <<: *default @@ -16,6 +16,9 @@ test: production_mysql: <<: *default adapter: trilogy + ssl: true + ssl_mode: 4 <%# Trilogy::SSL_PREFERRED_NOVERIFY %> + tls_min_version: 3 <%# Trilogy::TLS_VERSION_12 %> production_postgresql: <<: *default diff --git a/frameworks/Ruby/rails/config/environments/development.rb b/frameworks/Ruby/rails/config/environments/development.rb index 8620b53db5a..ab2b0a86d2f 100644 --- a/frameworks/Ruby/rails/config/environments/development.rb +++ b/frameworks/Ruby/rails/config/environments/development.rb @@ -3,10 +3,8 @@ Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. - # In the development environment your application's code is reloaded any time - # it changes. This slows down response time but is perfect for development - # since you don't have to restart the web server when you make code changes. - config.cache_classes = false + # Make code changes take effect immediately without server restart. + config.enable_reloading = true # Do not eager load code on boot. config.eager_load = false @@ -14,50 +12,40 @@ # Show full error reports. config.consider_all_requests_local = true - # Enable server timing + # Enable server timing. config.server_timing = true - # Enable/disable caching. By default caching is disabled. - # Run rails dev:cache to toggle caching. + # Enable/disable Action Controller caching. By default Action Controller caching is disabled. + # Run rails dev:cache to toggle Action Controller caching. if Rails.root.join("tmp/caching-dev.txt").exist? config.action_controller.perform_caching = true config.action_controller.enable_fragment_cache_logging = true - - config.cache_store = :memory_store - config.public_file_server.headers = { - "Cache-Control" => "public, max-age=#{2.days.to_i}" - } + config.public_file_server.headers = { "cache-control" => "public, max-age=#{2.days.to_i}" } else config.action_controller.perform_caching = false - - config.cache_store = :null_store end + # Change to :null_store to avoid any caching. + config.cache_store = :memory_store + # Print deprecation notices to the Rails logger. config.active_support.deprecation = :log - # Raise exceptions for disallowed deprecations. - config.active_support.disallowed_deprecation = :raise - - # Tell Active Support which deprecation messages to disallow. - config.active_support.disallowed_deprecation_warnings = [] - # Raise an error on page load if there are pending migrations. config.active_record.migration_error = :page_load # Highlight code that triggered database queries in logs. config.active_record.verbose_query_logs = true + # Append comments with runtime information tags to SQL queries in logs. + config.active_record.query_log_tags_enabled = true # Raises error for missing translations. # config.i18n.raise_on_missing_translations = true # Annotate rendered view with file names. - # config.action_view.annotate_rendered_view_with_filenames = true - - # Uncomment if you wish to allow Action Cable access from any origin. - # config.action_cable.disable_request_forgery_protection = true + config.action_view.annotate_rendered_view_with_filenames = true - # Raise error when a before_action's only/except options reference missing actions + # Raise error when a before_action's only/except options reference missing actions. config.action_controller.raise_on_missing_callback_actions = true end diff --git a/frameworks/Ruby/rails/config/environments/production.rb b/frameworks/Ruby/rails/config/environments/production.rb index 3ad22143e26..b84b2807e96 100644 --- a/frameworks/Ruby/rails/config/environments/production.rb +++ b/frameworks/Ruby/rails/config/environments/production.rb @@ -4,42 +4,48 @@ # Settings specified here will take precedence over those in config/application.rb. # Code is not reloaded between requests. - config.cache_classes = true + config.enable_reloading = false - # Eager load code on boot. This eager loads most of Rails and - # your application in memory, allowing both threaded web servers - # and those relying on copy on write to perform better. - # Rake tasks automatically ignore this option for performance. + # Eager load code on boot for better performance and memory savings (ignored by Rake tasks). config.eager_load = true - # Full error reports are disabled and caching is turned on. - config.consider_all_requests_local = false + # Full error reports are disabled. + config.consider_all_requests_local = false + + # Turn on fragment caching in view templates. config.action_controller.perform_caching = true - # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] - # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). - # config.require_master_key = true + # Cache assets for far-future expiry since they are all digest stamped. + config.public_file_server.headers = { "cache-control" => "public, max-age=#{1.year.to_i}" } - # Disable serving static files from the `/public` folder by default since - # Apache or NGINX already handles this. - config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present? + # Disable serving static files from `public/`, relying on NGINX/Apache to do so instead. + # This disables the ActionDispatch::Static middleware. + config.public_file_server.enabled = false # Enable serving of images, stylesheets, and JavaScripts from an asset server. # config.asset_host = "http://assets.example.com" - # Specifies the header that your server uses for sending files. - # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache - # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX + # Assume all access to the app is happening through a SSL-terminating reverse proxy. + # config.assume_ssl = true # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. # config.force_ssl = true - # Include generic and useful information about system operation, but avoid logging too much - # information to avoid inadvertent exposure of personally identifiable information (PII). - config.log_level = :info + # Skip http-to-https redirect for the default health check endpoint. + # config.ssl_options = { redirect: { exclude: ->(request) { request.path == "/up" } } } + + # Log to STDOUT with the current request id as a default log tag. + # config.log_tags = [ :request_id ] + config.logger = nil - # Prepend all log lines with the following tags. - config.log_tags = [ :request_id ] + # Change to "debug" to log everything (including potentially personally-identifiable information!) + config.log_level = :fatal + + # Prevent health checks from clogging up the logs. + config.silence_healthcheck_path = "/up" + + # Don't log any deprecations. + config.active_support.report_deprecations = false # Use a different cache store in production. config.cache_store = :redis_cache_store, { @@ -54,30 +60,22 @@ } } - # Use a real queuing backend for Active Job (and separate queues per environment). - # config.active_job.queue_adapter = :resque - # config.active_job.queue_name_prefix = "hello_production" - # Enable locale fallbacks for I18n (makes lookups for any locale fall back to # the I18n.default_locale when a translation cannot be found). config.i18n.fallbacks = true - # Don't log any deprecations. - config.active_support.report_deprecations = false - - # Use default logging formatter so that PID and timestamp are not suppressed. - config.log_formatter = ::Logger::Formatter.new - - # Use a different logger for distributed setups. - # require "syslog/logger" - # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name") - - if ENV["RAILS_LOG_TO_STDOUT"].present? - logger = ActiveSupport::Logger.new(STDOUT) - logger.formatter = config.log_formatter - config.logger = ActiveSupport::TaggedLogging.new(logger) - end - # Do not dump schema after migrations. config.active_record.dump_schema_after_migration = false + + # Only use :id for inspections in production. + config.active_record.attributes_for_inspect = [ :id ] + + # Enable DNS rebinding protection and other `Host` header attacks. + # config.hosts = [ + # "example.com", # Allow requests from example.com + # /.*\.example\.com/ # Allow requests from subdomains like `www.example.com` + # ] + # + # Skip DNS rebinding protection for the default health check endpoint. + # config.host_authorization = { exclude: ->(request) { request.path == "/up" } } end diff --git a/frameworks/Ruby/rails/config/environments/test.rb b/frameworks/Ruby/rails/config/environments/test.rb index bfcd30081b1..14bc29e0659 100644 --- a/frameworks/Ruby/rails/config/environments/test.rb +++ b/frameworks/Ruby/rails/config/environments/test.rb @@ -1,5 +1,3 @@ -require "active_support/core_ext/integer/time" - # The test environment is used exclusively to run your application's # test suite. You never need to work with it otherwise. Remember that # your test database is "scratch space" for the test suite and is wiped @@ -8,27 +6,24 @@ Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. - # Turn false under Spring and add config.action_view.cache_template_loading = true. - config.cache_classes = true + # While tests run files are not watched, reloading is not necessary. + config.enable_reloading = false - # Eager loading loads your whole application. When running a single test locally, - # this probably isn't necessary. It's a good idea to do in a continuous integration - # system, or in some way before deploying your code. + # Eager loading loads your entire application. When running a single test locally, + # this is usually not necessary, and can slow down your test suite. However, it's + # recommended that you enable it in continuous integration systems to ensure eager + # loading is working properly before deploying your code. config.eager_load = ENV["CI"].present? - # Configure public file server for tests with Cache-Control for performance. - config.public_file_server.enabled = true - config.public_file_server.headers = { - "Cache-Control" => "public, max-age=#{1.hour.to_i}" - } + # Configure public file server for tests with cache-control for performance. + config.public_file_server.headers = { "cache-control" => "public, max-age=3600" } - # Show full error reports and disable caching. - config.consider_all_requests_local = true - config.action_controller.perform_caching = false + # Show full error reports. + config.consider_all_requests_local = true config.cache_store = :null_store - # Raise exceptions instead of rendering exception templates. - config.action_dispatch.show_exceptions = false + # Render exception templates for rescuable exceptions and raise for other exceptions. + config.action_dispatch.show_exceptions = :rescuable # Disable request forgery protection in test environment. config.action_controller.allow_forgery_protection = false @@ -36,18 +31,12 @@ # Print deprecation notices to the stderr. config.active_support.deprecation = :stderr - # Raise exceptions for disallowed deprecations. - config.active_support.disallowed_deprecation = :raise - - # Tell Active Support which deprecation messages to disallow. - config.active_support.disallowed_deprecation_warnings = [] - # Raises error for missing translations. # config.i18n.raise_on_missing_translations = true # Annotate rendered view with file names. # config.action_view.annotate_rendered_view_with_filenames = true - # Raise error when a before_action's only/except options reference missing actions + # Raise error when a before_action's only/except options reference missing actions. config.action_controller.raise_on_missing_callback_actions = true end diff --git a/frameworks/Ruby/rails/config/falcon_preload.rb b/frameworks/Ruby/rails/config/falcon_preload.rb new file mode 100644 index 00000000000..647c7b948d9 --- /dev/null +++ b/frameworks/Ruby/rails/config/falcon_preload.rb @@ -0,0 +1,3 @@ +# required by Falcon: +# https://github.com/socketry/falcon/blob/19fe8ece7cc49aa03222afe2c940682aeb69fe37/guides/rails-integration/readme.md?plain=1#L38 +require_relative "../config/environment" diff --git a/frameworks/Ruby/rails/config/initializers/filter_parameter_logging.rb b/frameworks/Ruby/rails/config/initializers/filter_parameter_logging.rb index 4b34a036689..e058dbb3656 100644 --- a/frameworks/Ruby/rails/config/initializers/filter_parameter_logging.rb +++ b/frameworks/Ruby/rails/config/initializers/filter_parameter_logging.rb @@ -1,6 +1,6 @@ # Be sure to restart your server when you modify this file. -# Configure sensitive parameters which will be filtered from the log file. -Rails.application.config.filter_parameters += [ - :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn -] +# Configure parameters to be partially matched (e.g. passw matches password) and filtered from the log file. +# Use this to limit dissemination of sensitive information. +# See the ActiveSupport::ParameterFilter documentation for supported notations and behaviors. +Rails.application.config.filter_parameters = [] diff --git a/frameworks/Ruby/rails/config/initializers/oj.rb b/frameworks/Ruby/rails/config/initializers/oj.rb deleted file mode 100644 index 8c00f0456ff..00000000000 --- a/frameworks/Ruby/rails/config/initializers/oj.rb +++ /dev/null @@ -1 +0,0 @@ -Oj.optimize_rails diff --git a/frameworks/Ruby/rails/config/nginx.conf b/frameworks/Ruby/rails/config/nginx.conf new file mode 100644 index 00000000000..83d4479f28d --- /dev/null +++ b/frameworks/Ruby/rails/config/nginx.conf @@ -0,0 +1,158 @@ +# This is example contains the bare mininum to get nginx going with +# Unicorn or Rainbows! servers. Generally these configuration settings +# are applicable to other HTTP application servers (and not just Ruby +# ones), so if you have one working well for proxying another app +# server, feel free to continue using it. +# +# The only setting we feel strongly about is the fail_timeout=0 +# directive in the "upstream" block. max_fails=0 also has the same +# effect as fail_timeout=0 for current versions of nginx and may be +# used in its place. +# +# Users are strongly encouraged to refer to nginx documentation for more +# details and search for other example configs. + +# you generally only need one nginx worker unless you're serving +# large amounts of static files which require blocking disk reads +worker_processes 8; + +# # drop privileges, root is needed on most systems for binding to port 80 +# # (or anything < 1024). Capability-based security may be available for +# # your system and worth checking out so you won't need to be root to +# # start nginx to bind on 80 +# user nobody nogroup; # for systems with a "nogroup" +#user nobody nobody; # for systems with "nobody" as a group instead + +# Feel free to change all paths to suite your needs here, of course +pid /tmp/nginx.pid; +#error_log /tmp/nginx.error.log; +error_log stderr error; + +events { + worker_connections 4096; # increase if you have lots of clients + accept_mutex off; # "on" if nginx worker_processes > 1 + use epoll; # enable for Linux 2.6+ + # use kqueue; # enable for FreeBSD, OSX +} + +http { + # nginx will find this file in the config directory set at nginx build time + include /etc/nginx/mime.types; + + # fallback in case we can't determine a type + default_type application/octet-stream; + + # click tracking! + #access_log /tmp/nginx.access.log combined; + access_log off; + + # you generally want to serve static files with nginx since neither + # Unicorn nor Rainbows! is optimized for it at the moment + sendfile on; + + tcp_nopush on; # off may be better for *some* Comet/long-poll stuff + tcp_nodelay off; # on may be better for some Comet/long-poll stuff + + # we haven't checked to see if Rack::Deflate on the app server is + # faster or not than doing compression via nginx. It's easier + # to configure it all in one place here for static files and also + # to disable gzip for clients who don't get gzip/deflate right. + # There are other gzip settings that may be needed used to deal with + # bad clients out there, see http://wiki.nginx.org/NginxHttpGzipModule + #gzip on; + #gzip_http_version 1.0; + #gzip_proxied any; + #gzip_min_length 500; + #gzip_disable "MSIE [1-6]\."; + #gzip_types text/plain text/html text/xml text/css + # text/comma-separated-values + # text/javascript application/x-javascript + # application/atom+xml; + + # this can be any application server, not just Unicorn/Rainbows! + upstream app_server { + # fail_timeout=0 means we always retry an upstream even if it failed + # to return a good HTTP response (in case the Unicorn master nukes a + # single worker for timing out). + + # for UNIX domain socket setups: + server unix:/tmp/.sock fail_timeout=0; + + # for TCP setups, point these to your backend servers + # server 192.168.0.7:8080 fail_timeout=0; + # server 192.168.0.8:8080 fail_timeout=0; + # server 192.168.0.9:8080 fail_timeout=0; + } + + server { + # enable one of the following if you're on Linux or FreeBSD + listen 8080 default deferred; # for Linux + # listen 80 default accept_filter=httpready; # for FreeBSD + + # If you have IPv6, you'll likely want to have two separate listeners. + # One on IPv4 only (the default), and another on IPv6 only instead + # of a single dual-stack listener. A dual-stack listener will make + # for ugly IPv4 addresses in $remote_addr (e.g ":ffff:10.0.0.1" + # instead of just "10.0.0.1") and potentially trigger bugs in + # some software. + # listen [::]:80 ipv6only=on; # deferred or accept_filter recommended + + client_max_body_size 4G; + server_name _; + + # ~2 seconds is often enough for most folks to parse HTML/CSS and + # retrieve needed images/icons/frames, connections are cheap in + # nginx so increasing this is generally safe... + keepalive_timeout 10; + + # path for static files + root /path/to/app/current/public; + + # Prefer to serve static files directly from nginx to avoid unnecessary + # data copies from the application server. + # + # try_files directive appeared in in nginx 0.7.27 and has stabilized + # over time. Older versions of nginx (e.g. 0.6.x) requires + # "if (!-f $request_filename)" which was less efficient: + # http://bogomips.org/unicorn.git/tree/examples/nginx.conf?id=v3.3.1#n127 + try_files $uri/index.html $uri.html $uri @app; + + location @app { + # an HTTP header important enough to have its own Wikipedia entry: + # http://en.wikipedia.org/wiki/X-Forwarded-For + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + + # enable this if you forward HTTPS traffic to unicorn, + # this helps Rack set the proper URL scheme for doing redirects: + # proxy_set_header X-Forwarded-Proto $scheme; + + # pass the Host: header from the client right along so redirects + # can be set properly within the Rack application + proxy_set_header Host $http_host; + + # we don't want nginx trying to do something clever with + # redirects, we set the Host: header above already. + proxy_redirect off; + + # set "proxy_buffering off" *only* for Rainbows! when doing + # Comet/long-poll/streaming. It's also safe to set if you're using + # only serving fast clients with Unicorn + nginx, but not slow + # clients. You normally want nginx to buffer responses to slow + # clients, even with Rails 3.1 streaming because otherwise a slow + # client can become a bottleneck of Unicorn. + # + # The Rack application may also set "X-Accel-Buffering (yes|no)" + # in the response headers do disable/enable buffering on a + # per-response basis. + # proxy_buffering off; + + proxy_pass http://app_server; + } + + # Rails error pages + error_page 500 502 503 504 /500.html; + location = /500.html { + root /path/to/app/current/public; + } + } +} diff --git a/frameworks/Ruby/rails/config/pitchfork.rb b/frameworks/Ruby/rails/config/pitchfork.rb new file mode 100644 index 00000000000..e50470d2ed8 --- /dev/null +++ b/frameworks/Ruby/rails/config/pitchfork.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +require_relative 'auto_tune' + +num_workers, = auto_tune + +worker_processes num_workers + +listen "/tmp/.sock", :backlog => 4096 diff --git a/frameworks/Ruby/rails/config/puma.rb b/frameworks/Ruby/rails/config/puma.rb index 3c5a8d92fe1..7a8e1da62e5 100644 --- a/frameworks/Ruby/rails/config/puma.rb +++ b/frameworks/Ruby/rails/config/puma.rb @@ -1,49 +1,37 @@ -require_relative 'auto_tune' +# This configuration file will be evaluated by Puma. The top-level methods that +# are invoked here are part of Puma's configuration DSL. For more information +# about methods provided by the DSL, see https://puma.io/puma/Puma/DSL.html. -# FWBM only... use the puma_auto_tune gem in production! -tuned_num_workers, tuned_num_threads = auto_tune +require_relative 'auto_tune' -# Puma can serve each request in a thread from an internal thread pool. -# The `threads` method setting takes two numbers: a minimum and maximum. -# Any libraries that use thread pools should be configured to match -# the maximum value specified for Puma. Default is set to 5 threads for minimum -# and maximum; this matches the default thread size of Active Record. +# Puma starts a configurable number of processes (workers) and each process +# serves each request in a thread from an internal thread pool. # -max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } -min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } -threads min_threads_count, max_threads_count - -# Specifies the `worker_timeout` threshold that Puma will use to wait before -# terminating a worker in development environments. +# The ideal number of threads per worker depends both on how much time the +# application spends waiting for IO operations and on how much you wish to +# to prioritize throughput over latency. # -worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" - -# Specifies the `port` that Puma will listen on to receive requests; default is 3000. +# As a rule of thumb, increasing the number of threads will increase how much +# traffic a given process can handle (throughput), but due to CRuby's +# Global VM Lock (GVL) it has diminishing returns and will degrade the +# response time (latency) of the application. # -port ENV.fetch("PORT") { 3000 } - -# Specifies the `environment` that Puma will run in. +# The default is set to 3 threads as it's deemed a decent compromise between +# throughput and latency for the average Rails application. # -environment ENV.fetch("RAILS_ENV") { "development" } +# Any libraries that use a connection pool or another resource pool should +# be configured to provide at least as many connections as the number of +# threads. This includes Active Record's `pool` parameter in `database.yml`. +threads_count = ENV.fetch("RAILS_MAX_THREADS", 3) +threads threads_count, threads_count -# Specifies the `pidfile` that Puma will use. -pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } - -# Specifies the number of `workers` to boot in clustered mode. -# Workers are forked web server processes. If using threads and workers together -# the concurrency of the application would be max `threads` * `workers`. -# Workers do not work on JRuby or Windows (both of which do not support -# processes). -# -# workers ENV.fetch("WEB_CONCURRENCY") { 2 } -workers tuned_num_workers +worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" -# Use the `preload_app!` method when specifying a `workers` number. -# This directive tells Puma to first boot the application and load code -# before forking the application. This takes advantage of Copy On Write -# process behavior so workers use less memory. -# -preload_app! +# Specifies the `port` that Puma will listen on to receive requests; default is 3000. +port ENV.fetch("PORT", 3000) -# Allow puma to be restarted by `rails restart` command. +# Allow puma to be restarted by `bin/rails restart` command. plugin :tmp_restart + +# Only use a pidfile when requested +pidfile ENV["PIDFILE"] if ENV["PIDFILE"] diff --git a/frameworks/Ruby/rails/config/routes.rb b/frameworks/Ruby/rails/config/routes.rb index 5556bc3ed17..22c47dc8704 100644 --- a/frameworks/Ruby/rails/config/routes.rb +++ b/frameworks/Ruby/rails/config/routes.rb @@ -1,11 +1,53 @@ Rails.application.routes.draw do # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html - get "json", to: JsonController.action(:index) + JsonApp = if defined?(Falcon) || defined?(Puma) || defined?(Agoo) + ->(env) do + [200, + { + 'Server' => 'Rails', + 'Content-Type' => 'application/json', + 'Date' => Time.now.httpdate, + }, + [{ 'message' => 'Hello, World!' }.to_json]] + end + else + ->(env) do + [200, + { + 'Server' => 'Rails', + 'Content-Type' => 'application/json' + }, + [{ 'message' => 'Hello, World!' }.to_json]] + end + end + + PlaintextApp = if defined?(Falcon) || defined?(Puma) || defined?(Agoo) + ->(env) do + [200, + { + 'Server' => 'Rails', + 'Content-Type' => 'text/plain', + 'Date' => Time.now.httpdate + }, + ['Hello, World!']] + end + else + ->(env) do + [200, + { + 'Server' => 'Rails', + 'Content-Type' => 'text/plain' + }, + ['Hello, World!']] + end + end + + get "json", to: JsonApp get "db", to: "hello_world#db" get "queries", to: "hello_world#query" - get "fortunes", to: "hello_world#fortune" + get "fortunes", to: "fortunes#index" get "updates", to: "hello_world#update" - get "plaintext", to: PlaintextController.action(:index) + get "plaintext", to: PlaintextApp get "cached", to: "hello_world#cached_query" end diff --git a/frameworks/Ruby/rails/falcon.rb b/frameworks/Ruby/rails/falcon.rb new file mode 100644 index 00000000000..147d6b3b66f --- /dev/null +++ b/frameworks/Ruby/rails/falcon.rb @@ -0,0 +1,12 @@ +#!/usr/bin/env -S falcon host +# frozen_string_literal: true + +load :rack + +hostname = File.basename(__dir__) +port = ENV["PORT"] || 8080 + +rack hostname do + append preload "config/falcon_preload.rb" + endpoint Async::HTTP::Endpoint.parse("http://0.0.0.0:#{port}") +end diff --git a/frameworks/Ruby/rails/rails-falcon.dockerfile b/frameworks/Ruby/rails/rails-falcon.dockerfile new file mode 100644 index 00000000000..6ede5622c05 --- /dev/null +++ b/frameworks/Ruby/rails/rails-falcon.dockerfile @@ -0,0 +1,27 @@ +FROM ruby:3.5-rc + +RUN apt-get update -yqq && apt-get install -yqq --no-install-recommends redis-server + +EXPOSE 8080 +WORKDIR /rails + +# ENV RUBY_YJIT_ENABLE=1 YJIT is enabled in config/initializers/enable_yjit.rb + +# Use Jemalloc +RUN apt-get update && \ + apt-get install -y --no-install-recommends libjemalloc2 +ENV LD_PRELOAD=libjemalloc.so.2 + +COPY ./Gemfile* /rails/ + +ENV BUNDLE_FORCE_RUBY_PLATFORM=true +ENV BUNDLE_WITH=postgresql:falcon +RUN bundle install --jobs=8 + +COPY . /rails/ + +ENV RAILS_ENV=production_postgresql +ENV PORT=8080 +ENV REDIS_URL=redis://localhost:6379/0 +CMD service redis-server start && \ + bundle exec falcon host diff --git a/frameworks/Ruby/rails/rails-iodine.dockerfile b/frameworks/Ruby/rails/rails-iodine.dockerfile new file mode 100644 index 00000000000..ceab1c1ba4f --- /dev/null +++ b/frameworks/Ruby/rails/rails-iodine.dockerfile @@ -0,0 +1,27 @@ +FROM ruby:3.5-rc + +RUN apt-get update -yqq && apt-get install -yqq --no-install-recommends redis-server + +EXPOSE 8080 +WORKDIR /rails + +# ENV RUBY_YJIT_ENABLE=1 YJIT is enabled in config/initializers/enable_yjit.rb + +# Use Jemalloc +RUN apt-get update && \ + apt-get install -y --no-install-recommends libjemalloc2 +ENV LD_PRELOAD=libjemalloc.so.2 + +COPY ./Gemfile* /rails/ + +ENV BUNDLE_FORCE_RUBY_PLATFORM=true +ENV BUNDLE_WITH=postgresql:iodine +RUN bundle install --jobs=8 + +COPY . /rails/ + +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) diff --git a/frameworks/Ruby/rails/rails-mysql.dockerfile b/frameworks/Ruby/rails/rails-mysql.dockerfile index b5496825df0..1009954ca6e 100644 --- a/frameworks/Ruby/rails/rails-mysql.dockerfile +++ b/frameworks/Ruby/rails/rails-mysql.dockerfile @@ -1,20 +1,29 @@ -FROM ruby:3.3-rc +FROM ruby:3.5-rc RUN apt-get update -yqq && apt-get install -yqq --no-install-recommends redis-server EXPOSE 8080 WORKDIR /rails +# ENV RUBY_YJIT_ENABLE=1 YJIT is enabled in config/initializers/enable_yjit.rb + +# Use Jemalloc +RUN apt-get update && \ + apt-get install -y --no-install-recommends libjemalloc2 +ENV LD_PRELOAD=libjemalloc.so.2 + COPY ./Gemfile* /rails/ ENV BUNDLE_FORCE_RUBY_PLATFORM=true -ENV BUNDLE_WITHOUT=postgresql +ENV BUNDLE_WITH=mysql:puma RUN bundle install --jobs=8 COPY . /rails/ -ENV RUBY_YJIT_ENABLE=1 +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 ./run-with-redis.sh +CMD service redis-server start && \ + bin/rails server diff --git a/frameworks/Ruby/rails/rails-pitchfork.dockerfile b/frameworks/Ruby/rails/rails-pitchfork.dockerfile new file mode 100644 index 00000000000..190f30a4926 --- /dev/null +++ b/frameworks/Ruby/rails/rails-pitchfork.dockerfile @@ -0,0 +1,30 @@ +FROM ruby:3.5-rc + +RUN apt-get update -yqq && apt-get install -yqq --no-install-recommends redis-server + +EXPOSE 8080 +WORKDIR /rails + +# ENV RUBY_YJIT_ENABLE=1 YJIT is enabled in config/initializers/enable_yjit.rb + +# Use Jemalloc +RUN apt-get update && \ + apt-get install -y --no-install-recommends libjemalloc2 +ENV LD_PRELOAD=libjemalloc.so.2 + +RUN apt-get install -yqq nginx + +COPY ./Gemfile* /rails/ + +ENV BUNDLE_FORCE_RUBY_PLATFORM=true +ENV BUNDLE_WITH=postgresql:pitchfork +RUN bundle install --jobs=8 + +COPY . /rails/ + +ENV RAILS_ENV=production_postgresql +ENV PORT=8080 +ENV REDIS_URL=redis://localhost:6379/0 +CMD service redis-server start && \ + nginx -c /rails/config/nginx.conf && \ + RACK_ENV=production bundle exec pitchfork -c config/pitchfork.rb diff --git a/frameworks/Ruby/rails/rails.dockerfile b/frameworks/Ruby/rails/rails.dockerfile index 627831fc6e5..a1095428571 100644 --- a/frameworks/Ruby/rails/rails.dockerfile +++ b/frameworks/Ruby/rails/rails.dockerfile @@ -1,20 +1,29 @@ -FROM ruby:3.3-rc +FROM ruby:3.5-rc RUN apt-get update -yqq && apt-get install -yqq --no-install-recommends redis-server EXPOSE 8080 WORKDIR /rails +# ENV RUBY_YJIT_ENABLE=1 YJIT is enabled in config/initializers/enable_yjit.rb + +# Use Jemalloc +RUN apt-get update && \ + apt-get install -y --no-install-recommends libjemalloc2 +ENV LD_PRELOAD=libjemalloc.so.2 + COPY ./Gemfile* /rails/ ENV BUNDLE_FORCE_RUBY_PLATFORM=true -ENV BUNDLE_WITHOUT=trilogy +ENV BUNDLE_WITH=postgresql:puma RUN bundle install --jobs=8 COPY . /rails/ -ENV RUBY_YJIT_ENABLE=1 +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 ./run-with-redis.sh +CMD service redis-server start && \ + bin/rails server diff --git a/frameworks/Ruby/rails/run-with-redis.sh b/frameworks/Ruby/rails/run-with-redis.sh deleted file mode 100755 index 9ce9b243b74..00000000000 --- a/frameworks/Ruby/rails/run-with-redis.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash -service redis-server start -rails server diff --git a/frameworks/Ruby/roda-sequel/Gemfile b/frameworks/Ruby/roda-sequel/Gemfile index c9c6a48ab89..c78013dc75d 100644 --- a/frameworks/Ruby/roda-sequel/Gemfile +++ b/frameworks/Ruby/roda-sequel/Gemfile @@ -1,19 +1,26 @@ source "https://rubygems.org" gem "erubi", "~> 1.12" -gem "passenger", "~> 6.0", platforms: %i[ruby mswin], require: false -gem "puma", "~> 6.2", require: false +gem "json", "~> 2.8" gem "sequel", "~> 5.67" gem "roda", "~> 3.66" gem "tilt", "~> 2.1", require: "tilt/erb" -gem "unicorn", "~> 6.1", platforms: %i[ruby mswin], require: false -gem "oj", "~> 3.14" +gem "cgi" # Make sure the h plugin uses the faster CGI.escape_html +gem "concurrent-ruby" -group :mysql do - gem "mysql2", "~> 0.5", platforms: %i[ruby mswin] +group :mysql, optional: true do + gem 'trilogy', '~> 2.9', platforms: [:ruby, :windows] end -group :postgresql do - gem "pg", "~> 1.4", platforms: %i[ruby mswin] +group :postgresql, optional: true do + gem "pg", "~> 1.4", platforms: %i[ruby windows] gem "sequel_pg", "~> 1.17", platforms: :ruby, require: false 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 new file mode 100644 index 00000000000..cb7fb373054 --- /dev/null +++ b/frameworks/Ruby/roda-sequel/Gemfile.lock @@ -0,0 +1,47 @@ +GEM + remote: https://rubygems.org/ + specs: + bigdecimal (3.1.9) + cgi (0.5.0) + concurrent-ruby (1.3.5) + erubi (1.13.1) + iodine (0.7.58) + json (2.13.2) + 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) + rack + sequel (5.90.0) + bigdecimal + sequel_pg (1.17.1) + pg (>= 0.18.0, != 1.2.0) + sequel (>= 4.38.0) + tilt (2.6.0) + trilogy (2.9.0) + +PLATFORMS + ruby + x86_64-darwin-22 + x86_64-linux + +DEPENDENCIES + cgi + concurrent-ruby + erubi (~> 1.12) + iodine (~> 0.7) + json (~> 2.8) + pg (~> 1.4) + puma (~> 7.1) + roda (~> 3.66) + sequel (~> 5.67) + sequel_pg (~> 1.17) + tilt (~> 2.1) + trilogy (~> 2.9) + +BUNDLED WITH + 2.7.0 diff --git a/frameworks/Ruby/roda-sequel/README.md b/frameworks/Ruby/roda-sequel/README.md index 311ecd7b500..195efafd585 100644 --- a/frameworks/Ruby/roda-sequel/README.md +++ b/frameworks/Ruby/roda-sequel/README.md @@ -12,12 +12,9 @@ comparing a variety of web platforms. The tests will be run with: -* [Ruby 2.4](http://www.ruby-lang.org) -* [JRuby 9.1](http://jruby.org) -* [Rubinius 3](https://rubinius.com)\* -* [Puma 3](http://puma.io) -* [Passenger 5](https://www.phusionpassenger.com) -* [Unicorn 5](https://bogomips.org/unicorn/) +* [Ruby 3.4](http://www.ruby-lang.org) +* [Puma 6](http://puma.io) +* [Iodine](https://github.com/boazsegev/iodine) * [Roda 3](http://roda.jeremyevans.net) * [Sequel 5](http://sequel.jeremyevans.net) * [Erubi 1](https://github.com/jeremyevans/erubi) diff --git a/frameworks/Ruby/roda-sequel/benchmark_config.json b/frameworks/Ruby/roda-sequel/benchmark_config.json index 27db92a9b59..c028cc7008c 100644 --- a/frameworks/Ruby/roda-sequel/benchmark_config.json +++ b/frameworks/Ruby/roda-sequel/benchmark_config.json @@ -20,7 +20,7 @@ "webserver": "Puma", "os": "Linux", "database_os": "Linux", - "display_name": "roda-sequel-puma-mri", + "display_name": "roda-sequel [puma, mysql]", "versus": "rack-sequel-puma-mri", "notes": "" }, @@ -40,11 +40,11 @@ "webserver": "Puma", "os": "Linux", "database_os": "Linux", - "display_name": "roda-sequel-postgres-puma-mri", + "display_name": "roda-sequel [puma, postgres]", "versus": "rack-sequel-postgres-puma-mri", "notes": "" }, - "passenger-mri": { + "postgres-iodine-mri": { "json_url": "/json", "db_url": "/db", "query_url": "/queries?queries=", @@ -54,78 +54,16 @@ "port": 8080, "approach": "Realistic", "classification": "Micro", - "database": "MySQL", - "framework": "roda-sequel", - "language": "Ruby", - "orm": "Full", - "platform": "Rack", - "webserver": "Passenger", - "os": "Linux", - "database_os": "Linux", - "display_name": "roda-sequel-passenger-mri", - "versus": "rack-sequel-passenger-mri", - "notes": "" - }, - "postgres-passenger-mri": { - "db_url": "/db", - "query_url": "/queries?queries=", - "fortune_url": "/fortunes", - "update_url": "/updates?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "Postgres", - "framework": "roda-sequel", - "language": "Ruby", - "orm": "Full", - "platform": "Rack", - "webserver": "Passenger", - "os": "Linux", - "database_os": "Linux", - "display_name": "roda-sequel-postgres-passenger-mri", - "versus": "rack-sequel-postgres-passenger-mri", - "notes": "" - }, - "unicorn-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": "MySQL", - "framework": "roda-sequel", - "language": "Ruby", - "orm": "Full", - "platform": "Rack", - "webserver": "Unicorn", - "os": "Linux", - "database_os": "Linux", - "display_name": "roda-sequel-unicorn-mri", - "versus": "rack-sequel-unicorn-mri", - "notes": "" - }, - "postgres-unicorn-mri": { - "db_url": "/db", - "query_url": "/queries?queries=", - "fortune_url": "/fortunes", - "update_url": "/updates?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", "database": "Postgres", "framework": "roda-sequel", "language": "Ruby", "orm": "Full", "platform": "Rack", - "webserver": "Unicorn", + "webserver": "Iodine", "os": "Linux", "database_os": "Linux", - "display_name": "roda-sequel-postgres-unicorn-mri", - "versus": "rack-sequel-postgres-unicorn-mri", + "display_name": "roda-sequel [iodine, postgres]", + "versus": "rack-sequel-postgres-iodine-mri", "notes": "" } } diff --git a/frameworks/Ruby/roda-sequel/boot.rb b/frameworks/Ruby/roda-sequel/boot.rb index f9026ae794b..0878b21e9d3 100644 --- a/frameworks/Ruby/roda-sequel/boot.rb +++ b/frameworks/Ruby/roda-sequel/boot.rb @@ -1,65 +1,50 @@ # frozen_string_literal: true require "bundler/setup" require "time" -require "oj" 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 -# Use the OJ gem instead of the JSON one -Oj.mimic_JSON() - -SERVER_STRING = - if defined?(PhusionPassenger) - [ - PhusionPassenger::SharedConstants::SERVER_TOKEN_NAME, - PhusionPassenger::VERSION_STRING - ].join("/").freeze - elsif defined?(Puma) - Puma::Const::PUMA_SERVER_STRING - elsif defined?(Unicorn) - Unicorn::HttpParser::DEFAULTS["SERVER_SOFTWARE"] - end +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 - adapters = { - mysql: { - jruby: "jdbc:mysql", - mri: "mysql2" - }, - postgresql: { - jruby: "jdbc:postgresql", - mri: "postgres" - } - } - 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?(JRUBY_VERSION) - opts[:max_connections] = ( - 2 * Math.log(Integer(ENV.fetch("MAX_CONCURRENCY"))) - ).floor - opts[:pool_timeout] = 10 - elsif defined?(Puma) && + if defined?(Puma) && (threads = Puma.cli_config.options.fetch(:max_threads)) > 1 - opts[:max_connections] = (2 * Math.log(threads)).floor + opts[:max_connections] = threads opts[:pool_timeout] = 10 else - Sequel.single_threaded = true + opts[:max_connections] = 512 end Sequel.connect "%{adapter}://%{host}/%{database}?user=%{user}&password=%{password}" % { - adapter: - adapters.fetch(dbtype).fetch( - defined?(JRUBY_VERSION) ? :jruby : :mri - ), + adapter: adapter, host: "tfb-database", database: "hello_world", user: "benchmarkdbuser", @@ -73,6 +58,21 @@ def connect(dbtype) # 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) diff --git a/frameworks/Ruby/roda-sequel/config.toml b/frameworks/Ruby/roda-sequel/config.toml index 28a942e4137..a819496996e 100644 --- a/frameworks/Ruby/roda-sequel/config.toml +++ b/frameworks/Ruby/roda-sequel/config.toml @@ -34,71 +34,3 @@ orm = "Full" platform = "Rack" webserver = "Puma" versus = "rack-sequel-puma-mri" - -[postgres-passenger-mri] -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 = "Full" -platform = "Rack" -webserver = "Passenger" -versus = "rack-sequel-postgres-passenger-mri" - -[postgres-unicorn-mri] -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 = "Full" -platform = "Rack" -webserver = "Unicorn" -versus = "rack-sequel-postgres-unicorn-mri" - -[passenger-mri] -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 = "MySQL" -database_os = "Linux" -os = "Linux" -orm = "Full" -platform = "Rack" -webserver = "Passenger" -versus = "rack-sequel-passenger-mri" - -[unicorn-mri] -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 = "MySQL" -database_os = "Linux" -os = "Linux" -orm = "Full" -platform = "Rack" -webserver = "Unicorn" -versus = "rack-sequel-unicorn-mri" diff --git a/frameworks/Ruby/roda-sequel/config/java_tune.sh b/frameworks/Ruby/roda-sequel/config/java_tune.sh deleted file mode 100644 index 412b1e74fdc..00000000000 --- a/frameworks/Ruby/roda-sequel/config/java_tune.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/sh -stack_size=1 -cache_size=240 -meta_size=192 -avail_mem=$(awk '/^MemAvailable/ { print int(0.6 * $2 / 1024); exit }' /proc/meminfo) -heap_size=$(( avail_mem - meta_size - cache_size - (stack_size * MAX_CONCURRENCY * THREAD_FACTOR) )) - -JRUBY_OPTS="-J-server -J-XX:+AggressiveOpts -J-Djava.net.preferIPv4Stack=true" -#JRUBY_OPTS="$JRUBY_OPTS -J-XX:+UseSerialGC" -JRUBY_OPTS="$JRUBY_OPTS -J-XX:+CMSClassUnloadingEnabled -J-XX:+UseConcMarkSweepGC" -#JRUBY_OPTS="$JRUBY_OPTS -J-XX:+UseG1GC -J-XX:+UseStringDeduplication" -JRUBY_OPTS="$JRUBY_OPTS -J-Xms${heap_size}m -J-Xmx${heap_size}m" -JRUBY_OPTS="$JRUBY_OPTS -J-Xss${stack_size}m" -JRUBY_OPTS="$JRUBY_OPTS -J-XX:MaxMetaspaceSize=${meta_size}m" -JRUBY_OPTS="$JRUBY_OPTS -J-XX:ReservedCodeCacheSize=${cache_size}m" -JRUBY_OPTS="$JRUBY_OPTS -Xcompile.invokedynamic=true -J-XX:+UseNUMA -J-XX:+AlwaysPreTouch" - -export JRUBY_OPTS diff --git a/frameworks/Ruby/roda-sequel/config/mri_puma.rb b/frameworks/Ruby/roda-sequel/config/mri_puma.rb index 95b855bafd3..794c18f0c08 100644 --- a/frameworks/Ruby/roda-sequel/config/mri_puma.rb +++ b/frameworks/Ruby/roda-sequel/config/mri_puma.rb @@ -1,7 +1,10 @@ require_relative 'auto_tune' # FWBM only... use the puma_auto_tune gem in production! -num_workers, num_threads = auto_tune +_, num_threads = auto_tune -workers num_workers -threads num_threads, num_threads +threads num_threads + +before_fork do + Sequel::DATABASES.each(&:disconnect) +end diff --git a/frameworks/Ruby/roda-sequel/config/mri_unicorn.rb b/frameworks/Ruby/roda-sequel/config/mri_unicorn.rb deleted file mode 100644 index c9a0c55083e..00000000000 --- a/frameworks/Ruby/roda-sequel/config/mri_unicorn.rb +++ /dev/null @@ -1,6 +0,0 @@ -require_relative 'auto_tune' - -# FWBM only... -num_workers, = auto_tune - -worker_processes num_workers diff --git a/frameworks/Ruby/roda-sequel/hello_world.rb b/frameworks/Ruby/roda-sequel/hello_world.rb index 7d290896112..a3da529b8d2 100644 --- a/frameworks/Ruby/roda-sequel/hello_world.rb +++ b/frameworks/Ruby/roda-sequel/hello_world.rb @@ -7,9 +7,7 @@ class HelloWorld < Roda def bounded_queries queries = request.params["queries"].to_i - return QUERIES_MIN if queries < QUERIES_MIN - return QUERIES_MAX if queries > QUERIES_MAX - queries + queries.clamp(QUERIES_MIN, QUERIES_MAX) end # Return a random number between 1 and MAX_PK @@ -17,34 +15,48 @@ 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| - response["Date"] = Time.now.httpdate - response["Server"] = SERVER_STRING if SERVER_STRING - #default content type - response["Content-Type"] = "application/json" + set_default_headers(response) # Test type 1: JSON serialization r.is "json" do + response[CONTENT_TYPE] = JSON_TYPE { message: "Hello, World!" }.to_json end # Test type 2: Single database query r.is "db" do + response[CONTENT_TYPE] = JSON_TYPE World.with_pk(rand1).values.to_json end # Test type 3: Multiple database queries r.is "queries" do + response[CONTENT_TYPE] = JSON_TYPE + ids = ALL_IDS.sample(bounded_queries) worlds = DB.synchronize do - Array.new(bounded_queries) { World.with_pk(rand1).values } + ids.map do |id| + World.with_pk(id).values + end end worlds.to_json end # Test type 4: Fortunes r.is "fortunes" do - response["Content-Type"] = "text/html; charset=utf-8" + response[CONTENT_TYPE] = HTML_TYPE @fortunes = Fortune.all @fortunes << Fortune.new( id: 0, @@ -56,22 +68,26 @@ def rand1 # Test type 5: Database updates r.is "updates" do - worlds = - DB.synchronize do - Array.new(bounded_queries) do - world = World.with_pk(rand1) + response[CONTENT_TYPE] = JSON_TYPE + worlds = [] + ids = ALL_IDS.sample(bounded_queries) + DB.synchronize do + worlds = + ids.map do |id| + world = World.with_pk(id) new_value = rand1 new_value = rand1 while new_value == world.randomnumber - world.update(randomnumber: new_value) - world.values + world.randomnumber = new_value + world end - end - worlds.to_json + World.batch_update(worlds) + end + worlds.map!(&:values).to_json end # Test type 6: Plaintext r.is "plaintext" do - response["Content-Type"] = "text/plain" + response[CONTENT_TYPE] = PLAINTEXT_TYPE "Hello, World!" end end diff --git a/frameworks/Ruby/roda-sequel/roda-sequel-passenger-mri.dockerfile b/frameworks/Ruby/roda-sequel/roda-sequel-passenger-mri.dockerfile deleted file mode 100644 index 73c319ebc2d..00000000000 --- a/frameworks/Ruby/roda-sequel/roda-sequel-passenger-mri.dockerfile +++ /dev/null @@ -1,22 +0,0 @@ -FROM ruby:3.3-rc - -ADD ./ /roda-sequel -WORKDIR /roda-sequel - -ENV BUNDLE_FORCE_RUBY_PLATFORM=true -ENV RUBY_YJIT_ENABLE=1 - -RUN bundle install --jobs=8 - -# TODO: https://github.com/phusion/passenger/issues/1916 -ENV _PASSENGER_FORCE_HTTP_SESSION=true -ENV DBTYPE=mysql - -RUN ruby -r /roda-sequel/config/auto_tune -e 'puts auto_tune.first' > instances - -EXPOSE 8080 - -CMD bundle exec passenger start --log-level 1 \ - --engine builtin --disable-turbocaching --disable-security-update-check \ - --spawn-method direct --max-pool-size $(cat instances) --min-instances $(cat instances) --max-request-queue-size 1024 \ - --address 0.0.0.0 --port 8080 --environment production diff --git a/frameworks/Ruby/roda-sequel/roda-sequel-postgres-iodine-mri.dockerfile b/frameworks/Ruby/roda-sequel/roda-sequel-postgres-iodine-mri.dockerfile new file mode 100644 index 00000000000..2ab0b2de6cc --- /dev/null +++ b/frameworks/Ruby/roda-sequel/roda-sequel-postgres-iodine-mri.dockerfile @@ -0,0 +1,22 @@ +FROM ruby:3.5-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-passenger-mri.dockerfile b/frameworks/Ruby/roda-sequel/roda-sequel-postgres-passenger-mri.dockerfile deleted file mode 100644 index a315438d86a..00000000000 --- a/frameworks/Ruby/roda-sequel/roda-sequel-postgres-passenger-mri.dockerfile +++ /dev/null @@ -1,22 +0,0 @@ -FROM ruby:3.3-rc - -ADD ./ /roda-sequel -WORKDIR /roda-sequel - -ENV BUNDLE_FORCE_RUBY_PLATFORM=true -ENV RUBY_YJIT_ENABLE=1 - -RUN bundle install --jobs=8 - -# TODO: https://github.com/phusion/passenger/issues/1916 -ENV _PASSENGER_FORCE_HTTP_SESSION=true -ENV DBTYPE=postgresql - -RUN ruby -r /roda-sequel/config/auto_tune -e 'puts auto_tune.first' > instances - -EXPOSE 8080 - -CMD bundle exec passenger start --log-level 1 \ - --engine builtin --disable-turbocaching --disable-security-update-check \ - --spawn-method direct --max-pool-size $(cat instances) --min-instances $(cat instances) --max-request-queue-size 1024 \ - --address 0.0.0.0 --port 8080 --environment production diff --git a/frameworks/Ruby/roda-sequel/roda-sequel-postgres-unicorn-mri.dockerfile b/frameworks/Ruby/roda-sequel/roda-sequel-postgres-unicorn-mri.dockerfile deleted file mode 100644 index 623d8840e5d..00000000000 --- a/frameworks/Ruby/roda-sequel/roda-sequel-postgres-unicorn-mri.dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -FROM ruby:3.3-rc - -ADD ./ /roda-sequel -WORKDIR /roda-sequel - -ENV BUNDLE_FORCE_RUBY_PLATFORM=true -ENV RUBY_YJIT_ENABLE=1 - -RUN bundle install --jobs=8 - -ENV DBTYPE=postgresql - -EXPOSE 8080 - -CMD bundle exec unicorn -c config/mri_unicorn.rb -o 0.0.0.0 -p 8080 -E production diff --git a/frameworks/Ruby/roda-sequel/roda-sequel-postgres.dockerfile b/frameworks/Ruby/roda-sequel/roda-sequel-postgres.dockerfile index 787e4080ea1..46cff7f1b39 100644 --- a/frameworks/Ruby/roda-sequel/roda-sequel-postgres.dockerfile +++ b/frameworks/Ruby/roda-sequel/roda-sequel-postgres.dockerfile @@ -1,15 +1,23 @@ -FROM ruby:3.3-rc +FROM ruby:3.5-rc ADD ./ /roda-sequel WORKDIR /roda-sequel -ENV BUNDLE_FORCE_RUBY_PLATFORM=true 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 puma' RUN bundle install --jobs=8 +ENV RACK_ENV=production ENV DBTYPE=postgresql +ENV WEB_CONCURRENCY=auto EXPOSE 8080 -CMD bundle exec puma -C config/mri_puma.rb -b tcp://0.0.0.0:8080 -e production +CMD bundle exec puma -C config/mri_puma.rb -b tcp://0.0.0.0:8080 diff --git a/frameworks/Ruby/roda-sequel/roda-sequel-unicorn-mri.dockerfile b/frameworks/Ruby/roda-sequel/roda-sequel-unicorn-mri.dockerfile deleted file mode 100644 index fad6582b85a..00000000000 --- a/frameworks/Ruby/roda-sequel/roda-sequel-unicorn-mri.dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -FROM ruby:3.3-rc - -ADD ./ /roda-sequel -WORKDIR /roda-sequel - -ENV BUNDLE_FORCE_RUBY_PLATFORM=true -ENV RUBY_YJIT_ENABLE=1 - -RUN bundle install --jobs=8 - -ENV DBTYPE=mysql - -EXPOSE 8080 - -CMD bundle exec unicorn -c config/mri_unicorn.rb -o 0.0.0.0 -p 8080 -E production diff --git a/frameworks/Ruby/roda-sequel/roda-sequel.dockerfile b/frameworks/Ruby/roda-sequel/roda-sequel.dockerfile index 34fd0da0dd0..1506324b59c 100644 --- a/frameworks/Ruby/roda-sequel/roda-sequel.dockerfile +++ b/frameworks/Ruby/roda-sequel/roda-sequel.dockerfile @@ -1,15 +1,24 @@ -FROM ruby:3.3-rc +FROM ruby:3.5-rc ADD ./ /roda-sequel WORKDIR /roda-sequel -ENV BUNDLE_FORCE_RUBY_PLATFORM=true ENV RUBY_YJIT_ENABLE=1 +ENV RUBY_THREAD_TIMESLICE=10 + +# 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 'mysql puma' RUN bundle install --jobs=8 +ENV RACK_ENV=production ENV DBTYPE=mysql +ENV WEB_CONCURRENCY=auto EXPOSE 8080 -CMD bundle exec puma -C config/mri_puma.rb -b tcp://0.0.0.0:8080 -e production +CMD bundle exec puma -C config/mri_puma.rb -b tcp://0.0.0.0:8080 diff --git a/frameworks/Ruby/sinatra-sequel/Gemfile b/frameworks/Ruby/sinatra-sequel/Gemfile index 8320982e7df..6a685b432a6 100644 --- a/frameworks/Ruby/sinatra-sequel/Gemfile +++ b/frameworks/Ruby/sinatra-sequel/Gemfile @@ -1,20 +1,23 @@ source 'https://rubygems.org' -gem 'json', '~> 2.0' -gem 'passenger', '~> 5.1', :platforms=>[:ruby, :mswin], :require=>false -gem 'puma', '~> 6.4', :require=>false +gem 'json', '~> 2.8' gem 'sequel', '~> 5.0' -gem 'sinatra', '~> 2.0', :require=>'sinatra/base' -gem 'slim', '~> 3.0' -gem 'unicorn', '~> 5.2', :platforms=>[:ruby, :mswin], :require=>false +gem 'sinatra', '~> 4.0', :require=>'sinatra/base' -group :mysql do - gem 'jdbc-mysql', '~> 5.1', :platforms=>:jruby, :require=>'jdbc/mysql' - gem 'mysql2', '~> 0.4', :platforms=>[:ruby, :mswin] +group :mysql, optional: true do + gem 'trilogy', '~> 2.9', platforms: [:ruby, :windows] end -group :postgresql do - gem 'jdbc-postgres', '~> 9.4', :platforms=>:jruby, :require=>'jdbc/postgres' - gem 'pg', '~> 1.5', :platforms=>[:ruby, :mswin] +group :postgresql, optional: true do + gem 'pg', '~> 1.5', :platforms=>[:ruby, :windows] gem 'sequel_pg', '~> 1.6', :platforms=>:ruby, :require=>false end + +group :iodine, optional: true do + gem 'iodine', '~> 0.7', platforms: [:ruby, :windows], require: false +end + +group :puma, optional: true do + gem 'puma', '~> 7.1', require: false + gem 'concurrent-ruby' # used by Puma for auto-tuning +end diff --git a/frameworks/Ruby/sinatra-sequel/Gemfile.lock b/frameworks/Ruby/sinatra-sequel/Gemfile.lock new file mode 100644 index 00000000000..e9d49e6d9b1 --- /dev/null +++ b/frameworks/Ruby/sinatra-sequel/Gemfile.lock @@ -0,0 +1,59 @@ +GEM + remote: https://rubygems.org/ + specs: + base64 (0.2.0) + bigdecimal (3.3.1) + concurrent-ruby (1.3.5) + iodine (0.7.58) + json (2.13.2) + logger (1.6.6) + mustermann (3.0.3) + 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.0) + rack (3.2.0) + rack-protection (4.1.1) + base64 (>= 0.1.0) + logger (>= 1.6.0) + rack (>= 3.0.0, < 4) + rack-session (2.1.0) + base64 (>= 0.1.0) + rack (>= 3.0.0) + ruby2_keywords (0.0.5) + sequel (5.97.0) + bigdecimal + sequel_pg (1.17.2) + pg (>= 0.18.0, != 1.2.0) + sequel (>= 4.38.0) + sinatra (4.1.1) + logger (>= 1.6.0) + mustermann (~> 3.0) + rack (>= 3.0.0, < 4) + rack-protection (= 4.1.1) + rack-session (>= 2.0.0, < 3) + tilt (~> 2.0) + tilt (2.6.0) + trilogy (2.9.0) + +PLATFORMS + ruby + x86_64-darwin-23 + x86_64-linux + +DEPENDENCIES + concurrent-ruby + iodine (~> 0.7) + json (~> 2.8) + pg (~> 1.5) + puma (~> 7.1) + sequel (~> 5.0) + sequel_pg (~> 1.6) + sinatra (~> 4.0) + trilogy (~> 2.9) + +BUNDLED WITH + 2.7.0 diff --git a/frameworks/Ruby/sinatra-sequel/README.md b/frameworks/Ruby/sinatra-sequel/README.md index 89ee66adb32..a031a9566df 100644 --- a/frameworks/Ruby/sinatra-sequel/README.md +++ b/frameworks/Ruby/sinatra-sequel/README.md @@ -12,14 +12,10 @@ comparing a variety of web platforms. The tests will be run with: -* [Ruby 3.3-rc1](http://www.ruby-lang.org) -* [JRuby 9.4](http://jruby.org) -* [Puma 3](http://puma.io) -* [Passenger 5](https://www.phusionpassenger.com) -* [Unicorn 5](https://bogomips.org/unicorn/) -* [Sinatra 2](http://www.sinatrarb.com) +* [Ruby 3.4](http://www.ruby-lang.org) +* [Puma 7](http://puma.io) +* [Sinatra 4](http://www.sinatrarb.com) * [Sequel 5](http://sequel.jeremyevans.net) -* [Slim 3](http://slim-lang.com) * [MySQL 5.5](https://www.mysql.com) * [Postgres 9.3](https://www.postgresql.org) diff --git a/frameworks/Ruby/sinatra-sequel/benchmark_config.json b/frameworks/Ruby/sinatra-sequel/benchmark_config.json index 906e08a6611..008e63a8148 100644 --- a/frameworks/Ruby/sinatra-sequel/benchmark_config.json +++ b/frameworks/Ruby/sinatra-sequel/benchmark_config.json @@ -11,14 +11,14 @@ "approach": "Realistic", "classification": "Micro", "database": "MySQL", - "framework": "sinatra-sequel", + "framework": "sinatra", "language": "Ruby", "orm": "Full", "platform": "Rack", "webserver": "Puma", "os": "Linux", "database_os": "Linux", - "display_name": "sinatra-sequel-puma-mri", + "display_name": "sinatra-sequel [puma, mysql]", "versus": "rack-sequel-puma-mri", "notes": "" }, @@ -31,78 +31,18 @@ "approach": "Realistic", "classification": "Micro", "database": "Postgres", - "framework": "sinatra-sequel", + "framework": "sinatra", "language": "Ruby", "orm": "Full", "platform": "Rack", "webserver": "Puma", "os": "Linux", "database_os": "Linux", - "display_name": "sinatra-sequel-postgres-puma-mri", + "display_name": "sinatra-sequel [puma, postgres]", "versus": "rack-sequel-postgres-puma-mri", "notes": "" }, - "passenger-mri": { - "db_url": "/db", - "query_url": "/queries?queries=", - "fortune_url": "/fortunes", - "update_url": "/updates?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "MySQL", - "framework": "sinatra-sequel", - "language": "Ruby", - "orm": "Full", - "platform": "Rack", - "webserver": "Passenger", - "os": "Linux", - "database_os": "Linux", - "display_name": "sinatra-sequel-passenger-mri", - "versus": "rack-sequel-passenger-mri", - "notes": "" - }, - "postgres-passenger-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-sequel", - "language": "Ruby", - "orm": "Full", - "platform": "Rack", - "webserver": "Passenger", - "os": "Linux", - "database_os": "Linux", - "display_name": "sinatra-sequel-postgres-passenger-mri", - "versus": "rack-sequel-postgres-passenger-mri", - "notes": "" - }, - "unicorn-mri": { - "db_url": "/db", - "query_url": "/queries?queries=", - "fortune_url": "/fortunes", - "update_url": "/updates?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "MySQL", - "framework": "sinatra-sequel", - "language": "Ruby", - "orm": "Full", - "platform": "Rack", - "webserver": "Unicorn", - "os": "Linux", - "database_os": "Linux", - "display_name": "sinatra-sequel-unicorn-mri", - "versus": "rack-sequel-unicorn-mri", - "notes": "" - }, - "postgres-unicorn-mri": { + "postgres-iodine-mri": { "db_url": "/db", "query_url": "/queries?queries=", "fortune_url": "/fortunes", @@ -111,15 +51,15 @@ "approach": "Realistic", "classification": "Micro", "database": "Postgres", - "framework": "sinatra-sequel", + "framework": "sinatra", "language": "Ruby", "orm": "Full", "platform": "Rack", - "webserver": "Unicorn", + "webserver": "Iodine", "os": "Linux", "database_os": "Linux", - "display_name": "sinatra-sequel-postgres-unicorn-mri", - "versus": "rack-sequel-postgres-unicorn-mri", + "display_name": "sinatra-sequel [iodine, postgres]", + "versus": "rack-sequel-postgres-iodine-mri", "notes": "" } } diff --git a/frameworks/Ruby/sinatra-sequel/boot.rb b/frameworks/Ruby/sinatra-sequel/boot.rb index e012694c06a..ca44bdc08df 100644 --- a/frameworks/Ruby/sinatra-sequel/boot.rb +++ b/frameworks/Ruby/sinatra-sequel/boot.rb @@ -3,52 +3,44 @@ 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 = - if defined?(PhusionPassenger) - [ - PhusionPassenger::SharedConstants::SERVER_TOKEN_NAME, - PhusionPassenger::VERSION_STRING - ].join('/').freeze - elsif defined?(Puma) - Puma::Const::PUMA_SERVER_STRING - elsif defined?(Unicorn) - Unicorn::HttpParser::DEFAULTS['SERVER_SOFTWARE'] - end +SERVER_STRING = "Sinatra" Bundler.require(:default) # Load core modules def connect(dbtype) Bundler.require(dbtype) # Load database-specific modules - adapters = { - :mysql=>{ :jruby=>'jdbc:mysql', :mri=>'mysql2' }, - :postgresql=>{ :jruby=>'jdbc:postgresql', :mri=>'postgres' } - } - 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?(JRUBY_VERSION) - opts[:max_connections] = (2 * Math.log(Integer(ENV.fetch('MAX_CONCURRENCY')))).floor - opts[:pool_timeout] = 10 - elsif defined?(Puma) && (threads = Puma.cli_config.options.fetch(:max_threads)) > 1 - opts[:max_connections] = (2 * Math.log(threads)).floor + if defined?(Puma) && (threads = Puma.cli_config.options.fetch(:max_threads)) > 1 + opts[:max_connections] = threads opts[:pool_timeout] = 10 else - Sequel.single_threaded = true + opts[:max_connections] = 512 end Sequel.connect \ '%{adapter}://%{host}/%{database}?user=%{user}&password=%{password}' % { - :adapter=>adapters.fetch(dbtype).fetch(defined?(JRUBY_VERSION) ? :jruby : :mri), - :host=>'tfb-database', - :database=>'hello_world', - :user=>'benchmarkdbuser', - :password=>'benchmarkdbpass' + adapter: adapter, + host: 'tfb-database', + database: 'hello_world', + user: 'benchmarkdbuser', + password: 'benchmarkdbpass' }, opts end @@ -57,6 +49,21 @@ def connect(dbtype) # 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) diff --git a/frameworks/Ruby/sinatra-sequel/config.toml b/frameworks/Ruby/sinatra-sequel/config.toml index 4dd4f8ac1cc..93d9f2ded5c 100644 --- a/frameworks/Ruby/sinatra-sequel/config.toml +++ b/frameworks/Ruby/sinatra-sequel/config.toml @@ -34,71 +34,3 @@ orm = "Full" platform = "Rack" webserver = "Puma" versus = "rack-sequel-puma-mri" - -[postgres-passenger-mri] -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 = "Full" -platform = "Rack" -webserver = "Passenger" -versus = "rack-sequel-postgres-passenger-mri" - -[postgres-unicorn-mri] -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 = "Full" -platform = "Rack" -webserver = "Unicorn" -versus = "rack-sequel-postgres-unicorn-mri" - -[passenger-mri] -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 = "MySQL" -database_os = "Linux" -os = "Linux" -orm = "Full" -platform = "Rack" -webserver = "Passenger" -versus = "rack-sequel-passenger-mri" - -[unicorn-mri] -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 = "MySQL" -database_os = "Linux" -os = "Linux" -orm = "Full" -platform = "Rack" -webserver = "Unicorn" -versus = "rack-sequel-unicorn-mri" diff --git a/frameworks/Ruby/sinatra-sequel/config/java_tune.sh b/frameworks/Ruby/sinatra-sequel/config/java_tune.sh deleted file mode 100644 index 412b1e74fdc..00000000000 --- a/frameworks/Ruby/sinatra-sequel/config/java_tune.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/sh -stack_size=1 -cache_size=240 -meta_size=192 -avail_mem=$(awk '/^MemAvailable/ { print int(0.6 * $2 / 1024); exit }' /proc/meminfo) -heap_size=$(( avail_mem - meta_size - cache_size - (stack_size * MAX_CONCURRENCY * THREAD_FACTOR) )) - -JRUBY_OPTS="-J-server -J-XX:+AggressiveOpts -J-Djava.net.preferIPv4Stack=true" -#JRUBY_OPTS="$JRUBY_OPTS -J-XX:+UseSerialGC" -JRUBY_OPTS="$JRUBY_OPTS -J-XX:+CMSClassUnloadingEnabled -J-XX:+UseConcMarkSweepGC" -#JRUBY_OPTS="$JRUBY_OPTS -J-XX:+UseG1GC -J-XX:+UseStringDeduplication" -JRUBY_OPTS="$JRUBY_OPTS -J-Xms${heap_size}m -J-Xmx${heap_size}m" -JRUBY_OPTS="$JRUBY_OPTS -J-Xss${stack_size}m" -JRUBY_OPTS="$JRUBY_OPTS -J-XX:MaxMetaspaceSize=${meta_size}m" -JRUBY_OPTS="$JRUBY_OPTS -J-XX:ReservedCodeCacheSize=${cache_size}m" -JRUBY_OPTS="$JRUBY_OPTS -Xcompile.invokedynamic=true -J-XX:+UseNUMA -J-XX:+AlwaysPreTouch" - -export JRUBY_OPTS diff --git a/frameworks/Ruby/sinatra-sequel/config/mri_puma.rb b/frameworks/Ruby/sinatra-sequel/config/mri_puma.rb index 95b855bafd3..794c18f0c08 100644 --- a/frameworks/Ruby/sinatra-sequel/config/mri_puma.rb +++ b/frameworks/Ruby/sinatra-sequel/config/mri_puma.rb @@ -1,7 +1,10 @@ require_relative 'auto_tune' # FWBM only... use the puma_auto_tune gem in production! -num_workers, num_threads = auto_tune +_, num_threads = auto_tune -workers num_workers -threads num_threads, num_threads +threads num_threads + +before_fork do + Sequel::DATABASES.each(&:disconnect) +end diff --git a/frameworks/Ruby/sinatra-sequel/config/mri_unicorn.rb b/frameworks/Ruby/sinatra-sequel/config/mri_unicorn.rb deleted file mode 100644 index c9a0c55083e..00000000000 --- a/frameworks/Ruby/sinatra-sequel/config/mri_unicorn.rb +++ /dev/null @@ -1,6 +0,0 @@ -require_relative 'auto_tune' - -# FWBM only... -num_workers, = auto_tune - -worker_processes num_workers diff --git a/frameworks/Ruby/sinatra-sequel/hello_world.rb b/frameworks/Ruby/sinatra-sequel/hello_world.rb index 4008a286b42..f4410cd140c 100644 --- a/frameworks/Ruby/sinatra-sequel/hello_world.rb +++ b/frameworks/Ruby/sinatra-sequel/hello_world.rb @@ -1,8 +1,5 @@ # frozen_string_literal: true -# Configure Slim templating engine -Slim::Engine.set_options :format=>:html, :sort_attrs=>false - # Our Rack application to be executed by rackup class HelloWorld < Sinatra::Base configure do @@ -13,6 +10,9 @@ class HelloWorld < Sinatra::Base # XSS, CSRF, IP spoofing, etc. protection are not explicitly required disable :protection + # disable host_authorization for all environments + set :host_authorization, { permitted_hosts: [] } + # Only add the charset parameter to specific content types per the requirements set :add_charset, [mime_type(:html)] end @@ -20,14 +20,12 @@ class HelloWorld < Sinatra::Base helpers do def bounded_queries queries = params[:queries].to_i - return QUERIES_MIN if queries < QUERIES_MIN - return QUERIES_MAX if queries > QUERIES_MAX - queries + queries.clamp(QUERIES_MIN, QUERIES_MAX) end def json(data) content_type :json - JSON.fast_generate(data) + data.to_json end # Return a random number between 1 and MAX_PK @@ -38,7 +36,7 @@ def rand1 after do response['Date'] = Time.now.httpdate - end + end if defined?(Falcon) || defined?(Puma) after do response['Server'] = SERVER_STRING @@ -56,10 +54,11 @@ def rand1 # Test type 3: Multiple database queries get '/queries' do + ids = ALL_IDS.sample(bounded_queries) worlds = DB.synchronize do - Array.new(bounded_queries) do - World.with_pk(rand1) + ids.map do |id| + World.with_pk(id) end end @@ -75,21 +74,24 @@ def rand1 ) @fortunes.sort_by!(&:message) - slim :fortunes + erb :fortunes, :layout=>true end # Test type 5: Database updates get '/updates' do - worlds = - DB.synchronize do - Array.new(bounded_queries) do - world = World.with_pk(rand1) + worlds = nil + ids = ALL_IDS.sample(bounded_queries) + DB.synchronize do + worlds = + ids.map do |id| + world = World.with_pk(id) new_value = rand1 new_value = rand1 while new_value == world.randomnumber - world.update(randomnumber: new_value) + world.randomnumber = new_value world end - end + World.batch_update(worlds) + end json worlds.map!(&:values) end diff --git a/frameworks/Ruby/sinatra-sequel/sinatra-sequel-base.dockerfile b/frameworks/Ruby/sinatra-sequel/sinatra-sequel-base.dockerfile deleted file mode 100644 index d96f522e49d..00000000000 --- a/frameworks/Ruby/sinatra-sequel/sinatra-sequel-base.dockerfile +++ /dev/null @@ -1,8 +0,0 @@ -FROM ruby:3.3-rc - -ENV RUBY_YJIT_ENABLE=1 - -ADD ./ /sinatra-sequel -WORKDIR /sinatra-sequel - -RUN bundle install --jobs=4 --gemfile=/sinatra-sequel/Gemfile --path=/sinatra-sequel/sinatra-sequel/bundle diff --git a/frameworks/Ruby/sinatra-sequel/sinatra-sequel-jruby-base.dockerfile b/frameworks/Ruby/sinatra-sequel/sinatra-sequel-jruby-base.dockerfile deleted file mode 100644 index ff858dc6388..00000000000 --- a/frameworks/Ruby/sinatra-sequel/sinatra-sequel-jruby-base.dockerfile +++ /dev/null @@ -1,8 +0,0 @@ -FROM jruby:9.4-jdk17 - -ADD ./ /sinatra-sequel -WORKDIR /sinatra-sequel - -ENV THREAD_FACTOR=2 - -RUN bundle install --jobs=4 --gemfile=/sinatra-sequel/Gemfile --path=/sinatra-sequel/sinatra-sequel/bundle diff --git a/frameworks/Ruby/sinatra-sequel/sinatra-sequel-passenger-mri.dockerfile b/frameworks/Ruby/sinatra-sequel/sinatra-sequel-passenger-mri.dockerfile deleted file mode 100644 index dfe342c2a74..00000000000 --- a/frameworks/Ruby/sinatra-sequel/sinatra-sequel-passenger-mri.dockerfile +++ /dev/null @@ -1,21 +0,0 @@ -FROM ruby:3.3-rc - -ENV RUBY_YJIT_ENABLE=1 - -ADD ./ /sinatra-sequel -WORKDIR /sinatra-sequel - -RUN bundle install --jobs=4 --gemfile=/sinatra-sequel/Gemfile --path=/sinatra-sequel/sinatra-sequel/bundle - -# TODO: https://github.com/phusion/passenger/issues/1916 -ENV _PASSENGER_FORCE_HTTP_SESSION=true -ENV DBTYPE=mysql - -RUN ruby -r /sinatra-sequel/config/auto_tune -e 'puts auto_tune.first' > instances - -EXPOSE 8080 - -CMD bundle exec passenger start --log-level 1 \ - --engine builtin --disable-turbocaching --disable-security-update-check \ - --spawn-method direct --max-pool-size $(cat instances) --min-instances $(cat instances) --max-request-queue-size 1024 \ - --address 0.0.0.0 --port 8080 --environment production diff --git a/frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres-iodine-mri.dockerfile b/frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres-iodine-mri.dockerfile new file mode 100644 index 00000000000..83d1de64132 --- /dev/null +++ b/frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres-iodine-mri.dockerfile @@ -0,0 +1,21 @@ +FROM ruby:3.5-rc + +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=postgresql:iodine +RUN bundle install --jobs=4 --gemfile=/sinatra-sequel/Gemfile + +ENV APP_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/sinatra-sequel/sinatra-sequel-postgres-passenger-mri.dockerfile b/frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres-passenger-mri.dockerfile deleted file mode 100644 index 3e5cc00c634..00000000000 --- a/frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres-passenger-mri.dockerfile +++ /dev/null @@ -1,22 +0,0 @@ -FROM ruby:3.3-rc - -ENV RUBY_YJIT_ENABLE=1 - -ADD ./ /sinatra-sequel -WORKDIR /sinatra-sequel - -RUN bundle install --jobs=4 --gemfile=/sinatra-sequel/Gemfile --path=/sinatra-sequel/sinatra-sequel/bundle - -# TODO: https://github.com/phusion/passenger/issues/1916 -ENV _PASSENGER_FORCE_HTTP_SESSION=true -ENV DBTYPE=postgresql - -RUN ruby -r /sinatra-sequel/config/auto_tune -e 'puts auto_tune.first' > instances - -EXPOSE 8080 - -CMD bundle exec passenger start --log-level 1 \ - --engine builtin --disable-turbocaching --disable-security-update-check \ - --spawn-method direct --max-pool-size $(cat instances) --min-instances $(cat instances) --max-request-queue-size 1024 \ - --address 0.0.0.0 --port 8080 --environment production - diff --git a/frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres-unicorn-mri.dockerfile b/frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres-unicorn-mri.dockerfile deleted file mode 100644 index 3be003d036b..00000000000 --- a/frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres-unicorn-mri.dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM ruby:3.3-rc - -ENV RUBY_YJIT_ENABLE=1 - -ADD ./ /sinatra-sequel -WORKDIR /sinatra-sequel - -RUN bundle install --jobs=4 --gemfile=/sinatra-sequel/Gemfile --path=/sinatra-sequel/sinatra-sequel/bundle - -ENV DBTYPE=postgresql - -EXPOSE 8080 - -CMD bundle exec unicorn -c config/mri_unicorn.rb -o 0.0.0.0 -p 8080 -E production diff --git a/frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres.dockerfile b/frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres.dockerfile index 1ddf88b4d0c..afbbc915d22 100644 --- a/frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres.dockerfile +++ b/frameworks/Ruby/sinatra-sequel/sinatra-sequel-postgres.dockerfile @@ -1,14 +1,22 @@ -FROM ruby:3.3-rc +FROM ruby:3.5-rc 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 -RUN bundle install --jobs=4 --gemfile=/sinatra-sequel/Gemfile --path=/sinatra-sequel/sinatra-sequel/bundle +ENV BUNDLE_WITH=postgresql:puma +RUN bundle install --jobs=4 --gemfile=/sinatra-sequel/Gemfile +ENV WEB_CONCURRENCY=auto +ENV APP_ENV=production ENV DBTYPE=postgresql EXPOSE 8080 -CMD bundle exec puma -C config/mri_puma.rb -b tcp://0.0.0.0:8080 -e production +CMD bundle exec puma -C config/mri_puma.rb -b tcp://0.0.0.0:8080 diff --git a/frameworks/Ruby/sinatra-sequel/sinatra-sequel-unicorn-mri.dockerfile b/frameworks/Ruby/sinatra-sequel/sinatra-sequel-unicorn-mri.dockerfile deleted file mode 100644 index 3d42937031e..00000000000 --- a/frameworks/Ruby/sinatra-sequel/sinatra-sequel-unicorn-mri.dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM ruby:3.3-rc - -ENV RUBY_YJIT_ENABLE=1 - -ADD ./ /sinatra-sequel -WORKDIR /sinatra-sequel - -RUN bundle install --jobs=4 --gemfile=/sinatra-sequel/Gemfile --path=/sinatra-sequel/sinatra-sequel/bundle - -ENV DBTYPE=mysql - -EXPOSE 8080 - -CMD bundle exec unicorn -c config/mri_unicorn.rb -o 0.0.0.0 -p 8080 -E production diff --git a/frameworks/Ruby/sinatra-sequel/sinatra-sequel.dockerfile b/frameworks/Ruby/sinatra-sequel/sinatra-sequel.dockerfile index 78a9fbad91d..7f622501ddf 100644 --- a/frameworks/Ruby/sinatra-sequel/sinatra-sequel.dockerfile +++ b/frameworks/Ruby/sinatra-sequel/sinatra-sequel.dockerfile @@ -1,14 +1,22 @@ -FROM ruby:3.3-rc +FROM ruby:3.5-rc 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 -RUN bundle install --jobs=4 --gemfile=/sinatra-sequel/Gemfile --path=/sinatra-sequel/sinatra-sequel/bundle +ENV BUNDLE_WITH=mysql:puma +RUN bundle install --jobs=4 --gemfile=/sinatra-sequel/Gemfile +ENV WEB_CONCURRENCY=auto +ENV APP_ENV=production ENV DBTYPE=mysql EXPOSE 8080 -CMD bundle exec puma -C config/mri_puma.rb -b tcp://0.0.0.0:8080 -e production +CMD bundle exec puma -C config/mri_puma.rb -b tcp://0.0.0.0:8080 diff --git a/frameworks/Ruby/sinatra-sequel/views/fortunes.erb b/frameworks/Ruby/sinatra-sequel/views/fortunes.erb new file mode 100644 index 00000000000..6b773ec5dc5 --- /dev/null +++ b/frameworks/Ruby/sinatra-sequel/views/fortunes.erb @@ -0,0 +1,12 @@ + + + + + +<% @fortunes.each do |fortune| %> + + + + +<% end %> +
idmessage
<%= fortune.id %><%= ERB::Escape.html_escape(fortune.message) %>
diff --git a/frameworks/Ruby/sinatra-sequel/views/fortunes.slim b/frameworks/Ruby/sinatra-sequel/views/fortunes.slim deleted file mode 100644 index 14c18a58bc7..00000000000 --- a/frameworks/Ruby/sinatra-sequel/views/fortunes.slim +++ /dev/null @@ -1,8 +0,0 @@ -table - tr - th id - th message - - for fortune in @fortunes - tr - td =fortune.id - td =fortune.message \ No newline at end of file diff --git a/frameworks/Ruby/sinatra-sequel/views/layout.erb b/frameworks/Ruby/sinatra-sequel/views/layout.erb new file mode 100644 index 00000000000..7d6715a3e98 --- /dev/null +++ b/frameworks/Ruby/sinatra-sequel/views/layout.erb @@ -0,0 +1,11 @@ + + + + Fortunes + + + +<%= yield %> + + + diff --git a/frameworks/Ruby/sinatra-sequel/views/layout.slim b/frameworks/Ruby/sinatra-sequel/views/layout.slim deleted file mode 100644 index 2be47605c04..00000000000 --- a/frameworks/Ruby/sinatra-sequel/views/layout.slim +++ /dev/null @@ -1,6 +0,0 @@ -doctype html -html - head - title Fortunes - body - == yield \ No newline at end of file diff --git a/frameworks/Ruby/sinatra/Gemfile b/frameworks/Ruby/sinatra/Gemfile index e606bd250d8..6b0a0c45fd8 100644 --- a/frameworks/Ruby/sinatra/Gemfile +++ b/frameworks/Ruby/sinatra/Gemfile @@ -1,16 +1,21 @@ source 'https://rubygems.org' -gem 'activerecord', '~> 7.0', :require=>'active_record' -gem 'json', '~> 2.0' -gem 'passenger', '~> 6.0', :platforms=>[:ruby, :mswin], :require=>false -gem 'puma', '~> 6.4', :require=>false -gem 'sinatra', '~> 3.0', :require=>'sinatra/base' -gem 'unicorn', '~> 6.1', :platforms=>[:ruby, :mswin], :require=>false +gem 'activerecord', '~> 8.0', require: 'active_record' +gem 'json', '~> 2.8' +gem 'sinatra', '~> 4.2', require: 'sinatra/base' -group :mysql do - gem 'mysql2', '~> 0.5', :platforms=>[:ruby, :mswin] +group :mysql, optional: true do + gem 'trilogy', '~> 2.9.0', platforms: [:ruby, :windows] end -group :postgresql do - gem 'pg', '~> 1.5', :platforms=>[:ruby, :mswin] +group :postgresql, optional: true do + gem 'pg', '~> 1.5', platforms: [:ruby, :windows] +end + +group :iodine, optional: true do + gem 'iodine', '~> 0.7', platforms: [:ruby, :windows], require: false +end + +group :puma, optional: true do + gem 'puma', '~> 7.1', require: false end diff --git a/frameworks/Ruby/sinatra/Gemfile.lock b/frameworks/Ruby/sinatra/Gemfile.lock new file mode 100644 index 00000000000..a9909fd6604 --- /dev/null +++ b/frameworks/Ruby/sinatra/Gemfile.lock @@ -0,0 +1,82 @@ +GEM + remote: https://rubygems.org/ + specs: + activemodel (8.0.2.1) + activesupport (= 8.0.2.1) + activerecord (8.0.2.1) + activemodel (= 8.0.2.1) + activesupport (= 8.0.2.1) + timeout (>= 0.4.0) + activesupport (8.0.2.1) + base64 + benchmark (>= 0.3) + bigdecimal + concurrent-ruby (~> 1.0, >= 1.3.1) + connection_pool (>= 2.2.5) + drb + i18n (>= 1.6, < 2) + logger (>= 1.4.2) + minitest (>= 5.1) + securerandom (>= 0.3) + tzinfo (~> 2.0, >= 2.0.5) + uri (>= 0.13.1) + base64 (0.3.0) + benchmark (0.4.1) + bigdecimal (3.2.2) + concurrent-ruby (1.3.5) + connection_pool (2.5.3) + drb (2.2.3) + i18n (1.14.7) + concurrent-ruby (~> 1.0) + iodine (0.7.58) + json (2.13.2) + logger (1.7.0) + minitest (5.25.5) + 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.0) + rack (3.2.3) + rack-protection (4.2.0) + base64 (>= 0.1.0) + logger (>= 1.6.0) + rack (>= 3.0.0, < 4) + rack-session (2.1.1) + base64 (>= 0.1.0) + rack (>= 3.0.0) + ruby2_keywords (0.0.5) + securerandom (0.4.1) + sinatra (4.2.0) + logger (>= 1.6.0) + mustermann (~> 3.0) + rack (>= 3.0.0, < 4) + rack-protection (= 4.2.0) + rack-session (>= 2.0.0, < 3) + tilt (~> 2.0) + tilt (2.6.1) + timeout (0.4.3) + trilogy (2.9.0) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) + uri (1.0.3) + +PLATFORMS + ruby + x86_64-darwin-23 + x86_64-linux + +DEPENDENCIES + activerecord (~> 8.0) + iodine (~> 0.7) + json (~> 2.8) + pg (~> 1.5) + puma (~> 7.1) + sinatra (~> 4.2) + trilogy (~> 2.9.0) + +BUNDLED WITH + 2.7.0 diff --git a/frameworks/Ruby/sinatra/README.md b/frameworks/Ruby/sinatra/README.md index 38e5dc4ea0b..fabf6b58283 100644 --- a/frameworks/Ruby/sinatra/README.md +++ b/frameworks/Ruby/sinatra/README.md @@ -12,12 +12,10 @@ comparing a variety of web platforms. The tests will be run with: -* [Ruby 3.3-rc](http://www.ruby-lang.org) -* [Puma 6](http://puma.io) -* [Passenger 6](https://www.phusionpassenger.com) -* [Unicorn 6](https://bogomips.org/unicorn/) -* [Sinatra 3](http://www.sinatrarb.com) -* [ActiveRecord 7](https://github.com/rails/rails/tree/master/activerecord) +* [Ruby 3.4](http://www.ruby-lang.org) +* [Puma 7](http://puma.io) +* [Sinatra 4](http://www.sinatrarb.com) +* [ActiveRecord 8](https://github.com/rails/rails/tree/master/activerecord) * [MySQL 5.5](https://www.mysql.com) * [Postgres 9.3](https://www.postgresql.org) diff --git a/frameworks/Ruby/sinatra/benchmark_config.json b/frameworks/Ruby/sinatra/benchmark_config.json index 166a2e9e2bf..7bdbb62e853 100644 --- a/frameworks/Ruby/sinatra/benchmark_config.json +++ b/frameworks/Ruby/sinatra/benchmark_config.json @@ -20,7 +20,7 @@ "webserver": "Puma", "os": "Linux", "database_os": "Linux", - "display_name": "sinatra-puma-mri", + "display_name": "sinatra [puma, mysql]", "versus": "rack-puma-mri", "notes": "" }, @@ -40,11 +40,11 @@ "webserver": "Puma", "os": "Linux", "database_os": "Linux", - "display_name": "sinatra-postgres-puma-mri", + "display_name": "sinatra [puma, postgres]", "versus": "rack-postgres-puma-mri", "notes": "" }, - "passenger-mri": { + "postgres-iodine-mri": { "json_url": "/json", "db_url": "/db", "query_url": "/queries?queries=", @@ -54,78 +54,16 @@ "port": 8080, "approach": "Realistic", "classification": "Micro", - "database": "MySQL", - "framework": "sinatra", - "language": "Ruby", - "orm": "Full", - "platform": "Rack", - "webserver": "Passenger", - "os": "Linux", - "database_os": "Linux", - "display_name": "sinatra-passenger-mri", - "versus": "rack-passenger-mri", - "notes": "" - }, - "postgres-passenger-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", - "orm": "Full", - "platform": "Rack", - "webserver": "Passenger", - "os": "Linux", - "database_os": "Linux", - "display_name": "sinatra-postgres-passenger-mri", - "versus": "rack-postgres-passenger-mri", - "notes": "" - }, - "unicorn-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": "MySQL", - "framework": "sinatra", - "language": "Ruby", - "orm": "Full", - "platform": "Rack", - "webserver": "Unicorn", - "os": "Linux", - "database_os": "Linux", - "display_name": "sinatra-unicorn-mri", - "versus": "rack-unicorn-mri", - "notes": "" - }, - "postgres-unicorn-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", "orm": "Full", "platform": "Rack", - "webserver": "Unicorn", + "webserver": "Iodine", "os": "Linux", "database_os": "Linux", - "display_name": "sinatra-postgres-unicorn-mri", - "versus": "rack-postgres-unicorn-mri", + "display_name": "sinatra [iodine, postgres]", + "versus": "rack-postgres-iodine-mri", "notes": "" } } diff --git a/frameworks/Ruby/sinatra/boot.rb b/frameworks/Ruby/sinatra/boot.rb old mode 100755 new mode 100644 index 3b6c615f85e..e27fe4e928c --- a/frameworks/Ruby/sinatra/boot.rb +++ b/frameworks/Ruby/sinatra/boot.rb @@ -3,20 +3,11 @@ 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 = - if defined?(PhusionPassenger) - [ - PhusionPassenger::SharedConstants::SERVER_TOKEN_NAME, - PhusionPassenger::VERSION_STRING - ].join('/').freeze - elsif defined?(Puma) - Puma::Const::PUMA_SERVER_STRING - elsif defined?(Unicorn) - Unicorn::HttpParser::DEFAULTS['SERVER_SOFTWARE'] - end +SERVER_STRING = "Sinatra" Bundler.require(:default) # Load core modules @@ -24,24 +15,28 @@ def connect(dbtype) Bundler.require(dbtype) # Load database-specific modules opts = { - :adapter=>(dbtype == :mysql ? 'mysql2' : 'postgresql'), - :username=>'benchmarkdbuser', - :password=>'benchmarkdbpass', - :host=>'tfb-database', - :database=>'hello_world' + 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?(JRUBY_VERSION) - opts[:pool] = (2 * Math.log(Integer(ENV.fetch('MAX_CONCURRENCY')))).floor - opts[:checkout_timeout] = 10 - elsif defined?(Puma) && (threads = Puma.cli_config.options.fetch(:max_threads)) > 1 - opts[:pool] = (2 * Math.log(threads)).floor + if defined?(Puma) && (threads = Puma.cli_config.options.fetch(:max_threads)) > 1 + opts[:pool] = threads opts[:checkout_timeout] = 10 else - # TODO: ActiveRecord doesn't have a single-threaded mode? - opts[:pool] = 1 - opts[:checkout_timeout] = 0 + opts[:pool] = 512 end ActiveRecord::Base.establish_connection(opts) @@ -53,12 +48,22 @@ def connect(dbtype) class World < ActiveRecord::Base self.table_name = name - alias_attribute(:randomnumber, :randomNumber) \ - if connection.adapter_name.downcase.start_with?('mysql') + 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.clear_active_connections! +ActiveRecord::Base.connection_handler.clear_active_connections! diff --git a/frameworks/Ruby/sinatra/config.toml b/frameworks/Ruby/sinatra/config.toml index 035f0c5541e..fec67b1fc9b 100644 --- a/frameworks/Ruby/sinatra/config.toml +++ b/frameworks/Ruby/sinatra/config.toml @@ -34,71 +34,3 @@ orm = "Full" platform = "Rack" webserver = "Puma" versus = "rack-puma-mri" - -[postgres-passenger-mri] -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 = "Full" -platform = "Rack" -webserver = "Passenger" -versus = "rack-postgres-passenger-mri" - -[postgres-unicorn-mri] -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 = "Full" -platform = "Rack" -webserver = "Unicorn" -versus = "rack-postgres-unicorn-mri" - -[passenger-mri] -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 = "MySQL" -database_os = "Linux" -os = "Linux" -orm = "Full" -platform = "Rack" -webserver = "Passenger" -versus = "rack-passenger-mri" - -[unicorn-mri] -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 = "MySQL" -database_os = "Linux" -os = "Linux" -orm = "Full" -platform = "Rack" -webserver = "Unicorn" -versus = "rack-unicorn-mri" diff --git a/frameworks/Ruby/sinatra/config/mri_unicorn.rb b/frameworks/Ruby/sinatra/config/mri_unicorn.rb deleted file mode 100644 index c9a0c55083e..00000000000 --- a/frameworks/Ruby/sinatra/config/mri_unicorn.rb +++ /dev/null @@ -1,6 +0,0 @@ -require_relative 'auto_tune' - -# FWBM only... -num_workers, = auto_tune - -worker_processes num_workers diff --git a/frameworks/Ruby/sinatra/hello_world.rb b/frameworks/Ruby/sinatra/hello_world.rb index 44d6d3af0dd..3c5a96ba2a4 100644 --- a/frameworks/Ruby/sinatra/hello_world.rb +++ b/frameworks/Ruby/sinatra/hello_world.rb @@ -10,6 +10,9 @@ class HelloWorld < Sinatra::Base # XSS, CSRF, IP spoofing, etc. protection are not explicitly required disable :protection + # disable it for all environments + set :host_authorization, { permitted_hosts: [] } + # Only add the charset parameter to specific content types per the requirements set :add_charset, [mime_type(:html)] end @@ -17,14 +20,12 @@ class HelloWorld < Sinatra::Base helpers do def bounded_queries queries = params[:queries].to_i - return QUERIES_MIN if queries < QUERIES_MIN - return QUERIES_MAX if queries > QUERIES_MAX - queries + queries.clamp(QUERIES_MIN, QUERIES_MAX) end def json(data) content_type :json - JSON.fast_generate(data) + data.to_json end # Return a random number between 1 and MAX_PK @@ -35,25 +36,21 @@ def rand1 after do response['Date'] = Time.now.httpdate - end + end if defined?(Falcon) || defined?(Puma) || defined?(Agoo) after do response['Server'] = SERVER_STRING end if SERVER_STRING - after do - ActiveRecord::Base.clear_active_connections! - end - # Test type 1: JSON serialization get '/json' do - json :message=>'Hello, World!' + json message: 'Hello, World!' end # Test type 2: Single database query get '/db' do world = - ActiveRecord::Base.connection_pool.with_connection do + ActiveRecord::Base.with_connection do World.find(rand1).attributes end @@ -62,44 +59,48 @@ def rand1 # Test type 3: Multiple database queries get '/queries' do + ids = ALL_IDS.sample(bounded_queries) worlds = - ActiveRecord::Base.connection_pool.with_connection do - Array.new(bounded_queries) do - World.find(rand1) + ActiveRecord::Base.with_connection do + ids.map do |id| + World.find(id).attributes end end - json worlds.map!(&:attributes) + json worlds end # Test type 4: Fortunes get '/fortunes' do - @fortunes = ActiveRecord::Base.connection_pool.with_connection do + @fortunes = ActiveRecord::Base.with_connection do Fortune.all end.to_a @fortunes << Fortune.new( - :id=>0, - :message=>'Additional fortune added at request time.' + id: 0, + message: 'Additional fortune added at request time.' ) @fortunes.sort_by!(&:message) - erb :fortunes, :layout=>true + erb :fortunes, layout: true end # Test type 5: Database updates get '/updates' do - worlds = - ActiveRecord::Base.connection_pool.with_connection do - Array.new(bounded_queries) do - world = World.find(rand1) - new_value = rand1 - new_value = rand1 while new_value == world.randomnumber - world.update(randomnumber: new_value) - world - end + 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 - - json worlds.map!(&:attributes) + end + worlds.sort_by!{_1[:id]} + ActiveRecord::Base.with_connection do + World.upsert_all(worlds) + end + json worlds end # Test type 6: Plaintext diff --git a/frameworks/Ruby/sinatra/sinatra-passenger-mri.dockerfile b/frameworks/Ruby/sinatra/sinatra-passenger-mri.dockerfile deleted file mode 100644 index 9ef7f70943d..00000000000 --- a/frameworks/Ruby/sinatra/sinatra-passenger-mri.dockerfile +++ /dev/null @@ -1,21 +0,0 @@ -FROM ruby:3.3-rc - -ENV RUBY_YJIT_ENABLE=1 - -ADD ./ /sinatra -WORKDIR /sinatra - -RUN bundle install --jobs=4 --gemfile=/sinatra/Gemfile --path=/sinatra/sinatra/bundle - -# TODO: https://github.com/phusion/passenger/issues/1916 -ENV _PASSENGER_FORCE_HTTP_SESSION=true -ENV DBTYPE=mysql - -RUN ruby -r /sinatra/config/auto_tune -e 'puts auto_tune.first' > instances - -EXPOSE 8080 - -CMD bundle exec passenger start --log-level 1 \ - --engine builtin --disable-turbocaching --disable-security-update-check \ - --spawn-method direct --max-pool-size $(cat instances) --min-instances $(cat instances) --max-request-queue-size 1024 \ - --address 0.0.0.0 --port 8080 --environment production diff --git a/frameworks/Ruby/sinatra/sinatra-postgres-iodine-mri.dockerfile b/frameworks/Ruby/sinatra/sinatra-postgres-iodine-mri.dockerfile new file mode 100644 index 00000000000..a6a29633958 --- /dev/null +++ b/frameworks/Ruby/sinatra/sinatra-postgres-iodine-mri.dockerfile @@ -0,0 +1,21 @@ +FROM ruby:3.5-rc + +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=postgresql:iodine +RUN bundle install --jobs=4 --gemfile=/sinatra/Gemfile + +ENV APP_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/sinatra/sinatra-postgres-passenger-mri.dockerfile b/frameworks/Ruby/sinatra/sinatra-postgres-passenger-mri.dockerfile deleted file mode 100644 index 92c66ae5985..00000000000 --- a/frameworks/Ruby/sinatra/sinatra-postgres-passenger-mri.dockerfile +++ /dev/null @@ -1,22 +0,0 @@ -FROM ruby:3.3-rc - -ENV RUBY_YJIT_ENABLE=1 - -ADD ./ /sinatra -WORKDIR /sinatra - -RUN bundle install --jobs=4 --gemfile=/sinatra/Gemfile --path=/sinatra/sinatra/bundle - -# TODO: https://github.com/phusion/passenger/issues/1916 -ENV _PASSENGER_FORCE_HTTP_SESSION=true -ENV DBTYPE=postgresql - -RUN ruby -r /sinatra/config/auto_tune -e 'puts auto_tune.first' > instances - -EXPOSE 8080 - -CMD bundle exec passenger start --log-level 1 \ - --engine builtin --disable-turbocaching --disable-security-update-check \ - --spawn-method direct --max-pool-size $(cat instances) --min-instances $(cat instances) --max-request-queue-size 1024 \ - --address 0.0.0.0 --port 8080 --environment production - diff --git a/frameworks/Ruby/sinatra/sinatra-postgres-unicorn-mri.dockerfile b/frameworks/Ruby/sinatra/sinatra-postgres-unicorn-mri.dockerfile deleted file mode 100644 index e264737b84f..00000000000 --- a/frameworks/Ruby/sinatra/sinatra-postgres-unicorn-mri.dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM ruby:3.3-rc - -ENV RUBY_YJIT_ENABLE=1 - -ADD ./ /sinatra -WORKDIR /sinatra - -RUN bundle install --jobs=4 --gemfile=/sinatra/Gemfile --path=/sinatra/sinatra/bundle - -ENV DBTYPE=postgresql - -EXPOSE 8080 - -CMD bundle exec unicorn -c config/mri_unicorn.rb -o 0.0.0.0 -p 8080 -E production diff --git a/frameworks/Ruby/sinatra/sinatra-postgres.dockerfile b/frameworks/Ruby/sinatra/sinatra-postgres.dockerfile index 52c38f195fb..5d16f620330 100644 --- a/frameworks/Ruby/sinatra/sinatra-postgres.dockerfile +++ b/frameworks/Ruby/sinatra/sinatra-postgres.dockerfile @@ -1,14 +1,22 @@ -FROM ruby:3.3-rc +FROM ruby:3.5-rc 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 -RUN bundle install --jobs=4 --gemfile=/sinatra/Gemfile --path=/sinatra/sinatra/bundle +ENV BUNDLE_WITH=postgresql:puma +RUN bundle install --jobs=4 --gemfile=/sinatra/Gemfile +ENV WEB_CONCURRENCY=auto +ENV APP_ENV=production ENV DBTYPE=postgresql EXPOSE 8080 -CMD bundle exec puma -C config/mri_puma.rb -b tcp://0.0.0.0:8080 -e production +CMD bundle exec puma -C config/mri_puma.rb -b tcp://0.0.0.0:8080 diff --git a/frameworks/Ruby/sinatra/sinatra-unicorn-mri.dockerfile b/frameworks/Ruby/sinatra/sinatra-unicorn-mri.dockerfile deleted file mode 100644 index 330670f9962..00000000000 --- a/frameworks/Ruby/sinatra/sinatra-unicorn-mri.dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM ruby:3.3-rc - -ENV RUBY_YJIT_ENABLE=1 - -ADD ./ /sinatra -WORKDIR /sinatra - -RUN bundle install --jobs=4 --gemfile=/sinatra/Gemfile --path=/sinatra/sinatra/bundle - -ENV DBTYPE=mysql - -EXPOSE 8080 - -CMD bundle exec unicorn -c config/mri_unicorn.rb -o 0.0.0.0 -p 8080 -E production diff --git a/frameworks/Ruby/sinatra/sinatra.dockerfile b/frameworks/Ruby/sinatra/sinatra.dockerfile index 614b265a6ea..252f6743a01 100644 --- a/frameworks/Ruby/sinatra/sinatra.dockerfile +++ b/frameworks/Ruby/sinatra/sinatra.dockerfile @@ -1,14 +1,22 @@ -FROM ruby:3.3-rc +FROM ruby:3.5-rc 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 -RUN bundle install --jobs=4 --gemfile=/sinatra/Gemfile --path=/sinatra/sinatra/bundle +ENV BUNDLE_WITH=mysql:puma +RUN bundle install --jobs=4 --gemfile=/sinatra/Gemfile +ENV APP_ENV=production ENV DBTYPE=mysql +ENV WEB_CONCURRENCY=auto EXPOSE 8080 -CMD bundle exec puma -C config/mri_puma.rb -b tcp://0.0.0.0:8080 -e production +CMD bundle exec puma -C config/mri_puma.rb -b tcp://0.0.0.0:8080 diff --git a/frameworks/Ruby/sinatra/views/fortunes.erb b/frameworks/Ruby/sinatra/views/fortunes.erb index 3d27f4dc50f..6b773ec5dc5 100644 --- a/frameworks/Ruby/sinatra/views/fortunes.erb +++ b/frameworks/Ruby/sinatra/views/fortunes.erb @@ -6,7 +6,7 @@ <% @fortunes.each do |fortune| %> <%= fortune.id %> - <%= Rack::Utils.escape_html(fortune.message) %> + <%= ERB::Escape.html_escape(fortune.message) %> <% end %> diff --git a/frameworks/Rust/actix/Cargo.lock b/frameworks/Rust/actix/Cargo.lock index 501124b789a..559b8a510fb 100644 --- a/frameworks/Rust/actix/Cargo.lock +++ b/frameworks/Rust/actix/Cargo.lock @@ -1,16 +1,17 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "actix" -version = "0.13.0" +version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f728064aca1c318585bf4bb04ffcfac9e75e508ab4e8b1bd9ba5dfe04e2cbed5" +checksum = "de7fa236829ba0841304542f7614c42b80fca007455315c45c785ccfa873a85b" dependencies = [ + "actix-macros", "actix-rt", "actix_derive", - "bitflags", + "bitflags 2.9.0", "bytes", "crossbeam-channel", "futures-core", @@ -23,24 +24,7 @@ dependencies = [ "pin-project-lite", "smallvec", "tokio", - "tokio-util 0.7.8", -] - -[[package]] -name = "actix-codec" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a36c014a3e811624313b51a227b775ecba55d36ef9462bbaac7d4f13e54c9271" -dependencies = [ - "bitflags", - "bytes", - "futures-core", - "futures-sink", - "log", - "memchr", - "pin-project-lite", - "tokio", - "tokio-util 0.6.10", + "tokio-util", ] [[package]] @@ -49,30 +33,30 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "617a8268e3537fe1d8c9ead925fca49ef6400927ee7bc26750e90ecee14ce4b8" dependencies = [ - "bitflags", + "bitflags 1.3.2", "bytes", "futures-core", "futures-sink", "memchr", "pin-project-lite", "tokio", - "tokio-util 0.7.8", + "tokio-util", "tracing", ] [[package]] name = "actix-http" -version = "3.3.1" +version = "3.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2079246596c18b4a33e274ae10c0e50613f4d32a4198e09c7b93771013fed74" +checksum = "d48f96fc3003717aeb9856ca3d02a8c7de502667ad76eeacd830b48d2e91fac4" dependencies = [ - "actix-codec 0.5.1", + "actix-codec", "actix-rt", "actix-service", "actix-utils", - "ahash 0.8.3", - "base64 0.21.2", - "bitflags", + "ahash", + "base64 0.22.1", + "bitflags 2.9.0", "brotli", "bytes", "bytestring", @@ -84,17 +68,17 @@ dependencies = [ "http", "httparse", "httpdate", - "itoa 1.0.8", + "itoa", "language-tags", "local-channel", "mime", "percent-encoding", "pin-project-lite", - "rand", + "rand 0.8.5", "sha1", "smallvec", "tokio", - "tokio-util 0.7.8", + "tokio-util", "tracing", "zstd", ] @@ -111,22 +95,24 @@ dependencies = [ [[package]] name = "actix-router" -version = "0.5.1" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d66ff4d247d2b160861fa2866457e85706833527840e4133f8f49aa423a38799" +checksum = "13d324164c51f63867b57e73ba5936ea151b8a41a1d23d1031eeb9f70d0236f8" dependencies = [ "bytestring", + "cfg-if", "http", "regex", + "regex-lite", "serde", "tracing", ] [[package]] name = "actix-rt" -version = "2.8.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15265b6b8e2347670eb363c47fc8c75208b4a4994b27192f345fcbe707804f3e" +checksum = "24eda4e2a6e042aa4e55ac438a2ae052d3b5da0ecf83d7411e1a368946925208" dependencies = [ "actix-macros", "futures-core", @@ -144,7 +130,7 @@ dependencies = [ "actix-utils", "futures-core", "futures-util", - "mio", + "mio 0.8.8", "num_cpus", "socket2 0.4.9", "tokio", @@ -174,11 +160,11 @@ dependencies = [ [[package]] name = "actix-web" -version = "4.3.1" +version = "4.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd3cb42f9566ab176e1ef0b8b3a896529062b4efc6be0123046095914c4c1c96" +checksum = "9180d76e5cc7ccbc4d60a506f2c727730b154010262df5b910eb17dbe4b8cb38" dependencies = [ - "actix-codec 0.5.1", + "actix-codec", "actix-http", "actix-macros", "actix-router", @@ -187,7 +173,7 @@ dependencies = [ "actix-service", "actix-utils", "actix-web-codegen", - "ahash 0.7.6", + "ahash", "bytes", "bytestring", "cfg-if", @@ -196,33 +182,34 @@ dependencies = [ "encoding_rs", "futures-core", "futures-util", - "http", - "itoa 1.0.8", + "impl-more", + "itoa", "language-tags", "log", "mime", "once_cell", "pin-project-lite", "regex", + "regex-lite", "serde", "serde_json", "serde_urlencoded", "smallvec", - "socket2 0.4.9", - "time 0.3.23", + "socket2 0.5.8", + "time 0.3.37", "url", ] [[package]] name = "actix-web-codegen" -version = "4.2.0" +version = "4.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2262160a7ae29e3415554a3f1fc04c764b1540c116aa524683208078b7a75bc9" +checksum = "f591380e2e68490b5dfaf1dd1aa0ebe78d84ba7067078512b4ea6e4492d622b8" dependencies = [ "actix-router", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.98", ] [[package]] @@ -251,17 +238,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" -[[package]] -name = "ahash" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" -dependencies = [ - "getrandom", - "once_cell", - "version_check", -] - [[package]] name = "ahash" version = "0.8.3" @@ -269,7 +245,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" dependencies = [ "cfg-if", - "getrandom", + "getrandom 0.2.10", "once_cell", "version_check", ] @@ -298,6 +274,12 @@ dependencies = [ "alloc-no-stdlib", ] +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + [[package]] name = "android-tzdata" version = "0.1.1" @@ -324,40 +306,88 @@ dependencies = [ ] [[package]] -name = "ansi_term" -version = "0.12.1" +name = "anstream" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" dependencies = [ - "winapi", + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" + +[[package]] +name = "anstyle-parse" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" +dependencies = [ + "anstyle", + "once_cell", + "windows-sys 0.59.0", ] [[package]] name = "anyhow" -version = "1.0.71" +version = "1.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" +checksum = "6b964d184e89d9b6b67dd2715bc8e74cf3107fb2b529990c90cf517326150bf4" [[package]] name = "askama" -version = "0.11.1" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb98f10f371286b177db5eeb9a6e5396609555686a35e1d4f7b9a9c6d8af0139" +checksum = "b79091df18a97caea757e28cd2d5fda49c6cd4bd01ddffd7ff01ace0c0ad2c28" dependencies = [ "askama_derive", "askama_escape", - "askama_shared", + "humansize", + "num-traits", + "percent-encoding", ] [[package]] name = "askama_derive" -version = "0.11.2" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87bf87e6e8b47264efa9bde63d6225c6276a52e05e91bf37eaa8afd0032d6b71" +checksum = "19fe8d6cb13c4714962c072ea496f3392015f0989b1a2847bb4b2d9effd71d83" dependencies = [ - "askama_shared", + "askama_parser", + "basic-toml", + "mime", + "mime_guess", "proc-macro2", - "syn 1.0.109", + "quote", + "serde", + "syn 2.0.98", ] [[package]] @@ -367,45 +397,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341" [[package]] -name = "askama_shared" -version = "0.12.2" +name = "askama_parser" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf722b94118a07fcbc6640190f247334027685d4e218b794dbfe17c32bf38ed0" +checksum = "acb1161c6b64d1c3d83108213c2a2533a342ac225aabd0bda218278c2ddb00c0" dependencies = [ - "askama_escape", - "humansize", - "mime", - "mime_guess", "nom", - "num-traits", - "percent-encoding", - "proc-macro2", - "quote", - "serde", - "syn 1.0.109", - "toml", ] [[package]] name = "async-trait" -version = "0.1.71" +version = "0.1.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a564d521dd56509c4c47480d00b80ee55f7e385ae48db5744c67ad50c92d2ebf" +checksum = "644dd749086bf3771a2fbc5f256fdb982d53f011c7d5d560304eafeecebce79d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.25", -] - -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi 0.1.19", - "libc", - "winapi", + "syn 2.0.98", ] [[package]] @@ -441,27 +449,39 @@ version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "basic-toml" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "823388e228f614e9558c6804262db37960ec8821856535f5c3f59913140558f8" +dependencies = [ + "serde", +] + [[package]] name = "bindgen" -version = "0.59.2" +version = "0.71.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bd2a9a458e8f4304c52c43ebb0cfbd520289f8379a52e329a38afda99bf8eb8" +checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3" dependencies = [ - "bitflags", + "bitflags 2.9.0", "cexpr", "clang-sys", - "clap", - "env_logger", - "lazy_static", - "lazycell", + "itertools", "log", - "peeking_take_while", + "prettyplease 0.2.29", "proc-macro2", "quote", "regex", "rustc-hash", "shlex", - "which", + "syn 2.0.98", ] [[package]] @@ -470,6 +490,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" + [[package]] name = "bitvec" version = "1.0.1" @@ -493,9 +519,9 @@ dependencies = [ [[package]] name = "brotli" -version = "3.3.4" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1a0b1dbcc8ae29329621f8d4f0d835787c1c38bb1401979b49d13b0b305ff68" +checksum = "74f7971dbd9326d58187408ab83117d8ac1bb9c17b085fdacd1cf2f598719b6b" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -504,9 +530,9 @@ dependencies = [ [[package]] name = "brotli-decompressor" -version = "2.3.4" +version = "4.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b6561fd3f895a11e8f72af2cb7d22e08366bebc2b6b57f7744c4bda27034744" +checksum = "74fa05ad7d803d413eb8380983b092cbbaf9a85f151b871360e7b00cd7060b37" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -514,31 +540,27 @@ dependencies = [ [[package]] name = "bson" -version = "2.6.1" +version = "2.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aeb8bae494e49dbc330dd23cf78f6f7accee22f640ce3ab17841badaa4ce232" +checksum = "7969a9ba84b0ff843813e7249eed1678d9b6607ce5a3b8f0a47af3fcf7978e6e" dependencies = [ - "ahash 0.7.6", - "base64 0.13.1", + "ahash", + "base64 0.22.1", "bitvec", + "getrandom 0.2.10", + "getrandom 0.3.1", "hex", - "indexmap 1.9.3", + "indexmap 2.7.1", "js-sys", - "lazy_static", - "rand", + "once_cell", + "rand 0.9.0", "serde", "serde_bytes", "serde_json", - "time 0.3.23", + "time 0.3.37", "uuid", ] -[[package]] -name = "buf-min" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4531c8a9fe2fb94e0d2afdf6bb4effd4797baf98dd26b6e20be71a92ac78e8d" - [[package]] name = "buf-min" version = "0.7.1" @@ -574,11 +596,13 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.79" +version = "1.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c" dependencies = [ "jobserver", + "libc", + "shlex", ] [[package]] @@ -606,6 +630,7 @@ dependencies = [ "iana-time-zone", "js-sys", "num-traits", + "serde", "time 0.1.45", "wasm-bindgen", "winapi", @@ -623,27 +648,38 @@ dependencies = [ ] [[package]] -name = "clap" -version = "2.34.0" +name = "cmake" +version = "0.1.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" +checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130" dependencies = [ - "ansi_term", - "atty", - "bitflags", - "strsim 0.8.0", - "textwrap", - "unicode-width", - "vec_map", + "cc", ] [[package]] -name = "cmake" -version = "0.1.50" +name = "colorchoice" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" + +[[package]] +name = "const-random" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" dependencies = [ - "cc", + "const-random-macro", +] + +[[package]] +name = "const-random-macro" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" +dependencies = [ + "getrandom 0.2.10", + "once_cell", + "tiny-keccak", ] [[package]] @@ -659,7 +695,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb" dependencies = [ "percent-encoding", - "time 0.3.23", + "time 0.3.37", "version_check", ] @@ -706,6 +742,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crunchy" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" + [[package]] name = "crypto-common" version = "0.1.6" @@ -718,9 +760,9 @@ dependencies = [ [[package]] name = "darling" -version = "0.13.4" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" dependencies = [ "darling_core", "darling_macro", @@ -728,27 +770,27 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.13.4" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", - "strsim 0.10.0", - "syn 1.0.109", + "strsim", + "syn 2.0.98", ] [[package]] name = "darling_macro" -version = "0.13.4" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 1.0.109", + "syn 2.0.98", ] [[package]] @@ -759,27 +801,27 @@ checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" [[package]] name = "deadpool" -version = "0.9.5" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "421fe0f90f2ab22016f32a9881be5134fdd71c65298917084b0c7477cbc3856e" +checksum = "5ed5957ff93768adf7a65ab167a17835c3d2c3c50d084fe305174c112f468e2f" dependencies = [ - "async-trait", "deadpool-runtime", "num_cpus", - "retain_mut", "tokio", ] [[package]] name = "deadpool-postgres" -version = "0.10.5" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836a24a9d49deefe610b8b60c767a7412e9a931d79a89415cd2d2d71630ca8d7" +checksum = "3d697d376cbfa018c23eb4caab1fd1883dd9c906a8c034e8d9a3cb06a7e0bef9" dependencies = [ + "async-trait", "deadpool", - "log", + "getrandom 0.2.10", "tokio", "tokio-postgres", + "tracing", ] [[package]] @@ -792,14 +834,35 @@ dependencies = [ ] [[package]] -name = "derivative" -version = "2.2.0" +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", + "serde", +] + +[[package]] +name = "derive-syn-parse" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +checksum = "d65d7ce8132b7c0e54497a4d9a55a1c2a0912a0d786cf894472ba818fba45762" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.98", +] + +[[package]] +name = "derive-where" +version = "1.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62d671cc41a825ebabc75757b62d3d168c577f9149b2d49ece1dad1f72119d25" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", ] [[package]] @@ -811,31 +874,43 @@ dependencies = [ "convert_case", "proc-macro2", "quote", - "rustc_version 0.4.0", + "rustc_version", "syn 1.0.109", ] [[package]] name = "diesel" -version = "1.4.8" +version = "2.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b28135ecf6b7d446b43e27e225622a038cc4e2930a1022f51cdb97ada19b8e4d" +checksum = "04001f23ba8843dc315804fa324000376084dfb1c30794ff68dd279e6e5696d5" dependencies = [ - "bitflags", + "bitflags 2.9.0", "byteorder", "diesel_derives", + "itoa", "pq-sys", ] [[package]] name = "diesel_derives" -version = "1.4.1" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45f5098f628d02a7a0f68ddba586fb61e80edec3bdc1be3b921f4ceec60858d3" +checksum = "e7f2c3de51e2ba6bf2a648285696137aaf0f5f487bcbea93972fe8a364e131a4" dependencies = [ + "diesel_table_macro_syntax", + "dsl_auto_type", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.98", +] + +[[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.98", ] [[package]] @@ -849,6 +924,31 @@ dependencies = [ "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.98", +] + +[[package]] +name = "dsl_auto_type" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139ae9aca7527f85f26dd76483eb38533fd84bd571065da1739656ef71c5ff5b" +dependencies = [ + "darling", + "either", + "heck", + "proc-macro2", + "quote", + "syn 2.0.98", +] + [[package]] name = "dtoa" version = "1.0.8" @@ -872,27 +972,37 @@ dependencies = [ [[package]] name = "enum-as-inner" -version = "0.4.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21cdad81446a7f7dc43f6a77409efeb9733d2fa65553efef6018ef257c959b73" +checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" dependencies = [ "heck", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.98", +] + +[[package]] +name = "env_filter" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" +dependencies = [ + "log", + "regex", ] [[package]] name = "env_logger" -version = "0.9.3" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" +checksum = "dcaee3d8e3cfc3fd92428d477bc97fc29ec8716d180c0d74c643bb26166660e0" dependencies = [ - "atty", + "anstream", + "anstyle", + "env_filter", "humantime", "log", - "regex", - "termcolor", ] [[package]] @@ -919,9 +1029,9 @@ dependencies = [ [[package]] name = "float-cmp" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" +checksum = "b09cf3155332e944990140d967ff5eceb70df778b34f77d8075db46e4704e6d8" dependencies = [ "num-traits", ] @@ -934,9 +1044,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "form_urlencoded" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] @@ -949,9 +1059,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.28" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", @@ -964,9 +1074,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.28" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -974,15 +1084,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.28" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.28" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -991,38 +1101,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.28" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-macro" -version = "0.3.28" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.98", ] [[package]] name = "futures-sink" -version = "0.3.28" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.28" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" -version = "0.3.28" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-channel", "futures-core", @@ -1053,8 +1163,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi 0.13.3+wasi-0.2.2", + "wasm-bindgen", + "windows-targets 0.52.6", ] [[package]] @@ -1071,9 +1197,9 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "h2" -version = "0.3.20" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97ec8491ebaf99c8eaa73058b045fe58073cd6be7f596ac993ced0b0a0c01049" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" dependencies = [ "bytes", "fnv", @@ -1081,20 +1207,20 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap 1.9.3", + "indexmap 2.7.1", "slab", "tokio", - "tokio-util 0.7.8", + "tokio-util", "tracing", ] [[package]] name = "halfbrown" -version = "0.1.18" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e2a3c70a9c00cc1ee87b54e89f9505f73bb17d63f1b25c9a462ba8ef885444f" +checksum = "8588661a8607108a5ca69cab034063441a0413a0b041c13618a7dd348021ef6f" dependencies = [ - "hashbrown 0.13.2", + "hashbrown 0.14.0", "serde", ] @@ -1106,33 +1232,25 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.13.2" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" dependencies = [ - "ahash 0.8.3", + "ahash", + "allocator-api2", ] [[package]] name = "hashbrown" -version = "0.14.0" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" [[package]] name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -[[package]] -name = "hermit-abi" -version = "0.1.19" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" @@ -1147,17 +1265,62 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] -name = "hmac" -version = "0.12.1" +name = "hickory-proto" +version = "0.24.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +checksum = "92652067c9ce6f66ce53cc38d1169daa36e6e7eb7dd3b63b5103bd9d97117248" dependencies = [ - "digest", + "async-trait", + "cfg-if", + "data-encoding", + "enum-as-inner", + "futures-channel", + "futures-io", + "futures-util", + "idna", + "ipnet", + "once_cell", + "rand 0.8.5", + "thiserror", + "tinyvec", + "tokio", + "tracing", + "url", ] [[package]] -name = "hostname" -version = "0.3.1" +name = "hickory-resolver" +version = "0.24.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbb117a1ca520e111743ab2f6688eddee69db4e0ea242545a604dce8a66fd22e" +dependencies = [ + "cfg-if", + "futures-util", + "hickory-proto", + "ipconfig", + "lru-cache", + "once_cell", + "parking_lot", + "rand 0.8.5", + "resolv-conf", + "smallvec", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "hostname" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" dependencies = [ @@ -1174,7 +1337,7 @@ checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" dependencies = [ "bytes", "fnv", - "itoa 1.0.8", + "itoa", ] [[package]] @@ -1191,9 +1354,12 @@ checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" [[package]] name = "humansize" -version = "1.1.1" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02296996cb8796d7c6e3bc2d9211b7802812d36999a51bb754123ead7d37d026" +checksum = "6cb51c9a029ddc91b07a787f1d86b53ccfa49b0e86688c946ebe8d3555685dd7" +dependencies = [ + "libm", +] [[package]] name = "humantime" @@ -1224,6 +1390,124 @@ dependencies = [ "cc", ] +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + [[package]] name = "ident_case" version = "1.0.1" @@ -1232,25 +1516,31 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "0.2.3" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" dependencies = [ - "matches", - "unicode-bidi", - "unicode-normalization", + "idna_adapter", + "smallvec", + "utf8_iter", ] [[package]] -name = "idna" -version = "0.4.0" +name = "idna_adapter" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "icu_normalizer", + "icu_properties", ] +[[package]] +name = "impl-more" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8a5a9a0ff0086c7a148acb942baaabeadf9504d10400b5a05645853729b9cd2" + [[package]] name = "indexmap" version = "1.9.3" @@ -1259,16 +1549,18 @@ checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", "hashbrown 0.12.3", + "serde", ] [[package]] name = "indexmap" -version = "2.0.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" dependencies = [ "equivalent", - "hashbrown 0.14.0", + "hashbrown 0.15.2", + "serde", ] [[package]] @@ -1277,9 +1569,9 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" dependencies = [ - "socket2 0.5.3", + "socket2 0.5.8", "widestring", - "windows-sys", + "windows-sys 0.48.0", "winreg", ] @@ -1290,10 +1582,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" [[package]] -name = "itoa" -version = "0.4.8" +name = "is_terminal_polyfill" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] [[package]] name = "itoa" @@ -1303,19 +1604,20 @@ checksum = "62b02a5381cc465bd3041d84623d0fa3b66738b52b8e2fc3bab8ad63ab032f4a" [[package]] name = "jobserver" -version = "0.1.26" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" dependencies = [ "libc", ] [[package]] name = "js-sys" -version = "0.3.64" +version = "0.3.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305" dependencies = [ + "once_cell", "wasm-bindgen", ] @@ -1325,23 +1627,11 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388" -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[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.147" +version = "0.2.170" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828" [[package]] name = "libloading" @@ -1353,12 +1643,24 @@ dependencies = [ "winapi", ] +[[package]] +name = "libm" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" + [[package]] name = "linked-hash-map" version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" +[[package]] +name = "litemap" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" + [[package]] name = "local-channel" version = "0.1.3" @@ -1389,9 +1691,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.19" +version = "0.4.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" +checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" [[package]] name = "lru-cache" @@ -1403,16 +1705,58 @@ dependencies = [ ] [[package]] -name = "match_cfg" -version = "0.1.0" +name = "macro_magic" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" +checksum = "cc33f9f0351468d26fbc53d9ce00a096c8522ecb42f19b50f34f2c422f76d21d" +dependencies = [ + "macro_magic_core", + "macro_magic_macros", + "quote", + "syn 2.0.98", +] [[package]] -name = "matches" -version = "0.1.10" +name = "macro_magic_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1687dc887e42f352865a393acae7cf79d98fab6351cde1f58e9e057da89bf150" +dependencies = [ + "const-random", + "derive-syn-parse", + "macro_magic_core_macros", + "proc-macro2", + "quote", + "syn 2.0.98", +] + +[[package]] +name = "macro_magic_core_macros" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b02abfe41815b5bd98dbd4260173db2c116dda171dc0fe7838cb206333b83308" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + +[[package]] +name = "macro_magic_macros" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73ea28ee64b88876bf45277ed9a5817c1817df061a74f2b988971a12570e5869" +dependencies = [ + "macro_magic_core", + "quote", + "syn 2.0.98", +] + +[[package]] +name = "match_cfg" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" +checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" [[package]] name = "md-5" @@ -1469,56 +1813,81 @@ dependencies = [ "libc", "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys", + "windows-sys 0.48.0", +] + +[[package]] +name = "mio" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +dependencies = [ + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.52.0", ] [[package]] name = "mongodb" -version = "2.6.0" +version = "3.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebcd85ec209a5b84fd9f54b9e381f6fa17462bc74160d018fc94fd8b9f61faa8" +checksum = "f6e3788f35159bbcf461227af84711950525343b64451fdd90de4e237a0b8a13" dependencies = [ "async-trait", "base64 0.13.1", - "bitflags", + "bitflags 1.3.2", "bson", "chrono", - "derivative", + "derive-where", "derive_more", "futures-core", "futures-executor", "futures-io", "futures-util", "hex", + "hickory-proto", + "hickory-resolver", "hmac", - "lazy_static", + "macro_magic", "md-5", + "mongodb-internal-macros", + "once_cell", "pbkdf2", "percent-encoding", - "rand", + "rand 0.8.5", "rustc_version_runtime", "rustls", "rustls-pemfile", "serde", "serde_bytes", "serde_with", - "sha-1", + "sha1", "sha2", - "socket2 0.4.9", + "socket2 0.5.8", "stringprep", - "strsim 0.10.0", + "strsim", "take_mut", "thiserror", "tokio", "tokio-rustls", - "tokio-util 0.7.8", - "trust-dns-proto", - "trust-dns-resolver", + "tokio-util", "typed-builder", "uuid", "webpki-roots", ] +[[package]] +name = "mongodb-internal-macros" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63981427a0f26b89632fd2574280e069d09fb2912a3138da15de0174d11dd077" +dependencies = [ + "macro_magic", + "proc-macro2", + "quote", + "syn 2.0.98", +] + [[package]] name = "nom" version = "7.1.3" @@ -1529,6 +1898,12 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-traits" version = "0.2.15" @@ -1544,7 +1919,7 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.3.2", + "hermit-abi", "libc", ] @@ -1559,9 +1934,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.18.0" +version = "1.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" [[package]] name = "parking_lot" @@ -1581,9 +1956,9 @@ checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.3.5", "smallvec", - "windows-targets", + "windows-targets 0.48.1", ] [[package]] @@ -1601,17 +1976,11 @@ dependencies = [ "digest", ] -[[package]] -name = "peeking_take_while" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" - [[package]] name = "percent-encoding" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "phf" @@ -1633,9 +2002,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.10" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "pin-utils" @@ -1645,39 +2014,45 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.27" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "postgres-protocol" -version = "0.6.5" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b7fa9f396f51dffd61546fd8573ee20592287996568e6175ceb0f8699ad75d" +checksum = "76ff0abab4a9b844b93ef7b81f1efc0a366062aaef2cd702c76256b5dc075c54" dependencies = [ - "base64 0.21.2", + "base64 0.22.1", "byteorder", "bytes", "fallible-iterator", "hmac", "md-5", "memchr", - "rand", + "rand 0.9.0", "sha2", "stringprep", ] [[package]] name = "postgres-types" -version = "0.2.5" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f028f05971fe20f512bcc679e2c10227e57809a3af86a7606304435bc8896cd6" +checksum = "613283563cd90e1dfc3518d548caee47e0e725455ed619881f5cf21f36de4b48" 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.17" @@ -1703,11 +2078,21 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "prettyplease" +version = "0.2.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6924ced06e1f7dfe3fa48d57b9f74f55d8915f5036121bef647ef4b204895fac" +dependencies = [ + "proc-macro2", + "syn 2.0.98", +] + [[package]] name = "proc-macro2" -version = "1.0.64" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78803b62cbf1f46fde80d7c0e803111524b9877184cfe7c3033659490ac7a7da" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" dependencies = [ "unicode-ident", ] @@ -1720,9 +2105,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.29" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ "proc-macro2", ] @@ -1740,8 +2125,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha", - "rand_core", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.3", + "zerocopy", ] [[package]] @@ -1751,7 +2147,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "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]] @@ -1760,7 +2166,16 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom", + "getrandom 0.2.10", +] + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom 0.3.1", ] [[package]] @@ -1769,7 +2184,36 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ - "bitflags", + "bitflags 1.3.2", +] + +[[package]] +name = "redox_syscall" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b568323e98e49e2a0899dcee453dd679fae22d69adf9b11dd508d1549b7e2f" +dependencies = [ + "bitflags 2.9.0", +] + +[[package]] +name = "ref-cast" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf0a6f84d5f1d581da8b41b47ec8600871962f2a528115b542b362d4b744931" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcc303e793d3734489387d205e9b186fac9c6cfacedd98cbb2e8a5943595f3e6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", ] [[package]] @@ -1795,6 +2239,12 @@ dependencies = [ "regex-syntax", ] +[[package]] +name = "regex-lite" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a" + [[package]] name = "regex-syntax" version = "0.7.4" @@ -1811,12 +2261,6 @@ dependencies = [ "quick-error", ] -[[package]] -name = "retain_mut" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4389f1d5789befaf6029ebd9f7dac4af7f7e3d61b69d4f30e2ac02b57e7712b0" - [[package]] name = "ring" version = "0.16.20" @@ -1827,11 +2271,25 @@ dependencies = [ "libc", "once_cell", "spin", - "untrusted", + "untrusted 0.7.1", "web-sys", "winapi", ] +[[package]] +name = "ring" +version = "0.17.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da5349ae27d3887ca812fb375b45a4fbb36d8d12d2df394968cd86e35683fe73" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.10", + "libc", + "untrusted 0.9.0", + "windows-sys 0.52.0", +] + [[package]] name = "rustc-demangle" version = "0.1.23" @@ -1840,18 +2298,9 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustc-hash" -version = "1.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -dependencies = [ - "semver 0.9.0", -] +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" [[package]] name = "rustc_version" @@ -1859,29 +2308,29 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.17", + "semver", ] [[package]] name = "rustc_version_runtime" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d31b7153270ebf48bf91c65ae5b0c00e749c4cfad505f66530ac74950249582f" +checksum = "2dd18cd2bae1820af0b6ad5e54f4a51d0f3fcc53b05f845675074efcc7af071d" dependencies = [ - "rustc_version 0.2.3", - "semver 0.9.0", + "rustc_version", + "semver", ] [[package]] name = "rustls" -version = "0.20.8" +version = "0.21.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" dependencies = [ "log", - "ring", + "ring 0.17.11", + "rustls-webpki", "sct", - "webpki", ] [[package]] @@ -1893,6 +2342,22 @@ dependencies = [ "base64 0.21.2", ] +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring 0.17.11", + "untrusted 0.9.0", +] + +[[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.14" @@ -1911,17 +2376,8 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" dependencies = [ - "ring", - "untrusted", -] - -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser", + "ring 0.16.20", + "untrusted 0.7.1", ] [[package]] @@ -1930,17 +2386,11 @@ version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" - [[package]] name = "serde" -version = "1.0.171" +version = "1.0.218" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30e27d1e4fd7659406c492fd6cfaf2066ba8773de45ca75e855590f856dc34a9" +checksum = "e8dfc9d19bdbf6d17e22319da49161d5d0108e4188e8b680aef6299eed22df60" dependencies = [ "serde_derive", ] @@ -1956,13 +2406,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.171" +version = "1.0.218" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "389894603bd18c46fa56231694f8d827779c0951a667087194cf9de94ed24682" +checksum = "f09503e191f4e797cb8aac08e9a4a4695c5edf6a2e70e376d961ddd5c969f82b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.98", ] [[package]] @@ -1971,8 +2421,8 @@ version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5062a995d481b2308b6064e9af76011f2921c35f97b0468811ed9f6cd91dfed" dependencies = [ - "indexmap 2.0.0", - "itoa 1.0.8", + "indexmap 2.7.1", + "itoa", "ryu", "serde", ] @@ -1984,42 +2434,39 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" dependencies = [ "form_urlencoded", - "itoa 1.0.8", + "itoa", "ryu", "serde", ] [[package]] name = "serde_with" -version = "1.14.0" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "678b5a069e50bf00ecd22d0cd8ddf7c236f68581b03db652061ed5eb13a312ff" +checksum = "d6b6f7f2fcb69f747921f79f3926bd1e203fce4fef62c268dd3abfb6d86029aa" dependencies = [ + "base64 0.22.1", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.7.1", "serde", + "serde_derive", + "serde_json", "serde_with_macros", + "time 0.3.37", ] [[package]] name = "serde_with_macros" -version = "1.5.2" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082" +checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e" dependencies = [ "darling", "proc-macro2", "quote", - "syn 1.0.109", -] - -[[package]] -name = "sha-1" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", + "syn 2.0.98", ] [[package]] @@ -2046,9 +2493,9 @@ dependencies = [ [[package]] name = "shlex" -version = "1.1.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" @@ -2061,11 +2508,13 @@ dependencies = [ [[package]] name = "simd-json" -version = "0.4.15" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0c3aaa7729b636ed4843efa96722f0d5823825b4f388d74c83757a3227f64d4" +checksum = "aa2bcf6c6e164e81bc7a5d49fc6988b3d515d9e8c07457d7b74ffb9324b9cd40" dependencies = [ + "getrandom 0.2.10", "halfbrown", + "ref-cast", "serde", "serde_json", "simdutf8", @@ -2074,28 +2523,30 @@ dependencies = [ [[package]] name = "simd-json-derive" -version = "0.2.2" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3221374cc85242d6da1fea48d5b6edb417cf79cf9f6d6c636cd8425161faa096" +checksum = "dde9e4ab4322320af4f9709170ca77dec74ef4e44db7c0600cf6f3d601b74cee" dependencies = [ "chrono", - "itoa 0.4.8", + "itoa", "ryu", "simd-json", "simd-json-derive-int", + "thiserror", "value-trait", ] [[package]] name = "simd-json-derive-int" -version = "0.2.1" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "929b468389809e93768ab7962f21aad7911774d472aca6211e332f74824c4635" +checksum = "cebcbb57e77f41aee1cef06b800c6c79288b133054a478135a9a0e8e79c938dd" dependencies = [ "proc-macro2", "quote", "simd-json", - "syn 1.0.109", + "syn 2.0.98", + "thiserror", ] [[package]] @@ -2121,24 +2572,24 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.11.0" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" +checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" [[package]] name = "snmalloc-rs" -version = "0.2.28" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36acaace2719c972eab3ef6a6b3aee4495f0bf300f59715bb9cff6c5acf4ae20" +checksum = "eb317153089fdfa4d8a2eec059d40a5a23c3bde43995ea23b19121c3f621e74a" dependencies = [ "snmalloc-sys", ] [[package]] name = "snmalloc-sys" -version = "0.2.28" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35a7e6e7d5fe756bee058ddedefc7e0a9f9c8dbaa9401b48ed3c17d6578e40b5" +checksum = "065fea53d32bb77bc36cca466cb191f2e5216ebfd0ed360b1d64889ee6e559ea" dependencies = [ "cmake", ] @@ -2155,12 +2606,12 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.3" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2538b18701741680e0322a2302176d3253a35388e2e62f172f64f4f16605f877" +checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -2169,6 +2620,12 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "stringprep" version = "0.1.2" @@ -2181,15 +2638,9 @@ dependencies = [ [[package]] name = "strsim" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" - -[[package]] -name = "strsim" -version = "0.10.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "subtle" @@ -2210,15 +2661,26 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.25" +version = "2.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15e3fc8c0c74267e2df136e5e5fb656a464158aa57624053375eb9c8c6e25ae2" +checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + [[package]] name = "take_mut" version = "0.2.2" @@ -2231,30 +2693,12 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" -[[package]] -name = "termcolor" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "textwrap" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -dependencies = [ - "unicode-width", -] - [[package]] name = "tfb-actix" -version = "3.0.0" +version = "4.0.0" dependencies = [ "actix", - "actix-codec 0.4.2", + "actix-codec", "actix-http", "actix-rt", "actix-server", @@ -2268,11 +2712,10 @@ dependencies = [ "diesel", "env_logger", "futures", - "http", "log", "mongodb", "num_cpus", - "rand", + "rand 0.9.0", "serde", "serde_json", "simd-json", @@ -2280,30 +2723,30 @@ dependencies = [ "snmalloc-rs", "tokio", "tokio-postgres", - "tokio-util 0.7.8", + "tokio-util", "url", - "v_htmlescape 0.14.1", + "v_htmlescape", "yarte", ] [[package]] name = "thiserror" -version = "1.0.43" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a35fc5b8971143ca348fa6df4f024d4d55264f3468c71ad1c2f365b0a4d58c42" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.43" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "463fe12d7993d3b327787537ce8dd4dfa058de32fc2b195ef3cde03dc4771e8f" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.98", ] [[package]] @@ -2319,11 +2762,14 @@ dependencies = [ [[package]] name = "time" -version = "0.3.23" +version = "0.3.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59e399c068f43a5d116fedaf73b203fa4f9c519f17e2b34f63221d3792f81446" +checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" dependencies = [ - "itoa 1.0.8", + "deranged", + "itoa", + "num-conv", + "powerfmt", "serde", "time-core", "time-macros", @@ -2331,19 +2777,39 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.10" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96ba15a897f3c86766b757e5ac7221554c6750054d74d5b28844fce5fb36a6c4" +checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" dependencies = [ + "num-conv", "time-core", ] +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", +] + [[package]] name = "tinyvec" version = "1.6.0" @@ -2361,40 +2827,38 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.29.1" +version = "1.44.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da" +checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48" dependencies = [ - "autocfg", "backtrace", "bytes", "libc", - "mio", - "num_cpus", + "mio 1.0.3", "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.4.9", + "socket2 0.5.8", "tokio-macros", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] name = "tokio-macros" -version = "2.1.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.98", ] [[package]] name = "tokio-postgres" -version = "0.7.8" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e89f6234aa8fd43779746012fcf53603cdb91fdd8399aa0de868c2d56b6dde1" +checksum = "6c95d533c83082bb6490e0189acaa0bbeef9084e60471b696ca6988cd0541fb0" dependencies = [ "async-trait", "byteorder", @@ -2409,41 +2873,28 @@ dependencies = [ "pin-project-lite", "postgres-protocol", "postgres-types", - "socket2 0.5.3", + "rand 0.9.0", + "socket2 0.5.8", "tokio", - "tokio-util 0.7.8", + "tokio-util", + "whoami", ] [[package]] name = "tokio-rustls" -version = "0.23.4" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ "rustls", "tokio", - "webpki", -] - -[[package]] -name = "tokio-util" -version = "0.6.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36943ee01a6d67977dd3f84a5a1d2efeb4ada3a1ae771cadfaa535d9d9fc6507" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "log", - "pin-project-lite", - "tokio", ] [[package]] name = "tokio-util" -version = "0.7.8" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" +checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" dependencies = [ "bytes", "futures-core", @@ -2451,7 +2902,6 @@ dependencies = [ "futures-sink", "pin-project-lite", "tokio", - "tracing", ] [[package]] @@ -2472,61 +2922,28 @@ dependencies = [ "cfg-if", "log", "pin-project-lite", + "tracing-attributes", "tracing-core", ] [[package]] -name = "tracing-core" -version = "0.1.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" -dependencies = [ - "once_cell", -] - -[[package]] -name = "trust-dns-proto" -version = "0.21.2" +name = "tracing-attributes" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c31f240f59877c3d4bb3b3ea0ec5a6a0cff07323580ff8c7a605cd7d08b255d" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ - "async-trait", - "cfg-if", - "data-encoding", - "enum-as-inner", - "futures-channel", - "futures-io", - "futures-util", - "idna 0.2.3", - "ipnet", - "lazy_static", - "log", - "rand", - "smallvec", - "thiserror", - "tinyvec", - "tokio", - "url", + "proc-macro2", + "quote", + "syn 2.0.98", ] [[package]] -name = "trust-dns-resolver" -version = "0.21.2" +name = "tracing-core" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4ba72c2ea84515690c9fcef4c6c660bb9df3036ed1051686de84605b74fd558" +checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" dependencies = [ - "cfg-if", - "futures-util", - "ipconfig", - "lazy_static", - "log", - "lru-cache", - "parking_lot", - "resolv-conf", - "smallvec", - "thiserror", - "tokio", - "trust-dns-proto", + "once_cell", ] [[package]] @@ -2594,44 +3011,50 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + [[package]] name = "url" -version = "2.4.0" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" dependencies = [ "form_urlencoded", - "idna 0.4.0", + "idna", "percent-encoding", ] [[package]] -name = "uuid" -version = "1.4.0" +name = "utf16_iter" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d023da39d1fde5a8a3fe1f3e01ca9632ada0a63e9797de55a879d6e2236277be" -dependencies = [ - "getrandom", - "serde", -] +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" [[package]] -name = "v_escape" -version = "0.18.0" +name = "utf8_iter" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79d297315e8ca0b98255614f409699ea189e5929e820f07f69afcebf96c41f9b" -dependencies = [ - "buf-min 0.6.1", - "v_escape_derive", -] +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] -name = "v_escape_derive" -version = "0.9.1" +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "uuid" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fe81cf194472e6ddd6545f8e91ee9780de636194c2e896b8ac201ac78389809" +checksum = "d023da39d1fde5a8a3fe1f3e01ca9632ada0a63e9797de55a879d6e2236277be" dependencies = [ - "syn 1.0.109", + "getrandom 0.2.10", + "serde", + "wasm-bindgen", ] [[package]] @@ -2644,34 +3067,24 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "v_htmlescape" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04b32732bcd549ad15fcb01ee63ad03dd6a0289e9ba72b8164707d1f9fa80478" -dependencies = [ - "cfg-if", - "v_escape", -] - [[package]] name = "v_htmlescape" version = "0.15.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e8257fbc510f0a46eb602c10215901938b5c2a7d5e70fc11483b1d3c9b5b18c" dependencies = [ - "buf-min 0.7.1", + "buf-min", ] [[package]] name = "value-trait" -version = "0.2.12" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fe40a74a6f052b10668ef021c8c3ae56ab38269f9c0f401daa6ed36f96662fd" +checksum = "9170e001f458781e92711d2ad666110f153e4e50bfd5cbd02db6547625714187" dependencies = [ "float-cmp", "halfbrown", - "itoa 0.4.8", + "itoa", "ryu", ] @@ -2681,12 +3094,6 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" -[[package]] -name = "vec_map" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" - [[package]] name = "version_check" version = "0.9.4" @@ -2705,36 +3112,53 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasi" +version = "0.13.3+wasi-0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +dependencies = [ + "wit-bindgen-rt", +] + +[[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.87" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d" dependencies = [ "cfg-if", + "once_cell", + "rustversion", "wasm-bindgen-macro", + "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.87" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19" dependencies = [ "bumpalo", "log", - "once_cell", "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.98", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.87" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2742,22 +3166,25 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.87" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.25", + "syn 2.0.98", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.87" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" +checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1" +dependencies = [ + "unicode-ident", +] [[package]] name = "web-sys" @@ -2769,34 +3196,21 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "webpki" -version = "0.22.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07ecc0cd7cac091bf682ec5efa18b1cff79d617b84181f38b3951dbe135f607f" -dependencies = [ - "ring", - "untrusted", -] - [[package]] name = "webpki-roots" -version = "0.22.6" +version = "0.25.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87" -dependencies = [ - "webpki", -] +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] -name = "which" -version = "4.4.0" +name = "whoami" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269" +checksum = "372d5b87f58ec45c384ba03563b03544dc5fadc3983e434b286913f5b4a9bb6d" dependencies = [ - "either", - "libc", - "once_cell", + "redox_syscall 0.5.9", + "wasite", + "web-sys", ] [[package]] @@ -2821,15 +3235,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -2842,7 +3247,7 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" dependencies = [ - "windows-targets", + "windows-targets 0.48.1", ] [[package]] @@ -2851,7 +3256,25 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets", + "windows-targets 0.48.1", +] + +[[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]] @@ -2860,13 +3283,29 @@ version = "0.48.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.48.0", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm 0.48.0", + "windows_x86_64_msvc 0.48.0", +] + +[[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]] @@ -2875,42 +3314,90 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +[[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.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +[[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.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +[[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.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +[[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.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +[[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.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +[[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.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + [[package]] name = "winreg" version = "0.50.0" @@ -2918,9 +3405,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" dependencies = [ "cfg-if", - "windows-sys", + "windows-sys 0.48.0", ] +[[package]] +name = "wit-bindgen-rt" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" +dependencies = [ + "bitflags 2.9.0", +] + +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + [[package]] name = "wyz" version = "0.5.1" @@ -2945,7 +3453,7 @@ version = "0.15.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfce1df93f3b16e5272221a559e60bbbaaa71dbc042a43996d223e51a690aab2" dependencies = [ - "buf-min 0.7.1", + "buf-min", "yarte_derive", "yarte_helpers", ] @@ -2984,15 +3492,15 @@ version = "0.15.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0d1076f8cee9541ea5ffbecd9102f751252c91f085e7d30a18a3ce805ebd3ee" dependencies = [ - "buf-min 0.7.1", + "buf-min", "dtoa", - "itoa 1.0.8", - "prettyplease", + "itoa", + "prettyplease 0.1.25", "ryu", "serde", "syn 1.0.109", "toml", - "v_htmlescape 0.15.8", + "v_htmlescape", ] [[package]] @@ -3006,7 +3514,7 @@ dependencies = [ "quote", "syn 1.0.109", "v_eval", - "v_htmlescape 0.15.8", + "v_htmlescape", "yarte_helpers", "yarte_parser", ] @@ -3027,32 +3535,117 @@ dependencies = [ "yarte_helpers", ] +[[package]] +name = "yoke" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf01143b2dd5d134f11f545cf9f1431b13b749695cb33bcce051e7568f99478" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712c8386f4f4299382c9abee219bee7084f78fb939d88b6840fcc1320d5f6da2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + +[[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.98", + "synstructure", +] + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + [[package]] name = "zstd" -version = "0.12.3+zstd.1.5.2" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76eea132fb024e0e13fd9c2f5d5d595d8a967aa72382ac2f9d39fcc95afd0806" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" dependencies = [ "zstd-safe", ] [[package]] name = "zstd-safe" -version = "6.0.5+zstd.1.5.4" +version = "7.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d56d9e60b4b1758206c238a10165fbcae3ca37b01744e394c463463f6529d23b" +checksum = "f3051792fbdc2e1e143244dc28c60f73d8470e93f3f9cbd0ead44da5ed802722" dependencies = [ - "libc", "zstd-sys", ] [[package]] name = "zstd-sys" -version = "2.0.8+zstd.1.5.5" +version = "2.0.14+zstd.1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5556e6ee25d32df2586c098bbfa278803692a20d0ab9565e049480d52707ec8c" +checksum = "8fb060d4926e4ac3a3ad15d864e99ceb5f343c6b34f5bd6d81ae6ed417311be5" dependencies = [ "cc", - "libc", "pkg-config", ] diff --git a/frameworks/Rust/actix/Cargo.toml b/frameworks/Rust/actix/Cargo.toml old mode 100755 new mode 100644 index a7ae6720cce..67e60eb04c4 --- a/frameworks/Rust/actix/Cargo.toml +++ b/frameworks/Rust/actix/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "tfb-actix" -version = "3.0.0" -edition = "2018" +version = "4.0.0" +edition = "2024" [[bin]] name = "tfb-web" @@ -28,41 +28,40 @@ name = "tfb-web-pg-deadpool" path = "src/main_pg_deadpool.rs" [dependencies] -anyhow = "1" -actix = "0.13" -actix-web = "4.3.1" -actix-http = "3.3.1" -actix-rt = "2" -actix-codec = "0.4" +anyhow = "1.0.96" +actix = "0.13.5" +actix-web = "4.9.0" +actix-http = "3.9.0" +actix-rt = "2.10.0" +actix-codec = "0.5" actix-server = "2" actix-service = "2" -askama = "0.11" +askama = "0.12" bytes = "1" -diesel = { version = "1.4", features = ["postgres"] } -env_logger = "0.9" -futures = "0.3.7" -http = "0.2" +diesel = { version = "2.2.7", features = ["postgres"] } +env_logger = "0.11" +futures = "0.3.31" log = { version = "0.4", features = ["release_max_level_debug"] } num_cpus = "1.13" -rand = { version = "0.8", features = ["small_rng"] } +rand = { version = "0.9", features = ["small_rng"] } serde = { version = "1", features = ["derive"] } serde_json = "1" -simd-json = "0.4" -simd-json-derive = "0.2" -snmalloc-rs = "0.2.6" +simd-json = "0.14" +simd-json-derive = "0.15" +snmalloc-rs = "0.3.8" tokio = { version = "1", features = ["full"] } -tokio-util = "0.7.8" -tokio-postgres = "0.7.5" -deadpool-postgres = "0.10.1" -mongodb = "2.2.0" -url = "2.1" -v_htmlescape = "0.14" +tokio-util = "0.7.13" +tokio-postgres = "0.7.13" +deadpool-postgres = "0.14.1" +mongodb = "3.2.5" +url = "2.5" +v_htmlescape = "0.15" yarte = { version = "0.15", features = ["bytes-buf"] } [build-dependencies] -askama = "0.11" -bindgen = "0.59" +askama = "0.12" +bindgen = "0.71" [profile.release] lto = true diff --git a/frameworks/Rust/actix/README.md b/frameworks/Rust/actix/README.md index def975cde32..78e6fd0306b 100644 --- a/frameworks/Rust/actix/README.md +++ b/frameworks/Rust/actix/README.md @@ -4,7 +4,7 @@ Actix web is a small, fast, pragmatic, open source rust web framework. -* [User Guide](https://actix.rs/book/actix-web/) +* [User Guide](https://actix.rs/docs/getting-started) * [API Documentation](https://docs.rs/actix-web/) * [Chat on gitter](https://gitter.im/actix/actix) * Cargo package: [actix-web](https://crates.io/crates/actix-web) diff --git a/frameworks/Rust/actix/actix-http.dockerfile b/frameworks/Rust/actix/actix-http.dockerfile index 1e2723b175d..e22a047c11a 100644 --- a/frameworks/Rust/actix/actix-http.dockerfile +++ b/frameworks/Rust/actix/actix-http.dockerfile @@ -1,4 +1,4 @@ -FROM rust:1.58 +FROM rust:1.85 RUN apt-get update -yqq && apt-get install -yqq cmake g++ diff --git a/frameworks/Rust/actix/actix-server.dockerfile b/frameworks/Rust/actix/actix-server.dockerfile index ae54cdea548..6c4adac18e7 100644 --- a/frameworks/Rust/actix/actix-server.dockerfile +++ b/frameworks/Rust/actix/actix-server.dockerfile @@ -1,4 +1,4 @@ -FROM rust:1.58 +FROM rust:1.85 RUN apt-get update -yqq && apt-get install -yqq cmake g++ diff --git a/frameworks/Rust/actix/actix-web-diesel.dockerfile b/frameworks/Rust/actix/actix-web-diesel.dockerfile index 43fc2424510..145ccb2fe5d 100644 --- a/frameworks/Rust/actix/actix-web-diesel.dockerfile +++ b/frameworks/Rust/actix/actix-web-diesel.dockerfile @@ -1,4 +1,4 @@ -FROM rust:1.58 +FROM rust:1.85 RUN apt-get update -yqq && apt-get install -yqq cmake g++ diff --git a/frameworks/Rust/actix/actix-web-mongodb.dockerfile b/frameworks/Rust/actix/actix-web-mongodb.dockerfile index f89e9552660..beb5f47fcd3 100644 --- a/frameworks/Rust/actix/actix-web-mongodb.dockerfile +++ b/frameworks/Rust/actix/actix-web-mongodb.dockerfile @@ -1,4 +1,4 @@ -FROM rust:1.57.0 +FROM rust:1.85 ENV ACTIX_TECHEMPOWER_MONGODB_URL=mongodb://tfb-database:27017 diff --git a/frameworks/Rust/actix/actix-web-pg-deadpool.dockerfile b/frameworks/Rust/actix/actix-web-pg-deadpool.dockerfile index 0ce0a4dbaac..e3674b64588 100644 --- a/frameworks/Rust/actix/actix-web-pg-deadpool.dockerfile +++ b/frameworks/Rust/actix/actix-web-pg-deadpool.dockerfile @@ -1,4 +1,4 @@ -FROM rust:1.57.0 +FROM rust:1.85 RUN apt-get update -yqq && apt-get install -yqq cmake g++ diff --git a/frameworks/Rust/actix/actix.dockerfile b/frameworks/Rust/actix/actix.dockerfile index 75e192e25f8..abe34444ab8 100644 --- a/frameworks/Rust/actix/actix.dockerfile +++ b/frameworks/Rust/actix/actix.dockerfile @@ -1,4 +1,4 @@ -FROM rust:1.58 +FROM rust:1.85.0 RUN apt-get update -yqq && apt-get install -yqq cmake g++ diff --git a/frameworks/Rust/actix/benchmark_config.json b/frameworks/Rust/actix/benchmark_config.json old mode 100755 new mode 100644 diff --git a/frameworks/Rust/actix/rust-toolchain.toml b/frameworks/Rust/actix/rust-toolchain.toml index 5d56faf9ae0..292fe499e3b 100644 --- a/frameworks/Rust/actix/rust-toolchain.toml +++ b/frameworks/Rust/actix/rust-toolchain.toml @@ -1,2 +1,2 @@ [toolchain] -channel = "nightly" +channel = "stable" diff --git a/frameworks/Rust/actix/src/db.rs b/frameworks/Rust/actix/src/db.rs index b1a2f0673dd..1630a68a567 100644 --- a/frameworks/Rust/actix/src/db.rs +++ b/frameworks/Rust/actix/src/db.rs @@ -6,7 +6,7 @@ use bytes::{Bytes, BytesMut}; use futures::{ stream::futures_unordered::FuturesUnordered, FutureExt, StreamExt, TryStreamExt, }; -use rand::{rngs::SmallRng, thread_rng, Rng, SeedableRng}; +use rand::{rngs::SmallRng, Rng, SeedableRng}; use tokio_postgres::{connect, types::ToSql, Client, NoTls, Statement}; use crate::{ @@ -101,9 +101,9 @@ impl PgConnection { } pub async fn get_world(&self) -> Result { - let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); + let mut rng = SmallRng::from_rng(&mut rand::rng()); - let random_id = (rng.gen::() % 10_000 + 1) as i32; + let random_id = (rng.random::() % 10_000 + 1) as i32; let world = self.query_one_world(random_id).await?; let mut body = BytesMut::with_capacity(40); @@ -113,12 +113,12 @@ impl PgConnection { } pub async fn get_worlds(&self, num: usize) -> Result, PgError> { - let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); + let mut rng = SmallRng::from_rng(&mut rand::rng()); let worlds = FuturesUnordered::new(); for _ in 0..num { - let w_id = (rng.gen::() % 10_000 + 1) as i32; + let w_id = (rng.random::() % 10_000 + 1) as i32; worlds.push(self.query_one_world(w_id)); } @@ -126,13 +126,13 @@ impl PgConnection { } pub async fn update(&self, num: u16) -> Result, PgError> { - let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); + let mut rng = SmallRng::from_rng(&mut rand::rng()); let worlds = FuturesUnordered::new(); for _ in 0..num { - let id = (rng.gen::() % 10_000 + 1) as i32; - let w_id = (rng.gen::() % 10_000 + 1) as i32; + let id = (rng.random::() % 10_000 + 1) as i32; + let w_id = (rng.random::() % 10_000 + 1) as i32; worlds.push(self.query_one_world(w_id).map(move |res| match res { Ok(mut world) => { diff --git a/frameworks/Rust/actix/src/db_diesel.rs b/frameworks/Rust/actix/src/db_diesel.rs index 9d38d0b96c6..7675e3d4b52 100644 --- a/frameworks/Rust/actix/src/db_diesel.rs +++ b/frameworks/Rust/actix/src/db_diesel.rs @@ -3,7 +3,7 @@ use std::io; use actix::prelude::*; -use diesel::{prelude::*, result::Error}; +use diesel::prelude::*; use rand::{rngs::SmallRng, Rng, SeedableRng}; use crate::models; @@ -18,7 +18,7 @@ impl DbExecutor { DbExecutor { conn: PgConnection::establish(db_url) .unwrap_or_else(|_| panic!("Error connecting to {}", db_url)), - rng: SmallRng::from_entropy(), + rng: SmallRng::from_os_rng(), } } } @@ -39,10 +39,10 @@ impl Handler for DbExecutor { fn handle(&mut self, _: RandomWorld, _: &mut Self::Context) -> Self::Result { use crate::schema::world::dsl::*; - let random_id = self.rng.gen_range(1..10_001); + let random_id = self.rng.random_range(1..10_001); match world .filter(id.eq(random_id)) - .load::(&self.conn) + .load::(&mut self.conn) { Ok(mut items) => Ok(items.pop().unwrap()), Err(_) => Err(io::Error::new(io::ErrorKind::Other, "Database error")), @@ -64,8 +64,8 @@ impl Handler for DbExecutor { let mut worlds = Vec::with_capacity(msg.0 as usize); for _ in 0..msg.0 { - let w_id = self.rng.gen_range(1..10_001); - let w = match world.filter(id.eq(w_id)).load::(&self.conn) { + let w_id = self.rng.random_range(1..10_001); + let w = match world.filter(id.eq(w_id)).load::(&mut self.conn) { Ok(mut items) => items.pop().unwrap(), Err(_) => { return Err(io::Error::new(io::ErrorKind::Other, "Database error")); @@ -91,27 +91,28 @@ impl Handler for DbExecutor { let mut worlds = Vec::with_capacity(msg.0 as usize); for _ in 0..msg.0 { - let w_id: i32 = self.rng.gen_range(1..10_001); - let mut w = match world.filter(id.eq(w_id)).load::(&self.conn) { + let w_id: i32 = self.rng.random_range(1..10_001); + let mut w = match world.filter(id.eq(w_id)).load::(&mut self.conn) { Ok(mut items) => items.pop().unwrap(), Err(_) => { return Err(io::Error::new(io::ErrorKind::Other, "Database error")); } }; - w.randomnumber = self.rng.gen_range(1..10_001); + w.randomnumber = self.rng.random_range(1..10_001); worlds.push(w); } worlds.sort_by_key(|w| w.id); - let _ = self.conn.transaction::<(), Error, _>(|| { + self.conn.transaction(|conn| { for w in &worlds { - let _ = diesel::update(world) + diesel::update(world) .filter(id.eq(w.id)) .set(randomnumber.eq(w.randomnumber)) - .execute(&self.conn); + .execute(conn)?; } Ok(()) - }); + }) + .map_err(|e: diesel::result::Error| io::Error::new(io::ErrorKind::Other, e))?; Ok(worlds) } @@ -129,7 +130,7 @@ impl Handler for DbExecutor { fn handle(&mut self, _: TellFortune, _: &mut Self::Context) -> Self::Result { use crate::schema::fortune::dsl::*; - match fortune.load::(&self.conn) { + match fortune.load::(&mut self.conn) { Ok(mut items) => { items.push(models::Fortune { id: 0, diff --git a/frameworks/Rust/actix/src/main_http.rs b/frameworks/Rust/actix/src/main_http.rs index a8ab73c1f55..a1e76742320 100644 --- a/frameworks/Rust/actix/src/main_http.rs +++ b/frameworks/Rust/actix/src/main_http.rs @@ -23,6 +23,7 @@ use crate::{ utils::Writer, }; +#[allow(dead_code)] #[derive(Debug)] enum Error { Pg(PgError), @@ -134,7 +135,7 @@ impl Service for App { } _ => Box::pin(ok(Response::with_body( - http::StatusCode::NOT_FOUND, + StatusCode::NOT_FOUND, Bytes::new(), ))), } diff --git a/frameworks/Rust/actix/src/main_mongodb.rs b/frameworks/Rust/actix/src/main_mongodb.rs index 251060fe2e1..ae26914f2d4 100644 --- a/frameworks/Rust/actix/src/main_mongodb.rs +++ b/frameworks/Rust/actix/src/main_mongodb.rs @@ -28,12 +28,12 @@ async fn find_random_world(data: web::Data) -> Result { let runtime = data.tokio_runtime.clone(); runtime .spawn(async move { - let mut rng = SmallRng::from_entropy(); - let id = (rng.gen::() % 10_000 + 1) as i32; + let mut rng = SmallRng::from_os_rng(); + let id = (rng.random::() % 10_000 + 1) as i32; let coll = data.client.database("hello_world").collection("world"); let world = coll - .find_one(doc! { "id": id as f32 }, None) + .find_one(doc! { "id": id as f32 }) .await? .expect("should find world"); Ok(world) @@ -101,10 +101,10 @@ async fn updates( let mut worlds = find_random_worlds(data, query.q).await?; - let mut rng = SmallRng::from_entropy(); + let mut rng = SmallRng::from_os_rng(); let mut updates = Vec::new(); for world in worlds.iter_mut() { - let new_random_number = (rng.gen::() % 10_000 + 1) as i32; + let new_random_number = (rng.random::() % 10_000 + 1) as i32; updates.push(doc! { "q": { "id": world.id }, "u": { "$set": { "randomNumber": new_random_number }} }); @@ -121,7 +121,6 @@ async fn updates( "updates": updates, "ordered": false, }, - None, ) .await }) @@ -145,7 +144,7 @@ async fn fortune(data: web::Data) -> Result>> { let fortunes_cursor = client .database("hello_world") .collection::("fortune") - .find(None, None) + .find(doc! {}) .await?; let mut fortunes: Vec = fortunes_cursor.try_collect().await?; diff --git a/frameworks/Rust/actix/src/main_pg_deadpool.rs b/frameworks/Rust/actix/src/main_pg_deadpool.rs index b24d5753d20..da0ff484eef 100644 --- a/frameworks/Rust/actix/src/main_pg_deadpool.rs +++ b/frameworks/Rust/actix/src/main_pg_deadpool.rs @@ -27,8 +27,8 @@ async fn find_random_world(pool: &Pool) -> Result { .await .unwrap(); - let mut rng = SmallRng::from_entropy(); - let id = (rng.gen::() % 10_000 + 1) as i32; + let mut rng = SmallRng::from_os_rng(); + let id = (rng.random::() % 10_000 + 1) as i32; let row = conn.query_one(&world, &[&id]).await?; @@ -95,14 +95,14 @@ async fn updates( ) -> Result>> { let mut worlds = find_random_worlds(&data, query.q).await?; - let mut rng = SmallRng::from_entropy(); + let mut rng = SmallRng::from_os_rng(); let mut updates = "UPDATE world SET randomnumber = CASE id ".to_string(); let mut params: Vec<&(dyn ToSql + Sync)> = Vec::with_capacity(query.q as usize * 3); let mut n_params = 1; for world in worlds.iter_mut() { - let new_random_number = (rng.gen::() % 10_000 + 1) as i32; + let new_random_number = (rng.random::() % 10_000 + 1) as i32; write!(&mut updates, "when ${} then ${} ", n_params, n_params + 1).unwrap(); world.randomnumber = new_random_number; n_params += 2; diff --git a/frameworks/Rust/anansi/Cargo.toml b/frameworks/Rust/anansi/Cargo.toml deleted file mode 100644 index a717e96e70b..00000000000 --- a/frameworks/Rust/anansi/Cargo.toml +++ /dev/null @@ -1,25 +0,0 @@ -[workspace] -members = [ - ".", -] - -[package] -name = "tfb-anansi" -version = "0.1.0" -edition = "2021" - -[features] -raw = [] - -[dependencies] -anansi = { git = "https://github.com/saru-tora/anansi", rev = "c350a23", features = ["postgres", "minimal", "redis"] } -async-trait = "0.1.57" -rand = "0.8.4" -serde = "1" -serde_json = "1" -tokio-postgres = "0.7.7" - -[profile.release] -lto = true -opt-level = 3 -codegen-units = 1 diff --git a/frameworks/Rust/anansi/README.md b/frameworks/Rust/anansi/README.md deleted file mode 100755 index ebddef843ca..00000000000 --- a/frameworks/Rust/anansi/README.md +++ /dev/null @@ -1,36 +0,0 @@ -# [Anansi](https://saru-tora.github.io/anansi/) Benchmarking Test - -Anansi is a simple full-stack web framework for Rust. - -### Test Type Implementation Source Code - -All tests can be found in: src/hello/world/ - -## Test URLs -### JSON - -http://localhost:8080/json - -### PLAINTEXT - -http://localhost:8080/plaintext - -### DB - -http://localhost:8080/db - -### QUERY - -http://localhost:8080/query?queries= - -### CACHED QUERY - -http://localhost:8080/cached_query?queries= - -### UPDATE - -http://localhost:8080/update?queries= - -### FORTUNES - -http://localhost:8080/fortunes diff --git a/frameworks/Rust/anansi/anansi-raw.dockerfile b/frameworks/Rust/anansi/anansi-raw.dockerfile deleted file mode 100644 index 96c284a8b7a..00000000000 --- a/frameworks/Rust/anansi/anansi-raw.dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM rust:1.64 - -ADD ./ /anansi -WORKDIR /anansi - -RUN cargo clean -RUN RUSTFLAGS="-C target-cpu=native" cargo build --release --features raw - -EXPOSE 8080 - -CMD RUST_LOG=off ./target/release/tfb-anansi 0.0.0.0:8080 diff --git a/frameworks/Rust/anansi/anansi.dockerfile b/frameworks/Rust/anansi/anansi.dockerfile deleted file mode 100644 index bf6f7596193..00000000000 --- a/frameworks/Rust/anansi/anansi.dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM rust:1.64 - -RUN apt-get update -yqq && apt-get install -yqq --no-install-recommends redis-server - -ADD ./ /anansi -WORKDIR /anansi - -RUN cargo clean -RUN RUSTFLAGS="-C target-cpu=native" cargo build --release - -EXPOSE 8080 - -ENV RUST_LOG=off -CMD service redis-server start && ./target/release/tfb-anansi 0.0.0.0:8080 diff --git a/frameworks/Rust/anansi/benchmark_config.json b/frameworks/Rust/anansi/benchmark_config.json deleted file mode 100755 index dd1c17b71bd..00000000000 --- a/frameworks/Rust/anansi/benchmark_config.json +++ /dev/null @@ -1,53 +0,0 @@ -{ - "framework": "anansi", - "tests": [ - { - "default": { - "json_url": "/json", - "plaintext_url": "/plaintext", - "db_url": "/db", - "fortune_url": "/fortunes", - "query_url": "/queries?q=", - "update_url": "/updates?q=", - "cached_query_url": "/cached-queries?q=", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "postgres", - "framework": "Anansi", - "language": "Rust", - "flavor": "None", - "orm": "Full", - "platform": "None", - "webserver": "hyper", - "os": "Linux", - "database_os": "Linux", - "display_name": "Anansi [minimal]", - "notes": "", - "versus": "None" - }, - "raw": { - "db_url": "/db", - "fortune_url": "/fortunes", - "query_url": "/queries?q=", - "update_url": "/updates?q=", - "cached_query_url": "/cached-queries?q=", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "postgres", - "framework": "Anansi", - "language": "Rust", - "flavor": "None", - "orm": "Raw", - "platform": "None", - "webserver": "hyper", - "os": "Linux", - "database_os": "Linux", - "display_name": "Anansi [minimal, raw]", - "notes": "", - "versus": "None" - } - } - ] -} diff --git a/frameworks/Rust/anansi/settings.toml b/frameworks/Rust/anansi/settings.toml deleted file mode 100644 index 6089347e428..00000000000 --- a/frameworks/Rust/anansi/settings.toml +++ /dev/null @@ -1,18 +0,0 @@ -secret_key = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -login_url = "/login" -smtp_relay = "" -smtp_username = "" -smtp_password = "" - -[caches] - -[caches.default] -location = "redis://127.0.0.1/" - -[databases] - -[databases.default] -name = "hello_world" -user = "benchmarkdbuser" -password = "benchmarkdbpass" -address = "tfb-database" diff --git a/frameworks/Rust/anansi/src/hello/middleware.rs b/frameworks/Rust/anansi/src/hello/middleware.rs deleted file mode 100644 index be369cb827d..00000000000 --- a/frameworks/Rust/anansi/src/hello/middleware.rs +++ /dev/null @@ -1,94 +0,0 @@ -use std::fmt::{self, Write}; -use std::sync::Arc; -use anansi::db::postgres::{PgDbPool, PgDbRow, PgDbRowVec, PgStatement}; - -#[macro_export] -macro_rules! impl_pg { - () => { - #[async_trait::async_trait] - impl crate::hello::middleware::Pg for HttpRequest { - async fn get_world(&self) -> anansi::web::Result { - use anansi::web::BaseRequest; - self.raw().app_state().stmt.0.world.fetch_one(&[&Self::random_num()], self.raw().pool()).await - } - async fn update_worlds(&self, n: usize, params: &[&(dyn tokio_postgres::types::ToSql + Sync)]) -> anansi::web::Result<()> { - use anansi::web::BaseRequest; - self.raw().app_state().stmt.0.updates[n].execute(params, self.raw().pool()).await - } - async fn get_fortunes(&self) -> anansi::web::Result { - use anansi::web::BaseRequest; - self.raw().app_state().stmt.0.fortune.fetch_all(&[], self.raw().pool()).await - } - } - impl crate::hello::middleware::AsStmt for AppData { - fn as_stmt(&self) -> &crate::hello::middleware::Stmt { - &self.stmt - } - } - } -} - -fn update_statement(num: u16) -> String { - let mut pl = 1; - let mut q = "UPDATE world SET randomnumber = CASE id ".to_string(); - for _ in 1..=num { - let _ = write!(q, "WHEN ${} THEN ${} ", pl, pl + 1); - pl += 2; - } - - q.push_str("ELSE randomnumber END WHERE id IN ("); - - for _ in 1..=num { - let _ = write!(q, "${},", pl); - pl += 1; - } - - q.pop(); - q.push(')'); - q -} - -#[derive(Clone)] -pub struct Stmt(pub Arc); - -impl fmt::Debug for Stmt { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Stmt") - .finish() - } -} - -impl Stmt { - pub async fn new(pool: &PgDbPool) -> anansi::web::Result { - let mut updates = vec![]; - for n in 1..=500 { - updates.push(PgStatement::new(&update_statement(n), pool).await?); - } - Ok(Self(Arc::new(State { - world: PgStatement::new("SELECT * FROM world WHERE id = $1", pool).await?, - updates, - fortune: PgStatement::new("SELECT * FROM fortune", pool).await?, - }))) - } -} - -pub struct State { - pub world: PgStatement, - pub updates: Vec, - pub fortune: PgStatement, -} - -pub trait AsStmt { - fn as_stmt(&self) -> &Stmt; -} - -#[async_trait::async_trait] -pub trait Pg { - fn random_num() -> i32 { - use rand::Rng; - rand::thread_rng().gen_range(1..=10_000) - } - async fn get_world(&self) -> anansi::web::Result; - async fn update_worlds(&self, n: usize, params: &[&(dyn tokio_postgres::types::ToSql + Sync)]) -> anansi::web::Result<()>; - async fn get_fortunes(&self) -> anansi::web::Result; -} diff --git a/frameworks/Rust/anansi/src/hello/migrations/mod.rs b/frameworks/Rust/anansi/src/hello/migrations/mod.rs deleted file mode 100644 index 72ca3a1f046..00000000000 --- a/frameworks/Rust/anansi/src/hello/migrations/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -use anansi::migrations::prelude::*; - -local_migrations! {} \ No newline at end of file diff --git a/frameworks/Rust/anansi/src/hello/mod.rs b/frameworks/Rust/anansi/src/hello/mod.rs deleted file mode 100644 index 74ca45e2a9d..00000000000 --- a/frameworks/Rust/anansi/src/hello/mod.rs +++ /dev/null @@ -1,8 +0,0 @@ -pub mod records; -pub mod migrations; - -pub const APP_NAME: &'static str = "hello"; -pub mod world; - -#[cfg(feature = "raw")] -pub mod middleware; diff --git a/frameworks/Rust/anansi/src/hello/records.rs b/frameworks/Rust/anansi/src/hello/records.rs deleted file mode 100644 index 6dc93a9c95c..00000000000 --- a/frameworks/Rust/anansi/src/hello/records.rs +++ /dev/null @@ -1,48 +0,0 @@ -#![allow(non_snake_case)] -use async_trait::async_trait; -use anansi::web::{Result, BaseRequest}; -use anansi::record; -use anansi::records::{Relate, Int, Text, random_int}; -use serde::Serialize; - -#[record(table_name = "World")] -#[derive(Serialize)] -pub struct World { - #[field(primary_key = "true", default_fn = "random_int")] - pub id: Int, - pub randomNumber: Int, -} - -#[async_trait] -impl Relate for World { - async fn on_save(&self, _req: &mut R) -> Result<()> { - unimplemented!(); - } - async fn on_delete(&self, _req: &R) -> Result<()> { - unimplemented!(); - } -} - -#[record(table_name = "Fortune")] -pub struct Fortune { - #[field(primary_key = "true", default_fn = "random_int")] - pub id: Int, - pub message: Text, -} - -#[cfg(not(feature = "raw"))] -impl Fortune { - pub fn additional() -> Self { - Self {id: Int::new(0), message: Text::from("Additional fortune added at request time.".to_string())} - } -} - -#[async_trait] -impl Relate for Fortune { - async fn on_save(&self, _req: &mut R) -> Result<()> { - unimplemented!(); - } - async fn on_delete(&self, _req: &R) -> Result<()> { - unimplemented!(); - } -} diff --git a/frameworks/Rust/anansi/src/hello/world/mod.rs b/frameworks/Rust/anansi/src/hello/world/mod.rs deleted file mode 100644 index 2d3508e5707..00000000000 --- a/frameworks/Rust/anansi/src/hello/world/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -#[cfg(not(feature = "raw"))] -pub mod views; -#[cfg(feature = "raw")] -pub mod raw; -pub mod util; diff --git a/frameworks/Rust/anansi/src/hello/world/raw.rs b/frameworks/Rust/anansi/src/hello/world/raw.rs deleted file mode 100644 index 6199bf0fb2e..00000000000 --- a/frameworks/Rust/anansi/src/hello/world/raw.rs +++ /dev/null @@ -1,110 +0,0 @@ -use crate::prelude::*; -use crate::hello::middleware::Pg; -use serde::Serialize; -use anansi::check; -use super::util::get_query; -use rand::Rng; -use tokio_postgres::types::ToSql; - -fn random_num() -> i32 { - rand::thread_rng().gen_range(1..=10_000) -} - -#[derive(Copy, Clone, Serialize, Debug)] -pub struct World { - id: i32, - randomnumber: i32, -} - -#[derive(Serialize, Debug)] -pub struct Fortune<'a> { - id: i32, - message: &'a str, -} - -#[base_view] -fn base(_req: &mut R) -> Result {} - -#[viewer] -impl WorldView { - async fn one_world(req: &R) -> Result { - let row = req.get_world().await?; - let world = World { - id: row.get_i32(0), - randomnumber: row.get_i32(1), - }; - Ok(world) - } - async fn get_worlds(req: &R) -> Result> { - let q = get_query(req.params()); - let mut worlds = Vec::with_capacity(q as usize); - for _ in 0..q { - let world = Self::one_world(req).await?; - worlds.push(world); - } - Ok(worlds) - } - #[check(Site::is_visitor)] - pub async fn db(req: &mut R) -> Result { - let world = Self::one_world(req).await?; - Response::json(&world) - } - #[check(Site::is_visitor)] - pub async fn queries(req: &mut R) -> Result { - let worlds = Self::get_worlds(req).await?; - Response::json(&worlds) - } - #[view(Site::is_visitor)] - pub async fn raw_fortunes(req: &mut R) -> Result { - let title = "Fortunes"; - let rows = req.get_fortunes().await?; - let mut fortunes = Vec::with_capacity(rows.len() + 1); - fortunes.push(Fortune { - id: 0, - message: "Additional fortune added at request time.", - }); - fortunes.extend(rows.iter().map(|row| Fortune { - id: row.get(0), - message: row.get(1), - })); - fortunes.sort_by(|it, next| it.message.cmp(&next.message)); - } - #[check(Site::is_visitor)] - pub async fn updates(req: &mut R) -> Result { - let q = get_query(req.params()) as usize; - let mut worlds = Vec::with_capacity(q); - let mut params: Vec<&(dyn ToSql + Sync)> = Vec::with_capacity(q * 3); - for _ in 0..q { - let row = req.get_world().await?; - let world = World { - id: row.get_i32(0), - randomnumber: random_num(), - }; - worlds.push(world); - } - for world in &worlds { - params.push(&world.id); - params.push(&world.randomnumber); - } - for world in &worlds { - params.push(&world.id); - } - req.update_worlds(q - 1, params.as_slice()).await?; - Response::json(&worlds) - } - #[check(Site::is_visitor)] - pub async fn cached_queries(req: &mut R) -> Result { - let q = get_query(req.params()); - let mut ids = vec![]; - for _ in 0..q { - ids.push(random_num().to_string()); - } - let mut worlds = vec!['[' as u8]; - for mut world in req.cache().get_many(ids).await? { - worlds.append(&mut world); - } - worlds.pop(); - worlds.push(']' as u8); - Response::json_bytes(worlds) - } -} diff --git a/frameworks/Rust/anansi/src/hello/world/templates/.parsed/base.in b/frameworks/Rust/anansi/src/hello/world/templates/.parsed/base.in deleted file mode 100644 index 0473720779d..00000000000 --- a/frameworks/Rust/anansi/src/hello/world/templates/.parsed/base.in +++ /dev/null @@ -1,9 +0,0 @@ -{let mut _c = String::new();_c.push_str(" - - - ");_c.push_str(&_base_args._title);_c.push_str(" - - - ");_c.push_str(&_base_args._content);_c.push_str(" - -");_c.into_bytes()} \ No newline at end of file diff --git a/frameworks/Rust/anansi/src/hello/world/templates/.parsed/base_args.in b/frameworks/Rust/anansi/src/hello/world/templates/.parsed/base_args.in deleted file mode 100644 index 9ad5b91f42b..00000000000 --- a/frameworks/Rust/anansi/src/hello/world/templates/.parsed/base_args.in +++ /dev/null @@ -1 +0,0 @@ -pub struct Args {pub _title: String,pub _content: String,}impl anansi::cache::Cacheable for Args {fn to_bytes(&self) -> Vec {let mut v = vec![];v.append(&mut self._title.len().to_ne_bytes().to_vec());v.append(&mut self._title.as_bytes().to_vec());v.append(&mut self._content.len().to_ne_bytes().to_vec());v.append(&mut self._content.as_bytes().to_vec());v} fn from_bytes(mut __b: Vec) -> anansi::web::Result {let mut buf = __b.split_off(8); let l = usize::from_ne_bytes(__b.try_into().unwrap()); let mut __b = buf.split_off(l); let _title = String::from_utf8(buf)?;let mut buf = __b.split_off(8); let l = usize::from_ne_bytes(__b.try_into().unwrap()); let mut __b = buf.split_off(l); let _content = String::from_utf8(buf)?;Ok(Self {_title, _content, })}} impl Args {pub fn new() -> Self {Self {_title: String::new(), _content: String::new(), }}} \ No newline at end of file diff --git a/frameworks/Rust/anansi/src/hello/world/templates/.parsed/fortunes.in b/frameworks/Rust/anansi/src/hello/world/templates/.parsed/fortunes.in deleted file mode 100644 index 7cf8984f743..00000000000 --- a/frameworks/Rust/anansi/src/hello/world/templates/.parsed/fortunes.in +++ /dev/null @@ -1,6 +0,0 @@ -{_args._title = {let mut _c = String::new();_c.push_str("");_c.push_str(&anansi::web::html_escape(&format!("{}", title)));_c.push_str(""); _c};_args._content = {let mut _c = String::new();_c.push_str(" - - ");for fortune in fortunes {_c.push_str(" - - ");}_c.push_str(" -
idmessage
");_c.push_str(&anansi::web::html_escape(&format!("{}", fortune.pk())));_c.push_str("");_c.push_str(&anansi::web::html_escape(&format!("{}", fortune.message)));_c.push_str("
"); _c};_args} \ No newline at end of file diff --git a/frameworks/Rust/anansi/src/hello/world/templates/.parsed/index.in b/frameworks/Rust/anansi/src/hello/world/templates/.parsed/index.in deleted file mode 100644 index 17b9c49d56b..00000000000 --- a/frameworks/Rust/anansi/src/hello/world/templates/.parsed/index.in +++ /dev/null @@ -1 +0,0 @@ -{_args._title = {let mut _c = String::new();_c.push_str("");_c.push_str(&anansi::web::html_escape(&format!("{}", title)));_c.push_str(""); _c};_args._content = {let mut _c = String::new();_c.push_str("

");_c.push_str(&anansi::web::html_escape(&format!("{}", title)));_c.push_str("

"); _c};_args} \ No newline at end of file diff --git a/frameworks/Rust/anansi/src/hello/world/templates/.parsed/raw_fortunes.in b/frameworks/Rust/anansi/src/hello/world/templates/.parsed/raw_fortunes.in deleted file mode 100644 index 83c5b13e6cf..00000000000 --- a/frameworks/Rust/anansi/src/hello/world/templates/.parsed/raw_fortunes.in +++ /dev/null @@ -1,4 +0,0 @@ -{_args._content = {let mut _c = String::new();_c.push_str(""); -for fortune in fortunes {_c.push_str(&format!("");} -_c.push_str("
idmessage
{}", fortune.id));anansi::web::html_escape2(&mut _c, fortune.message);_c.push_str("
"); _c}; -_args._title = {let mut _c = String::new();_c.push_str(&format!("{}", title)); _c};_args} diff --git a/frameworks/Rust/anansi/src/hello/world/templates/base.rs.html b/frameworks/Rust/anansi/src/hello/world/templates/base.rs.html deleted file mode 100644 index 440d37a95eb..00000000000 --- a/frameworks/Rust/anansi/src/hello/world/templates/base.rs.html +++ /dev/null @@ -1,9 +0,0 @@ - - - - @block title - - - @block content - - diff --git a/frameworks/Rust/anansi/src/hello/world/templates/fortunes.rs.html b/frameworks/Rust/anansi/src/hello/world/templates/fortunes.rs.html deleted file mode 100644 index 0d4e369792a..00000000000 --- a/frameworks/Rust/anansi/src/hello/world/templates/fortunes.rs.html +++ /dev/null @@ -1,10 +0,0 @@ -@block title {@title} - -@block content { - - - @for fortune in fortunes { - - } -
idmessage
@fortune.pk()@fortune.message
-} diff --git a/frameworks/Rust/anansi/src/hello/world/templates/raw_fortunes.rs.html b/frameworks/Rust/anansi/src/hello/world/templates/raw_fortunes.rs.html deleted file mode 100644 index 22edc654ba9..00000000000 --- a/frameworks/Rust/anansi/src/hello/world/templates/raw_fortunes.rs.html +++ /dev/null @@ -1,10 +0,0 @@ -@block title {@unescape title} - -@block content { - - - @for fortune in fortunes { - - } -
idmessage
@unescape fortune.id@fortune.message
-} diff --git a/frameworks/Rust/anansi/src/hello/world/util.rs b/frameworks/Rust/anansi/src/hello/world/util.rs deleted file mode 100644 index 8e8998f2b1f..00000000000 --- a/frameworks/Rust/anansi/src/hello/world/util.rs +++ /dev/null @@ -1,16 +0,0 @@ -use anansi::web::Parameters; - -pub fn get_query(params: &Parameters) -> i16 { - if let Ok(q) = params.get("q") { - if let Ok(q) = q.parse() { - if q > 1 { - return if q <= 500 { - q - } else { - 500 - }; - } - } - } - 1 -} diff --git a/frameworks/Rust/anansi/src/hello/world/views.rs b/frameworks/Rust/anansi/src/hello/world/views.rs deleted file mode 100644 index c75b2fcd4cb..00000000000 --- a/frameworks/Rust/anansi/src/hello/world/views.rs +++ /dev/null @@ -1,90 +0,0 @@ -use crate::prelude::*; -use anansi::cache::prelude::*; -use anansi::records::Int; -use super::super::records::{World, Fortune}; -use super::util::get_query; -use serde::Serialize; -use anansi::{check, raw_bulk_update}; -use rand::Rng; - -fn random_i32() -> i32 { - rand::thread_rng().gen_range(1..=10_000) -} - -fn random_int() -> Int { - Int::new(random_i32()) -} - -#[derive(Serialize)] -struct Message { - message: &'static str, -} - -#[base_view] -fn base(_req: &mut R) -> Result {} - -#[viewer] -impl WorldView { - #[check(Site::is_visitor)] - pub async fn json(req: &mut R) -> Result { - let message = Message {message: "Hello, World!"}; - Response::json(&message) - } - async fn get_world(req: &R) -> Result { - World::find(random_int()).get(req).await - } - async fn get_worlds(req: &R) -> Result> { - let q = get_query(req.params()); - let mut worlds = Vec::with_capacity(q as usize); - for _ in 0..q { - let world = Self::get_world(req).await?; - worlds.push(world); - } - Ok(worlds) - } - #[check(Site::is_visitor)] - pub async fn db(req: &mut R) -> Result { - let world = Self::get_world(req).await?; - Response::json(&world) - } - #[check(Site::is_visitor)] - pub async fn queries(req: &mut R) -> Result { - let worlds = Self::get_worlds(req).await?; - Response::json(&worlds) - } - #[view(Site::is_visitor)] - pub async fn fortunes(req: &mut R) -> Result { - let title = "Fortunes"; - let mut fortunes = Fortune::get_all().query(req).await?; - fortunes.push(Fortune::additional()); - fortunes.sort_by(|it, next| it.message.cmp(&next.message)); - } - #[check(Site::is_visitor)] - pub async fn updates(req: &mut R) -> Result { - let mut worlds = Self::get_worlds(req).await?; - for world in &mut worlds { - world.randomNumber = random_int(); - } - raw_bulk_update!(req, World, &worlds, randomNumber).await?; - Response::json(&worlds) - } - #[check(Site::is_visitor)] - pub async fn plaintext(req: &mut R) -> Result { - Ok(Response::text("Hello, World!".to_string())) - } - #[check(Site::is_visitor)] - pub async fn cached_queries(req: &mut R) -> Result { - let q = get_query(req.params()); - let mut ids = vec![]; - for _ in 0..q { - ids.push(random_i32().to_string()); - } - let mut worlds = vec!['[' as u8]; - for mut world in req.cache().get_many(ids).await? { - worlds.append(&mut world); - } - worlds.pop(); - worlds.push(']' as u8); - Response::json_bytes(worlds) - } -} diff --git a/frameworks/Rust/anansi/src/http_errors/500.html b/frameworks/Rust/anansi/src/http_errors/500.html deleted file mode 100644 index 1c14f7cd7f3..00000000000 --- a/frameworks/Rust/anansi/src/http_errors/500.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - - 500 Internal Server Error - - -

Internal Server Error

-

Sorry, something went wrong.

- - diff --git a/frameworks/Rust/anansi/src/http_errors/mod.rs b/frameworks/Rust/anansi/src/http_errors/mod.rs deleted file mode 100644 index 38b44033152..00000000000 --- a/frameworks/Rust/anansi/src/http_errors/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod views; diff --git a/frameworks/Rust/anansi/src/http_errors/templates/.parsed/not_found.in b/frameworks/Rust/anansi/src/http_errors/templates/.parsed/not_found.in deleted file mode 100644 index c13f6730bf5..00000000000 --- a/frameworks/Rust/anansi/src/http_errors/templates/.parsed/not_found.in +++ /dev/null @@ -1,11 +0,0 @@ -{let mut _c = String::new();_c.push_str(" - - - - Not Found - - -

404

-

Page not found.

- -");_c.into_bytes()} \ No newline at end of file diff --git a/frameworks/Rust/anansi/src/http_errors/templates/not_found.rs.html b/frameworks/Rust/anansi/src/http_errors/templates/not_found.rs.html deleted file mode 100644 index eaf9a979ee7..00000000000 --- a/frameworks/Rust/anansi/src/http_errors/templates/not_found.rs.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - - Not Found - - -

404

-

Page not found.

- - diff --git a/frameworks/Rust/anansi/src/http_errors/views.rs b/frameworks/Rust/anansi/src/http_errors/views.rs deleted file mode 100644 index 04872858818..00000000000 --- a/frameworks/Rust/anansi/src/http_errors/views.rs +++ /dev/null @@ -1,12 +0,0 @@ -use anansi::{check, viewer, render}; -use anansi::web::{Result, Response}; -use anansi::site::Site; -use crate::project::Request; - -#[viewer] -impl ErrorView { - #[check(Site::is_visitor)] - pub async fn not_found(_req: &mut R) -> Result { - render!("not_found") - } -} diff --git a/frameworks/Rust/anansi/src/main.rs b/frameworks/Rust/anansi/src/main.rs deleted file mode 100644 index 24e3fd87292..00000000000 --- a/frameworks/Rust/anansi/src/main.rs +++ /dev/null @@ -1,28 +0,0 @@ -use anansi::*; - -mod urls; -mod project; -mod http_errors; -mod hello; - -apps! { - hello, -} - -app_statics! {} - -min_main!(server, { - use anansi::cache::prelude::*; - use hello::records::World; - use anansi::records::Record; - use anansi::db::AsDb; - let worlds = World::get_all().raw_query(server.app_data.as_db()).await.expect("problem fetching worlds"); - let mut items = vec![]; - for world in worlds { - let id = world.pk().to_string(); - let mut bytes = serde_json::to_vec(&world).expect("problem serializing world"); - bytes.push(',' as u8); - items.push((id, bytes)); - } - server.cache.set_many(&items).await.expect("problem caching world"); -}); diff --git a/frameworks/Rust/anansi/src/project.rs b/frameworks/Rust/anansi/src/project.rs deleted file mode 100644 index 074460a6b46..00000000000 --- a/frameworks/Rust/anansi/src/project.rs +++ /dev/null @@ -1,62 +0,0 @@ -use anansi::project::prelude::*; -use crate::app_migrations; - -#[cfg(feature = "raw")] -use super::hello::middleware::Stmt; - -#[cfg(feature = "raw")] -use crate::impl_pg; - -#[cfg(feature = "raw")] -app_cache!(local); - -#[cfg(not(feature = "raw"))] -app_cache!(redis); - -database!(postgres); - -#[cfg(feature = "raw")] -raw_middleware!(); - -#[cfg(feature = "raw")] -anansi::setup!(); - -#[cfg(feature = "raw")] -impl_pg!(); - -#[cfg(not(feature = "raw"))] -middleware!(); - -#[derive(Clone, Debug)] -pub struct AppData { - pub pool: Pool, - #[cfg(feature = "raw")] - pub stmt: Stmt, -} - -#[cfg(feature = "raw")] -impl AppData { - pub async fn new() -> Self { - let pool = anansi::server::get_db::(app_migrations).await; - let stmt = Stmt::new(&pool).await.unwrap(); - Self {pool, stmt} - } -} - -#[cfg(not(feature = "raw"))] -impl AppData { - pub async fn new() -> Self { - let pool = anansi::server::get_db::(app_migrations).await; - Self {pool} - } -} - -impl anansi::db::AsDb for AppData { - type SqlDb = Pool; - fn as_db(&self) -> &Pool { - &self.pool - } - fn as_db_mut(&mut self) -> &mut Pool { - &mut self.pool - } -} diff --git a/frameworks/Rust/anansi/src/urls.rs b/frameworks/Rust/anansi/src/urls.rs deleted file mode 100644 index bd04cbaad43..00000000000 --- a/frameworks/Rust/anansi/src/urls.rs +++ /dev/null @@ -1,32 +0,0 @@ -use anansi::web::prelude::*; -use crate::prelude::Request; -#[cfg(not(feature = "raw"))] -use crate::hello::world::views::WorldView; - -#[cfg(not(feature = "raw"))] -pub fn routes() -> Router { - Router::new() - .route("/json", WorldView::json) - .route("/db", WorldView::db) - .route("/queries", WorldView::queries) - .route("/fortunes", WorldView::fortunes) - .route("/updates", WorldView::updates) - .route("/plaintext", WorldView::plaintext) - .route("/cached-queries", WorldView::cached_queries) -} - -#[cfg(feature = "raw")] -use crate::hello::world::raw::WorldView; - -#[cfg(feature = "raw")] -use crate::hello::middleware::Pg; - -#[cfg(feature = "raw")] -pub fn routes() -> Router { - Router::new() - .route("/db", WorldView::db) - .route("/queries", WorldView::queries) - .route("/fortunes", WorldView::raw_fortunes) - .route("/updates", WorldView::updates) - .route("/cached-queries", WorldView::cached_queries) -} diff --git a/frameworks/Rust/astra/Cargo.lock b/frameworks/Rust/astra/Cargo.lock index 3cd9550884b..de8ed1f1b7d 100644 --- a/frameworks/Rust/astra/Cargo.lock +++ b/frameworks/Rust/astra/Cargo.lock @@ -125,7 +125,7 @@ checksum = "d39cd93900197114fa1fcb7ae84ca742095eed9442088988ae74fa744e930e77" dependencies = [ "cfg-if", "libc", - "wasi", + "wasi 0.10.2+wasi-snapshot-preview1", ] [[package]] @@ -262,17 +262,18 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.108" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8521a1b57e76b1ec69af7599e75e38e7b7fad6610f037db8c79b127201b5d119" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "libmimalloc-sys" -version = "0.1.24" +version = "0.1.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7705fc40f6ed493f73584abbb324e74f96b358ff60dfe5659a0f8fc12c590a69" +checksum = "23aa6811d3bd4deb8a84dde645f943476d13b248d818edcf8ce0b2f37f036b44" dependencies = [ "cc", + "libc", ] [[package]] @@ -292,42 +293,23 @@ checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" [[package]] name = "mimalloc" -version = "0.1.28" +version = "0.1.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0dfa131390c2f6bdb3242f65ff271fcdaca5ff7b6c08f28398be7f2280e3926" +checksum = "fa01922b5ea280a911e323e4d2fd24b7fe5cc4042e0d2cda3c40775cdc4bdc9c" dependencies = [ "libmimalloc-sys", ] [[package]] name = "mio" -version = "0.8.0" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba272f85fa0b41fc91872be579b3bbe0f56b792aa361a380eb669469f68dafb2" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", "log", - "miow", - "ntapi", - "winapi", -] - -[[package]] -name = "miow" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" -dependencies = [ - "winapi", -] - -[[package]] -name = "ntapi" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" -dependencies = [ - "winapi", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys", ] [[package]] @@ -556,23 +538,73 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" [[package]] -name = "winapi" -version = "0.3.9" +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", + "windows-targets", ] [[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[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_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[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_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[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_gnullvm" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" +name = "windows_x86_64_msvc" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" diff --git a/frameworks/Rust/axum/Cargo.lock b/frameworks/Rust/axum/Cargo.lock index b13924bd25f..d19c9254f3f 100644 --- a/frameworks/Rust/axum/Cargo.lock +++ b/frameworks/Rust/axum/Cargo.lock @@ -1,33 +1,56 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] -name = "adler" -version = "1.0.2" +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 = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "ahash" -version = "0.7.6" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ - "getrandom", + "cfg-if", + "getrandom 0.3.3", "once_cell", "version_check", + "zerocopy", ] [[package]] name = "aho-corasick" -version = "0.7.20" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[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" @@ -39,9 +62,9 @@ dependencies = [ [[package]] name = "annotate-snippets" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3b9d411ecbaf79885c6df4d75fff75858d5995ff25385657a28af47e82f9c36" +checksum = "ccaf7e9dfbb6ab22c82e473cd1a8a7bd313c19a5b7e40970f3d89ef5a5c9e81e" dependencies = [ "unicode-width", "yansi-term", @@ -49,71 +72,51 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.68" +version = "0.1.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" +checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.104", ] [[package]] name = "atoi" -version = "1.0.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7c57d12312ff59c811c0643f4d80830505833c9ffaebd193d819392b265be8e" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" dependencies = [ "num-traits", ] [[package]] -name = "autocfg" -version = "1.1.0" +name = "atomic-waker" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] -name = "axum" -version = "0.2.0" -dependencies = [ - "axum 0.6.18", - "deadpool", - "deadpool-postgres", - "dotenv", - "futures", - "futures-util", - "hyper", - "mongodb", - "num_cpus", - "rand", - "serde", - "serde_json", - "sqlx", - "tokio", - "tokio-pg-mapper", - "tokio-pg-mapper-derive", - "tokio-postgres", - "tower", - "tower-http", - "yarte", -] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "axum" -version = "0.6.18" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8175979259124331c1d7bf6586ee7e0da434155e4b2d48ec2c8386281d8df39" +checksum = "021e862c184ae977658b36c4500f7feac3221ca5da43e3f25bd04ab6c79a29b5" dependencies = [ - "async-trait", "axum-core", - "bitflags", "bytes", + "form_urlencoded", "futures-util", - "headers", "http", "http-body", + "http-body-util", "hyper", + "hyper-util", "itoa", "matchit", "memchr", @@ -134,192 +137,304 @@ dependencies = [ [[package]] name = "axum-core" -version = "0.3.4" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" +checksum = "68464cd0412f486726fb3373129ef5d2993f90c34bc2bc1c1e9943b2f4fc7ca6" dependencies = [ - "async-trait", "bytes", - "futures-util", + "futures-core", "http", "http-body", + "http-body-util", "mime", + "pin-project-lite", "rustversion", + "sync_wrapper", "tower-layer", "tower-service", ] +[[package]] +name = "axum-techempower" +version = "0.3.0" +dependencies = [ + "axum", + "axum-core", + "bytes", + "deadpool", + "deadpool-postgres", + "dotenv", + "futures", + "futures-util", + "hyper", + "hyper-util", + "mimalloc", + "mime", + "mongodb", + "num_cpus", + "quick_cache", + "rand 0.9.2", + "serde", + "serde_json", + "serde_path_to_error", + "simd-json", + "socket2", + "sqlx", + "tokio", + "tokio-pg-mapper", + "tokio-pg-mapper-derive", + "tokio-postgres", + "tower", + "tower-http", + "yarte", +] + +[[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.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" +[[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.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" + [[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" +dependencies = [ + "serde", +] + +[[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 = "block-buffer" -version = "0.10.3" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ "generic-array", ] [[package]] name = "bson" -version = "2.4.0" +version = "2.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d76085681585d39016f4d3841eb019201fc54d2dd0d92ad1e4fab3bfb32754" +checksum = "7969a9ba84b0ff843813e7249eed1678d9b6607ce5a3b8f0a47af3fcf7978e6e" dependencies = [ "ahash", - "base64", + "base64 0.22.1", + "bitvec", + "getrandom 0.2.16", + "getrandom 0.3.3", "hex", - "indexmap", - "lazy_static", - "rand", + "indexmap 2.10.0", + "js-sys", + "once_cell", + "rand 0.9.2", "serde", "serde_bytes", "serde_json", - "time 0.3.17", - "uuid 1.2.2", + "time", + "uuid", ] [[package]] name = "bumpalo" -version = "3.12.0" +version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "byteorder" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.3.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" [[package]] name = "cc" -version = "1.0.77" +version = "1.2.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4" +checksum = "deec109607ca693028562ed836a5f1c4b8bd77755c4e132fc5ce11b0b6211ae7" dependencies = [ "jobserver", + "libc", + "shlex", ] [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" [[package]] name = "chrono" -version = "0.4.23" +version = "0.4.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f" +checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" dependencies = [ + "android-tzdata", "iana-time-zone", - "js-sys", - "num-integer", "num-traits", - "time 0.1.45", - "wasm-bindgen", - "winapi", + "serde", + "windows-link", ] [[package]] -name = "codespan-reporting" -version = "0.11.1" +name = "concurrent-queue" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" dependencies = [ - "termcolor", - "unicode-width", + "crossbeam-utils", ] [[package]] -name = "convert_case" -version = "0.4.0" +name = "const-oid" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] -name = "core-foundation" -version = "0.9.3" +name = "const-random" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" dependencies = [ - "core-foundation-sys", - "libc", + "const-random-macro", +] + +[[package]] +name = "const-random-macro" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" +dependencies = [ + "getrandom 0.2.16", + "once_cell", + "tiny-keccak", ] +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + [[package]] name = "core-foundation-sys" -version = "0.8.3" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.5" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" dependencies = [ "libc", ] [[package]] name = "crc" -version = "3.0.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53757d12b596c16c78b83458d732a5d1a17ab3f53f2f7412f6fb57cc8a140ab3" +checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675" dependencies = [ "crc-catalog", ] [[package]] name = "crc-catalog" -version = "2.1.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d0165d2900ae6778e36e80bbc4da3b5eefccee9ba939761f9c2882a5d9af3ff" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" [[package]] name = "crc32fast" -version = "1.3.2" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" dependencies = [ "cfg-if", ] [[package]] name = "crossbeam-queue" -version = "0.3.8" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" +checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" dependencies = [ - "cfg-if", "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.14" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f" -dependencies = [ - "cfg-if", -] +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] name = "crypto-common" @@ -331,55 +446,11 @@ dependencies = [ "typenum", ] -[[package]] -name = "cxx" -version = "1.0.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdf07d07d6531bfcdbe9b8b739b104610c6508dcc4d63b410585faf338241daf" -dependencies = [ - "cc", - "cxxbridge-flags", - "cxxbridge-macro", - "link-cplusplus", -] - -[[package]] -name = "cxx-build" -version = "1.0.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2eb5b96ecdc99f72657332953d4d9c50135af1bac34277801cc3937906ebd39" -dependencies = [ - "cc", - "codespan-reporting", - "once_cell", - "proc-macro2", - "quote", - "scratch", - "syn 1.0.105", -] - -[[package]] -name = "cxxbridge-flags" -version = "1.0.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac040a39517fd1674e0f32177648334b0f4074625b5588a64519804ba0553b12" - -[[package]] -name = "cxxbridge-macro" -version = "1.0.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1362b0ddcfc4eb0a1f57b68bd77dd99f0e826958a96abd0ae9bd092e114ffed6" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.105", -] - [[package]] name = "darling" -version = "0.13.4" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" dependencies = [ "darling_core", "darling_macro", @@ -387,123 +458,148 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.13.4" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", "strsim", - "syn 1.0.105", + "syn 2.0.104", ] [[package]] name = "darling_macro" -version = "0.13.4" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core", "quote", - "syn 1.0.105", + "syn 2.0.104", ] [[package]] name = "data-encoding" -version = "2.3.3" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d8666cb01533c39dde32bcbab8e227b4ed6679b2c925eba05feabea39508fb" +checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" [[package]] name = "deadpool" -version = "0.9.5" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "421fe0f90f2ab22016f32a9881be5134fdd71c65298917084b0c7477cbc3856e" +checksum = "5ed5957ff93768adf7a65ab167a17835c3d2c3c50d084fe305174c112f468e2f" dependencies = [ - "async-trait", "deadpool-runtime", "num_cpus", - "retain_mut", "serde", "tokio", ] [[package]] name = "deadpool-postgres" -version = "0.10.3" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e866e414e9e12fc988f0bfb89a0b86228e7ed196ca509fbc4dcbc738c56e753c" +checksum = "3d697d376cbfa018c23eb4caab1fd1883dd9c906a8c034e8d9a3cb06a7e0bef9" dependencies = [ + "async-trait", "deadpool", - "log", + "getrandom 0.2.16", + "serde", "tokio", "tokio-postgres", + "tracing", ] [[package]] name = "deadpool-runtime" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaa37046cc0f6c3cc6090fbdbf73ef0b8ef4cfcc37f6befc0020f63e8cf121e1" +checksum = "092966b41edc516079bdf31ec78a2e0588d1d0c08f78b91d8307215928642b2b" dependencies = [ "tokio", ] [[package]] -name = "derivative" -version = "2.2.0" +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.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" +dependencies = [ + "powerfmt", + "serde", +] + +[[package]] +name = "derive-syn-parse" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d65d7ce8132b7c0e54497a4d9a55a1c2a0912a0d786cf894472ba818fba45762" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + +[[package]] +name = "derive-where" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +checksum = "510c292c8cf384b1a340b816a9a6cf2599eb8f566a44949024af88418000c50b" dependencies = [ "proc-macro2", "quote", - "syn 1.0.105", + "syn 2.0.104", ] [[package]] name = "derive_more" -version = "0.99.17" +version = "0.99.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f" dependencies = [ "convert_case", "proc-macro2", "quote", - "rustc_version 0.4.0", - "syn 1.0.105", + "rustc_version", + "syn 2.0.104", ] [[package]] name = "digest" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", + "const-oid", "crypto-common", "subtle", ] [[package]] -name = "dirs" -version = "4.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" -dependencies = [ - "dirs-sys", -] - -[[package]] -name = "dirs-sys" -version = "0.3.7" +name = "displaydoc" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ - "libc", - "redox_users", - "winapi", + "proc-macro2", + "quote", + "syn 2.0.104", ] [[package]] @@ -514,100 +610,139 @@ checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" [[package]] name = "dotenvy" -version = "0.15.6" +version = "0.15.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03d8c417d7a8cb362e0c37e5d815f5eb7c37f79ff93707329d5a194e42e54ca0" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" [[package]] name = "dtoa" -version = "1.0.4" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8a6eee2d5d0d113f015688310da018bd1d864d86bd567c8fca9c266889e1bfa" +checksum = "d6add3b8cff394282be81f3fc1a0605db594ed69890078ca6e2cab1c408bcf04" + +[[package]] +name = "dyn-clone" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c7a8fb8a9fbf66c1f703fe16184d10ca0ee9d23be5b4436400408ba54a95005" [[package]] name = "either" -version = "1.8.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +dependencies = [ + "serde", +] [[package]] name = "enum-as-inner" -version = "0.4.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21cdad81446a7f7dc43f6a77409efeb9733d2fa65553efef6018ef257c959b73" +checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" dependencies = [ "heck", "proc-macro2", "quote", - "syn 1.0.105", + "syn 2.0.104", ] [[package]] -name = "event-listener" -version = "2.5.3" +name = "equivalent" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] -name = "fallible-iterator" -version = "0.2.0" +name = "etcetera" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" +checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" +dependencies = [ + "cfg-if", + "home", + "windows-sys 0.48.0", +] [[package]] -name = "fastrand" -version = "1.8.0" +name = "event-listener" +version = "5.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" +checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae" dependencies = [ - "instant", + "concurrent-queue", + "parking", + "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 = "flate2" -version = "1.0.25" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" +checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" dependencies = [ "crc32fast", "miniz_oxide", ] [[package]] -name = "fnv" -version = "1.0.7" +name = "float-cmp" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +checksum = "b09cf3155332e944990140d967ff5eceb70df778b34f77d8075db46e4704e6d8" +dependencies = [ + "num-traits", +] [[package]] -name = "foreign-types" -version = "0.3.2" +name = "flume" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" dependencies = [ - "foreign-types-shared", + "futures-core", + "futures-sink", + "spin", ] [[package]] -name = "foreign-types-shared" -version = "0.1.1" +name = "fnv" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" +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.1.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] +[[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.25" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", @@ -620,9 +755,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.25" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -630,15 +765,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.25" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.25" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7acc85df6714c176ab5edf386123fafe217be88c0840ec11f199441134a074e2" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -647,49 +782,49 @@ dependencies = [ [[package]] name = "futures-intrusive" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a604f7a68fbf8103337523b1fadc8ade7361ee3f112f7c680ad179651616aed5" +checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" dependencies = [ "futures-core", "lock_api", - "parking_lot 0.11.2", + "parking_lot", ] [[package]] name = "futures-io" -version = "0.3.25" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-macro" -version = "0.3.25" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 1.0.105", + "syn 2.0.104", ] [[package]] name = "futures-sink" -version = "0.3.25" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.25" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" -version = "0.3.25" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-channel", "futures-core", @@ -705,9 +840,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.6" +version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", @@ -715,87 +850,160 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.8" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", + "js-sys", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi 0.11.1+wasi-snapshot-preview1", + "wasm-bindgen", ] [[package]] -name = "hashbrown" -version = "0.12.3" +name = "getrandom" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ - "ahash", + "cfg-if", + "js-sys", + "libc", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", + "wasm-bindgen", ] [[package]] -name = "hashlink" -version = "0.8.1" +name = "gimli" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69fe1fcf8b4278d860ad0548329f892a3631fb63f82574df68275f34cdbe0ffa" -dependencies = [ - "hashbrown", -] +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] -name = "headers" -version = "0.3.8" +name = "h2" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3e372db8e5c0d213e0cd0b9be18be2aca3d44cf2fe30a9d46a65581cd454584" +checksum = "17da50a276f1e01e0ba6c029e47b7100754904ee8a278f886546e98575380785" dependencies = [ - "base64", - "bitflags", + "atomic-waker", "bytes", - "headers-core", + "fnv", + "futures-core", + "futures-sink", "http", - "httpdate", - "mime", - "sha1", + "indexmap 2.10.0", + "slab", + "tokio", + "tokio-util", + "tracing", ] [[package]] -name = "headers-core" -version = "0.2.0" +name = "halfbrown" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" +checksum = "aa2c385c6df70fd180bbb673d93039dbd2cd34e41d782600bdf6e1ca7bce39aa" dependencies = [ - "http", + "hashbrown 0.15.4", + "serde", ] [[package]] -name = "heck" -version = "0.4.0" +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" +checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" dependencies = [ - "unicode-segmentation", + "allocator-api2", + "equivalent", + "foldhash", ] [[package]] -name = "hermit-abi" -version = "0.1.19" +name = "hashlink" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" dependencies = [ - "libc", + "hashbrown 0.15.4", ] +[[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.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + [[package]] name = "hex" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hickory-proto" +version = "0.24.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92652067c9ce6f66ce53cc38d1169daa36e6e7eb7dd3b63b5103bd9d97117248" +dependencies = [ + "async-trait", + "cfg-if", + "data-encoding", + "enum-as-inner", + "futures-channel", + "futures-io", + "futures-util", + "idna", + "ipnet", + "once_cell", + "rand 0.8.5", + "thiserror 1.0.69", + "tinyvec", + "tokio", + "tracing", + "url", +] + +[[package]] +name = "hickory-resolver" +version = "0.24.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbb117a1ca520e111743ab2f6688eddee69db4e0ea242545a604dce8a66fd22e" +dependencies = [ + "cfg-if", + "futures-util", + "hickory-proto", + "ipconfig", + "lru-cache", + "once_cell", + "parking_lot", + "rand 0.8.5", + "resolv-conf", + "smallvec", + "thiserror 1.0.69", + "tokio", + "tracing", +] + [[package]] name = "hkdf" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" dependencies = [ "hmac", ] @@ -810,21 +1018,19 @@ dependencies = [ ] [[package]] -name = "hostname" -version = "0.3.1" +name = "home" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" +checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" dependencies = [ - "libc", - "match_cfg", - "winapi", + "windows-sys 0.59.0", ] [[package]] name = "http" -version = "0.2.9" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" dependencies = [ "bytes", "fnv", @@ -833,78 +1039,183 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.5" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", "http", - "pin-project-lite", ] [[package]] -name = "http-range-header" -version = "0.3.0" +name = "http-body-util" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bfe8eed0a9285ef776bb792479ea3834e8b94e13d615c2f66d03dd50a435a29" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] [[package]] name = "httparse" -version = "1.8.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] name = "httpdate" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "0.14.26" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab302d72a6f11a3b910431ff93aae7e773078c769f0a3ef15fb9ec692ed147d4" +checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" dependencies = [ "bytes", "futures-channel", - "futures-core", "futures-util", + "h2", "http", "http-body", "httparse", "httpdate", "itoa", "pin-project-lite", - "socket2", + "smallvec", + "tokio", +] + +[[package]] +name = "hyper-util" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f66d5bd4c6f02bf0542fad85d626775bab9258cf795a4256dcaf3161114d1df" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "hyper", + "pin-project-lite", "tokio", "tower-service", - "tracing", - "want", ] [[package]] name = "iana-time-zone" -version = "0.1.53" +version = "0.1.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765" +checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", + "log", "wasm-bindgen", - "winapi", + "windows-core", ] [[package]] name = "iana-time-zone-haiku" -version = "0.1.1" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "icu_collections" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" + +[[package]] +name = "icu_properties" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" + +[[package]] +name = "icu_provider" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" dependencies = [ - "cxx", - "cxx-build", + "displaydoc", + "icu_locale_core", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", ] [[package]] @@ -915,114 +1226,141 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "0.2.3" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" dependencies = [ - "matches", - "unicode-bidi", - "unicode-normalization", + "idna_adapter", + "smallvec", + "utf8_iter", ] [[package]] -name = "idna" -version = "0.3.0" +name = "idna_adapter" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "icu_normalizer", + "icu_properties", ] [[package]] name = "indexmap" -version = "1.9.2" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "indexmap" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" +dependencies = [ + "equivalent", + "hashbrown 0.15.4", + "serde", ] [[package]] -name = "instant" -version = "0.1.12" +name = "io-uring" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +checksum = "b86e202f00093dcba4275d4636b93ef9dd75d025ae560d2521b45ea28ab49013" dependencies = [ + "bitflags 2.9.1", "cfg-if", + "libc", ] [[package]] name = "ipconfig" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd302af1b90f2463a98fa5ad469fc212c8e3175a41c3068601bfa2727591c5be" +checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" dependencies = [ "socket2", "widestring", - "winapi", + "windows-sys 0.48.0", "winreg", ] [[package]] name = "ipnet" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11b0d96e660696543b251e58030cf9787df56da39dab19ad60eae7353040917e" - -[[package]] -name = "itertools" -version = "0.10.5" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" [[package]] name = "itoa" -version = "1.0.6" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jobserver" -version = "0.1.25" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "068b1ee6743e4d11fb9c6a1e6064b3693a1b600e7f5f5988047d98b3dc9fb90b" +checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" dependencies = [ + "getrandom 0.3.3", "libc", ] [[package]] name = "js-sys" -version = "0.3.60" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" dependencies = [ + "once_cell", "wasm-bindgen", ] [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin", +] [[package]] name = "libc" -version = "0.2.138" +version = "0.2.174" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8" +checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" [[package]] -name = "link-cplusplus" -version = "1.0.7" +name = "libm" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9272ab7b96c9046fbc5bc56c06c117cb639fe2d509df0c421cad82d2915cf369" +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" + +[[package]] +name = "libmimalloc-sys" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88cd67e9de251c1781dbe2f641a1a3ad66eaae831b8a2c38fbdc5ddae16d4d" dependencies = [ "cc", + "libc", +] + +[[package]] +name = "libsqlite3-sys" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" +dependencies = [ + "pkg-config", + "vcpkg", ] [[package]] @@ -1031,11 +1369,17 @@ version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" +[[package]] +name = "litemap" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" + [[package]] name = "lock_api" -version = "0.4.9" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" dependencies = [ "autocfg", "scopeguard", @@ -1043,12 +1387,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.17" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] name = "lru-cache" @@ -1060,431 +1401,467 @@ dependencies = [ ] [[package]] -name = "match_cfg" -version = "0.1.0" +name = "macro_magic" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" +checksum = "cc33f9f0351468d26fbc53d9ce00a096c8522ecb42f19b50f34f2c422f76d21d" +dependencies = [ + "macro_magic_core", + "macro_magic_macros", + "quote", + "syn 2.0.104", +] [[package]] -name = "matches" -version = "0.1.9" +name = "macro_magic_core" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" +checksum = "1687dc887e42f352865a393acae7cf79d98fab6351cde1f58e9e057da89bf150" +dependencies = [ + "const-random", + "derive-syn-parse", + "macro_magic_core_macros", + "proc-macro2", + "quote", + "syn 2.0.104", +] [[package]] -name = "matchit" -version = "0.7.0" +name = "macro_magic_core_macros" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b87248edafb776e59e6ee64a79086f65890d3510f2c656c000bf2a7e8a0aea40" +checksum = "b02abfe41815b5bd98dbd4260173db2c116dda171dc0fe7838cb206333b83308" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] [[package]] -name = "md-5" -version = "0.10.5" +name = "macro_magic_macros" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6365506850d44bff6e2fbcb5176cf63650e48bd45ef2fe2665ae1570e0f4b9ca" +checksum = "73ea28ee64b88876bf45277ed9a5817c1817df061a74f2b988971a12570e5869" dependencies = [ - "digest", + "macro_magic_core", + "quote", + "syn 2.0.104", ] [[package]] -name = "memchr" -version = "2.5.0" +name = "matchit" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" [[package]] -name = "mime" -version = "0.3.16" +name = "md-5" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if", + "digest", +] [[package]] -name = "minimal-lexical" -version = "0.2.1" +name = "memchr" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" [[package]] -name = "miniz_oxide" -version = "0.6.2" +name = "mimalloc" +version = "0.1.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" +checksum = "b1791cbe101e95af5764f06f20f6760521f7158f69dbf9d6baf941ee1bf6bc40" dependencies = [ - "adler", + "libmimalloc-sys", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", ] [[package]] name = "mio" -version = "0.8.5" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" +checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" dependencies = [ "libc", - "log", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.42.0", + "wasi 0.11.1+wasi-snapshot-preview1", + "windows-sys 0.59.0", ] [[package]] name = "mongodb" -version = "2.3.1" +version = "3.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5a1df476ac9541b0e4fdc8e2cc48884e66c92c933cd17a1fd75e68caf75752e" +checksum = "d0f8c69f13acf07eae386a2974f48ffd9187ea2aba8defbea9aa34e7e272c5f3" dependencies = [ "async-trait", - "base64", - "bitflags", + "base64 0.13.1", + "bitflags 1.3.2", "bson", "chrono", - "derivative", + "derive-where", + "derive_more", "flate2", "futures-core", "futures-executor", + "futures-io", "futures-util", "hex", + "hickory-proto", + "hickory-resolver", "hmac", - "lazy_static", + "macro_magic", "md-5", - "os_info", + "mongodb-internal-macros", + "once_cell", "pbkdf2", "percent-encoding", - "rand", + "rand 0.8.5", "rustc_version_runtime", - "rustls", + "rustls 0.21.12", "rustls-pemfile", "serde", "serde_bytes", "serde_with", - "sha-1", + "sha1", "sha2", "snap", "socket2", "stringprep", "strsim", "take_mut", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-rustls", "tokio-util", - "trust-dns-proto", - "trust-dns-resolver", "typed-builder", - "uuid 0.8.2", - "webpki-roots", + "uuid", + "webpki-roots 0.25.4", "zstd", ] [[package]] -name = "native-tls" -version = "0.2.11" +name = "mongodb-internal-macros" +version = "3.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +checksum = "b9202de265a3a8bbb43f9fe56db27c93137d4f9fb04c093f47e9c7de0c61ac7d" dependencies = [ - "lazy_static", - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", + "macro_magic", + "proc-macro2", + "quote", + "syn 2.0.104", ] [[package]] -name = "nom" -version = "7.1.1" +name = "num-bigint-dig" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" +checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" dependencies = [ - "memchr", - "minimal-lexical", + "byteorder", + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand 0.8.5", + "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.45" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ - "autocfg", "num-traits", ] [[package]] -name = "num-traits" -version = "0.2.15" +name = "num-iter" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" dependencies = [ "autocfg", + "num-integer", + "num-traits", ] [[package]] -name = "num_cpus" -version = "1.14.0" +name = "num-traits" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ - "hermit-abi", - "libc", + "autocfg", + "libm", ] [[package]] -name = "once_cell" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" - -[[package]] -name = "openssl" -version = "0.10.55" +name = "num_cpus" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "345df152bc43501c5eb9e4654ff05f794effb78d4efe3d53abc158baddc0703d" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" dependencies = [ - "bitflags", - "cfg-if", - "foreign-types", + "hermit-abi", "libc", - "once_cell", - "openssl-macros", - "openssl-sys", ] [[package]] -name = "openssl-macros" -version = "0.1.0" +name = "object" +version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.105", -] - -[[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.90" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374533b0e45f3a7ced10fcaeccca020e66656bc03dac384f852e4e5a7a8104a6" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", + "memchr", ] [[package]] -name = "os_info" -version = "3.5.1" +name = "once_cell" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4750134fb6a5d49afc80777394ad5d95b04bc12068c6abb92fae8f43817270f" -dependencies = [ - "log", - "winapi", -] +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] -name = "parking_lot" -version = "0.11.2" +name = "parking" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" -dependencies = [ - "instant", - "lock_api", - "parking_lot_core 0.8.5", -] +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" -version = "0.12.1" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" dependencies = [ "lock_api", - "parking_lot_core 0.9.5", + "parking_lot_core", ] [[package]] name = "parking_lot_core" -version = "0.8.5" +version = "0.9.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" dependencies = [ "cfg-if", - "instant", "libc", "redox_syscall", "smallvec", - "winapi", + "windows-targets 0.52.6", ] [[package]] -name = "parking_lot_core" -version = "0.9.5" +name = "pbkdf2" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ff9f3fef3968a3ec5945535ed654cb38ff72d7495a25619e2247fb15a2ed9ba" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-sys 0.42.0", + "digest", ] [[package]] -name = "paste" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1de2e551fb905ac83f73f7aedf2f0cb4a0da7e35efa24a202a936269f1f18e1" - -[[package]] -name = "pbkdf2" -version = "0.10.1" +name = "pem-rfc7468" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271779f35b581956db91a3e55737327a03aa051e90b1c47aeb189508533adfd7" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" dependencies = [ - "digest", + "base64ct", ] [[package]] name = "percent-encoding" -version = "2.2.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "phf" -version = "0.11.1" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "928c6535de93548188ef63bb7c4036bd415cd8f36ad25af44b9789b2ee72a48c" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" dependencies = [ "phf_shared", ] [[package]] name = "phf_shared" -version = "0.11.1" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1fb5f6f826b772a8d4c0394209441e7d37cbbb967ae9c7e0e8134365c9ee676" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" dependencies = [ "siphasher", ] [[package]] -name = "pin-project" -version = "1.0.12" +name = "pin-project-lite" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" -dependencies = [ - "pin-project-internal", -] +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] -name = "pin-project-internal" -version = "1.0.12" +name = "pin-utils" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.105", -] +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] -name = "pin-project-lite" -version = "0.2.9" +name = "pkcs1" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der", + "pkcs8", + "spki", +] [[package]] -name = "pin-utils" -version = "0.1.0" +name = "pkcs8" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] [[package]] name = "pkg-config" -version = "0.3.26" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] name = "postgres-protocol" -version = "0.6.4" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "878c6cbf956e03af9aa8204b407b9cbf47c072164800aa918c516cd4b056c50c" +checksum = "76ff0abab4a9b844b93ef7b81f1efc0a366062aaef2cd702c76256b5dc075c54" dependencies = [ - "base64", + "base64 0.22.1", "byteorder", "bytes", "fallible-iterator", "hmac", "md-5", "memchr", - "rand", + "rand 0.9.2", "sha2", "stringprep", ] [[package]] name = "postgres-types" -version = "0.2.4" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73d946ec7d256b04dfadc4e6a3292324e6f417124750fc5c0950f981b703a0f1" +checksum = "613283563cd90e1dfc3518d548caee47e0e725455ed619881f5cf21f36de4b48" dependencies = [ "bytes", "fallible-iterator", "postgres-protocol", ] +[[package]] +name = "potential_utf" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +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.17" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] [[package]] name = "prettyplease" -version = "0.1.21" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c142c0e46b57171fe0c528bee8c5b7569e80f0c17e377cd0e30ea57dbc11bb51" +checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" dependencies = [ "proc-macro2", - "syn 1.0.105", + "syn 1.0.109", ] [[package]] name = "proc-macro2" -version = "1.0.60" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] [[package]] -name = "quick-error" -version = "1.2.3" +name = "quick_cache" +version = "0.6.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" +checksum = "6b450dad8382b1b95061d5ca1eb792081fb082adf48c678791fe917509596d5f" +dependencies = [ + "ahash", + "equivalent", + "hashbrown 0.15.4", + "parking_lot", +] [[package]] name = "quote" -version = "1.0.28" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" 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 = "rand" version = "0.8.5" @@ -1492,8 +1869,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha", - "rand_core", + "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]] @@ -1503,7 +1890,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "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]] @@ -1512,270 +1909,313 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom", + "getrandom 0.2.16", ] [[package]] -name = "redox_syscall" -version = "0.2.16" +name = "rand_core" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "bitflags", + "getrandom 0.3.3", ] [[package]] -name = "redox_users" -version = "0.4.3" +name = "redox_syscall" +version = "0.5.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +checksum = "de3a5d9f0aba1dbcec1cc47f0ff94a4b778fe55bca98a6dfa92e4e094e57b1c4" dependencies = [ - "getrandom", - "redox_syscall", - "thiserror", + "bitflags 2.9.1", ] [[package]] -name = "regex" -version = "1.7.0" +name = "ref-cast" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a" +checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf" dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", + "ref-cast-impl", ] [[package]] -name = "regex-syntax" -version = "0.6.28" +name = "ref-cast-impl" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" +checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] [[package]] -name = "remove_dir_all" -version = "0.5.3" +name = "regex" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ - "winapi", + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", ] [[package]] -name = "resolv-conf" -version = "0.7.0" +name = "regex-automata" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ - "hostname", - "quick-error", + "aho-corasick", + "memchr", + "regex-syntax", ] [[package]] -name = "retain_mut" -version = "0.1.9" +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "resolv-conf" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4389f1d5789befaf6029ebd9f7dac4af7f7e3d61b69d4f30e2ac02b57e7712b0" +checksum = "95325155c684b1c89f7765e30bc1c42e4a6da51ca513615660cb8a62ef9a88e3" [[package]] name = "ring" -version = "0.16.20" +version = "0.17.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", + "cfg-if", + "getrandom 0.2.16", "libc", - "once_cell", - "spin", "untrusted", - "web-sys", - "winapi", + "windows-sys 0.52.0", ] [[package]] -name = "rustc_version" -version = "0.2.3" +name = "rsa" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +checksum = "78928ac1ed176a5ca1d17e578a1825f3d81ca54cf41053a592584b020cfd691b" dependencies = [ - "semver 0.9.0", + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core 0.6.4", + "signature", + "spki", + "subtle", + "zeroize", ] +[[package]] +name = "rustc-demangle" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" + [[package]] name = "rustc_version" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ - "semver 1.0.14", + "semver", ] [[package]] name = "rustc_version_runtime" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d31b7153270ebf48bf91c65ae5b0c00e749c4cfad505f66530ac74950249582f" +checksum = "2dd18cd2bae1820af0b6ad5e54f4a51d0f3fcc53b05f845675074efcc7af071d" dependencies = [ - "rustc_version 0.2.3", - "semver 0.9.0", + "rustc_version", + "semver", ] [[package]] name = "rustls" -version = "0.20.7" +version = "0.21.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "539a2bfe908f471bfa933876bd1eb6a19cf2176d375f82ef7f99530a40e48c2c" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" dependencies = [ "log", "ring", + "rustls-webpki 0.101.7", "sct", - "webpki", +] + +[[package]] +name = "rustls" +version = "0.23.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2491382039b29b9b11ff08b76ff6c97cf287671dbb74f0be44bda389fffe9bd1" +dependencies = [ + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki 0.103.4", + "subtle", + "zeroize", ] [[package]] name = "rustls-pemfile" -version = "0.3.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ee86d63972a7c661d1536fefe8c3c8407321c3df668891286de28abcd087360" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" dependencies = [ - "base64", + "base64 0.21.7", ] [[package]] -name = "rustversion" -version = "1.0.9" +name = "rustls-pki-types" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97477e48b4cf8603ad5f7aaf897467cf42ab4218a38ef76fb14c2d6773a6d6a8" +checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" +dependencies = [ + "zeroize", +] [[package]] -name = "ryu" -version = "1.0.11" +name = "rustls-webpki" +version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring", + "untrusted", +] [[package]] -name = "schannel" -version = "0.1.20" +name = "rustls-webpki" +version = "0.103.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2" +checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc" dependencies = [ - "lazy_static", - "windows-sys 0.36.1", + "ring", + "rustls-pki-types", + "untrusted", ] [[package]] -name = "scopeguard" -version = "1.1.0" +name = "rustversion" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" [[package]] -name = "scratch" -version = "1.0.2" +name = "ryu" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] -name = "sct" -version = "0.7.0" +name = "schemars" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f" dependencies = [ - "ring", - "untrusted", + "dyn-clone", + "ref-cast", + "serde", + "serde_json", ] [[package]] -name = "security-framework" -version = "2.7.0" +name = "schemars" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bc1bb97804af6631813c55739f771071e0f2ed33ee20b68c86ec505d906356c" +checksum = "82d20c4491bc164fa2f6c5d44565947a52ad80b9505d8e36f8d54c27c739fcd0" dependencies = [ - "bitflags", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", + "dyn-clone", + "ref-cast", + "serde", + "serde_json", ] [[package]] -name = "security-framework-sys" -version = "2.6.1" +name = "scopeguard" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" -dependencies = [ - "core-foundation-sys", - "libc", -] +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] -name = "semver" -version = "0.9.0" +name = "sct" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ - "semver-parser", + "ring", + "untrusted", ] [[package]] name = "semver" -version = "1.0.14" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4" - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" [[package]] name = "serde" -version = "1.0.150" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e326c9ec8042f1b5da33252c8a37e9ffbd2c9bef0155215b6e6c80c790e05f91" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" dependencies = [ "serde_derive", ] [[package]] name = "serde_bytes" -version = "0.11.7" +version = "0.11.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfc50e8183eeeb6178dcb167ae34a8051d63535023ae38b5d8d12beae193d37b" +checksum = "8437fd221bde2d4ca316d61b90e337e9e702b3820b87d63caa9ba6c02bd06d96" dependencies = [ "serde", ] [[package]] name = "serde_derive" -version = "1.0.150" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42a3df25b0713732468deadad63ab9da1f1fd75a48a15024b50363f128db627e" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn 1.0.105", + "syn 2.0.104", ] [[package]] name = "serde_json" -version = "1.0.89" +version = "1.0.141" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db" +checksum = "30b9eff21ebe718216c6ec64e1d9ac57087aad11efc64e32002bce4a0d4c03d3" dependencies = [ - "indexmap", + "indexmap 2.10.0", "itoa", + "memchr", "ryu", "serde", ] [[package]] name = "serde_path_to_error" -version = "0.1.8" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "184c643044780f7ceb59104cef98a5a6f12cb2288a7bc701ab93a362b49fd47d" +checksum = "59fab13f937fa393d08645bf3a84bdfe86e296747b506ada67bb15f10f218b2a" dependencies = [ + "itoa", "serde", ] @@ -1793,31 +2233,41 @@ dependencies = [ [[package]] name = "serde_with" -version = "1.14.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "678b5a069e50bf00ecd22d0cd8ddf7c236f68581b03db652061ed5eb13a312ff" +checksum = "f2c45cd61fefa9db6f254525d46e392b852e0e61d9a1fd36e5bd183450a556d5" dependencies = [ + "base64 0.22.1", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.10.0", + "schemars 0.9.0", + "schemars 1.0.4", "serde", + "serde_derive", + "serde_json", "serde_with_macros", + "time", ] [[package]] name = "serde_with_macros" -version = "1.5.2" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082" +checksum = "de90945e6565ce0d9a25098082ed4ee4002e047cb59892c318d66821e14bb30f" dependencies = [ "darling", "proc-macro2", "quote", - "syn 1.0.105", + "syn 2.0.104", ] [[package]] -name = "sha-1" -version = "0.10.1" +name = "sha1" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", "cpufeatures", @@ -1825,10 +2275,10 @@ dependencies = [ ] [[package]] -name = "sha1" -version = "0.10.5" +name = "sha2" +version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", "cpufeatures", @@ -1836,197 +2286,331 @@ dependencies = [ ] [[package]] -name = "sha2" -version = "0.10.6" +name = "shlex" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook-registry" +version = "1.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" +dependencies = [ + "libc", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ - "cfg-if", - "cpufeatures", "digest", + "rand_core 0.6.4", ] [[package]] -name = "signal-hook-registry" -version = "1.4.0" +name = "simd-json" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +checksum = "c962f626b54771990066e5435ec8331d1462576cd2d1e62f24076ae014f92112" dependencies = [ - "libc", + "getrandom 0.3.3", + "halfbrown", + "ref-cast", + "serde", + "serde_json", + "simdutf8", + "value-trait", ] +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + [[package]] name = "siphasher" -version = "0.3.10" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" [[package]] name = "slab" -version = "0.4.7" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" -dependencies = [ - "autocfg", -] +checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d" [[package]] name = "smallvec" -version = "1.10.0" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +dependencies = [ + "serde", +] [[package]] name = "snap" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e9f0ab6ef7eb7353d9119c170a436d1bf248eea575ac42d19d12f4e34130831" +checksum = "1b6b67fb9a61334225b5b790716f609cd58395f895b3fe8b328786812a40bc3b" [[package]] name = "socket2" -version = "0.4.7" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" dependencies = [ "libc", - "winapi", + "windows-sys 0.52.0", ] [[package]] name = "spin" -version = "0.5.2" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] [[package]] -name = "sqlformat" -version = "0.2.0" +name = "spki" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f87e292b4291f154971a43c3774364e2cbcaec599d3f5bf6fa9d122885dbc38a" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" dependencies = [ - "itertools", - "nom", - "unicode_categories", + "base64ct", + "der", ] [[package]] name = "sqlx" -version = "0.6.2" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9249290c05928352f71c077cc44a464d880c63f26f7534728cca008e135c0428" +checksum = "1fefb893899429669dcdd979aff487bd78f4064e5e7907e4269081e0ef7d97dc" dependencies = [ "sqlx-core", "sqlx-macros", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", ] [[package]] name = "sqlx-core" -version = "0.6.2" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcbc16ddba161afc99e14d1713a453747a2b07fc097d2009f4c300ec99286105" +checksum = "ee6798b1838b6a0f69c007c133b8df5866302197e404e8b6ee8ed3e3a5e68dc6" dependencies = [ - "ahash", - "atoi", - "base64", - "bitflags", - "byteorder", + "base64 0.22.1", "bytes", "crc", "crossbeam-queue", - "dirs", - "dotenvy", "either", "event-listener", - "futures-channel", "futures-core", "futures-intrusive", + "futures-io", "futures-util", + "hashbrown 0.15.4", "hashlink", - "hex", - "hkdf", - "hmac", - "indexmap", - "itoa", - "libc", + "indexmap 2.10.0", "log", - "md-5", "memchr", "once_cell", - "paste", "percent-encoding", - "rand", + "rustls 0.23.29", "serde", "serde_json", - "sha1", "sha2", "smallvec", - "sqlformat", - "sqlx-rt", - "stringprep", - "thiserror", + "thiserror 2.0.12", + "tokio", "tokio-stream", + "tracing", "url", - "whoami", + "webpki-roots 0.26.11", ] [[package]] name = "sqlx-macros" -version = "0.6.2" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b850fa514dc11f2ee85be9d055c512aa866746adfacd1cb42d867d68e6a5b0d9" +checksum = "a2d452988ccaacfbf5e0bdbc348fb91d7c8af5bee192173ac3636b5fb6e6715d" +dependencies = [ + "proc-macro2", + "quote", + "sqlx-core", + "sqlx-macros-core", + "syn 2.0.104", +] + +[[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", + "hex", "once_cell", "proc-macro2", "quote", + "serde", + "serde_json", "sha2", "sqlx-core", - "sqlx-rt", - "syn 1.0.105", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", + "syn 2.0.104", + "tokio", "url", ] [[package]] -name = "sqlx-rt" -version = "0.6.2" +name = "sqlx-mysql" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24c5b2d25fa654cc5f841750b8e1cdedbe21189bf9a9382ee90bfa9dd3562396" +checksum = "aa003f0038df784eb8fecbbac13affe3da23b45194bd57dba231c8f48199c526" dependencies = [ - "native-tls", + "atoi", + "base64 0.22.1", + "bitflags 2.9.1", + "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", - "tokio", - "tokio-native-tls", + "percent-encoding", + "rand 0.8.5", + "rsa", + "serde", + "sha1", + "sha2", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror 2.0.12", + "tracing", + "whoami", +] + +[[package]] +name = "sqlx-postgres" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db58fcd5a53cf07c184b154801ff91347e4c30d17a3562a635ff028ad5deda46" +dependencies = [ + "atoi", + "base64 0.22.1", + "bitflags 2.9.1", + "byteorder", + "crc", + "dotenvy", + "etcetera", + "futures-channel", + "futures-core", + "futures-util", + "hex", + "hkdf", + "hmac", + "home", + "itoa", + "log", + "md-5", + "memchr", + "once_cell", + "rand 0.8.5", + "serde", + "serde_json", + "sha2", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror 2.0.12", + "tracing", + "whoami", +] + +[[package]] +name = "sqlx-sqlite" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2d12fe70b2c1b4401038055f90f151b78208de1f9f89a7dbfd41587a10c3eea" +dependencies = [ + "atoi", + "flume", + "futures-channel", + "futures-core", + "futures-executor", + "futures-intrusive", + "futures-util", + "libsqlite3-sys", + "log", + "percent-encoding", + "serde", + "serde_urlencoded", + "sqlx-core", + "thiserror 2.0.12", + "tracing", + "url", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "stringprep" -version = "0.1.2" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ee348cb74b87454fff4b551cbf727025810a004f88aeacae7f85b87f4e9a1c1" +checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" dependencies = [ "unicode-bidi", "unicode-normalization", + "unicode-properties", ] [[package]] name = "strsim" -version = "0.10.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "subtle" -version = "2.4.1" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "1.0.105" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b9b43d45702de4c839cb9b51d9f529c5dd26a4aff255b42b1ebc03e88ee908" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", "quote", @@ -2035,9 +2619,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.18" +version = "2.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" +checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" dependencies = [ "proc-macro2", "quote", @@ -2046,9 +2630,20 @@ dependencies = [ [[package]] name = "sync_wrapper" -version = "0.1.1" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" + +[[package]] +name = "synstructure" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20518fe4a4c9acf048008599e464deb21beeae3d3578418951a189c235a7a9a8" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] [[package]] name = "take_mut" @@ -2057,66 +2652,61 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" [[package]] -name = "tempfile" -version = "3.3.0" +name = "tap" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" -dependencies = [ - "cfg-if", - "fastrand", - "libc", - "redox_syscall", - "remove_dir_all", - "winapi", -] +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] -name = "termcolor" -version = "1.1.3" +name = "thiserror" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "winapi-util", + "thiserror-impl 1.0.69", ] [[package]] name = "thiserror" -version = "1.0.37" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" dependencies = [ - "thiserror-impl", + "thiserror-impl 2.0.12", ] [[package]] name = "thiserror-impl" -version = "1.0.37" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 1.0.105", + "syn 2.0.104", ] [[package]] -name = "time" -version = "0.1.45" +name = "thiserror-impl" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ - "libc", - "wasi 0.10.0+wasi-snapshot-preview1", - "winapi", + "proc-macro2", + "quote", + "syn 2.0.104", ] [[package]] name = "time" -version = "0.3.17" +version = "0.3.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376" +checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" dependencies = [ + "deranged", "itoa", + "num-conv", + "powerfmt", "serde", "time-core", "time-macros", @@ -2124,73 +2714,83 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.0" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" +checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" [[package]] name = "time-macros" -version = "0.2.6" +version = "0.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d967f99f534ca7e495c575c62638eebc2898a8c84c119b89e250477bc4ba16b2" +checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" dependencies = [ + "num-conv", "time-core", ] +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "tinystr" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +dependencies = [ + "displaydoc", + "zerovec", +] + [[package]] name = "tinyvec" -version = "1.6.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" dependencies = [ "tinyvec_macros", ] [[package]] name = "tinyvec_macros" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.26.0" +version = "1.46.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03201d01c3c27a29c8a5cee5b55a93ddae1ccf6f08f65365c2c918f8c1b76f64" +checksum = "0cc3a2344dafbe23a245241fe8b09735b521110d30fcefbbd5feb1797ca35d17" dependencies = [ - "autocfg", + "backtrace", "bytes", + "io-uring", "libc", - "memchr", "mio", - "num_cpus", - "parking_lot 0.12.1", + "parking_lot", "pin-project-lite", "signal-hook-registry", + "slab", "socket2", "tokio-macros", - "windows-sys 0.45.0", + "windows-sys 0.52.0", ] [[package]] name = "tokio-macros" -version = "1.8.2" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", - "syn 1.0.105", -] - -[[package]] -name = "tokio-native-tls" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" -dependencies = [ - "native-tls", - "tokio", + "syn 2.0.104", ] [[package]] @@ -2209,15 +2809,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8548f756cd6eb4069c5af0fb0cec57001fb42bd1fb7330d8f24067ee3fa62608" dependencies = [ "quote", - "syn 1.0.105", + "syn 1.0.109", "tokio-postgres", ] [[package]] name = "tokio-postgres" -version = "0.7.7" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29a12c1b3e0704ae7dfc25562629798b29c72e6b1d0a681b6f29ab4ae5e7f7bf" +checksum = "6c95d533c83082bb6490e0189acaa0bbeef9084e60471b696ca6988cd0541fb0" dependencies = [ "async-trait", "byteorder", @@ -2226,33 +2826,34 @@ dependencies = [ "futures-channel", "futures-util", "log", - "parking_lot 0.12.1", + "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.23.4" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ - "rustls", + "rustls 0.21.12", "tokio", - "webpki", ] [[package]] name = "tokio-stream" -version = "0.1.11" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d660770404473ccd7bc9f8b28494a811bc18542b915c0855c51e8f419d5223ce" +checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" dependencies = [ "futures-core", "pin-project-lite", @@ -2261,56 +2862,51 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.4" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740" +checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" dependencies = [ "bytes", "futures-core", + "futures-io", "futures-sink", "pin-project-lite", "tokio", - "tracing", ] [[package]] name = "toml" -version = "0.5.9" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" dependencies = [ "serde", ] [[package]] name = "tower" -version = "0.4.13" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" dependencies = [ "futures-core", "futures-util", - "pin-project", "pin-project-lite", + "sync_wrapper", "tokio", "tower-layer", "tower-service", - "tracing", ] [[package]] name = "tower-http" -version = "0.4.0" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d1d42a9b3f3ec46ba828e8d376aec14592ea199f70a06a548587ecd1c4ab658" +checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" dependencies = [ - "bitflags", + "bitflags 2.9.1", "bytes", - "futures-core", - "futures-util", "http", - "http-body", - "http-range-header", "pin-project-lite", "tower-layer", "tower-service", @@ -2318,88 +2914,48 @@ dependencies = [ [[package]] name = "tower-layer" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" [[package]] name = "tower-service" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ - "cfg-if", "log", "pin-project-lite", + "tracing-attributes", "tracing-core", ] [[package]] -name = "tracing-core" +name = "tracing-attributes" version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" -dependencies = [ - "once_cell", -] - -[[package]] -name = "trust-dns-proto" -version = "0.21.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c31f240f59877c3d4bb3b3ea0ec5a6a0cff07323580ff8c7a605cd7d08b255d" +checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ - "async-trait", - "cfg-if", - "data-encoding", - "enum-as-inner", - "futures-channel", - "futures-io", - "futures-util", - "idna 0.2.3", - "ipnet", - "lazy_static", - "log", - "rand", - "smallvec", - "thiserror", - "tinyvec", - "tokio", - "url", + "proc-macro2", + "quote", + "syn 2.0.104", ] [[package]] -name = "trust-dns-resolver" -version = "0.21.2" +name = "tracing-core" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4ba72c2ea84515690c9fcef4c6c660bb9df3036ed1051686de84605b74fd558" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" dependencies = [ - "cfg-if", - "futures-util", - "ipconfig", - "lazy_static", - "log", - "lru-cache", - "parking_lot 0.12.1", - "resolv-conf", - "smallvec", - "thiserror", - "tokio", - "trust-dns-proto", + "once_cell", ] -[[package]] -name = "try-lock" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" - [[package]] name = "typed-builder" version = "0.10.0" @@ -2408,94 +2964,87 @@ checksum = "89851716b67b937e393b3daa8423e67ddfc4bbbf1654bcf05488e95e0828db0c" dependencies = [ "proc-macro2", "quote", - "syn 1.0.105", + "syn 1.0.109", ] [[package]] name = "typenum" -version = "1.16.0" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" [[package]] name = "unicode-bidi" -version = "0.3.8" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" +checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" [[package]] name = "unicode-ident" -version = "1.0.5" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "unicode-normalization" -version = "0.1.22" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" dependencies = [ "tinyvec", ] [[package]] -name = "unicode-segmentation" -version = "1.10.0" +name = "unicode-properties" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fdbf052a0783de01e944a6ce7a8cb939e295b1e7be835a1112c3b9a7f047a5a" +checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" [[package]] name = "unicode-width" -version = "0.1.10" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "unicode-xid" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" - -[[package]] -name = "unicode_categories" -version = "0.1.1" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "untrusted" -version = "0.7.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.3.1" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" dependencies = [ "form_urlencoded", - "idna 0.3.0", + "idna", "percent-encoding", ] [[package]] -name = "uuid" -version = "0.8.2" +name = "utf8_iter" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" -dependencies = [ - "getrandom", -] +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "uuid" -version = "1.2.2" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "422ee0de9031b5b948b97a8fc04e3aa35230001a722ddd27943e0be31564ce4c" +checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d" dependencies = [ - "getrandom", + "getrandom 0.3.3", + "js-sys", "serde", + "wasm-bindgen", ] [[package]] @@ -2505,7 +3054,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dd8b599d797eb038d0dde9a3860aacb6bbba3bffa4ac64f807c8673820cc9d9" dependencies = [ "regex", - "syn 1.0.105", + "syn 1.0.109", ] [[package]] @@ -2514,6 +3063,18 @@ version = "0.15.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e8257fbc510f0a46eb602c10215901938b5c2a7d5e70fc11483b1d3c9b5b18c" +[[package]] +name = "value-trait" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0508fce11ad19e0aab49ce20b6bec7f8f82902ded31df1c9fc61b90f0eb396b8" +dependencies = [ + "float-cmp", + "halfbrown", + "itoa", + "ryu", +] + [[package]] name = "vcpkg" version = "0.2.15" @@ -2522,62 +3083,62 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] -name = "want" -version = "0.3.0" +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" -dependencies = [ - "log", - "try-lock", -] +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" +version = "0.14.2+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] [[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +name = "wasite" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.83" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if", + "once_cell", + "rustversion", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.83" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" dependencies = [ "bumpalo", "log", - "once_cell", "proc-macro2", "quote", - "syn 1.0.105", + "syn 2.0.104", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.83" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2585,68 +3146,76 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.83" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 1.0.105", + "syn 2.0.104", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.83" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] [[package]] name = "web-sys" -version = "0.3.60" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" dependencies = [ "js-sys", "wasm-bindgen", ] [[package]] -name = "webpki" -version = "0.22.2" +name = "webpki-roots" +version = "0.25.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" + +[[package]] +name = "webpki-roots" +version = "0.26.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07ecc0cd7cac091bf682ec5efa18b1cff79d617b84181f38b3951dbe135f607f" +checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" dependencies = [ - "ring", - "untrusted", + "webpki-roots 1.0.2", ] [[package]] name = "webpki-roots" -version = "0.22.6" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87" +checksum = "7e8983c3ab33d6fb807cfcdad2491c4ea8cbc8ed839181c7dfd9c67c83e261b2" dependencies = [ - "webpki", + "rustls-pki-types", ] [[package]] name = "whoami" -version = "1.2.3" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6631b6a2fd59b1841b622e8f1a7ad241ef0a46f2d580464ce8140ac94cbd571" +checksum = "6994d13118ab492c3c80c1f81928718159254c53c472bf9ce36f8dae4add02a7" dependencies = [ - "bumpalo", - "wasm-bindgen", + "redox_syscall", + "wasite", "web-sys", ] [[package]] name = "widestring" -version = "0.5.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17882f045410753661207383517a6f62ec3dbeb6a4ed2acce01f0728238d1983" +checksum = "dd7cf3379ca1aac9eea11fba24fd7e315d621f8dfe35c8d7d2be8b793726e07d" [[package]] name = "winapi" @@ -2665,151 +3234,250 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] -name = "winapi-util" -version = "0.1.5" +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.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" dependencies = [ - "winapi", + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", ] [[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" +name = "windows-implement" +version = "0.60.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + +[[package]] +name = "windows-interface" +version = "0.59.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + +[[package]] +name = "windows-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +dependencies = [ + "windows-link", +] [[package]] name = "windows-sys" -version = "0.36.1" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows_aarch64_msvc 0.36.1", - "windows_i686_gnu 0.36.1", - "windows_i686_msvc 0.36.1", - "windows_x86_64_gnu 0.36.1", - "windows_x86_64_msvc 0.36.1", + "windows-targets 0.48.5", ] [[package]] name = "windows-sys" -version = "0.42.0" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows_aarch64_gnullvm", - "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", - "windows_x86_64_msvc 0.42.2", + "windows-targets 0.52.6", ] [[package]] name = "windows-sys" -version = "0.45.0" +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 = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows-targets", + "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.42.2" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm", - "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", - "windows_x86_64_msvc 0.42.2", + "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.42.2" +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 = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" -version = "0.36.1" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.42.2" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" -version = "0.36.1" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.42.2" +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 = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" -version = "0.36.1" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.42.2" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" -version = "0.36.1" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.42.2" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" +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.36.1" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.42.2" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winreg" -version = "0.10.1" +version = "0.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" dependencies = [ - "winapi", + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags 2.9.1", +] + +[[package]] +name = "writeable" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", ] [[package]] @@ -2833,13 +3501,13 @@ dependencies = [ [[package]] name = "yarte_codegen" -version = "0.15.6" +version = "0.15.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1cf72076dbf4d39fe4779b58380d7213dcb3995d00666dd2d109f1b45879ea4" +checksum = "4a79312078b97a195de91a8c1457c2e0d7abd97e6e605f3cdeb01b3c105d2cff" dependencies = [ "proc-macro2", "quote", - "syn 1.0.105", + "syn 1.0.109", "yarte_helpers", "yarte_hir", ] @@ -2852,7 +3520,7 @@ checksum = "b296edd7e1a81717b6f794baa2de8dfe89646050847161550b2d963b3ca6fe80" dependencies = [ "proc-macro2", "quote", - "syn 1.0.105", + "syn 1.0.109", "yarte_codegen", "yarte_helpers", "yarte_hir", @@ -2861,15 +3529,15 @@ dependencies = [ [[package]] name = "yarte_helpers" -version = "0.15.7" +version = "0.15.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8dfe1ef3558dde14b4be5387bdd41e3bd45746570743521470ec3e9cd0826679" +checksum = "e0d1076f8cee9541ea5ffbecd9102f751252c91f085e7d30a18a3ce805ebd3ee" dependencies = [ "dtoa", "itoa", "prettyplease", "serde", - "syn 1.0.105", + "syn 1.0.109", "toml", "v_htmlescape", ] @@ -2883,7 +3551,7 @@ dependencies = [ "derive_more", "proc-macro2", "quote", - "syn 1.0.105", + "syn 1.0.109", "v_eval", "v_htmlescape", "yarte_helpers", @@ -2901,11 +3569,115 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 1.0.105", + "syn 1.0.109", "unicode-xid", "yarte_helpers", ] +[[package]] +name = "yoke" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", + "synstructure", +] + +[[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.104", +] + +[[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.104", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" + +[[package]] +name = "zerotrie" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + [[package]] name = "zstd" version = "0.11.2+zstd.1.5.2" @@ -2927,10 +3699,10 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "2.0.4+zstd.1.5.2" +version = "2.0.15+zstd.1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fa202f2ef00074143e219d15b62ffc317d17cc33909feac471c044087cad7b0" +checksum = "eb81183ddd97d0c74cedf1d50d85c8d08c1b8b68ee863bdee9e706eedba1a237" dependencies = [ "cc", - "libc", + "pkg-config", ] diff --git a/frameworks/Rust/axum/Cargo.toml b/frameworks/Rust/axum/Cargo.toml index 1236aab32f9..be0bf32250a 100644 --- a/frameworks/Rust/axum/Cargo.toml +++ b/frameworks/Rust/axum/Cargo.toml @@ -1,8 +1,8 @@ [package] -name = "axum" -version = "0.2.0" +name = "axum-techempower" +version = "0.3.0" authors = ["Dragos Varovici "] -edition = "2021" +edition = "2024" [[bin]] name = "axum" @@ -28,28 +28,65 @@ path = "src/main_mongo_raw.rs" name = "axum-pg" path = "src/main_pg.rs" +[features] +default = [] +simd-json = [ + "dep:simd-json", + "dep:axum-core", + "dep:mime", + "dep:bytes", + "dep:serde_path_to_error", +] + [dependencies] -axum = { version = "0.6.16", default-features = false, features = ["json", "query", "headers", "http1", "tokio"] } -deadpool = { version = "0.9.5", features = ["rt_tokio_1", "serde", "async-trait", "managed" ] } -deadpool-postgres = "0.10.3" +axum = { version = "0.8.4", default-features = false, features = [ + "json", + "query", + "http1", + "tokio", +] } +deadpool = { version = "0.12.2", features = ["rt_tokio_1", "serde", "managed"] } +deadpool-postgres = { version = "0.14.1", features = ["rt_tokio_1", "serde"] } dotenv = "0.15.0" -futures = "0.3.25" -futures-util = "0.3.25" -hyper = { version = "0.14.23", features = ["http1", "server"] } -mongodb = { version = "2.3.1", features = ["zstd-compression", "snappy-compression", "zlib-compression"] } -num_cpus = "1.14.0" -rand = { version = "0.8.5", features = ["small_rng"] } -serde = { version = "1.0.149", features = ["derive"] } -serde_json = "1.0.89" -sqlx = { version = "0.6.2", features = ["postgres", "macros", "runtime-tokio-native-tls"] } -tokio = { version = "1.24.2", features = ["full"] } -tokio-pg-mapper = "0.2.0" -tokio-pg-mapper-derive = "0.2.0" -tokio-postgres = "0.7.7" -tower = { version = "0.4.13", features = ["util"] } -tower-http = { version = "0.4.0", features = ["set-header"] } +futures = "0.3.31" +futures-util = "0.3.31" +mongodb = { version = "3.2.4", features = [ + "zstd-compression", + "snappy-compression", + "zlib-compression", +] } + +num_cpus = "1.17.0" +rand = { version = "0.9.2", features = ["small_rng"] } +serde = { version = "1.0.219", features = ["derive"] } +serde_json = "1.0.141" +sqlx = { version = "0.8.6", features = [ + "postgres", + "macros", + "runtime-tokio", + "tls-rustls", +] } +tokio = { version = "1.46.1", features = ["full"] } +tokio-pg-mapper = { version = "0.2.0" } +tokio-pg-mapper-derive = { version = "0.2.0" } +tokio-postgres = { version = "0.7.13" } +tower = { version = "0.5.2", features = ["util"] } +tower-http = { version = "0.6.6", features = ["set-header"] } yarte = "0.15.7" +simd-json = { version = "0.15.1", optional = true } +axum-core = { version = "0.5.2", optional = true } +mime = { version = "0.3.17", optional = true } +bytes = { version = "1.10.1", optional = true } +serde_path_to_error = { version = "0.1.17", optional = true } +socket2 = "0.5.10" +hyper = { version = "1.6", features = ["server", "http1"] } +hyper-util = { version = "0.1", features = ["tokio", "server-auto", "http1"] } +quick_cache = "0.6.14" +mimalloc = "0.1.47" + [profile.release] -lto = true +lto = "fat" codegen-units = 1 +# strip = true +opt-level = 3 diff --git a/frameworks/Rust/axum/README.md b/frameworks/Rust/axum/README.md index 55ca3e0978e..da95959dafa 100755 --- a/frameworks/Rust/axum/README.md +++ b/frameworks/Rust/axum/README.md @@ -1,42 +1,43 @@ - -# [Axum](https://github.com/tokio-rs/axum) - Ergonomic and modular web framework built with Tokio, Tower, and Hyper +# [Axum](https://github.com/tokio-rs/axum) ## Description -Axum is a web application framework that focuses on ergonomics and modularity. - -* [User Guide](https://docs.rs/axum/0.3/axum/) -* [API Documentation](https://docs.rs/axum/0.3/axum/) -* Cargo package: [axum](https://crates.io/crates/axum) +Axum is a web application framework that focuses on ergonomics and modularity, +built with Tokio, Tower, and Hyper. -## Database +- [User Guide](https://docs.rs/axum/latest/axum/) +- [API Documentation](https://docs.rs/axum/latest/axum/) +- [Cargo Package (`axum`)](https://crates.io/crates/axum) -PostgreSQL +## Variants -* Raw using [sqlx](https://github.com/launchbadge/sqlx) +- PostgreSQL using `SQLx`, `tokio_postgres`, and `deadpool`. +- MongoDB with `mongodb`. ## Test URLs -### Test 1: JSON Encoding - - http://localhost:8000/json - -### Test 2: Single Row Query - - http://localhost:8000/db - -### Test 3: Multi Row Query - - http://localhost:8000/queries?q=20 - -### Test 4: Fortunes (Template rendering) - - http://localhost:8000/fortunes - -### Test 5: Update Query - - http://localhost:8000/updates?q=20 - -### Test 6: Plaintext - - http://localhost:8000/plaintext +- Plaintext: http://localhost:8000/plaintext +- JSON Encoding: http://localhost:8000/json +- Single Row Query: http://localhost:8000/db +- Multi Row Query: http://localhost:8000/queries?q=20 +- Fortunes: http://localhost:8000/fortunes +- Update Query: http://localhost:8000/updates?q=20 +- Cached Query: http://localhost:8000/cached-queries?q=20 + +## Notable Points (both performance and build) + +- Use of `async`. +- Use of the most recent versions of Rust, `axum` and dependencies. +- (Disabled by default) Compile-time swap-in of `simd-json` instead of `serde_json` for faster JSON serialization. +- Release binaries are stripped and compiled with CPU native. +- Sockets configured with `TCP_NODELAY` and to support an increased number of pending connections. +- For very simple benchmarks, use of a separate, single-threaded Tokio runtime for each thread. +- Server configured to serve HTTP/1 only, with no need for websockets. +- Separation of build and deployment containers using multi-stage builds. +- Deployment into Google's minimal `distroless-cc` container. +- Use of pipelined database queries (where supported). +- Streaming database queries (where supported). +- Use of PostgreSQL prepared statements cache (where supported). +- Use of PostgreSQL arrays to execute multi-row database updates with a single `UPDATE` query. + - This is permitted by the [test requirements](https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview#database-updates), step (ix). +- Use of a fast PRNG \ No newline at end of file diff --git a/frameworks/Rust/axum/axum-mongo-raw.dockerfile b/frameworks/Rust/axum/axum-mongo-raw.dockerfile deleted file mode 100644 index 5eec4f41017..00000000000 --- a/frameworks/Rust/axum/axum-mongo-raw.dockerfile +++ /dev/null @@ -1,25 +0,0 @@ -FROM rust:1.67-slim-buster - -ENV AXUM_TECHEMPOWER_MONGODB_URL=mongodb://tfb-database:27017 -ENV AXUM_TECHEMPOWER_MAX_POOL_SIZE=28 -ENV AXUM_TECHEMPOWER_MIN_POOL_SIZE=14 - -RUN apt-get update && apt-get install -y --no-install-recommends \ - pkg-config libssl-dev \ - && rm -rf /var/lib/apt/lists/* - -WORKDIR /axum -COPY ./src ./src -COPY ./templates ./templates -COPY ./Cargo.toml ./Cargo.toml -COPY ./Cargo.lock ./Cargo.lock -COPY ./run.sh ./run.sh -RUN chmod +x ./run.sh - -ENV RUSTFLAGS "-C target-cpu=native" -RUN cargo build --release -RUN cp ./target/release/axum-mongo-raw ./target/release/axum-techempower - -EXPOSE 8000 - -CMD ["./run.sh"] diff --git a/frameworks/Rust/axum/axum-mongo.dockerfile b/frameworks/Rust/axum/axum-mongo.dockerfile deleted file mode 100644 index c9ed43a90b2..00000000000 --- a/frameworks/Rust/axum/axum-mongo.dockerfile +++ /dev/null @@ -1,25 +0,0 @@ -FROM rust:1.67-slim-buster - -ENV AXUM_TECHEMPOWER_MONGODB_URL=mongodb://tfb-database:27017 -ENV AXUM_TECHEMPOWER_MAX_POOL_SIZE=28 -ENV AXUM_TECHEMPOWER_MIN_POOL_SIZE=14 - -RUN apt-get update && apt-get install -y --no-install-recommends \ - pkg-config libssl-dev \ - && rm -rf /var/lib/apt/lists/* - -WORKDIR /axum -COPY ./src ./src -COPY ./templates ./templates -COPY ./Cargo.toml ./Cargo.toml -COPY ./Cargo.lock ./Cargo.lock -COPY ./run.sh ./run.sh -RUN chmod +x ./run.sh - -ENV RUSTFLAGS "-C target-cpu=native" -RUN cargo build --release -RUN cp ./target/release/axum-mongo ./target/release/axum-techempower - -EXPOSE 8000 - -CMD ["./run.sh"] diff --git a/frameworks/Rust/axum/axum-pg-pool.dockerfile b/frameworks/Rust/axum/axum-pg-pool.dockerfile deleted file mode 100644 index 1a436f88b30..00000000000 --- a/frameworks/Rust/axum/axum-pg-pool.dockerfile +++ /dev/null @@ -1,24 +0,0 @@ -FROM rust:1.67-slim-buster - -ENV AXUM_TECHEMPOWER_DATABASE_URL=postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world -ENV AXUM_TECHEMPOWER_MAX_POOL_SIZE=28 - -RUN apt-get update && apt-get install -y --no-install-recommends \ - libpq-dev pkg-config libssl-dev \ - && rm -rf /var/lib/apt/lists/* - -WORKDIR /axum -COPY ./src ./src -COPY ./templates ./templates -COPY ./Cargo.toml ./Cargo.toml -COPY ./Cargo.lock ./Cargo.lock -COPY ./run.sh ./run.sh -RUN chmod +x ./run.sh - -ENV RUSTFLAGS "-C target-cpu=native" -RUN cargo build --release -RUN cp ./target/release/axum-pg-pool ./target/release/axum-techempower - -EXPOSE 8000 - -CMD ["./run.sh"] diff --git a/frameworks/Rust/axum/axum-pg.dockerfile b/frameworks/Rust/axum/axum-pg.dockerfile deleted file mode 100644 index 375e82ce7d3..00000000000 --- a/frameworks/Rust/axum/axum-pg.dockerfile +++ /dev/null @@ -1,23 +0,0 @@ -FROM rust:1.67-slim-buster - -ENV AXUM_TECHEMPOWER_DATABASE_URL=postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world - -RUN apt-get update && apt-get install -y --no-install-recommends \ - libpq-dev pkg-config libssl-dev \ - && rm -rf /var/lib/apt/lists/* - -WORKDIR /axum -COPY ./src ./src -COPY ./templates ./templates -COPY ./Cargo.toml ./Cargo.toml -COPY ./Cargo.lock ./Cargo.lock -COPY ./run.sh ./run.sh -RUN chmod +x ./run.sh - -ENV RUSTFLAGS "-C target-cpu=native" -RUN cargo build --release -RUN cp ./target/release/axum-pg ./target/release/axum-techempower - -EXPOSE 8000 - -CMD ["./run.sh"] diff --git a/frameworks/Rust/axum/axum-sqlx.dockerfile b/frameworks/Rust/axum/axum-sqlx.dockerfile deleted file mode 100644 index 455e282abd0..00000000000 --- a/frameworks/Rust/axum/axum-sqlx.dockerfile +++ /dev/null @@ -1,26 +0,0 @@ -FROM rust:1.67-slim-buster - -ENV AXUM_TECHEMPOWER_DATABASE_URL=postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world -ENV AXUM_TECHEMPOWER_MAX_POOL_SIZE=56 -ENV AXUM_TECHEMPOWER_MIN_POOL_SIZE=56 - -RUN apt-get update && apt-get install -y --no-install-recommends \ - libpq-dev pkg-config libssl-dev \ - && rm -rf /var/lib/apt/lists/* - -WORKDIR /axum -COPY ./src ./src -COPY ./templates ./templates -COPY ./Cargo.toml ./Cargo.toml -COPY ./Cargo.lock ./Cargo.lock -COPY ./run.sh ./run.sh -RUN chmod +x ./run.sh - -ENV RUSTFLAGS "-C target-cpu=native" -RUN cargo build --release -RUN cp ./target/release/axum-sqlx ./target/release/axum-techempower - - -EXPOSE 8000 - -CMD ["./run.sh"] diff --git a/frameworks/Rust/axum/axum.dockerfile b/frameworks/Rust/axum/axum.dockerfile index 6f23b4e1a44..35167203a19 100644 --- a/frameworks/Rust/axum/axum.dockerfile +++ b/frameworks/Rust/axum/axum.dockerfile @@ -1,21 +1,24 @@ -FROM rust:1.67-slim-buster +FROM docker.io/rust:1.88-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 /axum -COPY ./src ./src -COPY ./templates ./templates -COPY ./Cargo.toml ./Cargo.toml -COPY ./Cargo.lock ./Cargo.lock -COPY ./run.sh ./run.sh -RUN chmod +x ./run.sh - +WORKDIR /build +COPY ./Cargo.toml ./Cargo.lock /build/ +RUN cargo fetch +COPY ./templates/ /build/templates +COPY ./src/ /build/src ENV RUSTFLAGS "-C target-cpu=native" RUN cargo build --release -RUN cp ./target/release/axum ./target/release/axum-techempower +FROM gcr.io/distroless/cc-debian12 +ENV POSTGRES_URL=postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world +ENV POSTGRES_MIN_POOL_SIZE=56 +ENV POSTGRES_MAX_POOL_SIZE=56 +ENV MONGODB_URL=mongodb://tfb-database:27017 +ENV MONGODB_MIN_POOL_SIZE=56 +ENV MONGODB_MAX_POOL_SIZE=56 +COPY --from=builder /build/target/release/axum* /app/ EXPOSE 8000 - -CMD ["./run.sh"] +CMD ["/app/axum"] diff --git a/frameworks/Rust/axum/benchmark_config.json b/frameworks/Rust/axum/benchmark_config.json index f05dd4a67dd..c33a1edad78 100755 --- a/frameworks/Rust/axum/benchmark_config.json +++ b/frameworks/Rust/axum/benchmark_config.json @@ -3,6 +3,8 @@ "tests": [ { "default": { + "dockerfile": "axum.dockerfile", + "docker_cmd": "/app/axum", "json_url": "/json", "plaintext_url": "/plaintext", "port": 8000, @@ -22,8 +24,11 @@ "versus": "None" }, "sqlx": { + "dockerfile": "axum.dockerfile", + "docker_cmd": "/app/axum-sqlx", "db_url": "/db", "fortune_url": "/fortunes", + "cached_query_url": "/cached-queries?q=", "port": 8000, "approach": "Realistic", "classification": "Fullstack", @@ -41,10 +46,12 @@ "versus": "None" }, "pg": { + "dockerfile": "axum.dockerfile", + "docker_cmd": "/app/axum-pg", "db_url": "/db", "fortune_url": "/fortunes", - "query_url": "/queries?queries=", - "update_url": "/updates?queries=", + "query_url": "/queries?q=", + "update_url": "/updates?q=", "port": 8000, "approach": "Realistic", "classification": "Fullstack", @@ -62,9 +69,11 @@ "versus": "None" }, "pg-pool": { + "dockerfile": "axum.dockerfile", + "docker_cmd": "/app/axum-pg-pool", "db_url": "/db", - "query_url": "/queries?queries=", - "update_url": "/updates?queries=", + "query_url": "/queries?q=", + "update_url": "/updates?q=", "fortune_url": "/fortunes", "port": 8000, "approach": "Realistic", @@ -83,10 +92,12 @@ "versus": "None" }, "mongo": { + "dockerfile": "axum.dockerfile", + "docker_cmd": "/app/axum-mongo", "db_url": "/db", - "query_url": "/queries?queries=", + "query_url": "/queries?q=", "fortune_url": "/fortunes", - "update_url": "/updates?queries=", + "update_url": "/updates?q=", "port": 8000, "approach": "Realistic", "classification": "Fullstack", @@ -104,9 +115,11 @@ "versus": "None" }, "mongo-raw": { + "dockerfile": "axum.dockerfile", + "docker_cmd": "/app/axum-mongo-raw", "db_url": "/db", - "query_url": "/queries?queries=", - "update_url": "/updates?queries=", + "query_url": "/queries?q=", + "update_url": "/updates?q=", "port": 8000, "approach": "Realistic", "classification": "Fullstack", diff --git a/frameworks/Rust/axum/config.toml b/frameworks/Rust/axum/config.toml index d4bb9d7ad0e..b5695c19bf0 100644 --- a/frameworks/Rust/axum/config.toml +++ b/frameworks/Rust/axum/config.toml @@ -8,6 +8,7 @@ urls.db = "/db" urls.query = "/queries?q=" urls.update = "/updates?q=" urls.fortune = "/fortunes" +urls.cached_query = "/cached-queries?q=" approach = "Realistic" classification = "Fullstack" database = "Postgres" @@ -16,4 +17,4 @@ os = "Linux" orm = "Raw" platform = "Rust" webserver = "Hyper" -versus = "None" \ No newline at end of file +versus = "None" diff --git a/frameworks/Rust/axum/src/common/mod.rs b/frameworks/Rust/axum/src/common/mod.rs new file mode 100644 index 00000000000..f3488fbab9b --- /dev/null +++ b/frameworks/Rust/axum/src/common/mod.rs @@ -0,0 +1,49 @@ +use std::{env, str::FromStr}; + +use core::fmt::Debug; +use rand::{distr::Uniform, rngs::SmallRng, Rng, RngCore}; +pub mod models; +pub mod utils; + +#[cfg(feature = "simd-json")] +pub mod simd_json; + +#[allow(dead_code)] +pub const SELECT_ALL_FORTUNES: &str = "SELECT * FROM fortune"; +#[allow(dead_code)] +pub const SELECT_WORLD_BY_ID: &str = + "SELECT id, randomnumber FROM world WHERE id = $1 LIMIT 1"; +#[allow(dead_code)] +pub const SELECT_ALL_CACHED_WORLDS: &str = + "SELECT id, randomnumber FROM world ORDER BY id"; +#[allow(dead_code)] +pub const UPDATE_WORLDS: &str = r#"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"#; + +/// Return the value of an environment variable. +#[allow(dead_code)] +pub fn get_env(key: &str) -> T +where + ::Err: Debug, +{ + env::var(key) + .unwrap_or_else(|_| panic!("{key} environment variable was not set")) + .parse::() + .unwrap_or_else(|_| panic!("could not parse {key}")) +} + +/// Generate a single integer in the range 1 to 10,000 (inclusive) +#[allow(dead_code)] +#[inline(always)] +pub fn random_id(rng: &mut impl RngCore) -> i32 { + rng.random_range(1..=10_000) +} + +/// Generate an iterator of integers in the range 1 to 10,000 (inclusive) +#[allow(dead_code)] +#[inline(always)] +pub fn random_ids(rng: &mut SmallRng, count: usize) -> impl Iterator + use<'_> { + rng.sample_iter(Uniform::new_inclusive(1, 10_000).unwrap()) + .take(count) +} \ No newline at end of file diff --git a/frameworks/Rust/axum/src/common/models.rs b/frameworks/Rust/axum/src/common/models.rs new file mode 100644 index 00000000000..1644447c3cd --- /dev/null +++ b/frameworks/Rust/axum/src/common/models.rs @@ -0,0 +1,25 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Serialize)] +pub struct Message { + pub message: &'static str, +} + +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] +pub struct Fortune { + pub id: i32, + pub message: String, +} + +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] +pub struct FortuneInfo { + pub id: i32, + pub message: String, +} + +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] +pub struct World { + pub id: i32, + #[serde(rename = "randomNumber")] + pub random_number: i32, +} diff --git a/frameworks/Rust/axum/src/common/simd_json.rs b/frameworks/Rust/axum/src/common/simd_json.rs new file mode 100644 index 00000000000..e8a2aafeee1 --- /dev/null +++ b/frameworks/Rust/axum/src/common/simd_json.rs @@ -0,0 +1,152 @@ +use axum::extract::rejection::JsonRejection::MissingJsonContentType; +use axum::extract::Request; +use axum::extract::{rejection::*, FromRequest}; +use axum::{async_trait, http}; +use axum_core::response::{IntoResponse, Response}; +use bytes::{BufMut, Bytes, BytesMut}; +use http::{ + header::{self, HeaderMap, HeaderValue}, + StatusCode, +}; +use serde::{de::DeserializeOwned, Serialize}; +use simd_json; + +#[derive(Debug, Clone, Copy, Default)] +pub struct Json(pub T); + +pub enum SimdJsonRejection { + Json(JsonRejection), + Bytes(BytesRejection), + Simd(String), +} + +impl IntoResponse for SimdJsonRejection { + fn into_response(self) -> Response { + todo!() + } +} + +impl From for SimdJsonRejection { + fn from(err: JsonRejection) -> Self { + SimdJsonRejection::Json(err) + } +} + +impl From for SimdJsonRejection { + fn from(err: BytesRejection) -> Self { + SimdJsonRejection::Bytes(err) + } +} + +impl From for SimdJsonRejection { + fn from(err: simd_json::Error) -> Self { + SimdJsonRejection::Simd(err.to_string()) + } +} + +#[async_trait] +impl FromRequest for Json +where + T: DeserializeOwned, + S: Send + Sync, +{ + type Rejection = SimdJsonRejection; + + async fn from_request(req: Request, state: &S) -> Result { + if json_content_type(req.headers()) { + let bytes = Bytes::from_request(req, state).await?; + Self::from_bytes(&bytes) + } else { + Err(SimdJsonRejection::Json(MissingJsonContentType( + axum::extract::rejection::MissingJsonContentType::default(), + ))) + } + } +} + +fn json_content_type(headers: &HeaderMap) -> bool { + let content_type = if let Some(content_type) = headers.get(header::CONTENT_TYPE) { + content_type + } else { + return false; + }; + + let content_type = if let Ok(content_type) = content_type.to_str() { + content_type + } else { + return false; + }; + + let mime = if let Ok(mime) = content_type.parse::() { + mime + } else { + return false; + }; + + let is_json_content_type = mime.type_() == "application" + && (mime.subtype() == "json" + || mime.suffix().map_or(false, |name| name == "json")); + + is_json_content_type +} + +axum_core::__impl_deref!(Json); + +impl From for Json { + fn from(inner: T) -> Self { + Self(inner) + } +} + +impl Json +where + T: DeserializeOwned, +{ + /// Construct a `Json` from a byte slice. Most users should prefer to use the `FromRequest` impl + /// but special cases may require first extracting a `Request` into `Bytes` then optionally + /// constructing a `Json`. + pub fn from_bytes(bytes: &[u8]) -> Result { + let body = &mut bytes.to_owned(); + let deserializer = simd_json::from_slice::(body); + + let value = match deserializer { + Ok(v) => v, + Err(err) => { + let rejection = { SimdJsonRejection::from(err) }; + return Err(rejection); + } + }; + + Ok(Json(value)) + } +} + +impl IntoResponse for Json +where + T: Serialize, +{ + fn into_response(self) -> Response { + // Use a small initial capacity of 128 bytes like serde_json::to_vec + // https://docs.rs/serde_json/1.0.82/src/serde_json/ser.rs.html#2189 + let mut buf = BytesMut::with_capacity(128).writer(); + match simd_json::to_writer(&mut buf, &self.0) { + Ok(()) => ( + [( + header::CONTENT_TYPE, + HeaderValue::from_static(mime::APPLICATION_JSON.as_ref()), + )], + buf.into_inner().freeze(), + ) + .into_response(), + Err(err) => ( + StatusCode::INTERNAL_SERVER_ERROR, + [( + header::CONTENT_TYPE, + HeaderValue::from_static(mime::TEXT_PLAIN_UTF_8.as_ref()), + )], + err.to_string(), + ) + .into_response(), + } + } +} diff --git a/frameworks/Rust/axum/src/common/utils.rs b/frameworks/Rust/axum/src/common/utils.rs new file mode 100644 index 00000000000..0da86151e62 --- /dev/null +++ b/frameworks/Rust/axum/src/common/utils.rs @@ -0,0 +1,54 @@ +use axum::{ + body::Bytes, + http::{header, HeaderValue, StatusCode}, + response::{IntoResponse, Response}, +}; +use serde::Deserialize; + +#[derive(Debug, Deserialize)] +pub struct Params { + q: Option, +} + +#[allow(dead_code)] +#[inline(always)] +pub fn parse_params(params: Params) -> usize { + params + .q + .and_then(|q| q.parse().ok()) + .unwrap_or(1) + .clamp(1, 500) +} + +/// Utility function for mapping any error into a `500 Internal Server Error` +/// response. +#[allow(dead_code)] +pub fn internal_error(err: E) -> (StatusCode, String) +where + E: std::error::Error, +{ + (StatusCode::INTERNAL_SERVER_ERROR, err.to_string()) +} + +#[derive(Clone, Copy, Debug)] +pub struct Utf8Html(pub T); + +impl IntoResponse for Utf8Html +where + T: Into, +{ + fn into_response(self) -> Response { + let mut res = (StatusCode::OK, self.0.into()).into_response(); + res.headers_mut().insert( + header::CONTENT_TYPE, + HeaderValue::from_static("text/html; charset=utf-8"), + ); + res + } +} + +impl From for Utf8Html { + fn from(inner: T) -> Self { + Self(inner) + } +} diff --git a/frameworks/Rust/axum/src/database_mongo.rs b/frameworks/Rust/axum/src/database_mongo.rs deleted file mode 100644 index dcb9b1bebb9..00000000000 --- a/frameworks/Rust/axum/src/database_mongo.rs +++ /dev/null @@ -1,108 +0,0 @@ -use std::{convert::Infallible, io}; - -use axum::{async_trait, extract::FromRequestParts, http::request::Parts}; -use futures_util::{stream::FuturesUnordered, StreamExt, TryStreamExt}; -use mongodb::{bson::doc, Database}; - -use crate::{Fortune, World}; - -pub struct DatabaseConnection(pub Database); - -#[async_trait] -impl FromRequestParts for DatabaseConnection { - type Rejection = Infallible; - - async fn from_request_parts( - _parts: &mut Parts, - db: &Database, - ) -> Result { - Ok(Self(db.clone())) - } -} - -#[derive(Debug)] -pub enum MongoError { - Io(io::Error), - Mongo(mongodb::error::Error), -} - -impl From for MongoError { - fn from(err: io::Error) -> Self { - MongoError::Io(err) - } -} - -impl From for MongoError { - fn from(err: mongodb::error::Error) -> Self { - MongoError::Mongo(err) - } -} - -pub async fn find_world_by_id(db: Database, id: i32) -> Result { - let world_collection = db.collection::("world"); - - let filter = doc! { "_id": id as f32 }; - - let world: World = world_collection - .find_one(Some(filter), None) - .await - .unwrap() - .expect("expected world, found none"); - Ok(world) -} - -pub async fn find_worlds(db: Database, ids: Vec) -> Result, MongoError> { - let future_worlds = FuturesUnordered::new(); - - for id in ids { - future_worlds.push(find_world_by_id(db.clone(), id)); - } - - let worlds: Result, MongoError> = future_worlds.try_collect().await; - worlds -} - -pub async fn fetch_fortunes(db: Database) -> Result, MongoError> { - let fortune_collection = db.collection::("fortune"); - - let mut fortune_cursor = fortune_collection - .find(None, None) - .await - .expect("fortunes could not be loaded"); - - let mut fortunes: Vec = Vec::new(); - - while let Some(doc) = fortune_cursor.next().await { - fortunes.push(doc.expect("could not load fortune")); - } - - fortunes.push(Fortune { - id: 0, - message: "Additional fortune added at request time.".to_string(), - }); - - fortunes.sort_by(|a, b| a.message.cmp(&b.message)); - Ok(fortunes) -} - -pub async fn update_worlds( - db: Database, - worlds: Vec, -) -> Result { - let mut updates = Vec::new(); - - for world in worlds { - updates.push(doc! { - "q": { "id": world.id }, "u": { "$set": { "randomNumber": world.random_number }} - }); - } - - db.run_command( - doc! {"update": "world", "updates": updates, "ordered": false}, - None, - ) - .await - .expect("could not update worlds"); - - Ok(true) -} diff --git a/frameworks/Rust/axum/src/database_mongo_raw.rs b/frameworks/Rust/axum/src/database_mongo_raw.rs deleted file mode 100644 index 2fa02c07ec4..00000000000 --- a/frameworks/Rust/axum/src/database_mongo_raw.rs +++ /dev/null @@ -1,102 +0,0 @@ -use std::{convert::Infallible, io}; - -use axum::{async_trait, extract::FromRequestParts, http::request::Parts}; -use futures_util::{stream::FuturesUnordered, TryStreamExt}; -use mongodb::{ - bson::{doc, RawDocumentBuf}, - Database, -}; - -use crate::World; - -pub struct DatabaseConnection(pub Database); - -#[async_trait] -impl FromRequestParts for DatabaseConnection { - type Rejection = Infallible; - - async fn from_request_parts( - _parts: &mut Parts, - db: &Database, - ) -> Result { - Ok(Self(db.clone())) - } -} - -#[derive(Debug)] -pub enum MongoError { - Io(io::Error), - Mongo(mongodb::error::Error), -} - -impl From for MongoError { - fn from(err: io::Error) -> Self { - MongoError::Io(err) - } -} - -impl From for MongoError { - fn from(err: mongodb::error::Error) -> Self { - MongoError::Mongo(err) - } -} - -pub async fn find_world_by_id(db: Database, id: i32) -> Result { - let world_collection = db.collection::("world"); - - let filter = doc! { "_id": id as f32 }; - - let raw: RawDocumentBuf = world_collection - .find_one(Some(filter), None) - .await - .unwrap() - .expect("expected world, found none"); - - Ok(World { - id: raw - .get("id") - .expect("expected to parse world id") - .expect("could not get world id") - .as_i32() - .expect("could not extract world id"), - random_number: raw - .get("id") - .expect("expected to parse world id") - .expect("could not get world id") - .as_i32() - .expect("could not extract world id"), - }) -} - -pub async fn find_worlds(db: Database, ids: Vec) -> Result, MongoError> { - let future_worlds = FuturesUnordered::new(); - - for id in ids { - future_worlds.push(find_world_by_id(db.clone(), id)); - } - - let worlds: Result, MongoError> = future_worlds.try_collect().await; - worlds -} - -pub async fn update_worlds( - db: Database, - worlds: Vec, -) -> Result { - let mut updates = Vec::new(); - - for world in worlds { - updates.push(doc! { - "q": { "id": world.id }, "u": { "$set": { "randomNumber": world.random_number }} - }); - } - - db.run_command( - doc! {"update": "world", "updates": updates, "ordered": false}, - None, - ) - .await - .expect("could not update worlds"); - - Ok(true) -} diff --git a/frameworks/Rust/axum/src/database_pg.rs b/frameworks/Rust/axum/src/database_pg.rs deleted file mode 100644 index 56e07553af3..00000000000 --- a/frameworks/Rust/axum/src/database_pg.rs +++ /dev/null @@ -1,199 +0,0 @@ -use std::{collections::HashMap, convert::Infallible, fmt::Write, io, sync::Arc}; - -use axum::{async_trait, extract::FromRequestParts, http::request::Parts}; -use futures::{ - stream::futures_unordered::FuturesUnordered, FutureExt, StreamExt, TryStreamExt, -}; -use rand::{rngs::SmallRng, thread_rng, Rng, SeedableRng}; -use tokio::pin; -use tokio_postgres::{connect, types::ToSql, Client, NoTls, Statement}; - -use crate::models_pg::{Fortune, World}; - -#[derive(Debug)] -pub enum PgError { - Io(io::Error), - Pg(tokio_postgres::Error), -} - -impl From for PgError { - fn from(err: io::Error) -> Self { - PgError::Io(err) - } -} - -impl From for PgError { - fn from(err: tokio_postgres::Error) -> Self { - PgError::Pg(err) - } -} - -/// Postgres interface -pub struct PgConnection { - client: Client, - fortune: Statement, - world: Statement, - updates: HashMap, -} - -impl PgConnection { - pub async fn connect(db_url: String) -> Arc { - let (cl, conn) = connect(&db_url, NoTls) - .await - .expect("can not connect to postgresql"); - - // Spawn connection - tokio::spawn(async move { - if let Err(error) = conn.await { - eprintln!("Connection error: {error}"); - } - }); - - let fortune = cl.prepare("SELECT * FROM fortune").await.unwrap(); - let mut updates = HashMap::new(); - - for num in 1..=500u16 { - let mut pl = 1; - let mut q = String::new(); - - q.push_str("UPDATE world SET randomnumber = CASE id "); - - for _ in 1..=num { - let _ = write!(q, "when ${pl} then ${} ", pl + 1); - pl += 2; - } - - q.push_str("ELSE randomnumber END WHERE id IN ("); - - for _ in 1..=num { - let _ = write!(q, "${pl},"); - pl += 1; - } - - q.pop(); - q.push(')'); - - updates.insert(num, cl.prepare(&q).await.unwrap()); - } - - let world = cl.prepare("SELECT * FROM world WHERE id=$1").await.unwrap(); - - Arc::new(PgConnection { - client: cl, - fortune, - world, - updates, - }) - } -} - -impl PgConnection { - async fn query_one_world(&self, id: i32) -> Result { - let stream = self.client.query_raw(&self.world, &[&id]).await?; - pin!(stream); - let row = stream.next().await.unwrap()?; - Ok(World { - id: row.get(0), - randomnumber: row.get(1), - }) - } - - pub async fn get_world(&self) -> Result { - let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); - - let random_id = (rng.gen::() % 10_000 + 1) as i32; - - let world = self.query_one_world(random_id).await?; - Ok(world) - } - - pub async fn get_worlds(&self, num: usize) -> Result, PgError> { - let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); - - let worlds = FuturesUnordered::new(); - - for _ in 0..num { - let w_id = (rng.gen::() % 10_000 + 1) as i32; - worlds.push(self.query_one_world(w_id)); - } - - worlds.try_collect().await - } - - pub async fn update(&self, num: u16) -> Result, PgError> { - let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); - - let worlds = FuturesUnordered::new(); - - for _ in 0..num { - let id = (rng.gen::() % 10_000 + 1) as i32; - let w_id = (rng.gen::() % 10_000 + 1) as i32; - - worlds.push(self.query_one_world(w_id).map(move |res| match res { - Ok(mut world) => { - world.randomnumber = id; - Ok(world) - } - - Err(err) => Err(err), - })); - } - - let st = self.updates.get(&num).unwrap().clone(); - - let worlds: Vec = worlds.try_collect().await?; - - let mut params: Vec<&(dyn ToSql + Sync)> = Vec::with_capacity(num as usize * 3); - - for w in &worlds { - params.push(&w.id); - params.push(&w.randomnumber); - } - - for w in &worlds { - params.push(&w.id); - } - - self.client.query(&st, ¶ms[..]).await?; - - Ok(worlds) - } - - pub async fn tell_fortune(&self) -> Result, PgError> { - let mut items = vec![Fortune { - id: 0, - message: "Additional fortune added at request time.".parse().unwrap(), - }]; - - let fut = self.client.query_raw::<_, _, &[i32; 0]>(&self.fortune, &[]); - - let stream = fut.await?; - pin!(stream); - - while let Some(row) = stream.next().await { - let row = row?; - - items.push(Fortune { - id: row.get(0), - message: row.get(1), - }); - } - - items.sort_by(|it, next| it.message.cmp(&next.message)); - Ok(items) - } -} - -pub struct DatabaseConnection(pub Arc); - -#[async_trait] -impl FromRequestParts> for DatabaseConnection { - type Rejection = Infallible; - - async fn from_request_parts( - _parts: &mut Parts, - pg_connection: &Arc, - ) -> Result { - Ok(Self(pg_connection.clone())) - } -} diff --git a/frameworks/Rust/axum/src/database_pg_pool.rs b/frameworks/Rust/axum/src/database_pg_pool.rs deleted file mode 100644 index f86c002845a..00000000000 --- a/frameworks/Rust/axum/src/database_pg_pool.rs +++ /dev/null @@ -1,122 +0,0 @@ -use std::io; - -use axum::{ - async_trait, - extract::FromRequestParts, - http::{request::Parts, StatusCode}, -}; -use deadpool_postgres::{Client, Manager, ManagerConfig, RecyclingMethod}; -use tokio_pg_mapper::FromTokioPostgresRow; -use tokio_postgres::{NoTls, Row, Statement}; - -use crate::{utils::internal_error, Fortune, World}; - -#[derive(Debug)] -pub enum PgError { - Io(io::Error), - Pg(tokio_postgres::Error), -} - -impl From for PgError { - fn from(err: io::Error) -> Self { - PgError::Io(err) - } -} - -impl From for PgError { - fn from(err: tokio_postgres::Error) -> Self { - PgError::Pg(err) - } -} - -pub async fn create_pool( - database_url: String, - max_pool_size: u32, -) -> deadpool_postgres::Pool { - let pg_config: tokio_postgres::Config = - database_url.parse().expect("invalid database url"); - - let mgr_config = ManagerConfig { - recycling_method: RecyclingMethod::Fast, - }; - let mgr = Manager::from_config(pg_config, NoTls, mgr_config); - let pool: deadpool_postgres::Pool = deadpool_postgres::Pool::builder(mgr) - .max_size(max_pool_size as usize) - .build() - .unwrap(); - - pool -} - -pub struct DatabaseClient(pub Client); - -#[async_trait] -impl FromRequestParts for DatabaseClient { - type Rejection = (StatusCode, String); - - async fn from_request_parts( - _parts: &mut Parts, - pool: &deadpool_postgres::Pool, - ) -> Result { - let conn = pool.get().await.map_err(internal_error)?; - - Ok(Self(conn)) - } -} - -pub async fn fetch_world_by_id( - client: &Client, - number: i32, - select: &Statement, -) -> Result { - let row: Row = client.query_one(select, &[&number]).await.unwrap(); - - Ok(World::from_row(row).unwrap()) -} - -pub async fn update_world( - client: &Client, - update: &Statement, - random_id: i32, - w_id: i32, -) -> Result { - let rows_modified: u64 = client.execute(update, &[&random_id, &w_id]).await.unwrap(); - - Ok(rows_modified) -} - -pub async fn fetch_all_fortunes( - client: Client, - select: &Statement, -) -> Result, PgError> { - let rows: Vec = client.query(select, &[]).await.unwrap(); - - let mut fortunes: Vec = Vec::with_capacity(rows.capacity()); - - for row in rows { - fortunes.push(Fortune::from_row(row).unwrap()); - } - - Ok(fortunes) -} - -pub async fn prepare_fetch_all_fortunes_statement(client: &Client) -> Statement { - client - .prepare_cached("SELECT * FROM Fortune") - .await - .unwrap() -} - -pub async fn prepare_fetch_world_by_id_statement(client: &Client) -> Statement { - client - .prepare_cached("SELECT id, randomnumber FROM World WHERE id = $1") - .await - .unwrap() -} - -pub async fn prepare_update_world_by_id_statement(client: &Client) -> Statement { - client - .prepare_cached("UPDATE World SET randomnumber = $1 WHERE id = $2") - .await - .unwrap() -} diff --git a/frameworks/Rust/axum/src/database_sqlx.rs b/frameworks/Rust/axum/src/database_sqlx.rs deleted file mode 100644 index e26baebde03..00000000000 --- a/frameworks/Rust/axum/src/database_sqlx.rs +++ /dev/null @@ -1,86 +0,0 @@ -use std::io; - -use axum::{ - async_trait, - extract::FromRequestParts, - http::{request::Parts, StatusCode}, -}; -use sqlx::{ - pool::PoolConnection, - postgres::{PgArguments, PgPoolOptions}, - Arguments, PgPool, Postgres, -}; - -use crate::{utils::internal_error, Fortune, World}; - -#[derive(Debug)] -pub enum PgError { - Io(io::Error), - Pg(sqlx::Error), -} - -impl From for PgError { - fn from(err: io::Error) -> Self { - PgError::Io(err) - } -} - -impl From for PgError { - fn from(err: sqlx::Error) -> Self { - PgError::Pg(err) - } -} - -pub async fn create_pool( - database_url: String, - max_pool_size: u32, - min_pool_size: u32, -) -> PgPool { - PgPoolOptions::new() - .max_connections(max_pool_size) - .min_connections(min_pool_size) - .connect(&database_url) - .await - .unwrap() -} - -pub struct DatabaseConnection(pub PoolConnection); - -#[async_trait] -impl FromRequestParts for DatabaseConnection { - type Rejection = (StatusCode, String); - - async fn from_request_parts( - _parts: &mut Parts, - pool: &PgPool, - ) -> Result { - let conn = pool.acquire().await.map_err(internal_error)?; - - Ok(Self(conn)) - } -} - -pub async fn fetch_world( - mut conn: PoolConnection, - number: i32, -) -> Result { - let mut args = PgArguments::default(); - args.add(number); - - let world: World = - sqlx::query_as_with("SELECT id, randomnumber FROM World WHERE id = $1", args) - .fetch_one(&mut conn) - .await - .expect("error loading world"); - Ok(world) -} - -pub async fn fetch_fortunes( - mut conn: PoolConnection, -) -> Result, PgError> { - let fortunes: Vec = sqlx::query_as("SELECT * FROM Fortune") - .fetch_all(&mut conn) - .await - .expect("error loading Fortunes"); - Ok(fortunes) -} diff --git a/frameworks/Rust/axum/src/main.rs b/frameworks/Rust/axum/src/main.rs index 075ee1c01e6..0d79ce33bef 100644 --- a/frameworks/Rust/axum/src/main.rs +++ b/frameworks/Rust/axum/src/main.rs @@ -1,46 +1,47 @@ -use axum::{ - http::{header, HeaderValue, StatusCode}, - response::IntoResponse, - routing::get, - Json, Router, -}; +mod common; +mod server; + +use axum::{response::IntoResponse, routing::get, Router}; +use common::models::Message; use dotenv::dotenv; -use tower_http::set_header::SetResponseHeaderLayer; +use mimalloc::MiMalloc; -mod models_common; -mod server; +#[global_allocator] +static GLOBAL: MiMalloc = MiMalloc; + +#[cfg(not(feature = "simd-json"))] +use axum::Json; +#[cfg(feature = "simd-json")] +use common::simd_json::Json; -use self::models_common::Message; +const HELLO_WORLD: &str = "Hello, World!"; +/// Return a plaintext static string. +#[inline(always)] pub async fn plaintext() -> &'static str { - "Hello, World!" + &HELLO_WORLD } +/// Return a JSON message. +#[inline(always)] pub async fn json() -> impl IntoResponse { let message = Message { - message: "Hello, World!", + message: HELLO_WORLD, }; - (StatusCode::OK, Json(message)) + Json(message) } -#[tokio::main] -async fn main() { +fn main() { dotenv().ok(); + server::start_tokio(serve_app) +} - let server_header_value = HeaderValue::from_static("Axum"); +async fn serve_app() { let app = Router::new() .route("/plaintext", get(plaintext)) - .route("/json", get(json)) - .layer(SetResponseHeaderLayer::if_not_present( - header::SERVER, - server_header_value, - )); - - server::builder() - .http1_pipeline_flush(true) - .serve(app.into_make_service()) - .await - .unwrap(); -} + .route("/json", get(json)); + + server::serve_hyper(app, Some(8000)).await +} \ No newline at end of file diff --git a/frameworks/Rust/axum/src/main_mongo.rs b/frameworks/Rust/axum/src/main_mongo.rs index 8219113f583..a08c8095257 100644 --- a/frameworks/Rust/axum/src/main_mongo.rs +++ b/frameworks/Rust/axum/src/main_mongo.rs @@ -1,33 +1,39 @@ +mod common; +mod mongo; +mod server; +//mod mongo_raw; + use std::time::Duration; use axum::{ - extract::Query, - http::{header, HeaderValue, StatusCode}, - response::IntoResponse, - routing::get, - Json, Router, + extract::Query, http::StatusCode, response::IntoResponse, routing::get, Router, +}; + +#[cfg(not(feature = "simd-json"))] +use axum::Json; +#[cfg(feature = "simd-json")] +use common::simd_json::Json; +use common::{ + models::{FortuneInfo, World}, random_id }; use dotenv::dotenv; use mongodb::{ options::{ClientOptions, Compressor}, Client, }; -use rand::{rngs::SmallRng, thread_rng, Rng, SeedableRng}; -use tower_http::set_header::SetResponseHeaderLayer; +use rand::{rngs::SmallRng, rng, SeedableRng}; use yarte::Template; +use mimalloc::MiMalloc; -mod database_mongo; -mod models_common; -mod models_mongo; -mod server; -mod utils; - -use self::{ - database_mongo::{ - fetch_fortunes, find_world_by_id, find_worlds, update_worlds, DatabaseConnection, - }, - models_mongo::{Fortune, FortuneInfo, World}, - utils::{get_environment_variable, parse_params, Params, Utf8Html}, +#[global_allocator] +static GLOBAL: MiMalloc = MiMalloc; + +use common::{ + get_env, + utils::{parse_params, Params, Utf8Html}, +}; +use mongo::database::{ + fetch_fortunes, find_world_by_id, find_worlds, update_worlds, DatabaseConnection, }; #[derive(Template)] @@ -37,9 +43,7 @@ pub struct FortunesTemplate<'a> { } async fn db(DatabaseConnection(db): DatabaseConnection) -> impl IntoResponse { - let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); - - let random_id = (rng.gen::() % 10_000 + 1) as i32; + let random_id = random_id(&mut rng()); let world = find_world_by_id(db, random_id) .await @@ -54,16 +58,8 @@ async fn queries( ) -> impl IntoResponse { let q = parse_params(params); - let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); - let mut ids: Vec = Vec::with_capacity(q as usize); - - for _ in 0..q { - let random_id = (rng.gen::() % 10_000 + 1) as i32; - - ids.push(random_id); - } - - let worlds = find_worlds(db, ids).await; + let mut rng = SmallRng::from_rng(&mut rng()); + let worlds = find_worlds(db, &mut rng, q).await; let results = worlds.expect("worlds could not be retrieved"); (StatusCode::OK, Json(results)) @@ -75,24 +71,15 @@ async fn updates( ) -> impl IntoResponse { let q = parse_params(params); - let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); - let mut ids: Vec = Vec::with_capacity(q as usize); - - for _ in 0..q { - let random_id = (rng.gen::() % 10_000 + 1) as i32; - - ids.push(random_id); - } + let mut rng = SmallRng::from_rng(&mut rng()); - let worlds = find_worlds(db.clone(), ids) + let worlds = find_worlds(db.clone(), &mut rng, q) .await .expect("worlds could not be retrieved"); - let mut updated_worlds: Vec = Vec::with_capacity(q as usize); + let mut updated_worlds: Vec = Vec::with_capacity(q); for mut world in worlds { - let random_number = (rng.gen::() % 10_000 + 1) as i32; - - world.random_number = random_number; + world.random_number = random_id(&mut rng); updated_worlds.push(world); } @@ -125,28 +112,13 @@ async fn fortunes(DatabaseConnection(db): DatabaseConnection) -> impl IntoRespon fn main() { dotenv().ok(); - - let rt = tokio::runtime::Builder::new_current_thread() - .enable_all() - .build() - .unwrap(); - - for _ in 1..num_cpus::get() { - std::thread::spawn(move || { - let rt = tokio::runtime::Builder::new_current_thread() - .enable_all() - .build() - .unwrap(); - rt.block_on(serve()); - }); - } - rt.block_on(serve()); + server::start_tokio(serve_app) } -async fn serve() { - let database_url: String = get_environment_variable("AXUM_TECHEMPOWER_MONGODB_URL"); - let max_pool_size: u32 = get_environment_variable("AXUM_TECHEMPOWER_MAX_POOL_SIZE"); - let min_pool_size: u32 = get_environment_variable("AXUM_TECHEMPOWER_MIN_POOL_SIZE"); +async fn serve_app() { + let database_url: String = get_env("MONGODB_URL"); + let max_pool_size: u32 = get_env("MONGODB_MAX_POOL_SIZE"); + let min_pool_size: u32 = get_env("MONGODB_MIN_POOL_SIZE"); let mut client_options = ClientOptions::parse(database_url).await.unwrap(); @@ -168,21 +140,13 @@ async fn serve() { let client = Client::with_options(client_options).unwrap(); let database = client.database("hello_world"); - let server_header_value = HeaderValue::from_static("Axum"); let app = Router::new() .route("/fortunes", get(fortunes)) .route("/db", get(db)) .route("/queries", get(queries)) .route("/updates", get(updates)) - .with_state(database) - .layer(SetResponseHeaderLayer::if_not_present( - header::SERVER, - server_header_value, - )); - - server::builder() - .serve(app.into_make_service()) - .await - .unwrap(); + .with_state(database); + + server::serve(app, Some(8000)).await } diff --git a/frameworks/Rust/axum/src/main_mongo_raw.rs b/frameworks/Rust/axum/src/main_mongo_raw.rs index 72db28af280..64c9141c239 100644 --- a/frameworks/Rust/axum/src/main_mongo_raw.rs +++ b/frameworks/Rust/axum/src/main_mongo_raw.rs @@ -1,38 +1,41 @@ +mod common; +mod mongo_raw; +mod server; + +use common::{models::World, random_id}; +use mongo_raw::database::{ + find_world_by_id, find_worlds, update_worlds, DatabaseConnection, +}; + +use common::{ + get_env, + utils::{parse_params, Params}, +}; use std::time::Duration; use axum::{ - extract::Query, - http::{header, HeaderValue, StatusCode}, - response::IntoResponse, - routing::get, - Json, Router, + extract::Query, http::StatusCode, response::IntoResponse, routing::get, Router, }; + +use mimalloc::MiMalloc; + +#[global_allocator] +static GLOBAL: MiMalloc = MiMalloc; + +#[cfg(not(feature = "simd-json"))] +use axum::Json; +#[cfg(feature = "simd-json")] +use common::simd_json::Json; + use dotenv::dotenv; use mongodb::{ options::{ClientOptions, Compressor}, Client, }; -use rand::{rngs::SmallRng, thread_rng, Rng, SeedableRng}; -use tower_http::set_header::SetResponseHeaderLayer; - -mod database_mongo_raw; -mod models_common; -mod models_mongo; -mod server; -mod utils; - -use self::{ - database_mongo_raw::{ - find_world_by_id, find_worlds, update_worlds, DatabaseConnection, - }, - models_mongo::World, - utils::{get_environment_variable, parse_params, Params}, -}; +use rand::{rngs::SmallRng, rng, SeedableRng}; async fn db(DatabaseConnection(db): DatabaseConnection) -> impl IntoResponse { - let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); - - let random_id = (rng.gen::() % 10_000 + 1) as i32; + let random_id = random_id(&mut rng()); let world = find_world_by_id(db, random_id) .await @@ -47,16 +50,8 @@ async fn queries( ) -> impl IntoResponse { let q = parse_params(params); - let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); - let mut ids: Vec = Vec::with_capacity(q as usize); - - for _ in 0..q { - let random_id = (rng.gen::() % 10_000 + 1) as i32; - - ids.push(random_id); - } - - let worlds = find_worlds(db, ids).await; + let mut rng = SmallRng::from_rng(&mut rng()); + let worlds = find_worlds(db, &mut rng, q).await; let results = worlds.expect("worlds could not be retrieved"); (StatusCode::OK, Json(results)) @@ -68,24 +63,15 @@ async fn updates( ) -> impl IntoResponse { let q = parse_params(params); - let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); - let mut ids: Vec = Vec::with_capacity(q as usize); - - for _ in 0..q { - let random_id = (rng.gen::() % 10_000 + 1) as i32; - - ids.push(random_id); - } + let mut rng = SmallRng::from_rng(&mut rng()); - let worlds = find_worlds(db.clone(), ids) + let worlds = find_worlds(db.clone(), &mut rng, q) .await .expect("worlds could not be retrieved"); - let mut updated_worlds: Vec = Vec::with_capacity(q as usize); + let mut updated_worlds: Vec = Vec::with_capacity(q); for mut world in worlds { - let random_number = (rng.gen::() % 10_000 + 1) as i32; - - world.random_number = random_number; + world.random_number = random_id(&mut rng); updated_worlds.push(world); } @@ -98,28 +84,13 @@ async fn updates( fn main() { dotenv().ok(); - - let rt = tokio::runtime::Builder::new_current_thread() - .enable_all() - .build() - .unwrap(); - - for _ in 1..num_cpus::get() { - std::thread::spawn(move || { - let rt = tokio::runtime::Builder::new_current_thread() - .enable_all() - .build() - .unwrap(); - rt.block_on(serve()); - }); - } - rt.block_on(serve()); + server::start_tokio(serve_app) } -async fn serve() { - let database_url: String = get_environment_variable("AXUM_TECHEMPOWER_MONGODB_URL"); - let max_pool_size: u32 = get_environment_variable("AXUM_TECHEMPOWER_MAX_POOL_SIZE"); - let min_pool_size: u32 = get_environment_variable("AXUM_TECHEMPOWER_MIN_POOL_SIZE"); +async fn serve_app() { + let database_url: String = get_env("MONGODB_URL"); + let max_pool_size: u32 = get_env("MONGODB_MAX_POOL_SIZE"); + let min_pool_size: u32 = get_env("MONGODB_MIN_POOL_SIZE"); let mut client_options = ClientOptions::parse(database_url).await.unwrap(); @@ -141,20 +112,12 @@ async fn serve() { let client = Client::with_options(client_options).unwrap(); let database = client.database("hello_world"); - let server_header_value = HeaderValue::from_static("Axum"); let app = Router::new() .route("/db", get(db)) .route("/queries", get(queries)) .route("/updates", get(updates)) - .with_state(database) - .layer(SetResponseHeaderLayer::if_not_present( - header::SERVER, - server_header_value, - )); - - server::builder() - .serve(app.into_make_service()) - .await - .unwrap(); + .with_state(database); + + server::serve(app, Some(8000)).await } diff --git a/frameworks/Rust/axum/src/main_pg.rs b/frameworks/Rust/axum/src/main_pg.rs index 3b4748dfc39..3fb88378546 100644 --- a/frameworks/Rust/axum/src/main_pg.rs +++ b/frameworks/Rust/axum/src/main_pg.rs @@ -1,25 +1,30 @@ +mod common; +mod pg; + use axum::{ - extract::Query, - http::{header, HeaderValue, StatusCode}, - response::IntoResponse, - routing::get, - Json, Router, + extract::Query, http::StatusCode, response::IntoResponse, routing::get, Router, }; use dotenv::dotenv; -use tower_http::set_header::SetResponseHeaderLayer; +use rand::rng; use yarte::Template; +use mimalloc::MiMalloc; + +#[global_allocator] +static GLOBAL: MiMalloc = MiMalloc; + +#[cfg(not(feature = "simd-json"))] +use axum::Json; +#[cfg(feature = "simd-json")] +use common::simd_json::Json; -mod database_pg; -mod models_common; -mod models_pg; mod server; -mod utils; -use self::{ - database_pg::{DatabaseConnection, PgConnection}, - models_pg::Fortune, - utils::{get_environment_variable, parse_params, Params, Utf8Html}, +use common::{ + get_env, random_id, + utils::{parse_params, Params, Utf8Html}, }; +use pg::database::{DatabaseConnection, PgConnection}; +use pg::models::Fortune; #[derive(Template)] #[template(path = "fortunes.html.hbs")] @@ -28,7 +33,11 @@ pub struct FortunesTemplate<'a> { } async fn db(DatabaseConnection(conn): DatabaseConnection) -> impl IntoResponse { - let world = conn.get_world().await.expect("error loading world"); + let id = random_id(&mut rng()); + let world = conn + .fetch_world_by_id(id) + .await + .expect("error loading world"); (StatusCode::OK, Json(world)) } @@ -40,7 +49,7 @@ async fn queries( let q = parse_params(params); let results = conn - .get_worlds(q as usize) + .fetch_random_worlds(q) .await .expect("error loading worlds"); @@ -48,8 +57,10 @@ async fn queries( } async fn fortunes(DatabaseConnection(conn): DatabaseConnection) -> impl IntoResponse { - let fortunes: Vec = - conn.tell_fortune().await.expect("error loading fortunes"); + let fortunes: Vec = conn + .fetch_all_fortunes() + .await + .expect("error loading fortunes"); Utf8Html( FortunesTemplate { @@ -65,52 +76,28 @@ async fn updates( Query(params): Query, ) -> impl IntoResponse { let q = parse_params(params); + let worlds = conn.update_worlds(q).await.expect("error updating worlds"); - let results = conn.update(q as u16).await.expect("error updating worlds"); - - (StatusCode::OK, Json(results)) + (StatusCode::OK, Json(worlds)) } fn main() { dotenv().ok(); - - let rt = tokio::runtime::Builder::new_current_thread() - .enable_all() - .build() - .unwrap(); - - for _ in 1..num_cpus::get() { - std::thread::spawn(move || { - let rt = tokio::runtime::Builder::new_current_thread() - .enable_all() - .build() - .unwrap(); - rt.block_on(serve()); - }); - } - rt.block_on(serve()); + server::start_tokio(serve_app) } -async fn serve() { - let database_url: String = get_environment_variable("AXUM_TECHEMPOWER_DATABASE_URL"); +async fn serve_app() { + let database_url: String = get_env("POSTGRES_URL"); - // setup connection pool + // Create shared database connection let pg_connection = PgConnection::connect(database_url).await; - let server_header_value = HeaderValue::from_static("Axum"); - let router = Router::new() + let app = Router::new() .route("/fortunes", get(fortunes)) .route("/db", get(db)) .route("/queries", get(queries)) .route("/updates", get(updates)) - .with_state(pg_connection) - .layer(SetResponseHeaderLayer::if_not_present( - header::SERVER, - server_header_value, - )); - - server::builder() - .serve(router.into_make_service()) - .await - .unwrap(); + .with_state(pg_connection); + + server::serve_hyper(app, Some(8000)).await } diff --git a/frameworks/Rust/axum/src/main_pg_pool.rs b/frameworks/Rust/axum/src/main_pg_pool.rs index 4c767b4a06c..c99545331de 100644 --- a/frameworks/Rust/axum/src/main_pg_pool.rs +++ b/frameworks/Rust/axum/src/main_pg_pool.rs @@ -1,31 +1,35 @@ +mod common; +mod pg_pool; + use axum::{ - extract::Query, - http::{header, HeaderValue, StatusCode}, - response::IntoResponse, - routing::get, - Json, Router, + extract::Query, http::StatusCode, response::IntoResponse, routing::get, Router, }; + +#[cfg(not(feature = "simd-json"))] +use axum::Json; +#[cfg(feature = "simd-json")] +use common::simd_json::Json; + +use common::{random_ids, SELECT_ALL_FORTUNES, SELECT_WORLD_BY_ID, UPDATE_WORLDS}; use dotenv::dotenv; use futures_util::{stream::FuturesUnordered, TryStreamExt}; -use rand::{rngs::SmallRng, thread_rng, Rng, SeedableRng}; -use tower_http::set_header::SetResponseHeaderLayer; +use rand::{rngs::SmallRng, rng, SeedableRng}; use yarte::Template; +use mimalloc::MiMalloc; + +#[global_allocator] +static GLOBAL: MiMalloc = MiMalloc; -mod database_pg_pool; -mod models_common; -mod models_pg_pool; mod server; -mod utils; - -use self::{ - database_pg_pool::{ - create_pool, fetch_all_fortunes, fetch_world_by_id, - prepare_fetch_all_fortunes_statement, prepare_fetch_world_by_id_statement, - prepare_update_world_by_id_statement, update_world, DatabaseClient, PgError, - }, - models_pg_pool::{Fortune, World}, - utils::{get_environment_variable, parse_params, random_number, Params, Utf8Html}, + +use common::{ + get_env, random_id, + utils::{parse_params, Params, Utf8Html}, +}; +use pg_pool::database::{ + create_pool, fetch_all_fortunes, fetch_world_by_id, DatabaseClient, PgError, }; +use pg_pool::models::{Fortune, World}; #[derive(Template)] #[template(path = "fortunes.html.hbs")] @@ -34,12 +38,10 @@ pub struct FortunesTemplate<'a> { } async fn db(DatabaseClient(client): DatabaseClient) -> impl IntoResponse { - let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); - - let random_id = (rng.gen::() % 10_000 + 1) as i32; + let random_id = random_id(&mut rng()); - let select = prepare_fetch_world_by_id_statement(&client).await; - let world = fetch_world_by_id(&client, random_id, &select) + let select = &client.prepare_cached(SELECT_WORLD_BY_ID).await.unwrap(); + let world = fetch_world_by_id(&client, random_id, select) .await .expect("could not fetch world"); @@ -52,16 +54,12 @@ async fn queries( ) -> impl IntoResponse { let q = parse_params(params); - let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); - - let select = prepare_fetch_world_by_id_statement(&client).await; - + let mut rng = SmallRng::from_rng(&mut rng()); + let select = &client.prepare_cached(SELECT_WORLD_BY_ID).await.unwrap(); let future_worlds = FuturesUnordered::new(); - for _ in 0..q { - let w_id = (rng.gen::() % 10_000 + 1) as i32; - - future_worlds.push(fetch_world_by_id(&client, w_id, &select)); + for id in random_ids(&mut rng, q) { + future_worlds.push(fetch_world_by_id(&client, id, select)); } let worlds: Result, PgError> = future_worlds.try_collect().await; @@ -71,9 +69,9 @@ async fn queries( } async fn fortunes(DatabaseClient(client): DatabaseClient) -> impl IntoResponse { - let select = prepare_fetch_all_fortunes_statement(&client).await; + let select = &client.prepare_cached(SELECT_ALL_FORTUNES).await.unwrap(); - let mut fortunes = fetch_all_fortunes(client, &select) + let mut fortunes = fetch_all_fortunes(client, select) .await .expect("could not fetch fortunes"); @@ -99,67 +97,50 @@ async fn updates( ) -> impl IntoResponse { let q = parse_params(params); - let mut rng = SmallRng::from_entropy(); - - let select = prepare_fetch_world_by_id_statement(&client).await; + let mut rng = SmallRng::from_rng(&mut rng()); + let select = &client.prepare_cached(SELECT_WORLD_BY_ID).await.unwrap(); + let update = &client.prepare_cached(UPDATE_WORLDS).await.unwrap(); + // Select the random worlds. let future_worlds = FuturesUnordered::new(); - - for _ in 0..q { - let query_id = random_number(&mut rng); - - future_worlds.push(fetch_world_by_id(&client, query_id, &select)); - } - - let worlds: Result, PgError> = future_worlds.try_collect().await; - let results = worlds.expect("worlds could not be retrieved"); - - let update = prepare_update_world_by_id_statement(&client).await; - - let future_world_updates = FuturesUnordered::new(); - - for w in &results { - let random_id = random_number(&mut rng); - let w_id = w.id; - - future_world_updates.push(update_world(&client, &update, random_id, w_id)); + for id in random_ids(&mut rng, q) { + future_worlds.push(fetch_world_by_id(&client, id, select)); } - - let world_updates: Result, PgError> = - future_world_updates.try_collect().await; - world_updates.expect("updates could not be executed"); - - (StatusCode::OK, Json(results)) + let worlds: Vec = future_worlds.try_collect().await.unwrap(); + + let mut ids = Vec::with_capacity(q); + let mut nids = Vec::with_capacity(q); + let worlds: Vec = worlds + .into_iter() + .map(|mut w| { + w.randomnumber = random_id(&mut rng); + ids.push(w.id); + nids.push(w.randomnumber); + w + }) + .collect(); + + // Update the random worlds in the database. + client.execute(update, &[&ids, &nids]).await.unwrap(); + + (StatusCode::OK, Json(worlds)) } #[tokio::main] async fn main() { dotenv().ok(); - serve().await; -} + let database_url: String = get_env("POSTGRES_URL"); + let max_pool_size: u32 = get_env("POSTGRES_MAX_POOL_SIZE"); -async fn serve() { - let database_url: String = get_environment_variable("AXUM_TECHEMPOWER_DATABASE_URL"); - let max_pool_size: u32 = get_environment_variable("AXUM_TECHEMPOWER_MAX_POOL_SIZE"); - - // setup Client pool let pool = create_pool(database_url, max_pool_size).await; - let server_header_value = HeaderValue::from_static("Axum"); - let router = Router::new() + let app = Router::new() .route("/fortunes", get(fortunes)) .route("/db", get(db)) .route("/queries", get(queries)) .route("/updates", get(updates)) - .with_state(pool) - .layer(SetResponseHeaderLayer::if_not_present( - header::SERVER, - server_header_value, - )); - - server::builder() - .serve(router.into_make_service()) - .await - .unwrap(); + .with_state(pool); + + server::serve_hyper(app, Some(8000)).await } diff --git a/frameworks/Rust/axum/src/main_sqlx.rs b/frameworks/Rust/axum/src/main_sqlx.rs index c773233fcfa..692b398d9bb 100644 --- a/frameworks/Rust/axum/src/main_sqlx.rs +++ b/frameworks/Rust/axum/src/main_sqlx.rs @@ -1,27 +1,39 @@ +mod common; +mod sqlx; + +use std::{borrow::Cow, sync::Arc}; + +use ::sqlx::PgPool; use axum::{ - http::{header, HeaderValue, StatusCode}, + extract::{Query, State}, + http::StatusCode, response::IntoResponse, routing::get, - Json, Router, + Router, }; use dotenv::dotenv; -use rand::{rngs::SmallRng, thread_rng, Rng, SeedableRng}; -use sqlx::PgPool; -use tower_http::set_header::SetResponseHeaderLayer; +use quick_cache::sync::Cache; +use rand::{rngs::SmallRng, rng, SeedableRng}; +use sqlx::models::World; use yarte::Template; +use mimalloc::MiMalloc; + +#[global_allocator] +static GLOBAL: MiMalloc = MiMalloc; + +#[cfg(not(feature = "simd-json"))] +use axum::Json; +#[cfg(feature = "simd-json")] +use common::simd_json::Json; -mod database_sqlx; -mod models_common; -mod models_sqlx; mod server; -mod utils; -use self::{ - database_sqlx::{create_pool, fetch_fortunes, fetch_world, DatabaseConnection}, - models_sqlx::{Fortune, World}, - utils::get_environment_variable, - utils::Utf8Html, +use common::{ + get_env, random_id, random_ids, + utils::{parse_params, Params, Utf8Html}, }; +use sqlx::database::create_pool; +use sqlx::models::Fortune; #[derive(Template)] #[template(path = "fortunes.html.hbs")] @@ -29,26 +41,46 @@ pub struct FortunesTemplate<'a> { pub fortunes: &'a Vec, } -async fn db(DatabaseConnection(conn): DatabaseConnection) -> impl IntoResponse { - let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); - - let random_id = (rng.gen::() % 10_000 + 1) as i32; - - let world = fetch_world(conn, random_id) +async fn db(State(AppState { db, .. }): State) -> impl IntoResponse { + let id = random_id(&mut rng()); + let world: World = ::sqlx::query_as(common::SELECT_WORLD_BY_ID) + .bind(id) + .fetch_one(&mut *db.acquire().await.unwrap()) .await - .expect("could not fetch world"); + .expect("error loading world"); (StatusCode::OK, Json(world)) } -async fn fortunes(DatabaseConnection(conn): DatabaseConnection) -> impl IntoResponse { - let mut fortunes = fetch_fortunes(conn) +async fn queries( + State(AppState { db, .. }): State, + Query(params): Query, +) -> impl IntoResponse { + let mut rng = SmallRng::from_rng(&mut rng()); + let count = parse_params(params); + let mut worlds: Vec = Vec::with_capacity(count); + + for id in random_ids(&mut rng, count) { + let world: World = ::sqlx::query_as(common::SELECT_WORLD_BY_ID) + .bind(id) + .fetch_one(&mut *db.acquire().await.unwrap()) + .await + .expect("error loading world"); + worlds.push(world); + } + + (StatusCode::OK, Json(worlds)) +} + +async fn fortunes(State(AppState { db, .. }): State) -> impl IntoResponse { + let mut fortunes: Vec = ::sqlx::query_as(common::SELECT_ALL_FORTUNES) + .fetch_all(&mut *db.acquire().await.unwrap()) .await - .expect("could not fetch fortunes"); + .expect("error loading Fortunes"); fortunes.push(Fortune { id: 0, - message: "Additional fortune added at request time.".to_string(), + message: Cow::Borrowed("Additional fortune added at request time."), }); fortunes.sort_by(|a, b| a.message.cmp(&b.message)); @@ -62,34 +94,62 @@ async fn fortunes(DatabaseConnection(conn): DatabaseConnection) -> impl IntoResp ) } +async fn cache( + State(AppState { cache, .. }): State, + Query(params): Query, +) -> impl IntoResponse { + let count = parse_params(params); + let mut rng = SmallRng::from_rng(&mut rng()); + let mut worlds: Vec> = Vec::with_capacity(count); + + for id in random_ids(&mut rng, count) { + worlds.push(cache.get(&id)); + } + + (StatusCode::OK, Json(worlds)) +} + +/// Pre-load the cache with all worlds. +async fn preload_cache(AppState { db, cache }: &AppState) { + let worlds: Vec = ::sqlx::query_as(common::SELECT_ALL_CACHED_WORLDS) + .fetch_all(&mut *db.acquire().await.unwrap()) + .await + .expect("error loading worlds"); + + for world in worlds { + cache.insert(world.id, world); + } +} + +/// Application state +#[derive(Clone)] +struct AppState { + db: PgPool, + cache: Arc>, +} + #[tokio::main] async fn main() { dotenv().ok(); - let database_url: String = get_environment_variable("AXUM_TECHEMPOWER_DATABASE_URL"); - let max_pool_size: u32 = get_environment_variable("AXUM_TECHEMPOWER_MAX_POOL_SIZE"); - let min_pool_size: u32 = get_environment_variable("AXUM_TECHEMPOWER_MIN_POOL_SIZE"); + let database_url: String = get_env("POSTGRES_URL"); + let max_pool_size: u32 = get_env("POSTGRES_MAX_POOL_SIZE"); + let min_pool_size: u32 = get_env("POSTGRES_MIN_POOL_SIZE"); - // setup connection pool - let pool = create_pool(database_url, max_pool_size, min_pool_size).await; + let state = AppState { + db: create_pool(database_url, max_pool_size, min_pool_size).await, + cache: Arc::new(Cache::new(10_000)) + }; - let app = router(pool).await; + // Prime the cache with CachedWorld objects + preload_cache(&state).await; - server::builder() - .serve(app.into_make_service()) - .await - .unwrap(); -} - -async fn router(pool: PgPool) -> Router { - let server_header_value = HeaderValue::from_static("Axum"); - - Router::new() + let app = Router::new() .route("/fortunes", get(fortunes)) .route("/db", get(db)) - .with_state(pool) - .layer(SetResponseHeaderLayer::if_not_present( - header::SERVER, - server_header_value, - )) + .route("/queries", get(queries)) + .route("/cached-queries", get(cache)) + .with_state(state); + + server::serve_hyper(app, Some(8000)).await } diff --git a/frameworks/Rust/axum/src/models_common.rs b/frameworks/Rust/axum/src/models_common.rs deleted file mode 100644 index 9aed68955a4..00000000000 --- a/frameworks/Rust/axum/src/models_common.rs +++ /dev/null @@ -1,6 +0,0 @@ -use serde::Serialize; - -#[derive(Serialize)] -pub struct Message { - pub message: &'static str, -} diff --git a/frameworks/Rust/axum/src/models_mongo.rs b/frameworks/Rust/axum/src/models_mongo.rs deleted file mode 100644 index 31c76cc7c07..00000000000 --- a/frameworks/Rust/axum/src/models_mongo.rs +++ /dev/null @@ -1,20 +0,0 @@ -use serde::{Deserialize, Serialize}; - -#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] -pub struct Fortune { - pub id: i32, - pub message: String, -} - -#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] -pub struct FortuneInfo { - pub id: i32, - pub message: String, -} - -#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] -pub struct World { - pub id: i32, - #[serde(rename = "randomNumber")] - pub random_number: i32, -} diff --git a/frameworks/Rust/axum/src/mongo/database.rs b/frameworks/Rust/axum/src/mongo/database.rs new file mode 100644 index 00000000000..85d0e5c9221 --- /dev/null +++ b/frameworks/Rust/axum/src/mongo/database.rs @@ -0,0 +1,108 @@ +use std::{convert::Infallible, io}; + +use axum::{extract::FromRequestParts, http::request::Parts}; +use futures_util::{stream::FuturesUnordered, StreamExt, TryStreamExt}; +use mongodb::{bson::doc, Database}; +use rand::rngs::SmallRng; + +use crate::common::{models::{Fortune, World}, random_ids}; + +pub struct DatabaseConnection(pub Database); + +impl FromRequestParts for DatabaseConnection { + type Rejection = Infallible; + + async fn from_request_parts( + _parts: &mut Parts, + db: &Database, + ) -> Result { + Ok(Self(db.clone())) + } +} + +#[derive(Debug)] +#[allow(dead_code)] +pub enum MongoError { + Io(io::Error), + Mongo(mongodb::error::Error), +} + +impl From for MongoError { + fn from(err: io::Error) -> Self { + MongoError::Io(err) + } +} + +impl From for MongoError { + fn from(err: mongodb::error::Error) -> Self { + MongoError::Mongo(err) + } +} + +pub async fn find_world_by_id(db: Database, id: i32) -> Result { + let world_collection = db.collection::("world"); + + let filter = doc! { "_id": id as f32 }; + + let world: World = world_collection + .find_one(filter) + .await + .unwrap() + .expect("expected world, found none"); + Ok(world) +} + +pub async fn find_worlds(db: Database, rng: &mut SmallRng, count: usize) -> Result, MongoError> { + let future_worlds = FuturesUnordered::new(); + + for id in random_ids(rng, count) { + future_worlds.push(find_world_by_id(db.clone(), id)); + } + + let worlds: Result, MongoError> = future_worlds.try_collect().await; + worlds +} + +pub async fn fetch_fortunes(db: Database) -> Result, MongoError> { + let fortune_collection = db.collection::("fortune"); + + let mut fortune_cursor = fortune_collection + .find(doc! {}) + .await + .expect("fortunes could not be loaded"); + + let mut fortunes: Vec = Vec::new(); + + while let Some(doc) = fortune_cursor.next().await { + fortunes.push(doc.expect("could not load fortune")); + } + + fortunes.push(Fortune { + id: 0, + message: "Additional fortune added at request time.".to_string(), + }); + + fortunes.sort_by(|a, b| a.message.cmp(&b.message)); + Ok(fortunes) +} + +pub async fn update_worlds( + db: Database, + worlds: Vec, +) -> Result { + let mut updates = Vec::new(); + + for world in worlds { + updates.push(doc! { + "q": { "id": world.id }, "u": { "$set": { "randomNumber": world.random_number }} + }); + } + + db.run_command( + doc! {"update": "world", "updates": updates, "ordered": false} + ) + .await + .expect("could not update worlds"); + + Ok(true) +} diff --git a/frameworks/Rust/axum/src/mongo/mod.rs b/frameworks/Rust/axum/src/mongo/mod.rs new file mode 100644 index 00000000000..8fd0a6be869 --- /dev/null +++ b/frameworks/Rust/axum/src/mongo/mod.rs @@ -0,0 +1 @@ +pub mod database; diff --git a/frameworks/Rust/axum/src/mongo_raw/database.rs b/frameworks/Rust/axum/src/mongo_raw/database.rs new file mode 100644 index 00000000000..72642894db8 --- /dev/null +++ b/frameworks/Rust/axum/src/mongo_raw/database.rs @@ -0,0 +1,102 @@ +use std::{convert::Infallible, io}; + +use axum::{extract::FromRequestParts, http::request::Parts}; +use futures_util::{stream::FuturesUnordered, TryStreamExt}; +use mongodb::{ + bson::{doc, RawDocumentBuf}, + Database, +}; +use rand::rngs::SmallRng; + +use crate::common::{models::World, random_ids}; + +pub struct DatabaseConnection(pub Database); + +impl FromRequestParts for DatabaseConnection { + type Rejection = Infallible; + + async fn from_request_parts( + _parts: &mut Parts, + db: &Database, + ) -> Result { + Ok(Self(db.clone())) + } +} + +#[derive(Debug)] +#[allow(dead_code)] +pub enum MongoError { + Io(io::Error), + Mongo(mongodb::error::Error), +} + +impl From for MongoError { + fn from(err: io::Error) -> Self { + MongoError::Io(err) + } +} + +impl From for MongoError { + fn from(err: mongodb::error::Error) -> Self { + MongoError::Mongo(err) + } +} + +pub async fn find_world_by_id(db: Database, id: i32) -> Result { + let world_collection = db.collection::("world"); + + let filter = doc! { "_id": id as f32 }; + + let raw: RawDocumentBuf = world_collection + .find_one(filter) + .await + .unwrap() + .expect("expected world, found none"); + + Ok(World { + id: raw + .get("id") + .expect("expected to parse world id") + .expect("could not get world id") + .as_i32() + .expect("could not extract world id"), + random_number: raw + .get("id") + .expect("expected to parse world id") + .expect("could not get world id") + .as_i32() + .expect("could not extract world id"), + }) +} + +pub async fn find_worlds(db: Database, rng: &mut SmallRng, count: usize) -> Result, MongoError> { + let future_worlds = FuturesUnordered::new(); + + for id in random_ids(rng, count) { + future_worlds.push(find_world_by_id(db.clone(), id)); + } + + let worlds: Result, MongoError> = future_worlds.try_collect().await; + worlds +} + +pub async fn update_worlds( + db: Database, + worlds: Vec, +) -> Result { + let mut updates = Vec::new(); + + for world in worlds { + updates.push(doc! { + "q": { "id": world.id }, "u": { "$set": { "randomNumber": world.random_number }} + }); + } + + db.run_command( + doc! {"update": "world", "updates": updates, "ordered": false} + ) + .await + .expect("could not update worlds"); + + Ok(true) +} diff --git a/frameworks/Rust/axum/src/mongo_raw/mod.rs b/frameworks/Rust/axum/src/mongo_raw/mod.rs new file mode 100644 index 00000000000..8fd0a6be869 --- /dev/null +++ b/frameworks/Rust/axum/src/mongo_raw/mod.rs @@ -0,0 +1 @@ +pub mod database; diff --git a/frameworks/Rust/axum/src/pg/database.rs b/frameworks/Rust/axum/src/pg/database.rs new file mode 100644 index 00000000000..fcfcec520b7 --- /dev/null +++ b/frameworks/Rust/axum/src/pg/database.rs @@ -0,0 +1,150 @@ +use std::{borrow::Cow, convert::Infallible, io, sync::Arc}; + +use axum::{extract::FromRequestParts, http::request::Parts}; +use futures::{stream::futures_unordered::FuturesUnordered, StreamExt, TryStreamExt}; +use rand::{rngs::SmallRng, rng, SeedableRng}; +use tokio::pin; +use tokio_postgres::{connect, Client, NoTls, Statement}; + +use crate::common::{self, random_id, random_ids}; + +use super::models::{Fortune, World}; + +#[derive(Debug)] +#[allow(dead_code)] +pub enum PgError { + Io(io::Error), + Pg(tokio_postgres::Error), +} + +impl From for PgError { + fn from(err: io::Error) -> Self { + PgError::Io(err) + } +} + +impl From for PgError { + fn from(err: tokio_postgres::Error) -> Self { + PgError::Pg(err) + } +} + +/// Postgres interface +pub struct PgConnection { + client: Client, + fortune: Statement, + world: Statement, + updates: Statement, +} + +impl PgConnection { + pub async fn connect(db_url: String) -> Arc { + let (cl, conn) = connect(&db_url, NoTls) + .await + .expect("cannot connect to postgresql."); + + // Spawn connection + tokio::spawn(async move { + if let Err(error) = conn.await { + eprintln!("database connection error: {error}"); + } + }); + + // Prepare statements for the connection. + let fortune = cl.prepare(common::SELECT_ALL_FORTUNES).await.unwrap(); + let world = cl.prepare(common::SELECT_WORLD_BY_ID).await.unwrap(); + let updates = cl.prepare(common::UPDATE_WORLDS).await.unwrap(); + + Arc::new(PgConnection { + client: cl, + fortune, + world, + updates, + }) + } +} + +impl PgConnection { + pub async fn fetch_world_by_id(&self, id: i32) -> Result { + self.client + .query_one(&self.world, &[&id]) + .await + .map(|row| { + Ok(World { + id: row.get(0), + randomnumber: row.get(1), + }) + })? + } + + pub async fn fetch_random_worlds(&self, num: usize) -> Result, PgError> { + let mut rng = SmallRng::from_rng(&mut rng()); + + let futures = FuturesUnordered::new(); + + for id in random_ids(&mut rng, num) { + futures.push(self.fetch_world_by_id(id)); + } + + futures.try_collect().await + } + + pub async fn update_worlds(&self, num: usize) -> Result, PgError> { + let mut worlds = self.fetch_random_worlds(num).await?; + + // Update the worlds with new random numbers + let mut rng = SmallRng::from_rng(&mut rng()); + let mut ids = Vec::with_capacity(num); + let mut nids = Vec::with_capacity(num); + + for w in &mut worlds { + w.randomnumber = random_id(&mut rng); + ids.push(&w.id); + nids.push(&w.randomnumber); + } + + // Update the random worlds in the database. + self.client + .execute(&self.updates, &[&ids, &nids]) + .await?; + + Ok(worlds) + } + + pub async fn fetch_all_fortunes(&self) -> Result, PgError> { + let mut fortunes = vec![Fortune { + id: 0, + message: Cow::Borrowed("Additional fortune added at request time."), + }]; + + let rows = self + .client + .query_raw::<_, _, &[i32; 0]>(&self.fortune, &[]) + .await?; + + pin!(rows); + + while let Some(row) = rows.next().await.transpose()? { + fortunes.push(Fortune { + id: row.get(0), + message: Cow::Owned(row.get(1)), + }); + } + + fortunes.sort_by(|it, next| it.message.cmp(&next.message)); + Ok(fortunes) + } +} + +pub struct DatabaseConnection(pub Arc); + +impl FromRequestParts> for DatabaseConnection { + type Rejection = Infallible; + + async fn from_request_parts( + _parts: &mut Parts, + pg_connection: &Arc, + ) -> Result { + Ok(Self(pg_connection.clone())) + } +} diff --git a/frameworks/Rust/axum/src/pg/mod.rs b/frameworks/Rust/axum/src/pg/mod.rs new file mode 100644 index 00000000000..c51e02d23d3 --- /dev/null +++ b/frameworks/Rust/axum/src/pg/mod.rs @@ -0,0 +1,2 @@ +pub mod database; +pub mod models; diff --git a/frameworks/Rust/axum/src/pg/models.rs b/frameworks/Rust/axum/src/pg/models.rs new file mode 100644 index 00000000000..63d0dd081aa --- /dev/null +++ b/frameworks/Rust/axum/src/pg/models.rs @@ -0,0 +1,18 @@ +use std::borrow::Cow; + +use serde::{Deserialize, Serialize}; + +#[allow(non_snake_case)] +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] +pub struct Fortune { + pub id: i32, + pub message: Cow<'static, str>, +} + +#[allow(non_snake_case)] +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] +pub struct World { + pub id: i32, + #[serde(rename = "randomNumber")] + pub randomnumber: i32, +} diff --git a/frameworks/Rust/axum/src/pg_pool/database.rs b/frameworks/Rust/axum/src/pg_pool/database.rs new file mode 100644 index 00000000000..cf32fa1558b --- /dev/null +++ b/frameworks/Rust/axum/src/pg_pool/database.rs @@ -0,0 +1,94 @@ +use std::io; + +use crate::{ + common::utils::internal_error, + pg_pool::models::{Fortune, World}, +}; +use axum::{ + extract::FromRequestParts, + http::{request::Parts, StatusCode}, +}; +use deadpool_postgres::{Client, Manager, ManagerConfig, RecyclingMethod}; +use futures_util::StreamExt; +use tokio::pin; +use tokio_pg_mapper::FromTokioPostgresRow; +use tokio_postgres::{NoTls, Row, Statement}; + +#[derive(Debug)] +#[allow(dead_code)] +pub enum PgError { + Io(io::Error), + Pg(tokio_postgres::Error), +} + +impl From for PgError { + fn from(err: io::Error) -> Self { + PgError::Io(err) + } +} + +impl From for PgError { + fn from(err: tokio_postgres::Error) -> Self { + PgError::Pg(err) + } +} + +pub async fn create_pool( + database_url: String, + max_pool_size: u32, +) -> deadpool_postgres::Pool { + let pg_config: tokio_postgres::Config = + database_url.parse().expect("invalid database url"); + + let mgr_config = ManagerConfig { + recycling_method: RecyclingMethod::Fast, + }; + let mgr = Manager::from_config(pg_config, NoTls, mgr_config); + let pool: deadpool_postgres::Pool = deadpool_postgres::Pool::builder(mgr) + .max_size(max_pool_size as usize) + .build() + .unwrap(); + + pool +} + +pub struct DatabaseClient(pub Client); + +impl FromRequestParts for DatabaseClient { + type Rejection = (StatusCode, String); + + async fn from_request_parts( + _parts: &mut Parts, + pool: &deadpool_postgres::Pool, + ) -> Result { + let conn = pool.get().await.map_err(internal_error)?; + + Ok(Self(conn)) + } +} + +pub async fn fetch_world_by_id( + client: &Client, + id: i32, + select: &Statement, +) -> Result { + let row: Row = client.query_one(select, &[&id]).await.unwrap(); + + Ok(World::from_row(row).unwrap()) +} + +pub async fn fetch_all_fortunes( + client: Client, + select: &Statement, +) -> Result, PgError> { + let mut fortunes: Vec = Vec::new(); + let rows = client.query_raw::<_, _, &[i32; 0]>(select, &[]).await?; + pin!(rows); + + while let Some(row) = rows.next().await.transpose()? { + fortunes + .push(Fortune::from_row(row).expect("could not convert row to fortune.")); + } + + Ok(fortunes) +} diff --git a/frameworks/Rust/axum/src/pg_pool/mod.rs b/frameworks/Rust/axum/src/pg_pool/mod.rs new file mode 100644 index 00000000000..c51e02d23d3 --- /dev/null +++ b/frameworks/Rust/axum/src/pg_pool/mod.rs @@ -0,0 +1,2 @@ +pub mod database; +pub mod models; diff --git a/frameworks/Rust/axum/src/models_pg_pool.rs b/frameworks/Rust/axum/src/pg_pool/models.rs similarity index 100% rename from frameworks/Rust/axum/src/models_pg_pool.rs rename to frameworks/Rust/axum/src/pg_pool/models.rs diff --git a/frameworks/Rust/axum/src/server.rs b/frameworks/Rust/axum/src/server.rs index 29e165f6f5c..52705143dba 100644 --- a/frameworks/Rust/axum/src/server.rs +++ b/frameworks/Rust/axum/src/server.rs @@ -1,37 +1,130 @@ use std::{ + future::Future, io, - net::{Ipv4Addr, SocketAddr}, + net::{Ipv4Addr, SocketAddr, TcpListener}, }; -use hyper::server::conn::AddrIncoming; -use tokio::net::{TcpListener, TcpSocket}; - -pub fn builder() -> hyper::server::Builder { - let addr = SocketAddr::from((Ipv4Addr::UNSPECIFIED, 8000)); - let listener = reuse_listener(addr).expect("couldn't bind to addr"); - let incoming = AddrIncoming::from_listener(listener).unwrap(); +use axum::{ + http::{header, HeaderValue}, + Router, +}; - println!("Started axum server at 8000"); +use hyper::body::Incoming; +use hyper::Request; +use hyper_util::rt::{TokioExecutor, TokioIo}; +use tower::Service; +use tower_http::set_header::SetResponseHeaderLayer; - axum::Server::builder(incoming) - .http1_only(true) - .tcp_nodelay(true) -} +use socket2::{Domain, Socket, Type}; -fn reuse_listener(addr: SocketAddr) -> io::Result { +/// Reuse an existing listener, ensuring that the socket `backlog`` +/// is set to enable a higher number of pending connections. +fn set_socket_options(addr: SocketAddr) -> io::Result { let socket = match addr { - SocketAddr::V4(_) => TcpSocket::new_v4()?, - SocketAddr::V6(_) => TcpSocket::new_v6()?, + SocketAddr::V4(_) => Socket::new(Domain::IPV4, Type::STREAM, None)?, + SocketAddr::V6(_) => Socket::new(Domain::IPV6, Type::STREAM, None)?, }; - #[cfg(unix)] - { - if let Err(e) = socket.set_reuseport(true) { - eprintln!("error setting SO_REUSEPORT: {e}"); - } + socket.set_reuse_port(true)?; + socket.set_reuse_address(true)?; + socket.set_nonblocking(true)?; + socket.set_nodelay(true)?; + socket.bind(&addr.into())?; + socket.listen(4096)?; + + let listener: TcpListener = socket.into(); + tokio::net::TcpListener::from_std(listener) +} + +/// Build an Axum server with consistent configuration, using the high-level API exposed +/// by Axum 0.8. This is intended for convenience and intentionally does not provide much +/// customisability. +#[allow(dead_code)] +pub async fn serve(app: Router<()>, port: Option) { + let port = port.unwrap_or(8000); + let addr = SocketAddr::from((Ipv4Addr::UNSPECIFIED, port)); + let listener = set_socket_options(addr).expect("couldn't bind to address"); + println!("started axum server on port {port}."); + + let server_header_value = HeaderValue::from_static("Axum"); + let app = app.layer(SetResponseHeaderLayer::overriding( + header::SERVER, + server_header_value, + )); + + axum::serve(listener, app.into_make_service()) + .await + .unwrap(); +} + +/// Build an Axum server using the lower-level Hyper APIs for more +/// configurability. This has a few optimisations, including: +/// * Serving HTTP/1 only. +/// * Disabling connection upgrades (websockets are not needed). +/// * Setting TCP_NODELAY on the input stream. +/// * Aggregating flushes to better support pipelined responses. +/// +/// See for more details: +/// * https://github.com/tokio-rs/axum/blob/1ac617a1b540e8523347f5ee889d65cad9a45ec4/examples/serve-with-hyper/src/main.rs +#[allow(dead_code)] +pub async fn serve_hyper(app: Router<()>, port: Option) { + let port = port.unwrap_or(8000); + let addr = SocketAddr::from((Ipv4Addr::UNSPECIFIED, port)); + let listener = set_socket_options(addr).expect("couldn't bind to address"); + println!("started axum server on port {port}."); + + let server_header_value = HeaderValue::from_static("Axum"); + let app = app.layer(SetResponseHeaderLayer::overriding( + header::SERVER, + server_header_value, + )); + + // Continuously accept new connections. + loop { + let (socket, _remote_addr) = listener.accept().await.unwrap(); + socket + .set_nodelay(true) + .expect("could not set TCP_NODELAY!"); + + let tower_service = app.clone(); + tokio::spawn(async move { + let socket = TokioIo::new(socket); + + let hyper_service = + hyper::service::service_fn(move |request: Request| { + tower_service.clone().call(request) + }); + + if (hyper_util::server::conn::auto::Builder::new(TokioExecutor::new()) + .http1() + .pipeline_flush(true) + .serve_connection(socket, hyper_service) + .await) + .is_err() + {} + }); } +} - socket.set_reuseaddr(true)?; - socket.bind(addr)?; - socket.listen(1024) +/// Start a single-threaded tokio runtime on multiple threads. +#[allow(dead_code)] +pub fn start_tokio(f: fn() -> Fut) +where + Fut: Future + 'static, +{ + let rt = tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .unwrap(); + + for _ in 1..num_cpus::get() { + std::thread::spawn(move || { + let rt = tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .unwrap(); + rt.block_on(f()); + }); + } + rt.block_on(f()); } diff --git a/frameworks/Rust/axum/src/sqlx/database.rs b/frameworks/Rust/axum/src/sqlx/database.rs new file mode 100644 index 00000000000..1d824144696 --- /dev/null +++ b/frameworks/Rust/axum/src/sqlx/database.rs @@ -0,0 +1,36 @@ +use std::io; + +use sqlx::{postgres::PgPoolOptions, PgPool}; + +#[derive(Debug)] +#[allow(dead_code)] +pub enum PgError { + Io(io::Error), + Pg(sqlx::Error), +} + +impl From for PgError { + fn from(err: io::Error) -> Self { + PgError::Io(err) + } +} + +impl From for PgError { + fn from(err: sqlx::Error) -> Self { + PgError::Pg(err) + } +} + +pub async fn create_pool( + database_url: String, + max_pool_size: u32, + min_pool_size: u32, +) -> PgPool { + PgPoolOptions::new() + .max_connections(max_pool_size) + .min_connections(min_pool_size) + .test_before_acquire(false) + .connect(&database_url) + .await + .unwrap() +} diff --git a/frameworks/Rust/axum/src/sqlx/mod.rs b/frameworks/Rust/axum/src/sqlx/mod.rs new file mode 100644 index 00000000000..c51e02d23d3 --- /dev/null +++ b/frameworks/Rust/axum/src/sqlx/mod.rs @@ -0,0 +1,2 @@ +pub mod database; +pub mod models; diff --git a/frameworks/Rust/axum/src/sqlx/models.rs b/frameworks/Rust/axum/src/sqlx/models.rs new file mode 100644 index 00000000000..a3b4e174bf3 --- /dev/null +++ b/frameworks/Rust/axum/src/sqlx/models.rs @@ -0,0 +1,28 @@ +use std::borrow::Cow; + +use serde::{Deserialize, Serialize}; +use sqlx::{FromRow, Row}; +use sqlx::postgres::PgRow; + +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] +pub struct Fortune { + pub id: i32, + pub message: Cow<'static, str>, +} + +impl FromRow<'_, PgRow> for Fortune { + fn from_row(row: &PgRow) -> Result { + Ok(Fortune { + id: row.try_get(0usize)?, + message: Cow::Owned(row.try_get(1usize)?) + }) + } +} + +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize, FromRow)] +pub struct World { + pub id: i32, + #[sqlx(rename = "randomnumber")] + #[serde(rename = "randomNumber")] + pub random_number: i32, +} diff --git a/frameworks/Rust/axum/src/utils.rs b/frameworks/Rust/axum/src/utils.rs deleted file mode 100644 index 89ecaeae6ab..00000000000 --- a/frameworks/Rust/axum/src/utils.rs +++ /dev/null @@ -1,71 +0,0 @@ -use std::{env, fmt::Debug, str::FromStr}; - -use axum::{ - body::{Bytes, Full}, - http::{header, HeaderValue, StatusCode}, - response::{IntoResponse, Response}, -}; -use rand::{rngs::SmallRng, Rng}; -use serde::Deserialize; - -pub fn get_environment_variable(key: &str) -> T -where - ::Err: Debug, -{ - env::var(key) - .unwrap_or_else(|_| panic!("{key} environment variable was not set")) - .parse::() - .unwrap_or_else(|_| panic!("could not parse {key}")) -} - -#[derive(Debug, Deserialize)] -pub struct Params { - queries: Option, -} - -#[allow(dead_code)] -pub fn random_number(rng: &mut SmallRng) -> i32 { - (rng.gen::() % 10_000 + 1) as i32 -} - -#[allow(dead_code)] -pub fn parse_params(params: Params) -> i32 { - params - .queries - .and_then(|q| q.parse().ok()) - .unwrap_or(1) - .clamp(1, 500) -} - -/// Utility function for mapping any error into a `500 Internal Server Error` -/// response. -#[allow(dead_code)] -pub fn internal_error(err: E) -> (StatusCode, String) -where - E: std::error::Error, -{ - (StatusCode::INTERNAL_SERVER_ERROR, err.to_string()) -} - -#[derive(Clone, Copy, Debug)] -pub struct Utf8Html(pub T); - -impl IntoResponse for Utf8Html -where - T: Into>, -{ - fn into_response(self) -> Response { - let mut res = (StatusCode::OK, self.0.into()).into_response(); - res.headers_mut().insert( - header::CONTENT_TYPE, - HeaderValue::from_static("text/html; charset=utf-8"), - ); - res - } -} - -impl From for Utf8Html { - fn from(inner: T) -> Self { - Self(inner) - } -} diff --git a/frameworks/Rust/gotham/benchmark_config.json b/frameworks/Rust/gotham/benchmark_config.json index 2ee7db2a39f..8813ea15eed 100755 --- a/frameworks/Rust/gotham/benchmark_config.json +++ b/frameworks/Rust/gotham/benchmark_config.json @@ -19,6 +19,7 @@ "database_os": "Linux", "display_name": "Gotham", "notes": "", + "tags": ["broken"], "versus": "None" } } diff --git a/frameworks/Rust/hyper/.dockerignore b/frameworks/Rust/hyper/.dockerignore new file mode 100644 index 00000000000..2f7896d1d13 --- /dev/null +++ b/frameworks/Rust/hyper/.dockerignore @@ -0,0 +1 @@ +target/ diff --git a/frameworks/Rust/hyper/Cargo.lock b/frameworks/Rust/hyper/Cargo.lock index a8cdf6d1bb0..e0f90aad74a 100644 --- a/frameworks/Rust/hyper/Cargo.lock +++ b/frameworks/Rust/hyper/Cargo.lock @@ -1,89 +1,201 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +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 = "anstream" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" + +[[package]] +name = "anstyle-parse" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" +dependencies = [ + "anstyle", + "once_cell", + "windows-sys 0.59.0", +] [[package]] name = "async-trait" -version = "0.1.64" +version = "0.1.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd7fce9ba8c3c042128ce72d8b2ddbf3a05747efb67ea0313c635e10bda47a2" +checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" dependencies = [ - "proc-macro2 1.0.51", - "quote 1.0.23", - "syn 1.0.108", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "autocfg" -version = "1.1.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[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.13.1" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bitflags" -version = "1.3.2" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" [[package]] name = "block-buffer" -version = "0.10.3" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ "generic-array", ] [[package]] -name = "buf-min" -version = "0.1.1" +name = "bumpalo" +version = "3.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6ae7069aad07c7cdefe6a22a671f00650728bd2331a4cc62e1e5d0becdf9ca4" -dependencies = [ - "bytes 0.5.6", -] +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" [[package]] name = "byteorder" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "0.5.6" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" [[package]] -name = "bytes" -version = "1.4.0" +name = "cfg-if" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] -name = "cfg-if" -version = "0.1.10" +name = "clap" +version = "4.5.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +checksum = "6088f3ae8c3608d19260cd7445411865a485688711b78b5be70d78cd96136f83" +dependencies = [ + "clap_builder", + "clap_derive", +] [[package]] -name = "cfg-if" -version = "1.0.0" +name = "clap_builder" +version = "4.5.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "22a7ef7f676155edfb82daa97f99441f3ebf4a58d5e32f295a56259f1b6facc8" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", + "terminal_size", +] + +[[package]] +name = "clap_derive" +version = "4.5.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" + +[[package]] +name = "colorchoice" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "cpufeatures" -version = "0.2.5" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" dependencies = [ "libc", ] @@ -98,23 +210,73 @@ dependencies = [ "typenum", ] +[[package]] +name = "deadpool" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ed5957ff93768adf7a65ab167a17835c3d2c3c50d084fe305174c112f468e2f" +dependencies = [ + "deadpool-runtime", + "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.15", + "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.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", "crypto-common", "subtle", ] +[[package]] +name = "errno" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + [[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.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + [[package]] name = "fnv" version = "1.0.7" @@ -123,9 +285,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "futures-channel" -version = "0.3.26" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e5317663a9089767a1ec00a487df42e0ca174b61b4483213ac24448e4664df5" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -133,38 +295,38 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.26" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec90ff4d0fe1f57d600049061dc6bb68ed03c7d2fbd697274c41805dcb3f8608" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-macro" -version = "0.3.26" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95a73af87da33b5acf53acfebdc339fe592ecf5357ac7c0a7734ab9d8c876a70" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ - "proc-macro2 1.0.51", - "quote 1.0.23", - "syn 1.0.108", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "futures-sink" -version = "0.3.26" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f310820bb3e8cfd46c80db4d7fb8353e15dfff853a127158425f31e0be6c8364" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.26" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf79a1bf610b10f42aea489289c5a2c478a786509693b80cd39c44ccd936366" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" -version = "0.3.26" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c1d6de3acfef38d2be4b1f543f553131788603495be83da675e180c8d6b7bd1" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-core", "futures-macro", @@ -177,34 +339,57 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.6" +version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", - "version_check 0.9.4", + "version_check", ] [[package]] name = "getrandom" -version = "0.2.8" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", + "js-sys", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen", ] [[package]] -name = "hermit-abi" -version = "0.2.6" +name = "getrandom" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" dependencies = [ + "cfg-if", "libc", + "r-efi", + "wasi 0.14.2+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 = "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 = "hmac" version = "0.12.1" @@ -216,47 +401,58 @@ dependencies = [ [[package]] name = "http" -version = "0.2.9" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" dependencies = [ - "bytes 1.4.0", + "bytes", "fnv", "itoa", ] [[package]] name = "http-body" -version = "0.4.5" +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 = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ - "bytes 1.4.0", + "bytes", + "futures-core", "http", + "http-body", "pin-project-lite", ] [[package]] name = "httparse" -version = "1.8.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] name = "httpdate" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "0.14.24" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e011372fa0b68db8350aa7a248930ecc7839bf46d8485577d69f117a75f164c" +checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" dependencies = [ - "bytes 1.4.0", + "bytes", "futures-channel", - "futures-core", "futures-util", "http", "http-body", @@ -264,45 +460,97 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", + "smallvec", "tokio", - "tower-service", - "tracing", - "want", ] [[package]] name = "hyper-techempower" version = "0.5.0" dependencies = [ + "clap", + "deadpool-postgres", + "fastrand", + "http", + "http-body-util", "hyper", + "hyper-util", "log", "markup", - "net2", "num_cpus", "serde", "serde_json", + "socket2", + "strum", + "thiserror", "tokio", "tokio-postgres", + "tracing", + "tracing-subscriber", "v_htmlescape", ] +[[package]] +name = "hyper-util" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" +dependencies = [ + "bytes", + "futures-util", + "http", + "http-body", + "hyper", + "pin-project-lite", + "tokio", + "tower-service", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + [[package]] name = "itoa" -version = "1.0.5" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[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 = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.139" +version = "0.2.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" +checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" + +[[package]] +name = "linux-raw-sys" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413" [[package]] name = "lock_api" -version = "0.4.9" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", @@ -310,102 +558,105 @@ dependencies = [ [[package]] name = "log" -version = "0.4.17" +version = "0.4.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if 1.0.0", -] +checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" [[package]] name = "markup" -version = "0.3.1" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "360ec4d83ae8c3150530220fd89e0c5dba54cfc8d7675695f1fdc3581880dce9" +checksum = "74a887ad620fe1022257343ac77fcdd3720e92888e1b2e66e1b7a4707f453898" dependencies = [ "markup-proc-macro", ] [[package]] name = "markup-proc-macro" -version = "0.3.1" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba9c3711ed5187a843aaa960eb78db98f64d76ea22a47c204ca2affb3904bb92" +checksum = "9ab6ee21fd1855134cacf2f41afdf45f1bc456c7d7f6165d763b4647062dd2be" dependencies = [ - "proc-macro2 0.4.30", - "quote 0.6.13", - "syn 0.15.44", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "md-5" -version = "0.10.5" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6365506850d44bff6e2fbcb5176cf63650e48bd45ef2fe2665ae1570e0f4b9ca" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" dependencies = [ + "cfg-if", "digest", ] [[package]] name = "memchr" -version = "2.5.0" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] -name = "mio" -version = "0.8.6" +name = "miniz_oxide" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" +checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5" dependencies = [ - "libc", - "log", - "wasi", - "windows-sys 0.45.0", + "adler2", ] [[package]] -name = "net2" -version = "0.2.38" +name = "mio" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d0df99cfcd2530b2e694f6e17e7f37b8e26bb23983ac530c0c97408837c631" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ - "cfg-if 0.1.10", "libc", - "winapi", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.52.0", ] [[package]] -name = "nom" -version = "4.2.3" +name = "nu-ansi-term" +version = "0.50.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6" +checksum = "d4a28e057d01f97e61255210fcff094d74ed0466038633e95017f5beb68e4399" dependencies = [ - "memchr", - "version_check 0.1.5", + "windows-sys 0.52.0", ] [[package]] name = "num_cpus" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" 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 = "once_cell" -version = "1.17.1" +version = "1.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc" [[package]] name = "parking_lot" -version = "0.12.1" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", @@ -413,46 +664,46 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.7" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-sys 0.45.0", + "windows-targets", ] [[package]] name = "percent-encoding" -version = "2.2.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "phf" -version = "0.11.1" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "928c6535de93548188ef63bb7c4036bd415cd8f36ad25af44b9789b2ee72a48c" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" dependencies = [ "phf_shared", ] [[package]] name = "phf_shared" -version = "0.11.1" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1fb5f6f826b772a8d4c0394209441e7d37cbbb967ae9c7e0e8134365c9ee676" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" dependencies = [ "siphasher", ] [[package]] name = "pin-project-lite" -version = "0.2.9" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "pin-utils" @@ -462,13 +713,13 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "postgres-protocol" -version = "0.6.4" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "878c6cbf956e03af9aa8204b407b9cbf47c072164800aa918c516cd4b056c50c" +checksum = "76ff0abab4a9b844b93ef7b81f1efc0a366062aaef2cd702c76256b5dc075c54" dependencies = [ "base64", "byteorder", - "bytes 1.4.0", + "bytes", "fallible-iterator", "hmac", "md-5", @@ -480,73 +731,64 @@ dependencies = [ [[package]] name = "postgres-types" -version = "0.2.4" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73d946ec7d256b04dfadc4e6a3292324e6f417124750fc5c0950f981b703a0f1" +checksum = "613283563cd90e1dfc3518d548caee47e0e725455ed619881f5cf21f36de4b48" dependencies = [ - "bytes 1.4.0", + "bytes", "fallible-iterator", "postgres-protocol", ] [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "proc-macro2" -version = "0.4.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ - "unicode-xid", + "zerocopy", ] [[package]] name = "proc-macro2" -version = "1.0.51" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" +checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "0.6.13" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ - "proc-macro2 0.4.30", + "proc-macro2", ] [[package]] -name = "quote" -version = "1.0.23" +name = "r-efi" +version = "5.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" -dependencies = [ - "proc-macro2 1.0.51", -] +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" [[package]] name = "rand" -version = "0.8.5" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" dependencies = [ - "libc", "rand_chacha", "rand_core", + "zerocopy", ] [[package]] name = "rand_chacha" -version = "0.3.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", "rand_core", @@ -554,150 +796,243 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.6.4" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom", + "getrandom 0.3.2", ] [[package]] name = "redox_syscall" -version = "0.2.16" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1" dependencies = [ "bitflags", ] +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustix" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e56a18552996ac8d29ecc3b190b4fdbb2d91ca4ec396de7bbffaf43f3d637e96" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustversion" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" + [[package]] name = "ryu" -version = "1.0.12" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "scopeguard" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" -version = "1.0.152" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.152" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ - "proc-macro2 1.0.51", - "quote 1.0.23", - "syn 1.0.108", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "serde_json" -version = "1.0.93" +version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cad406b69c91885b5107daf2c29572f6c8cdb3c66826821e286c533490c0bc76" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] [[package]] name = "sha2" -version = "0.10.6" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ - "cfg-if 1.0.0", + "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 = "siphasher" -version = "0.3.10" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" [[package]] name = "slab" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] [[package]] name = "smallvec" -version = "1.10.0" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" [[package]] name = "socket2" -version = "0.4.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" +checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" dependencies = [ "libc", - "winapi", + "windows-sys 0.52.0", ] [[package]] name = "stringprep" -version = "0.1.2" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ee348cb74b87454fff4b551cbf727025810a004f88aeacae7f85b87f4e9a1c1" +checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" dependencies = [ "unicode-bidi", "unicode-normalization", + "unicode-properties", ] [[package]] -name = "subtle" -version = "2.4.1" +name = "strsim" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] -name = "syn" -version = "0.15.44" +name = "strum" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" +checksum = "f64def088c51c9510a8579e3c5d67c65349dcf755e5479ad3d010aa6454e2c32" dependencies = [ - "proc-macro2 0.4.30", - "quote 0.6.13", - "unicode-xid", + "strum_macros", ] +[[package]] +name = "strum_macros" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c77a8c5abcaf0f9ce05d62342b7d298c346515365c36b673df4ebe3ced01fde8" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + +[[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.108" +version = "2.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d56e159d99e6c2b93995d171050271edb50ecc5288fbc7cc17de8fdce4e58c14" +checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" dependencies = [ - "proc-macro2 1.0.51", - "quote 1.0.23", + "proc-macro2", + "quote", "unicode-ident", ] +[[package]] +name = "terminal_size" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45c6481c4829e4cc63825e62c49186a34538b7b2750b73b266581ffb612fb5ed" +dependencies = [ + "rustix", + "windows-sys 0.59.0", +] + +[[package]] +name = "thiserror" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + [[package]] name = "tinyvec" -version = "1.6.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" dependencies = [ "tinyvec_macros", ] @@ -710,29 +1045,28 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.25.0" +version = "1.44.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e00990ebabbe4c14c08aca901caed183ecd5c09562a12c824bb53d3c3fd3af" +checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48" dependencies = [ - "autocfg", - "bytes 1.4.0", + "backtrace", + "bytes", "libc", - "memchr", "mio", "pin-project-lite", "socket2", - "windows-sys 0.42.0", + "windows-sys 0.52.0", ] [[package]] name = "tokio-postgres" -version = "0.7.7" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29a12c1b3e0704ae7dfc25562629798b29c72e6b1d0a681b6f29ab4ae5e7f7bf" +checksum = "6c95d533c83082bb6490e0189acaa0bbeef9084e60471b696ca6988cd0541fb0" dependencies = [ "async-trait", "byteorder", - "bytes 1.4.0", + "bytes", "fallible-iterator", "futures-channel", "futures-util", @@ -743,205 +1077,273 @@ dependencies = [ "pin-project-lite", "postgres-protocol", "postgres-types", + "rand", "socket2", "tokio", "tokio-util", + "whoami", ] [[package]] name = "tokio-util" -version = "0.7.7" +version = "0.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5427d89453009325de0d8f342c9490009f76e999cb7672d77e46267448f7e6b2" +checksum = "6b9590b93e6fcc1739458317cccd391ad3955e2bde8913edf6f95f9e65a8f034" dependencies = [ - "bytes 1.4.0", + "bytes", "futures-core", "futures-sink", "pin-project-lite", "tokio", - "tracing", ] [[package]] name = "tower-service" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ - "cfg-if 1.0.0", "pin-project-lite", + "tracing-attributes", "tracing-core", ] +[[package]] +name = "tracing-attributes" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "tracing-core" -version = "0.1.30" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" dependencies = [ + "log", "once_cell", + "tracing-core", ] [[package]] -name = "try-lock" -version = "0.2.4" +name = "tracing-subscriber" +version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5" +dependencies = [ + "nu-ansi-term", + "sharded-slab", + "smallvec", + "thread_local", + "tracing-core", + "tracing-log", +] [[package]] name = "typenum" -version = "1.16.0" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" [[package]] name = "unicode-bidi" -version = "0.3.10" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54675592c1dbefd78cbd98db9bacd89886e1ca50692a0692baefffdeb92dd58" +checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" [[package]] name = "unicode-ident" -version = "1.0.6" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "unicode-normalization" -version = "0.1.22" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" dependencies = [ "tinyvec", ] [[package]] -name = "unicode-xid" -version = "0.1.0" +name = "unicode-properties" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" +checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" [[package]] -name = "v_escape" -version = "0.13.2" +name = "utf8parse" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "039a44473286eb84e4e74f90165feff67c802dbeced7ee4c5b00d719b0d0475e" -dependencies = [ - "buf-min", - "v_escape_derive", -] +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] -name = "v_escape_derive" -version = "0.8.5" +name = "v_htmlescape" +version = "0.15.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29769400af8b264944b851c961a4a6930e76604f59b1fcd51246bab6a296c8c" -dependencies = [ - "nom", - "proc-macro2 1.0.51", - "quote 1.0.23", - "syn 1.0.108", -] +checksum = "4e8257fbc510f0a46eb602c10215901938b5c2a7d5e70fc11483b1d3c9b5b18c" [[package]] -name = "v_htmlescape" -version = "0.10.4" +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasi" +version = "0.14.2+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d7c2a33ed7cf0dc1b42bcf39e01b6512f9df08f09e1cd8a49d9dc49a6a9482" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" dependencies = [ - "cfg-if 1.0.0", - "v_escape", + "wit-bindgen-rt", ] [[package]] -name = "version_check" -version = "0.1.5" +name = "wasite" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" +checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] -name = "version_check" -version = "0.9.4" +name = "wasm-bindgen" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +dependencies = [ + "cfg-if", + "once_cell", + "wasm-bindgen-macro", +] [[package]] -name = "want" -version = "0.3.0" +name = "wasm-bindgen-backend" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" dependencies = [ + "bumpalo", "log", - "try-lock", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", ] [[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +name = "wasm-bindgen-macro" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] [[package]] -name = "winapi" -version = "0.3.9" +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", + "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 = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", + "unicode-ident", ] [[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" +name = "web-sys" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +dependencies = [ + "js-sys", + "wasm-bindgen", +] [[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" +name = "whoami" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +checksum = "372d5b87f58ec45c384ba03563b03544dc5fadc3983e434b286913f5b4a9bb6d" +dependencies = [ + "redox_syscall", + "wasite", + "web-sys", +] [[package]] name = "windows-sys" -version = "0.42.0" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows-targets", ] [[package]] name = "windows-sys" -version = "0.45.0" +version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ "windows-targets", ] [[package]] name = "windows-targets" -version = "0.42.1" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" +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", @@ -950,42 +1352,77 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.1" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" -version = "0.42.1" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" -version = "0.42.1" +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 = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" -version = "0.42.1" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" -version = "0.42.1" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.1" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" -version = "0.42.1" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags", +] + +[[package]] +name = "zerocopy" +version = "0.8.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" +checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/frameworks/Rust/hyper/Cargo.toml b/frameworks/Rust/hyper/Cargo.toml index 2d3819863d7..829dadf8bcd 100644 --- a/frameworks/Rust/hyper/Cargo.toml +++ b/frameworks/Rust/hyper/Cargo.toml @@ -5,30 +5,47 @@ edition = "2018" authors = [ "Steve Klabnik ", "Alexander Polyakov ", - "Sean McArthur " + "Sean McArthur ", ] -[[bin]] -name = "hyper-techempower" -path = "src/main.rs" - -[[bin]] -name = "hyper-db-techempower" -path = "src/main_db.rs" - [dependencies] +clap = { version = "4.5.32", features = ["derive", "wrap_help"] } +deadpool-postgres = "0.14.1" +fastrand = "2.3.0" +http = "1.3.1" +http-body-util = "0.1.3" # Disable default runtime, so that tokio single thread can be used instead. -hyper = { version = "0.14", features = ["server", "http1"], default-features = false } +hyper = { version = "1.6.0", features = [ + "server", + "http1", +], default-features = false } +hyper-util = { version = "0.1.10", features = [ + "http1", + "server", + "service", + "tokio", +] } # Since no logs are allowed anyways, just compile-time turn them all off -log = { version = "0.4", features = ["release_max_level_off"] } -markup = "0.3.1" -net2 = "0.2" -num_cpus = "1.2" -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" -tokio = { version = "1", features = ["rt", "net", "time"] } -tokio-postgres = { version = "0.7", default-features = false, features = ["runtime"] } -v_htmlescape = "0.10" +log = { version = "0.4.26", features = ["release_max_level_off"] } +markup = "0.15.0" +num_cpus = "1.16.0" +serde = { version = "1.0.219", features = ["derive"] } +serde_json = "1.0.140" +socket2 = { version = "0.5.8", features = ["all"] } +strum = { version = "0.27.1", features = ["derive"] } +thiserror = "2.0.12" +tokio = { version = "1.44.2", features = [ + "rt", + "rt-multi-thread", + "net", + "time", +] } +tokio-postgres = { version = "0.7.13", default-features = false, features = [ + "runtime", +] } +tracing = "0.1.41" +tracing-subscriber = "0.3.20" +v_htmlescape = "0.15.8" [profile.release] opt-level = 3 diff --git a/frameworks/Rust/hyper/benchmark_config.json b/frameworks/Rust/hyper/benchmark_config.json index 4dab46b0554..f9f7ef8f673 100644 --- a/frameworks/Rust/hyper/benchmark_config.json +++ b/frameworks/Rust/hyper/benchmark_config.json @@ -1,9 +1,18 @@ { "framework": "hyper", + "maintainers": [ + "polachok", + "seanmonstar", + "steveklabnik" + ], "tests": [{ "default": { - "plaintext_url": "/plaintext", + "docker_cmd": "hyper-techempower --runtime current-thread", "json_url": "/json", + "plaintext_url": "/plaintext", + "db_url": "/db", + "query_url": "/queries?count=", + "fortune_url": "/fortunes", "port": 8080, "approach": "Realistic", "classification": "Micro", @@ -15,10 +24,16 @@ "webserver": "hyper", "os": "Linux", "database_os": "Linux", - "display_name": "hyper", + "display_name": "Hyper (current-thread runtime)", "notes": "" }, - "db": { + "multi-thread": { + "dockerfile": "hyper.dockerfile", + "docker_cmd": "hyper-techempower --runtime multi-thread", + "json_url": "/json", + "plaintext_url": "/plaintext", + "db_url": "/db", + "query_url": "/queries?count=", "fortune_url": "/fortunes", "port": 8080, "approach": "Realistic", @@ -31,7 +46,7 @@ "webserver": "hyper", "os": "Linux", "database_os": "Linux", - "display_name": "hyper", + "display_name": "Hyper (multi-thread runtime)", "notes": "" } }] diff --git a/frameworks/Rust/hyper/hyper-db.dockerfile b/frameworks/Rust/hyper/hyper-db.dockerfile deleted file mode 100644 index 8930ea7c28e..00000000000 --- a/frameworks/Rust/hyper/hyper-db.dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM rust:1.67 - -ADD ./ /hyper -WORKDIR /hyper - -RUN cargo clean -RUN RUSTFLAGS="-C target-cpu=native" cargo build --release - -EXPOSE 8080 - -CMD ["./target/release/hyper-db-techempower"] diff --git a/frameworks/Rust/hyper/hyper.dockerfile b/frameworks/Rust/hyper/hyper.dockerfile index e273f5c95c4..4816011104f 100644 --- a/frameworks/Rust/hyper/hyper.dockerfile +++ b/frameworks/Rust/hyper/hyper.dockerfile @@ -1,11 +1,17 @@ -FROM rust:1.67 +FROM rust:1.85 AS hyper -ADD ./ /hyper -WORKDIR /hyper +WORKDIR /src +ENV RUSTFLAGS="-C target-cpu=native" -RUN cargo clean -RUN RUSTFLAGS="-C target-cpu=native" cargo build --release +# Cache dependency builds (requires passing --force-rm False to tfb command) +COPY Cargo.toml Cargo.lock /src/ +RUN mkdir src \ + && echo "fn main() {println!(\"if you see this, the build broke\")}" > src/main.rs \ + && cargo build --release \ + && rm -rfv src/ target/release/hyper-techempower* target/release/deps/hyper_techempower* +COPY . /src/ +RUN cargo install --path . --locked EXPOSE 8080 - -CMD ["./target/release/hyper-techempower"] +CMD ["hyper-techempower"] +HEALTHCHECK CMD curl --fail http://localhost:8080/ping || exit 1 \ No newline at end of file diff --git a/frameworks/Rust/hyper/rustfmt.toml b/frameworks/Rust/hyper/rustfmt.toml new file mode 100644 index 00000000000..e37b2bf4664 --- /dev/null +++ b/frameworks/Rust/hyper/rustfmt.toml @@ -0,0 +1,4 @@ +# unstable_features +comment_width = 100 +group_imports = "StdExternalCrate" +imports_granularity = "Module" diff --git a/frameworks/Rust/hyper/src/db.rs b/frameworks/Rust/hyper/src/db.rs index d72de86f798..b6cb246af04 100644 --- a/frameworks/Rust/hyper/src/db.rs +++ b/frameworks/Rust/hyper/src/db.rs @@ -1,46 +1,21 @@ -use std::net::SocketAddr; +use std::sync::LazyLock; -use tokio::net::TcpStream; -use tokio::runtime::Handle; -use tokio_postgres::{Client, Config, NoTls, Statement}; +use deadpool_postgres::{Config, CreatePoolError, Pool}; +use tokio_postgres::NoTls; +use tracing::info; -pub struct Db { - client: Client, - fortune: Statement, -} - -pub struct Fortune { - pub id: i32, - pub message: String, -} - -pub async fn connect( - addr: SocketAddr, - config: Config, - handle: Handle, -) -> Result> { - let stream = TcpStream::connect(&addr).await?; - let (client, conn) = config.connect_raw(stream, NoTls).await?; - handle.spawn(conn); - let fortune = client.prepare("SELECT id, message FROM fortune").await?; - Ok(Db { client, fortune }) -} - -impl Db { - pub async fn tell_fortune(&self) -> Result, tokio_postgres::Error> { - let mut items = vec![Fortune { - id: 0, - message: "Additional fortune added at request time.".to_string(), - }]; +pub static POOL: LazyLock = + LazyLock::new(|| connect().expect("failed to create database connection pool")); - let rows = self.client.query(&self.fortune, &[]).await?; - for row in rows { - items.push(Fortune { - id: row.get(0), - message: row.get(1), - }); - } - items.sort_by(|it, next| it.message.cmp(&next.message)); - Ok(items) - } +fn connect() -> Result { + info!("Creating database connection pool"); + let config = Config { + host: Some("tfb-database".to_string()), + port: Some(5432), + dbname: Some("hello_world".to_string()), + user: Some("benchmarkdbuser".to_string()), + password: Some("benchmarkdbpass".to_string()), + ..Default::default() + }; + config.create_pool(None, NoTls) } diff --git a/frameworks/Rust/hyper/src/fortunes.rs b/frameworks/Rust/hyper/src/fortunes.rs new file mode 100644 index 00000000000..0cdbd2f3ccf --- /dev/null +++ b/frameworks/Rust/hyper/src/fortunes.rs @@ -0,0 +1,75 @@ +use std::convert::Infallible; + +use http::header::{CONTENT_LENGTH, CONTENT_TYPE, SERVER}; +use http::Response; +use http_body_util::combinators::BoxBody; +use http_body_util::{BodyExt, Full}; +use hyper::body::Bytes; +use tokio_postgres::Row; + +use crate::db::POOL; +use crate::{Error, SERVER_HEADER, TEXT_HTML}; + +const QUERY: &str = "SELECT id, message FROM fortune"; + +pub struct Fortune { + pub id: i32, + pub message: String, +} + +impl From<&Row> for Fortune { + fn from(row: &Row) -> Self { + Self { + id: row.get(0), + message: row.get(1), + } + } +} + +pub async fn get() -> crate::Result>> { + let fortunes = tell_fortune().await?; + let content = FortunesTemplate { fortunes }.to_string(); + Response::builder() + .header(SERVER, SERVER_HEADER.clone()) + .header(CONTENT_TYPE, TEXT_HTML.clone()) + .header(CONTENT_LENGTH, content.len()) + .body(Full::from(content).boxed()) + .map_err(Error::from) +} + +async fn tell_fortune() -> crate::Result> { + let db = POOL.get().await?; + let statement = db.prepare_cached(QUERY).await?; + let rows = db.query(&statement, &[]).await?; + let mut fortunes = rows.iter().map(Fortune::from).collect::>(); + + fortunes.push(Fortune { + id: 0, + message: "Additional fortune added at request time.".to_string(), + }); + fortunes.sort_by(|a, b| a.message.cmp(&b.message)); + + Ok(fortunes) +} + +markup::define! { + FortunesTemplate(fortunes: Vec) { + {markup::doctype()} + html { + head { + title { "Fortunes" } + } + body { + table { + tr { th { "id" } th { "message" } } + @for item in fortunes { + tr { + td { {item.id} } + td { {markup::raw(v_htmlescape::escape(&item.message))} } + } + } + } + } + } + } +} diff --git a/frameworks/Rust/hyper/src/json.rs b/frameworks/Rust/hyper/src/json.rs new file mode 100644 index 00000000000..c80ad50c09a --- /dev/null +++ b/frameworks/Rust/hyper/src/json.rs @@ -0,0 +1,29 @@ +use std::convert::Infallible; + +use http::header::{CONTENT_LENGTH, CONTENT_TYPE, SERVER}; +use http::Response; +use http_body_util::combinators::BoxBody; +use http_body_util::{BodyExt, Full}; +use hyper::body::Bytes; +use serde::Serialize; + +use crate::{Error, Result, APPLICATION_JSON, SERVER_HEADER}; + +#[derive(Serialize)] +struct JsonResponse<'a> { + message: &'a str, +} + +static CONTENT: JsonResponse = JsonResponse { + message: "Hello, world!", +}; + +pub fn get() -> Result>> { + let content = serde_json::to_vec(&CONTENT)?; + Response::builder() + .header(SERVER, SERVER_HEADER.clone()) + .header(CONTENT_TYPE, APPLICATION_JSON.clone()) + .header(CONTENT_LENGTH, content.len()) + .body(Full::from(content).boxed()) + .map_err(Error::from) +} diff --git a/frameworks/Rust/hyper/src/main.rs b/frameworks/Rust/hyper/src/main.rs index 663ed87afc0..81b79374172 100644 --- a/frameworks/Rust/hyper/src/main.rs +++ b/frameworks/Rust/hyper/src/main.rs @@ -1,91 +1,212 @@ -use hyper::header::{HeaderValue, CONTENT_LENGTH, CONTENT_TYPE, SERVER}; +use std::convert::Infallible; +use std::net::{Ipv4Addr, SocketAddr}; +use std::{io, thread}; + +use clap::{Parser, ValueEnum}; +use http_body_util::combinators::BoxBody; +use http_body_util::{BodyExt, Empty, Full}; +use hyper::body::{Bytes, Incoming}; +use hyper::header::{HeaderValue, SERVER}; +use hyper::server::conn::http1; use hyper::service::service_fn; -use hyper::{Body, Response, StatusCode}; -use serde::Serialize; +use hyper::{Request, Response, StatusCode}; +use hyper_util::rt::TokioIo; +use socket2::{Domain, SockAddr, Socket}; +use strum::Display; +use thiserror::Error; +use tokio::net::TcpListener; +use tokio::runtime; +use tracing::{error, info}; + +mod db; +mod fortunes; +mod json; +mod multiple_queries; +mod plaintext; +mod single_query; + +static SERVER_HEADER: HeaderValue = HeaderValue::from_static("hyper"); +static APPLICATION_JSON: HeaderValue = HeaderValue::from_static("application/json"); +static TEXT_HTML: HeaderValue = HeaderValue::from_static("text/html; charset=utf-8"); +static TEXT_PLAIN: HeaderValue = HeaderValue::from_static("text/plain"); + +type Result = std::result::Result; + +#[derive(Debug, Error)] +enum Error { + #[error("I/O error: {0}")] + Io(#[from] io::Error), + #[error("Hyper error: {0}")] + Hyper(#[from] hyper::Error), + #[error("Database error: {0}")] + TokioPostgres(#[from] tokio_postgres::Error), + #[error("Http error: {0}")] + Http(#[from] http::Error), + #[error("Database pool error: {0}")] + DbPool(#[from] deadpool_postgres::PoolError), + #[error("Serde error: {0}")] + Serde(#[from] serde_json::Error), +} + +#[derive(Debug, Parser)] +struct Args { + /// The runtime to use. + #[arg(short, long, default_value_t = Runtime::default())] + runtime: Runtime, + + /// The number of threads to use. + /// + /// Defaults to the number of logical CPUs cores available on the system. + /// + /// - For the current thread runtime, this is the number of threads to spawn in addition to the + /// main thread. + /// - For the multi-thread runtime, this is the number of worker threads to configure the + /// runtime to use. + #[arg(short, long, default_value_t = num_cpus::get())] + threads: usize, +} + +#[derive(Clone, Debug, Default, Display, ValueEnum)] +#[strum(serialize_all = "kebab-case")] +enum Runtime { + #[default] + CurrentThread, + MultiThread, +} + +fn main() -> Result<()> { + // Note: this is only here to capture logs outside of the hot path code. Avoid logging messages + // in the hot path code. + tracing_subscriber::fmt().with_thread_ids(true).init(); -mod server; + let args = Args::parse(); + match args.runtime { + Runtime::CurrentThread => run_current_thread(args.threads)?, + Runtime::MultiThread => run_multi_thread(args.threads)?, + } -static HELLO_WORLD: &[u8] = b"Hello, world!"; + Ok(()) +} + +/// Runs the server using multiple current thread runtimes. +fn run_current_thread(threads: usize) -> Result<()> { + info!("Running with {} threads", threads); + + // Spawn a new runtime on each thread. + for _ in 1..threads { + let runtime = runtime::Builder::new_current_thread() + .enable_all() + .build()?; + thread::spawn(|| run_server(runtime)); + } + // Run the server on the main thread. + let runtime = runtime::Builder::new_current_thread() + .enable_all() + .build()?; + run_server(runtime) +} -#[derive(Serialize)] -struct JsonResponse<'a> { - message: &'a str, +/// Runs the server using a single multi-thread runtime. +fn run_multi_thread(threads: usize) -> Result<()> { + let runtime = runtime::Builder::new_multi_thread() + .enable_all() + .worker_threads(threads) + .build()?; + run_server(runtime) } -fn main() { - // It seems most of the other benchmarks create static header values - // for performance, so just play by the same rules here... - let plaintext_len = HeaderValue::from_static("13"); - let plaintext_ct = HeaderValue::from_static("text/plain"); - let json_len = HeaderValue::from_static("27"); - let json_ct = HeaderValue::from_static("application/json"); - let server_header = HeaderValue::from_static("hyper"); - - server::run(move |socket, http, handle| { - // This closure is run for each connection... - - // The plaintext benchmarks use pipelined requests. - http.pipeline_flush(true); - - // Gotta clone these to be able to move into the Service... - let plaintext_len = plaintext_len.clone(); - let plaintext_ct = plaintext_ct.clone(); - let json_len = json_len.clone(); - let json_ct = json_ct.clone(); - let server_header = server_header.clone(); - - // This is the `Service` that will handle the connection. - // `service_fn_ok` is a helper to convert a function that - // returns a Response into a `Service`. - let svc = service_fn(move |req| { - // Gotta clone these to be able to move into future... - let plaintext_len = plaintext_len.clone(); - let plaintext_ct = plaintext_ct.clone(); - let json_len = json_len.clone(); - let json_ct = json_ct.clone(); - let server_header = server_header.clone(); - - async move { - let (req, _body) = req.into_parts(); - // For speed, reuse the allocated header map from the request, - // instead of allocating a new one. Because. - let mut headers = req.headers; - headers.clear(); - - let body = match req.uri.path() { - // Apparently, other benchmarks don't check the method, so we - // don't either. Yay? - "/plaintext" => { - headers.insert(CONTENT_LENGTH, plaintext_len.clone()); - headers.insert(CONTENT_TYPE, plaintext_ct.clone()); - Body::from(HELLO_WORLD) - } - "/json" => { - let rep = JsonResponse { - message: "Hello, world!", - }; - let rep_body = serde_json::to_vec(&rep).unwrap(); - headers.insert(CONTENT_LENGTH, json_len.clone()); - headers.insert(CONTENT_TYPE, json_ct.clone()); - Body::from(rep_body) - } - _ => { - let mut res = Response::new(Body::empty()); - *res.status_mut() = StatusCode::NOT_FOUND; - *res.headers_mut() = headers; - return Ok::<_, std::io::Error>(res); - } - }; - - headers.insert(SERVER, server_header.clone()); - - let mut res = Response::new(body); - *res.headers_mut() = headers; - Ok(res) +fn run_server(runtime: runtime::Runtime) -> Result<()> { + // It's important to use [`Runtime::block_on()`] here and not [`handle::block_on()`] as + // otherwise the runtime will not drive I/O operations. See the [`Handle::block_on`] + // documentation for more information. + runtime.block_on(serve(runtime.handle())) +} + +async fn serve(handle: &runtime::Handle) -> Result<()> { + let addr = SocketAddr::from((Ipv4Addr::UNSPECIFIED, 8080)); + let socket = create_socket(addr)?; + + let listener = TcpListener::from_std(socket.into())?; + let addr = listener.local_addr()?; + info!("Listening on: {}", addr); + + // spawn accept loop into a task so it is scheduled on the runtime with all the other tasks. + let accept_loop = accept_loop(handle.clone(), listener); + handle.spawn(accept_loop).await.unwrap() +} + +/// Create a socket that allows reuse of the address and port. +/// +/// This makes it possible for multiple instances of the server task to bind to the same address and +/// port. +fn create_socket(addr: SocketAddr) -> Result { + let domain = match addr { + SocketAddr::V4(_) => Domain::IPV4, + SocketAddr::V6(_) => Domain::IPV6, + }; + let addr = SockAddr::from(addr); + let socket = Socket::new(domain, socket2::Type::STREAM, None)?; + let backlog = 4096; // maximum number of pending connections + #[cfg(unix)] + socket.set_reuse_port(true)?; + socket.set_reuse_address(true)?; + socket.set_nodelay(true)?; + socket.set_nonblocking(true)?; // required for tokio + socket.bind(&addr)?; + socket.listen(backlog)?; + + Ok(socket) +} + +/// Accept loop that accepts incoming connections and spawns a new task to handle each connection. +async fn accept_loop(handle: runtime::Handle, listener: TcpListener) -> Result<()> { + let mut http = http1::Builder::new(); + http.pipeline_flush(true); + + let service = service_fn(router); + loop { + let (stream, _) = listener.accept().await?; + let http = http.clone(); + handle.spawn(async move { + let io = TokioIo::new(stream); + if let Err(_e) = http.serve_connection(io, service).await { + // ignore errors until https://github.com/hyperium/hyper/pull/3863/ is merged + // This PR will allow us to filter out shutdown errors which are expected. + // warn!("Connection error (this may be normal during shutdown): {e}"); } }); + } +} + +/// Routes requests to the appropriate handler. +async fn router(request: Request) -> Result>> { + // The method is always GET, so we don't check it. + match request.uri().path() { + "/ping" => ping(), + "/json" => json::get(), + "/db" => single_query::get().await, + "/queries" => multiple_queries::get(request.uri().query()).await, + "/fortunes" => fortunes::get().await, + "/plaintext" => plaintext::get(), + _ => not_found_error(), + } +} + +/// A handler that returns a "pong" response. +/// +/// This handler is used to verify that the server is running and can respond to requests. It is +/// used by the docker health check command. +fn ping() -> Result>> { + Response::builder() + .body(Full::from("pong").boxed()) + .map_err(Error::from) +} - // Spawn the `serve_connection` future into the runtime. - handle.spawn(http.serve_connection(socket, svc)); - }) +/// A handler that returns a 404 response. +fn not_found_error() -> Result>> { + Response::builder() + .status(StatusCode::NOT_FOUND) + .header(SERVER, SERVER_HEADER.clone()) + .body(Empty::new().boxed()) + .map_err(Error::from) } diff --git a/frameworks/Rust/hyper/src/main_db.rs b/frameworks/Rust/hyper/src/main_db.rs deleted file mode 100644 index 1ac93cd6b31..00000000000 --- a/frameworks/Rust/hyper/src/main_db.rs +++ /dev/null @@ -1,109 +0,0 @@ -use std::fmt::Write; -use std::sync::Arc; - -use hyper::header::{HeaderValue, CONTENT_TYPE, SERVER}; -use hyper::service::service_fn; -use hyper::{Body, Response}; -use std::net::ToSocketAddrs; - -mod db; -mod server; - -fn main() { - //"postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world"; - let mut psql_config = tokio_postgres::Config::new(); - psql_config - .user("benchmarkdbuser") - .password("benchmarkdbpass") - .dbname("hello_world"); - let psql_addr = ("tfb-database", 5432) - .to_socket_addrs() - .expect("must be able to resolve database hostname") - .next() - .expect("database hostname must resolve to an address"); - - server::run(move |socket, http, handle| { - let http = http.clone(); - let handle2 = handle.clone(); - - let html_ct = HeaderValue::from_static("text/html; charset=utf-8"); - let server_header = HeaderValue::from_static("hyper"); - let config = psql_config.clone(); - - // Before handling any requests, we should grab a DB connection. - let db_fut = async move { - let handle = handle2.clone(); - let db_conn = db::connect(psql_addr, config, handle).await?; - let db_conn = Arc::new(db_conn); - - let html_ct = html_ct.clone(); - let server_header = server_header.clone(); - - // This is the `Service` that will handle the connection. - // `service_fn` is a helper to convert a function that - // returns a Future into a `Service`. - let svc = service_fn(move |req| { - let html_ct = html_ct.clone(); - let server_header = server_header.clone(); - let db_conn = db_conn.clone(); - - async move { - let (req, _body) = req.into_parts(); - // For speed, reuse the allocated header map from the request, - // instead of allocating a new one. Because. - let mut headers = req.headers; - headers.clear(); - - headers.insert(CONTENT_TYPE, html_ct.clone()); - headers.insert(SERVER, server_header.clone()); - - match req.uri.path() { - "/fortunes" => { - let fortunes = db_conn.tell_fortune().await?; - let mut buf = String::with_capacity(2048); - let _ = write!(&mut buf, "{}", FortunesTemplate { fortunes }); - let mut res = Response::new(Body::from(buf)); - *res.headers_mut() = headers; - Ok::<_, Box>(res) - } - _ => { - let mut res = Response::new(Body::empty()); - *res.status_mut() = hyper::StatusCode::NOT_FOUND; - *res.headers_mut() = headers; - Ok(res) - } - } - } - }); - // Spawn the `serve_connection` future into the runtime. - handle2.spawn(http.serve_connection(socket, svc)); - Ok::<_, Box>(()) - }; - - handle.spawn(async move { - let _ = db_fut.await; - }); - }); -} - -markup::define! { - FortunesTemplate(fortunes: Vec) { - {markup::doctype()} - html { - head { - title { "Fortunes" } - } - body { - table { - tr { th { "id" } th { "message" } } - @for item in {fortunes} { - tr { - td { {item.id} } - td { {markup::raw(v_htmlescape::escape(&item.message))} } - } - } - } - } - } - } -} diff --git a/frameworks/Rust/hyper/src/multiple_queries.rs b/frameworks/Rust/hyper/src/multiple_queries.rs new file mode 100644 index 00000000000..f9aa862acad --- /dev/null +++ b/frameworks/Rust/hyper/src/multiple_queries.rs @@ -0,0 +1,59 @@ +use std::convert::Infallible; + +use http::header::{CONTENT_LENGTH, CONTENT_TYPE, SERVER}; +use http::Response; +use http_body_util::combinators::BoxBody; +use http_body_util::{BodyExt, Full}; +use hyper::body::Bytes; +use serde::Serialize; +use tokio_postgres::Row; + +use crate::db::POOL; +use crate::{Error, Result, APPLICATION_JSON, SERVER_HEADER}; + +const QUERY: &str = "SELECT id, randomnumber FROM world WHERE id = $1"; + +#[derive(Debug, Serialize)] +pub struct World { + id: i32, + randomnumber: i32, +} + +impl From for World { + fn from(row: Row) -> Self { + World { + id: row.get(0), + randomnumber: row.get(1), + } + } +} + +pub async fn get(query: Option<&str>) -> Result>> { + let count = query + .and_then(|query| query.strip_prefix("count=")) + .and_then(|query| query.parse().ok()) + .unwrap_or(1) + .clamp(1, 500); + + let worlds = query_worlds(count).await?; + let json = serde_json::to_vec(&worlds)?; + + Response::builder() + .header(SERVER, SERVER_HEADER.clone()) + .header(CONTENT_TYPE, APPLICATION_JSON.clone()) + .header(CONTENT_LENGTH, json.len()) + .body(Full::from(json).boxed()) + .map_err(Error::from) +} + +async fn query_worlds(count: usize) -> Result> { + let db = POOL.get().await?; + let statement = db.prepare_cached(QUERY).await?; + let mut worlds = Vec::with_capacity(count); + for _ in 0..count { + let id = fastrand::i32(1..10_000); + let row = db.query_one(&statement, &[&id]).await?; + worlds.push(World::from(row)); + } + Ok(worlds) +} diff --git a/frameworks/Rust/hyper/src/plaintext.rs b/frameworks/Rust/hyper/src/plaintext.rs new file mode 100644 index 00000000000..e2a081d2d39 --- /dev/null +++ b/frameworks/Rust/hyper/src/plaintext.rs @@ -0,0 +1,20 @@ +use std::convert::Infallible; + +use http::header::{CONTENT_LENGTH, CONTENT_TYPE, SERVER}; +use http::Response; +use http_body_util::combinators::BoxBody; +use http_body_util::{BodyExt, Full}; +use hyper::body::Bytes; + +use crate::{Error, Result, SERVER_HEADER, TEXT_PLAIN}; + +static CONTENT: &[u8] = b"Hello, world!"; + +pub fn get() -> Result>> { + Response::builder() + .header(SERVER, SERVER_HEADER.clone()) + .header(CONTENT_TYPE, TEXT_PLAIN.clone()) + .header(CONTENT_LENGTH, CONTENT.len()) + .body(Full::from(CONTENT).boxed()) + .map_err(Error::from) +} diff --git a/frameworks/Rust/hyper/src/server.rs b/frameworks/Rust/hyper/src/server.rs deleted file mode 100644 index 32ae0c8cc75..00000000000 --- a/frameworks/Rust/hyper/src/server.rs +++ /dev/null @@ -1,79 +0,0 @@ -use std::io; -use std::net::SocketAddr; -use std::thread; - -use hyper::server::conn::Http; -use tokio::net::{TcpListener, TcpStream}; -use tokio::runtime::{Builder as RuntimeBuilder, Handle}; - -pub(crate) fn run(per_connection: F) -where - F: Fn(TcpStream, &mut Http, Handle) + Clone + Send + 'static, -{ - // Spawn a thread for each available core, minus one, since we'll - // reuse the main thread as a server thread as well. - for _ in 1..num_cpus::get() { - let per_connection = per_connection.clone(); - thread::spawn(move || { - server_thread(per_connection); - }); - } - server_thread(per_connection); -} - -fn server_thread(per_connection: F) -where - F: Fn(TcpStream, &mut Http, Handle) + Send + 'static, -{ - let mut http = Http::new(); - http.http1_only(true); - - // Our event loop... - let core = RuntimeBuilder::new_current_thread() - .enable_all() - .build() - .expect("runtime"); - let handle = core.handle(); - - // Bind to 0.0.0.0:8080 - let addr = SocketAddr::from(([0, 0, 0, 0], 8080)); - - // For every accepted connection, spawn an HTTP task - let server = async move { - let tcp = reuse_listener(&addr).expect("couldn't bind to addr"); - loop { - match tcp.accept().await { - Ok((sock, _)) => { - let _ = sock.set_nodelay(true); - per_connection(sock, &mut http, handle.clone()); - } - Err(e) => { - log::warn!("accept error: {}", e) - } - } - } - }; - - core.block_on(server); -} - -fn reuse_listener(addr: &SocketAddr) -> io::Result { - let builder = match *addr { - SocketAddr::V4(_) => net2::TcpBuilder::new_v4()?, - SocketAddr::V6(_) => net2::TcpBuilder::new_v6()?, - }; - - #[cfg(unix)] - { - use net2::unix::UnixTcpBuilderExt; - if let Err(e) = builder.reuse_port(true) { - eprintln!("error setting SO_REUSEPORT: {}", e); - } - } - - builder.reuse_address(true)?; - builder.bind(addr)?; - let listener = builder.listen(1024)?; - listener.set_nonblocking(true)?; - TcpListener::from_std(listener) -} diff --git a/frameworks/Rust/hyper/src/single_query.rs b/frameworks/Rust/hyper/src/single_query.rs new file mode 100644 index 00000000000..62083dd4d3a --- /dev/null +++ b/frameworks/Rust/hyper/src/single_query.rs @@ -0,0 +1,50 @@ +use std::convert::Infallible; + +use http::header::{CONTENT_LENGTH, CONTENT_TYPE, SERVER}; +use http::Response; +use http_body_util::combinators::BoxBody; +use http_body_util::{BodyExt, Full}; +use hyper::body::Bytes; +use serde::Serialize; +use tokio_postgres::Row; + +use crate::db::POOL; +use crate::{Error, Result, APPLICATION_JSON, SERVER_HEADER}; + +static QUERY: &str = "SELECT id, randomnumber FROM world WHERE id = $1"; + +#[derive(Debug, Serialize)] +pub struct World { + id: i32, + randomnumber: i32, +} + +impl From for World { + fn from(row: Row) -> Self { + World { + id: row.get(0), + randomnumber: row.get(1), + } + } +} + +pub async fn get() -> Result>> { + let id = fastrand::i32(1..10_000); + let world = query_world(id).await?; + let json = serde_json::to_vec(&world)?; + + Response::builder() + .header(SERVER, SERVER_HEADER.clone()) + .header(CONTENT_TYPE, APPLICATION_JSON.clone()) + .header(CONTENT_LENGTH, json.len()) + .body(Full::from(json).boxed()) + .map_err(Error::from) +} + +async fn query_world(id: i32) -> Result { + let db = POOL.get().await?; + let statement = db.prepare_cached(QUERY).await?; + let row = db.query_one(&statement, &[&id]).await?; + let world = World::from(row); + Ok(world) +} diff --git a/frameworks/Rust/hyperlane/.gitignore b/frameworks/Rust/hyperlane/.gitignore new file mode 100644 index 00000000000..791af9f28cb --- /dev/null +++ b/frameworks/Rust/hyperlane/.gitignore @@ -0,0 +1,2 @@ +/target +/logs diff --git a/frameworks/Rust/hyperlane/Cargo.lock b/frameworks/Rust/hyperlane/Cargo.lock new file mode 100644 index 00000000000..2f8ba49c1ee --- /dev/null +++ b/frameworks/Rust/hyperlane/Cargo.lock @@ -0,0 +1,2057 @@ +# 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 = "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 = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "atoi" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" +dependencies = [ + "num-traits", +] + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" + +[[package]] +name = "bitflags" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +dependencies = [ + "serde_core", +] + +[[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 = "8.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bd8b9603c7aa97359dbd97ecf258968c95f3adddd6db2f7e7a5bef101c84560" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + +[[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 = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[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 = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crc" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675" +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.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[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 = "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", +] + +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +dependencies = [ + "serde", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[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 = "flate2" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc5a4e564e38c699f2880d3fda590bedc2e69f3f84cd48b457bd892ce61d0aa9" +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 = "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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[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-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-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[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.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" +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", + "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 = "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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" + +[[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 = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + +[[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-compress" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c1b2aca6817a5a211bd1aeafd3f3f5c9d222f3b1cac5416f667fd04d5ac655d" +dependencies = [ + "brotli", + "flate2", + "twox-hash", +] + +[[package]] +name = "http-constant" +version = "1.70.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1dd700ca01982ad65f60942687599f3ac04cf1010673b80af480f1f1f15592a" + +[[package]] +name = "http-type" +version = "5.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60e700017e6818aca191fd8a2f8ba8f524954375b9525f3dd9aabc83c4f999ec" +dependencies = [ + "hex", + "http-compress", + "http-constant", + "lombok-macros", + "serde", + "serde-xml-rs", + "serde_json", + "serde_urlencoded", + "tokio", + "url", +] + +[[package]] +name = "hyperlane" +version = "10.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8285c986ed79e5932f112dafb32ee32caf77b561bb782ac4b3b1af49cc27ff09" +dependencies = [ + "aho-corasick", + "http-type", + "inventory", + "lombok-macros", + "regex", + "serde", + "serde_json", +] + +[[package]] +name = "hyperlane-time" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c1902a81b87724c226187b798658dd38038afe79eb337735eff39ec5f4d3d30" + +[[package]] +name = "hyperlane_techempower" +version = "0.1.0" +dependencies = [ + "futures", + "hyperlane", + "hyperlane-time", + "num_cpus", + "once_cell", + "rand 0.9.2", + "serde", + "serde_json", + "sqlx", +] + +[[package]] +name = "icu_collections" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" + +[[package]] +name = "icu_properties" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" + +[[package]] +name = "icu_provider" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +dependencies = [ + "displaydoc", + "icu_locale_core", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[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.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" +dependencies = [ + "equivalent", + "hashbrown 0.16.0", +] + +[[package]] +name = "inventory" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc61209c082fbeb19919bee74b176221b27223e27b65d781eb91af24eb1fb46e" +dependencies = [ + "rustversion", +] + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[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.177" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" + +[[package]] +name = "libm" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" + +[[package]] +name = "libredox" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" +dependencies = [ + "bitflags", + "libc", + "redox_syscall", +] + +[[package]] +name = "libsqlite3-sys" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" +dependencies = [ + "pkg-config", + "vcpkg", +] + +[[package]] +name = "litemap" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" + +[[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.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" + +[[package]] +name = "lombok-macros" +version = "1.13.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bf89b026ebf6e1c51f466b40f60f8e90a64305d9cf07268e1adaeceefcb3c7a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.61.2", +] + +[[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 0.8.5", + "smallvec", + "zeroize", +] + +[[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 = "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 = "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", + "smallvec", + "windows-link", +] + +[[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 = "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.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a" +dependencies = [ + "zerovec", +] + +[[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.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" +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.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.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 = "rsa" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78928ac1ed176a5ca1d17e578a1825f3d81ca54cf41053a592584b020cfd691b" +dependencies = [ + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core 0.6.4", + "signature", + "spki", + "subtle", + "zeroize", +] + +[[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 = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[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-xml-rs" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53630160a98edebde0123eb4dfd0fce6adff091b2305db3154a9e920206eb510" +dependencies = [ + "log", + "serde", + "thiserror 1.0.69", + "xml-rs", +] + +[[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", +] + +[[package]] +name = "serde_json" +version = "1.0.145" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +dependencies = [ + "itoa", + "memchr", + "ryu", + "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 = "signal-hook-registry" +version = "1.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b" +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 0.6.4", +] + +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + +[[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" +dependencies = [ + "serde", +] + +[[package]] +name = "socket2" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" +dependencies = [ + "libc", + "windows-sys 0.60.2", +] + +[[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", + "bytes", + "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", + "serde", + "serde_json", + "sha2", + "smallvec", + "thiserror 2.0.17", + "tokio", + "tokio-stream", + "tracing", + "url", +] + +[[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", +] + +[[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", + "hex", + "once_cell", + "proc-macro2", + "quote", + "serde", + "serde_json", + "sha2", + "sqlx-core", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", + "syn", + "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", + "bitflags", + "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 0.8.5", + "rsa", + "serde", + "sha1", + "sha2", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror 2.0.17", + "tracing", + "whoami", +] + +[[package]] +name = "sqlx-postgres" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db58fcd5a53cf07c184b154801ff91347e4c30d17a3562a635ff028ad5deda46" +dependencies = [ + "atoi", + "base64", + "bitflags", + "byteorder", + "crc", + "dotenvy", + "etcetera", + "futures-channel", + "futures-core", + "futures-util", + "hex", + "hkdf", + "hmac", + "home", + "itoa", + "log", + "md-5", + "memchr", + "once_cell", + "rand 0.8.5", + "serde", + "serde_json", + "sha2", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror 2.0.17", + "tracing", + "whoami", +] + +[[package]] +name = "sqlx-sqlite" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2d12fe70b2c1b4401038055f90f151b78208de1f9f89a7dbfd41587a10c3eea" +dependencies = [ + "atoi", + "flume", + "futures-channel", + "futures-core", + "futures-executor", + "futures-intrusive", + "futures-util", + "libsqlite3-sys", + "log", + "percent-encoding", + "serde", + "serde_urlencoded", + "sqlx-core", + "thiserror 2.0.17", + "tracing", + "url", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[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 = "2.0.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +dependencies = [ + "thiserror-impl 2.0.17", +] + +[[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", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tinystr" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +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.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" +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", +] + +[[package]] +name = "tokio-stream" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "log", + "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", +] + +[[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 = "twox-hash" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ea3136b675547379c4bd395ca6b938e5ad3c3d20fad76e7fe85f9e0d011419c" +dependencies = [ + "rand 0.9.2", +] + +[[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.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06" + +[[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 = "url" +version = "2.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" +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 = "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 = "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.1+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" + +[[package]] +name = "whoami" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d4a4db5077702ca3015d3d02d74974948aba2ad9e12ab7df718ee64ccd7e97d" +dependencies = [ + "libredox", + "wasite", +] + +[[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.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.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.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", + "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.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.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.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + +[[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.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.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.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.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + +[[package]] +name = "wit-bindgen" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" + +[[package]] +name = "writeable" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" + +[[package]] +name = "xml-rs" +version = "0.8.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fd8403733700263c6eb89f192880191f1b83e332f7a20371ddcf421c4a337c7" + +[[package]] +name = "yoke" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[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", + "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.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/frameworks/Rust/hyperlane/Cargo.toml b/frameworks/Rust/hyperlane/Cargo.toml new file mode 100644 index 00000000000..88209c8ce36 --- /dev/null +++ b/frameworks/Rust/hyperlane/Cargo.toml @@ -0,0 +1,51 @@ +[package] +name = "hyperlane_techempower" +version = "0.1.0" +readme = "README.md" +edition = "2024" +authors = ["root@ltpp.vip"] +license = "MIT" +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.""" +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" +] + +[dependencies] +futures = "0.3.31" +hyperlane = "10.12.0" +hyperlane-time = "0.7.12" +num_cpus = "1.17.0" +once_cell = "1.21.3" +rand = "0.9.2" +serde = "1.0.228" +serde_json = "1.0.145" +sqlx = { version = "0.8.6", features = ["runtime-tokio", "postgres"] } + +[profile.dev] +incremental = false +opt-level = 3 +lto = true +panic = "unwind" +debug = false +codegen-units = 1 +strip = "debuginfo" + +[profile.release] +incremental = false +opt-level = 3 +lto = true +panic = "unwind" +debug = false +codegen-units = 1 +strip = "debuginfo" + +[features] +dev = [] diff --git a/frameworks/Rust/hyperlane/README.md b/frameworks/Rust/hyperlane/README.md new file mode 100644 index 00000000000..8afc763acc2 --- /dev/null +++ b/frameworks/Rust/hyperlane/README.md @@ -0,0 +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 diff --git a/frameworks/Rust/hyperlane/benchmark_config.json b/frameworks/Rust/hyperlane/benchmark_config.json new file mode 100644 index 00000000000..5476d84b5dd --- /dev/null +++ b/frameworks/Rust/hyperlane/benchmark_config.json @@ -0,0 +1,29 @@ +{ + "framework": "hyperlane", + "tests": [ + { + "default": { + "dockerfile": "hyperlane.default.dockerfile", + "json_url": "/json", + "plaintext_url": "/plaintext", + "fortune_url": "/fortunes", + "db_url": "/db", + "query_url": "/query?q=", + "update_url": "/upda?q=", + "cached_query_url": "/cached-quer?c=", + "port": 8080, + "approach": "Realistic", + "classification": "Platform", + "database": "Postgres", + "framework": "hyperlane", + "language": "Rust", + "orm": "raw", + "platform": "Rust", + "webserver": "hyperlane", + "os": "Linux", + "database_os": "Linux", + "display_name": "hyperlane" + } + } + ] +} diff --git a/frameworks/Rust/hyperlane/config.toml b/frameworks/Rust/hyperlane/config.toml new file mode 100644 index 00000000000..598616e6b2e --- /dev/null +++ b/frameworks/Rust/hyperlane/config.toml @@ -0,0 +1,20 @@ +[framework] +name = "hyperlane" + +[main] +urls.json = "/json" +urls.plaintext = "/plaintext" +urls.fortunes = "/fortunes" +urls.db = "/db" +urls.query = "/query?q=" +urls.update = "/upda?q=" +urls.cached_query = "/cached-quer?c=" +approach = "Realistic" +classification = "Micro" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "raw" +platform = "Rust" +webserver = "hyperlane" +versus = "None" diff --git a/frameworks/Rust/hyperlane/hyperlane.default.dockerfile b/frameworks/Rust/hyperlane/hyperlane.default.dockerfile new file mode 100644 index 00000000000..023ac9612cc --- /dev/null +++ b/frameworks/Rust/hyperlane/hyperlane.default.dockerfile @@ -0,0 +1,15 @@ +FROM rust:1.89 + +RUN apt-get update -yqq && apt-get install -yqq cmake g++ binutils lld + +ENV POSTGRES_URL=postgres://benchmarkdbuser:benchmarkdbpass@tfb-database:5432/hello_world + +ADD ./ /hyperlane_techempower +WORKDIR /hyperlane_techempower + +RUN cargo clean +RUN RUSTFLAGS="-C target-cpu=native -C link-arg=-fuse-ld=lld" cargo build --release + +EXPOSE 8080 + +CMD ./target/release/hyperlane_techempower diff --git a/frameworks/Rust/hyperlane/src/db/fn.rs b/frameworks/Rust/hyperlane/src/db/fn.rs new file mode 100644 index 00000000000..8418f711c88 --- /dev/null +++ b/frameworks/Rust/hyperlane/src/db/fn.rs @@ -0,0 +1,184 @@ +use super::*; + +pub(crate) fn get_db_connection() -> &'static DbPoolConnection { + &DB +} + +#[cfg(feature = "dev")] +pub(crate) async fn create_database() { + let db_pool: &DbPoolConnection = get_db_connection(); + let _ = db_query(&format!("CREATE DATABASE {DATABASE_NAME};")) + .execute(db_pool) + .await; +} + +#[cfg(feature = "dev")] +pub(crate) async fn create_table() { + let db_pool: &DbPoolConnection = get_db_connection(); + let _ = db_query(&format!( + "CREATE TABLE IF NOT EXISTS {TABLE_NAME_WORLD} ( + id SERIAL PRIMARY KEY, randomNumber INT NOT NULL + );" + )) + .execute(db_pool) + .await; + let _ = db_query(&format!( + "CREATE TABLE IF NOT EXISTS {TABLE_NAME_FORTUNE} ( + id SERIAL PRIMARY KEY, message VARCHAR NOT NULL + );" + )) + .execute(db_pool) + .await; +} + +#[cfg(feature = "dev")] +pub(crate) async fn insert_records() { + let db_pool: &DbPoolConnection = get_db_connection(); + let row: PgRow = db_query(&format!("SELECT COUNT(*) FROM {TABLE_NAME_WORLD}")) + .fetch_one(db_pool) + .await + .unwrap(); + let count: i64 = row.get(0); + let limit: i64 = RANDOM_MAX as i64; + if count >= limit { + return; + } + let missing_count: i64 = limit - count; + let mut values: Vec = Vec::new(); + for _ in 0..missing_count { + let random_number: i32 = get_random_id(); + values.push(format!("(DEFAULT, {random_number})")); + } + let sql: String = format!( + "INSERT INTO {TABLE_NAME_WORLD} (id, randomNumber) VALUES {}", + values.join(",") + ); + let _ = db_query(&sql).execute(db_pool).await; + let mut values: Vec = Vec::new(); + for _ in 0..missing_count { + let random_number: i32 = get_random_id(); + values.push(format!("(DEFAULT, {random_number})")); + } + let sql: String = format!( + "INSERT INTO {TABLE_NAME_FORTUNE} (id, message) VALUES {}", + values.join(",") + ); + let _ = db_query(&sql).execute(db_pool).await; +} + +pub(crate) async fn init_cache() -> Vec { + let mut res: Vec = Vec::with_capacity(RANDOM_MAX as usize); + let db_pool: &DbPoolConnection = get_db_connection(); + let sql: String = format!("SELECT id, randomNumber FROM {TABLE_NAME_WORLD} LIMIT {RANDOM_MAX}"); + if let Ok(rows) = db_query(&sql).fetch_all(db_pool).await { + for row in rows { + let id: i32 = row.get(KEY_ID); + let random_number: i32 = row.get(KEY_RANDOM_NUMBER); + res.push(QueryRow::new(id, random_number)); + } + } + res +} + +pub(crate) async fn connection_db() -> DbPoolConnection { + let db_url: &str = match option_env!("POSTGRES_URL") { + Some(it) => it, + _ => &format!( + "{DATABASE_TYPE}://{DATABASE_USER_NAME}:{DATABASE_USER_PASSWORD}@{DATABASE_HOST}:{DATABASE_PORT}/{DATABASE_NAME}" + ), + }; + let pool_size: u32 = (get_thread_count() as u32).min(DB_MAX_CONNECTIONS); + let pool: DbPoolConnection = PgPoolOptions::new() + .max_connections(DB_MAX_CONNECTIONS) + .min_connections(pool_size) + .max_lifetime(None) + .test_before_acquire(false) + .idle_timeout(None) + .connect(db_url) + .await + .unwrap(); + pool +} + +pub(crate) async fn get_update_data(limit: Queries) -> (Vec, Vec, Vec) { + let db_pool: &DbPoolConnection = get_db_connection(); + let mut query_res_list: Vec = Vec::with_capacity(limit as usize); + let rows: Vec = get_some_row_id(limit, db_pool).await; + let mut id_list: Vec = Vec::with_capacity(rows.len()); + let mut random_numbers: Vec = Vec::with_capacity(rows.len()); + for row in rows.iter() { + let new_random_number: i32 = get_random_id() as i32; + id_list.push(row.id); + random_numbers.push(new_random_number); + query_res_list.push(QueryRow::new(row.id, new_random_number)); + } + (query_res_list, id_list, random_numbers) +} + +pub(crate) async fn init_db() { + #[cfg(feature = "dev")] + { + create_database().await; + create_table().await; + insert_records().await; + } + let _ = get_db_connection(); + let _ = CACHE.first(); +} + +pub(crate) async fn random_world_row(db_pool: &DbPoolConnection) -> QueryRow { + let random_id: Queries = get_random_id(); + query_world_row(db_pool, random_id).await +} + +pub(crate) async fn query_world_row(db_pool: &DbPoolConnection, id: Queries) -> QueryRow { + let sql: &str = "SELECT id, randomNumber FROM World WHERE id = $1"; + if let Ok(rows) = db_query(sql).bind(id).fetch_one(db_pool).await { + let random_number: i32 = rows.get(KEY_RANDOM_NUMBER); + return QueryRow::new(id, random_number); + } + QueryRow::new(id, 1) +} + +pub(crate) async fn update_world_rows(limit: Queries) -> Vec { + let db_pool: &DbPoolConnection = get_db_connection(); + let (data, id_list, random_numbers) = get_update_data(limit).await; + let sql: &str = "UPDATE World SET randomNumber = $1 WHERE id = $2"; + let mut tasks: Vec> = Vec::with_capacity(limit as usize); + for (id, random_number) in id_list.into_iter().zip(random_numbers.into_iter()) { + let db_pool: Pool = db_pool.clone(); + tasks.push(spawn(async move { + db_query(sql) + .bind(random_number) + .bind(id) + .execute(&db_pool) + .await + })); + } + join_all(tasks).await; + data +} + +pub(crate) async fn all_world_row() -> Vec { + let db_pool: &DbPoolConnection = get_db_connection(); + let sql: String = format!("SELECT id, message FROM {TABLE_NAME_FORTUNE}"); + let res: Vec = db_query(&sql).fetch_all(db_pool).await.unwrap_or_default(); + res +} + +pub(crate) async fn get_some_row_id(limit: Queries, db_pool: &DbPoolConnection) -> Vec { + let tasks: Vec<_> = (0..limit) + .map(|_| { + let db_pool: Pool = db_pool.clone(); + spawn(async move { + let id: i32 = get_random_id(); + query_world_row(&db_pool, id).await + }) + }) + .collect(); + join_all(tasks) + .await + .into_iter() + .filter_map(Result::ok) + .collect() +} diff --git a/frameworks/Rust/hyperlane/src/db/mod.rs b/frameworks/Rust/hyperlane/src/db/mod.rs new file mode 100644 index 00000000000..7607362706f --- /dev/null +++ b/frameworks/Rust/hyperlane/src/db/mod.rs @@ -0,0 +1,9 @@ +pub(crate) mod r#fn; +pub(crate) mod r#static; +pub(crate) mod r#type; + +pub(crate) use r#fn::*; +pub(crate) use r#static::*; +pub(crate) use r#type::*; + +use super::*; diff --git a/frameworks/Rust/hyperlane/src/db/static.rs b/frameworks/Rust/hyperlane/src/db/static.rs new file mode 100644 index 00000000000..e50d528ce7a --- /dev/null +++ b/frameworks/Rust/hyperlane/src/db/static.rs @@ -0,0 +1,4 @@ +use super::*; + +pub static DB: Lazy = Lazy::new(|| block_on(async { connection_db().await })); +pub static CACHE: Lazy> = Lazy::new(|| block_on(async { init_cache().await })); diff --git a/frameworks/Rust/hyperlane/src/db/type.rs b/frameworks/Rust/hyperlane/src/db/type.rs new file mode 100644 index 00000000000..6598b97602c --- /dev/null +++ b/frameworks/Rust/hyperlane/src/db/type.rs @@ -0,0 +1,3 @@ +use super::*; + +pub type DbPoolConnection = Pool; diff --git a/frameworks/Rust/hyperlane/src/main.rs b/frameworks/Rust/hyperlane/src/main.rs new file mode 100644 index 00000000000..ea346052b05 --- /dev/null +++ b/frameworks/Rust/hyperlane/src/main.rs @@ -0,0 +1,55 @@ +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, +}; + +use middleware::*; +use route::*; + +#[tokio::main] +async fn main() { + init_db().await; + + let config: ServerConfig = ServerConfig::new().await; + config.host("0.0.0.0").await; + config.port(8080).await; + config.buffer(256).await; + config.disable_linger().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_or_default(); + server_hook.wait().await; +} diff --git a/frameworks/Rust/hyperlane/src/middleware/impl.rs b/frameworks/Rust/hyperlane/src/middleware/impl.rs new file mode 100644 index 00000000000..f0559d8d539 --- /dev/null +++ b/frameworks/Rust/hyperlane/src/middleware/impl.rs @@ -0,0 +1,22 @@ +use super::*; + +impl ServerHook for RequestMiddleware { + async fn new(_ctx: &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; + } +} diff --git a/frameworks/Rust/hyperlane/src/middleware/mod.rs b/frameworks/Rust/hyperlane/src/middleware/mod.rs new file mode 100644 index 00000000000..976fe87bede --- /dev/null +++ b/frameworks/Rust/hyperlane/src/middleware/mod.rs @@ -0,0 +1,6 @@ +pub(crate) mod r#impl; +pub(crate) mod r#struct; + +pub(crate) use r#struct::*; + +use super::*; diff --git a/frameworks/Rust/hyperlane/src/middleware/struct.rs b/frameworks/Rust/hyperlane/src/middleware/struct.rs new file mode 100644 index 00000000000..dd36f832031 --- /dev/null +++ b/frameworks/Rust/hyperlane/src/middleware/struct.rs @@ -0,0 +1 @@ +pub(crate) struct RequestMiddleware; diff --git a/frameworks/Rust/hyperlane/src/route/impl.rs b/frameworks/Rust/hyperlane/src/route/impl.rs new file mode 100644 index 00000000000..96eb1080be9 --- /dev/null +++ b/frameworks/Rust/hyperlane/src/route/impl.rs @@ -0,0 +1,189 @@ +use super::*; + +impl ServerHook for JsonRoute { + async fn new(_ctx: &Context) -> Self { + Self + } + + async fn handle(self, ctx: &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.closed().await; + } +} + +impl ServerHook for PlaintextRoute { + async fn new(_ctx: &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; + } + ctx.closed().await; + } +} + +impl ServerHook for DbRoute { + async fn new(_ctx: &Context) -> Self { + Self + } + + async fn handle(self, ctx: &Context) { + let db_connection: &DbPoolConnection = get_db_connection(); + let run = || async { + 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.closed().await; + } +} + +impl ServerHook for QueryRoute { + async fn new(_ctx: &Context) -> Self { + Self + } + + async fn handle(self, ctx: &Context) { + let run = || async { + let queries: Queries = ctx + .try_get_request_query(QUERY_DB_QUERY_KEY) + .await + .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.closed().await; + } +} + +impl ServerHook for FortunesRoute { + async fn new(_ctx: &Context) -> Self { + Self + } + + async fn handle(self, ctx: &Context) { + ctx.set_response_header( + CONTENT_TYPE, + &ContentType::format_content_type_with_charset(TEXT_HTML, UTF8), + ) + .await; + let run = || async { + 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.set_response_body(&res).await.send().await.unwrap(); + }; + run().await; + while ctx.http_from_stream(HTTP_BUFFER).await.is_ok() { + run().await; + } + ctx.closed().await; + } +} + +impl ServerHook for UpdateRoute { + async fn new(_ctx: &Context) -> Self { + Self + } + + async fn handle(self, ctx: &Context) { + let run = || async { + let queries: Queries = ctx + .try_get_request_query(UPDATE_DB_QUERY_KEY) + .await + .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.closed().await; + } +} + +impl ServerHook for CachedQueryRoute { + async fn new(_ctx: &Context) -> Self { + Self + } + + async fn handle(self, ctx: &Context) { + let run = || async { + let count: Queries = ctx + .try_get_request_query(CACHE_QUERY_KEY) + .await + .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.closed().await; + } +} diff --git a/frameworks/Rust/hyperlane/src/route/mod.rs b/frameworks/Rust/hyperlane/src/route/mod.rs new file mode 100644 index 00000000000..6d47ae6e8b4 --- /dev/null +++ b/frameworks/Rust/hyperlane/src/route/mod.rs @@ -0,0 +1,8 @@ +pub(crate) mod r#impl; +pub(crate) 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 new file mode 100644 index 00000000000..107268ec78a --- /dev/null +++ b/frameworks/Rust/hyperlane/src/route/struct.rs @@ -0,0 +1,7 @@ +pub(crate) struct JsonRoute; +pub(crate) struct PlaintextRoute; +pub(crate) struct DbRoute; +pub(crate) struct QueryRoute; +pub(crate) struct FortunesRoute; +pub(crate) struct UpdateRoute; +pub(crate) struct CachedQueryRoute; diff --git a/frameworks/Rust/hyperlane/src/server/const.rs b/frameworks/Rust/hyperlane/src/server/const.rs new file mode 100644 index 00000000000..c6c0cd98828 --- /dev/null +++ b/frameworks/Rust/hyperlane/src/server/const.rs @@ -0,0 +1,21 @@ +pub(crate) const RESPONSEDATA_STR: &str = "Hello, World!"; +pub(crate) const RESPONSEDATA_BIN: &[u8] = b"Hello, World!"; +pub(crate) const DATABASE_TYPE: &str = "postgres"; +pub(crate) const DATABASE_HOST: &str = "tfb-database"; +pub(crate) const DATABASE_USER_NAME: &str = "benchmarkdbuser"; +pub(crate) const DATABASE_USER_PASSWORD: &str = "benchmarkdbpass"; +pub(crate) const DATABASE_PORT: usize = 5_432; +pub(crate) const DATABASE_NAME: &str = "hello_world"; +pub(crate) const TABLE_NAME_WORLD: &str = "World"; +pub(crate) const TABLE_NAME_FORTUNE: &str = "Fortune"; +pub(crate) const ROW_LIMIT: i32 = 500; +pub(crate) const RANDOM_MAX: i32 = 10_000; +pub(crate) const RANDOM_MAX_ADD_ONE: u32 = 10_001; +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 new file mode 100644 index 00000000000..ee8045d2dff --- /dev/null +++ b/frameworks/Rust/hyperlane/src/server/impl.rs @@ -0,0 +1,42 @@ +use super::*; + +impl QueryRow { + pub fn new(id: Queries, random_number: Queries) -> Self { + Self { + id, + randomNumber: random_number, + } + } +} + +impl Fortunes { + pub fn new(id: Queries, message: String) -> Self { + Self { id, message } + } +} + +impl FortunesTemplate { + pub fn new(list: Vec) -> Self { + Self(list) + } +} + +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() { + let row: String = format!( + "", + tem.id, + escape_html(&tem.message) + ); + let _ = write!(f, "{row}"); + } + let _ = write!(f, "
idmessage
{}{}
"); + Ok(()) + } +} diff --git a/frameworks/Rust/hyperlane/src/server/mod.rs b/frameworks/Rust/hyperlane/src/server/mod.rs new file mode 100644 index 00000000000..d806bc43dc2 --- /dev/null +++ b/frameworks/Rust/hyperlane/src/server/mod.rs @@ -0,0 +1,10 @@ +pub(crate) mod r#const; +pub(crate) mod r#impl; +pub(crate) mod r#struct; +pub(crate) mod r#type; + +pub(crate) use r#const::*; +pub(crate) use r#struct::*; +pub(crate) use r#type::*; + +use super::*; diff --git a/frameworks/Rust/hyperlane/src/server/struct.rs b/frameworks/Rust/hyperlane/src/server/struct.rs new file mode 100644 index 00000000000..779f5dd691f --- /dev/null +++ b/frameworks/Rust/hyperlane/src/server/struct.rs @@ -0,0 +1,17 @@ +use super::*; + +#[allow(bad_style)] +#[derive(Serialize, Default, Clone)] +pub(crate) struct QueryRow { + pub(crate) id: Queries, + pub(crate) randomNumber: Queries, +} + +#[derive(Serialize)] +pub(crate) struct Fortunes { + pub(crate) id: Queries, + pub(crate) message: String, +} + +#[derive(Serialize)] +pub(crate) struct FortunesTemplate(pub(crate) Vec); diff --git a/frameworks/Rust/hyperlane/src/server/type.rs b/frameworks/Rust/hyperlane/src/server/type.rs new file mode 100644 index 00000000000..797ed2084a0 --- /dev/null +++ b/frameworks/Rust/hyperlane/src/server/type.rs @@ -0,0 +1 @@ +pub type Queries = i32; diff --git a/frameworks/Rust/hyperlane/src/utils/fn.rs b/frameworks/Rust/hyperlane/src/utils/fn.rs new file mode 100644 index 00000000000..bd29a75f21f --- /dev/null +++ b/frameworks/Rust/hyperlane/src/utils/fn.rs @@ -0,0 +1,26 @@ +use super::*; + +pub(crate) fn get_thread_count() -> usize { + num_cpus::get().max(1) +} + +pub(crate) fn escape_html(input: &str) -> String { + let mut result: String = String::new(); + for ch in input.chars() { + match ch { + '<' => result.push_str("<"), + '>' => result.push_str(">"), + '&' => result.push_str("&"), + '"' => result.push_str("""), + '\'' => result.push_str("'"), + _ => result.push(ch), + } + } + result +} + +pub(crate) fn get_random_id() -> Queries { + let mut rng: SmallRng = SmallRng::from_rng(&mut rng()); + let random_id: u32 = rng.random_range(1..RANDOM_MAX_ADD_ONE); + random_id as Queries +} diff --git a/frameworks/Rust/hyperlane/src/utils/mod.rs b/frameworks/Rust/hyperlane/src/utils/mod.rs new file mode 100644 index 00000000000..910fe065558 --- /dev/null +++ b/frameworks/Rust/hyperlane/src/utils/mod.rs @@ -0,0 +1,5 @@ +pub(crate) mod r#fn; + +pub(crate) use r#fn::*; + +use super::*; diff --git a/frameworks/Rust/ignitia/.gitignore b/frameworks/Rust/ignitia/.gitignore new file mode 100644 index 00000000000..fedaa2b1d2a --- /dev/null +++ b/frameworks/Rust/ignitia/.gitignore @@ -0,0 +1,2 @@ +/target +.env diff --git a/frameworks/Rust/ignitia/Cargo.lock b/frameworks/Rust/ignitia/Cargo.lock new file mode 100644 index 00000000000..229c20bd620 --- /dev/null +++ b/frameworks/Rust/ignitia/Cargo.lock @@ -0,0 +1,3438 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "addr2line" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" +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.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "getrandom 0.3.3", + "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 = "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 = "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 = "arc-swap" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" + +[[package]] +name = "async-compression" +version = "0.4.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a89bce6054c720275ac2432fbba080a66a2106a44a1b804553930ca6909f4e0" +dependencies = [ + "compression-codecs", + "compression-core", + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "async-tempfile" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acb90d9834a8015109afc79f1f548223a0614edcbab62fb35b62d4b707e975e7" +dependencies = [ + "tokio", +] + +[[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 = "backtrace" +version = "0.3.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-link 0.2.0", +] + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" + +[[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 = "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 = "8.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bd8b9603c7aa97359dbd97ecf258968c95f3adddd6db2f7e7a5bef101c84560" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + +[[package]] +name = "bson" +version = "2.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969a9ba84b0ff843813e7249eed1678d9b6607ce5a3b8f0a47af3fcf7978e6e" +dependencies = [ + "ahash", + "base64 0.22.1", + "bitvec", + "getrandom 0.2.16", + "getrandom 0.3.3", + "hex", + "indexmap 2.11.4", + "js-sys", + "once_cell", + "rand 0.9.2", + "serde", + "serde_bytes", + "serde_json", + "time", + "uuid", +] + +[[package]] +name = "bumpalo" +version = "3.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" + +[[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 = "cc" +version = "1.2.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d05d92f4b1fd76aad469d46cdd858ca761576082cd37df81416691e50199fb" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" + +[[package]] +name = "chrono" +version = "0.4.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-link 0.2.0", +] + +[[package]] +name = "compression-codecs" +version = "0.4.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef8a506ec4b81c460798f572caead636d57d3d7e940f998160f52bd254bf2d23" +dependencies = [ + "brotli", + "compression-core", + "flate2", + "memchr", +] + +[[package]] +name = "compression-core" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e47641d3deaf41fb1538ac1f54735925e275eaf3bf4d55c81b137fba797e5cbb" + +[[package]] +name = "const-random" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" +dependencies = [ + "const-random-macro", +] + +[[package]] +name = "const-random-macro" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" +dependencies = [ + "getrandom 0.2.16", + "once_cell", + "tiny-keccak", +] + +[[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-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-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[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 = "darling" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.106", +] + +[[package]] +name = "darling_macro" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "dashmap" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "data-encoding" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" + +[[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", + "serde", + "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.16", + "serde", + "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 = "deranged" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a41953f86f8a05768a6cda24def994fd2f424b04ec5c719cf89989779f199071" +dependencies = [ + "powerfmt", + "serde_core", +] + +[[package]] +name = "derive-syn-parse" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d65d7ce8132b7c0e54497a4d9a55a1c2a0912a0d786cf894472ba818fba45762" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "derive-where" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef941ded77d15ca19b40374869ac6000af1c9f2a4c0f3d4c70926287e6364a8f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[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 = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "dotenv" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" + +[[package]] +name = "dtoa" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6add3b8cff394282be81f3fc1a0605db594ed69890078ca6e2cab1c408bcf04" + +[[package]] +name = "dyn-clone" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" + +[[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 = "enum-as-inner" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[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.1", +] + +[[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.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "find-msvc-tools" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0399f9d26e5191ce32c498bebd31e7a3ceabc2745f0ac54af3f335126c3f24b3" + +[[package]] +name = "flate2" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" +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 = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[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-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.106", +] + +[[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", + "js-sys", + "libc", + "r-efi", + "wasi 0.14.7+wasi-0.2.4", + "wasm-bindgen", +] + +[[package]] +name = "gimli" +version = "0.32.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" + +[[package]] +name = "h2" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http", + "indexmap 2.11.4", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "hashbrown" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" + +[[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.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hickory-proto" +version = "0.24.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92652067c9ce6f66ce53cc38d1169daa36e6e7eb7dd3b63b5103bd9d97117248" +dependencies = [ + "async-trait", + "cfg-if", + "data-encoding", + "enum-as-inner", + "futures-channel", + "futures-io", + "futures-util", + "idna", + "ipnet", + "once_cell", + "rand 0.8.5", + "thiserror", + "tinyvec", + "tokio", + "tracing", + "url", +] + +[[package]] +name = "hickory-resolver" +version = "0.24.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbb117a1ca520e111743ab2f6688eddee69db4e0ea242545a604dce8a66fd22e" +dependencies = [ + "cfg-if", + "futures-util", + "hickory-proto", + "ipconfig", + "lru-cache", + "once_cell", + "parking_lot", + "rand 0.8.5", + "resolv-conf", + "smallvec", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "http" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +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.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.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb3aa54a13a0dfe7fbe3a59e0c76093041720fdc77b110cc0fc260fafb4dc51e" +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-util" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c6995591a8f1380fcb4ba966a252a4b29188d51d2b89e3a252f5305be65aea8" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "http", + "http-body", + "hyper", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2 0.6.0", + "system-configuration", + "tokio", + "tower-service", + "tracing", + "windows-registry", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" +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.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" + +[[package]] +name = "icu_properties" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" + +[[package]] +name = "icu_provider" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +dependencies = [ + "displaydoc", + "icu_locale_core", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[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 = "ignitia" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520e629828e7090b53df761ae703d2c1a5e89741570072804f5caa3018a75b1d" +dependencies = [ + "ahash", + "arc-swap", + "async-compression", + "async-tempfile", + "async-trait", + "bytes", + "chrono", + "dashmap", + "futures", + "futures-util", + "http", + "http-body-util", + "httpdate", + "hyper", + "hyper-util", + "libc", + "memchr", + "mimalloc", + "mime", + "mime_guess", + "multer", + "num_cpus", + "once_cell", + "parking_lot", + "pin-project", + "rand 0.8.5", + "regex", + "serde", + "serde_json", + "smallvec", + "socket2 0.5.10", + "tempfile", + "thiserror", + "tokio", + "tokio-util", + "tower", + "tower-service", + "tracing", + "tracing-subscriber", + "url", + "urlencoding", + "uuid", +] + +[[package]] +name = "ignitia-techempower" +version = "0.1.0" +dependencies = [ + "deadpool-postgres", + "dotenv", + "futures", + "futures-util", + "httpdate", + "ignitia", + "mimalloc", + "mongodb", + "num_cpus", + "rand 0.9.2", + "serde", + "serde_json", + "tokio", + "tokio-pg-mapper", + "tokio-pg-mapper-derive", + "tokio-postgres", + "yarte", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "indexmap" +version = "2.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" +dependencies = [ + "equivalent", + "hashbrown 0.16.0", + "serde", + "serde_core", +] + +[[package]] +name = "io-uring" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" +dependencies = [ + "bitflags 2.9.4", + "cfg-if", + "libc", +] + +[[package]] +name = "ipconfig" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" +dependencies = [ + "socket2 0.5.10", + "widestring", + "windows-sys 0.48.0", + "winreg", +] + +[[package]] +name = "ipnet" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" + +[[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.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305" +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.176" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" + +[[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.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" +dependencies = [ + "bitflags 2.9.4", + "libc", + "redox_syscall", +] + +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + +[[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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" + +[[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.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" + +[[package]] +name = "lru-cache" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" +dependencies = [ + "linked-hash-map", +] + +[[package]] +name = "macro_magic" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc33f9f0351468d26fbc53d9ce00a096c8522ecb42f19b50f34f2c422f76d21d" +dependencies = [ + "macro_magic_core", + "macro_magic_macros", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "macro_magic_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1687dc887e42f352865a393acae7cf79d98fab6351cde1f58e9e057da89bf150" +dependencies = [ + "const-random", + "derive-syn-parse", + "macro_magic_core_macros", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "macro_magic_core_macros" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b02abfe41815b5bd98dbd4260173db2c116dda171dc0fe7838cb206333b83308" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "macro_magic_macros" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73ea28ee64b88876bf45277ed9a5817c1817df061a74f2b988971a12570e5869" +dependencies = [ + "macro_magic_core", + "quote", + "syn 2.0.106", +] + +[[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 = "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", +] + +[[package]] +name = "mio" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" +dependencies = [ + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", + "windows-sys 0.59.0", +] + +[[package]] +name = "mongocrypt" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22426d6318d19c5c0773f783f85375265d6a8f0fa76a733da8dc4355516ec63d" +dependencies = [ + "bson", + "mongocrypt-sys", + "once_cell", + "serde", +] + +[[package]] +name = "mongocrypt-sys" +version = "0.1.4+1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dda42df21d035f88030aad8e877492fac814680e1d7336a57b2a091b989ae388" + +[[package]] +name = "mongodb" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622f272c59e54a3c85f5902c6b8e7b1653a6b6681f45e4c42d6581301119a4b8" +dependencies = [ + "async-trait", + "base64 0.13.1", + "bitflags 1.3.2", + "bson", + "chrono", + "derive-where", + "derive_more", + "flate2", + "futures-core", + "futures-executor", + "futures-io", + "futures-util", + "hex", + "hickory-proto", + "hickory-resolver", + "hmac", + "macro_magic", + "md-5", + "mongocrypt", + "mongodb-internal-macros", + "once_cell", + "pbkdf2", + "percent-encoding", + "rand 0.8.5", + "rustc_version_runtime", + "rustls", + "rustversion", + "serde", + "serde_bytes", + "serde_with", + "sha1", + "sha2", + "snap", + "socket2 0.5.10", + "stringprep", + "strsim", + "take_mut", + "thiserror", + "tokio", + "tokio-rustls", + "tokio-util", + "typed-builder", + "uuid", + "webpki-roots 0.26.11", + "zstd", +] + +[[package]] +name = "mongodb-internal-macros" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63981427a0f26b89632fd2574280e069d09fb2912a3138da15de0174d11dd077" +dependencies = [ + "macro_magic", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[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 = "nu-ansi-term" +version = "0.50.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4a28e057d01f97e61255210fcff094d74ed0466038633e95017f5beb68e4399" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[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.37.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[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 0.2.0", +] + +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest", +] + +[[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" +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 = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "postgres-protocol" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbef655056b916eb868048276cfd5d6a7dea4f81560dfd047f97c8c6fe3fcfd4" +dependencies = [ + "base64 0.22.1", + "byteorder", + "bytes", + "fallible-iterator", + "hmac", + "md-5", + "memchr", + "rand 0.9.2", + "sha2", + "stringprep", +] + +[[package]] +name = "postgres-types" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a120daaabfcb0e324d5bf6e411e9222994cb3795c79943a0ef28ed27ea76e4" +dependencies = [ + "bytes", + "fallible-iterator", + "postgres-protocol", +] + +[[package]] +name = "potential_utf" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a" +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 = "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.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" +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 = "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.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags 2.9.4", +] + +[[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.106", +] + +[[package]] +name = "regex" +version = "1.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b5288124840bee7b386bc413c487869b360b2b4ec421ea56425128692f2a82c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "833eb9ce86d40ef33cb1306d8accf7bc8ec2bfea4355cbdebb3df68b40925cad" +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 = "resolv-conf" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b3789b30bd25ba102de4beabd95d21ac45b69b1be7d14522bab988c526d6799" + +[[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 = "rustc-demangle" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustc_version_runtime" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dd18cd2bae1820af0b6ad5e54f4a51d0f3fcc53b05f845675074efcc7af071d" +dependencies = [ + "rustc_version", + "semver", +] + +[[package]] +name = "rustix" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" +dependencies = [ + "bitflags 2.9.4", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.1", +] + +[[package]] +name = "rustls" +version = "0.23.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd3c25631629d034ce7cd9940adc9d45762d46de2b0f57193c4443b92c6d4d40" +dependencies = [ + "log", + "once_cell", + "ring", + "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.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10b3f4191e8a80e6b43eebabfac91e5dcecebb27a71f04e820c47ec41d314bf" +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 = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "schemars" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + +[[package]] +name = "schemars" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82d20c4491bc164fa2f6c5d44565947a52ad80b9505d8e36f8d54c27c739fcd0" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + +[[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.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_bytes" +version = "0.11.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5d440709e79d88e51ac01c4b72fc6cb7314017bb7da9eeff678aa94c10e3ea8" +dependencies = [ + "serde", + "serde_core", +] + +[[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.106", +] + +[[package]] +name = "serde_json" +version = "1.0.145" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +dependencies = [ + "indexmap 2.11.4", + "itoa", + "memchr", + "ryu", + "serde", + "serde_core", +] + +[[package]] +name = "serde_with" +version = "3.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6093cd8c01b25262b84927e0f7151692158fab02d961e04c979d3903eba7ecc5" +dependencies = [ + "base64 0.22.1", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.11.4", + "schemars 0.9.0", + "schemars 1.0.4", + "serde_core", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7e6c180db0816026a61afa1cff5344fb7ebded7e4d3062772179f2501481c27" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[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.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 = "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 = "snap" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b6b67fb9a61334225b5b790716f609cd58395f895b3fe8b328786812a40bc3b" + +[[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" + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[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.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[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.106", +] + +[[package]] +name = "system-configuration" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" +dependencies = [ + "bitflags 2.9.4", + "core-foundation", + "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 = "take_mut" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "tempfile" +version = "3.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" +dependencies = [ + "fastrand", + "getrandom 0.3.3", + "once_cell", + "rustix", + "windows-sys 0.61.1", +] + +[[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.106", +] + +[[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.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" + +[[package]] +name = "time-macros" +version = "0.2.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "tinystr" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +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.47.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" +dependencies = [ + "backtrace", + "bytes", + "io-uring", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "slab", + "socket2 0.6.0", + "tokio-macros", + "windows-sys 0.59.0", +] + +[[package]] +name = "tokio-macros" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "tokio-pg-mapper" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93f2b78f3566383ffabc553c72bbb2f129962a54886c5c4d8e8c706f84eceab8" +dependencies = [ + "tokio-postgres", +] + +[[package]] +name = "tokio-pg-mapper-derive" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8548f756cd6eb4069c5af0fb0cec57001fb42bd1fb7330d8f24067ee3fa62608" +dependencies = [ + "quote", + "syn 1.0.109", + "tokio-postgres", +] + +[[package]] +name = "tokio-postgres" +version = "0.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156efe7fff213168257853e1dfde202eed5f487522cbbbf7d219941d753d853" +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.6.0", + "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.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5" +dependencies = [ + "bytes", + "futures-core", + "futures-io", + "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 = "tower" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +dependencies = [ + "tower-layer", + "tower-service", +] + +[[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.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", + "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-subscriber" +version = "0.3.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5" +dependencies = [ + "nu-ansi-term", + "sharded-slab", + "smallvec", + "thread_local", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "typed-builder" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd9d30e3a08026c78f246b173243cf07b3696d274debd26680773b6773c2afc7" +dependencies = [ + "typed-builder-macro", +] + +[[package]] +name = "typed-builder-macro" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c36781cc0e46a83726d9879608e4cf6c2505237e263a8eb8c24502989cfdb28" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "typenum" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" + +[[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.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" + +[[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 = "url" +version = "2.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "uuid" +version = "1.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" +dependencies = [ + "getrandom 0.3.3", + "js-sys", + "serde", + "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 = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[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 = "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.1+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +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.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn 2.0.106", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-sys" +version = "0.3.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9367c417a924a74cae129e6a2ae3b47fabb1f8995595ab474029da749a8be120" +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.2", +] + +[[package]] +name = "webpki-roots" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e8983c3ab33d6fb807cfcdad2491c4ea8cbc8ed839181c7dfd9c67c83e261b2" +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", + "web-sys", +] + +[[package]] +name = "widestring" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd7cf3379ca1aac9eea11fba24fd7e315d621f8dfe35c8d7d2be8b793726e07d" + +[[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.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6844ee5416b285084d3d3fffd743b925a6c9385455f64f6d4fa3031c4c2749a9" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link 0.2.0", + "windows-result 0.4.0", + "windows-strings 0.5.0", +] + +[[package]] +name = "windows-implement" +version = "0.60.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edb307e42a74fb6de9bf3a02d9712678b22399c87e6fa869d6dfcd8c1b7754e0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "windows-interface" +version = "0.59.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0abd1ddbc6964ac14db11c7213d6532ef34bd9aa042c2e5935f59d7908b46a5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + +[[package]] +name = "windows-link" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" + +[[package]] +name = "windows-registry" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b8a9ed28765efc97bbc954883f4e6796c33a06546ebafacbabee9696967499e" +dependencies = [ + "windows-link 0.1.3", + "windows-result 0.3.4", + "windows-strings 0.4.2", +] + +[[package]] +name = "windows-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows-result" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7084dcc306f89883455a206237404d3eaf961e5bd7e0f312f7c91f57eb44167f" +dependencies = [ + "windows-link 0.2.0", +] + +[[package]] +name = "windows-strings" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows-strings" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7218c655a553b0bed4426cf54b20d7ba363ef543b52d515b3e48d7fd55318dda" +dependencies = [ + "windows-link 0.2.0", +] + +[[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-sys" +version = "0.61.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f109e41dd4a3c848907eb83d5a42ea98b3769495597450cf6d153507b166f0f" +dependencies = [ + "windows-link 0.2.0", +] + +[[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 = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "wit-bindgen" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" + +[[package]] +name = "writeable" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[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", + "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 = "yoke" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[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.106", + "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.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "zstd" +version = "0.11.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "5.0.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +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/ignitia/Cargo.toml b/frameworks/Rust/ignitia/Cargo.toml new file mode 100644 index 00000000000..61487fc4504 --- /dev/null +++ b/frameworks/Rust/ignitia/Cargo.toml @@ -0,0 +1,46 @@ +[package] +name = "ignitia-techempower" +version = "0.1.0" +edition = "2024" + +[dependencies] +ignitia = { version = "0.2.4" } +tokio = { version = "1.46", features = ["full"] } +tokio-postgres = "0.7.13" +deadpool-postgres = { version = "0.14.1", features = ["rt_tokio_1", "serde"] } +tokio-pg-mapper = "0.2.0" +tokio-pg-mapper-derive = "0.2.0" +mongodb = { version = "3.2.4", features = ["zstd-compression", "snappy-compression", "zlib-compression"] } +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +dotenv = "0.15.0" +rand = { version = "0.9.2", features = ["small_rng"] } +futures = "0.3.31" +futures-util = "0.3.31" +yarte = "0.15.7" +mimalloc = "0.1.47" +num_cpus = "1.17.0" +httpdate = "1.0" + +[profile.release] +lto = "fat" +codegen-units = 1 +opt-level = 3 +strip = true + + +[[bin]] +name = "ignitia" +path = "src/main.rs" + +[[bin]] +name = "ignitia-pg" +path = "src/main_pg.rs" + +[[bin]] +name = "ignitia-pg-pool" +path = "src/main_pg_pool.rs" + +[[bin]] +name = "ignitia-mongo" +path = "src/main_mongo.rs" diff --git a/frameworks/Rust/ignitia/README.md b/frameworks/Rust/ignitia/README.md new file mode 100644 index 00000000000..1b8b73b8324 --- /dev/null +++ b/frameworks/Rust/ignitia/README.md @@ -0,0 +1,135 @@ +# Ignitia TechEmpower Benchmarks + +This repository contains the TechEmpower FrameworkBenchmarks implementations for the Ignitia web framework, designed to showcase high-performance web API serving in Rust. + +--- + +## Project Variants + +| Binary | Description | +|------------------|-------------------------------------------------| +| `ignitia` | Basic variant with JSON and plaintext endpoints | +| `ignitia-pg` | PostgreSQL variant using tokio-postgres | +| `ignitia-pg-pool`| PostgreSQL variant using deadpool connection pooling | +| `ignitia-mongo` | MongoDB variant | + +--- + +## Benchmarked Endpoints + +All variants implement the following HTTP endpoints: + +- `/plaintext` - Returns a simple plaintext "Hello, World!" +- `/json` - Returns a JSON-serialized message +- `/db` - Single database query for a random World record +- `/queries?q=N` - Multiple database queries, default 1, max 500 +- `/updates?q=N` - Database updates with N queries, default 1, max 500 +- `/fortunes` - Renders HTML table with fortunes and adds one dynamically + +--- + +## Getting Started + +### Prerequisites + +- Rust (latest stable) +- Docker & Docker Compose (for database services) +- PostgreSQL or MongoDB instance running (Docker recommended) + +### Setup Databases + +Use the provided `docker-compose.yml` to start PostgreSQL and MongoDB databases locally: + +``` +docker-compose up -d +``` + +Initialize databases using provided SQL and JS scripts (`init-db.sql`, `init-mongo.js`). + +Update `.env` with correct connection URLs and ports. + +### Build and Run + +Build all variants: + +``` +cargo build --release +``` + +Run a variant (example PostgreSQL): + +``` +./target/release/ignitia-pg +``` + +Change ports if needed by modifying `.env`. + +### Test APIs + +Use curl or the included test scripts to verify endpoints. + +Example: + +``` +curl http://localhost:8000/json +curl http://localhost:8000/queries?q=5 +curl http://localhost:8000/fortunes +``` + +--- + +## Performance + +Ignitia includes several performance optimizations: + +- Zero-copy response construction +- Efficient routing with a radix tree +- High-performance async runtime using Tokio +- Connection pooling (deadpool for PostgreSQL) +- MiMalloc memory allocator for improved throughput +- HTTP/2 support and TCP tuning + +The expected throughput matches or exceeds other Rust web frameworks in TechEmpower benchmarks. + +--- + +## Docker Support + +Build the container image: + +``` +docker build -t ignitia-techempower -f ignitia.dockerfile . +``` + +Run the container (default JSON/plaintext variant): + +``` +docker run -p 8000:8000 ignitia-techempower +``` + +Override command to run other variants: + +``` +docker run -p 8000:8000 ignitia-techempower /app/ignitia-pg +``` + +--- + +## Contributing + +Contributions, bug reports, and feature requests are welcome. + +Please submit issues or pull requests following the project coding and style guidelines. + +--- + +## License + +This project is licensed under MIT License. + +--- + +## Acknowledgements + +- Inspired by the TechEmpower Framework Benchmarks project +- Thanks to the Rust community and authors of Ignitia framework diff --git a/frameworks/Rust/ignitia/benchmark_config.json b/frameworks/Rust/ignitia/benchmark_config.json new file mode 100644 index 00000000000..96a3522b92e --- /dev/null +++ b/frameworks/Rust/ignitia/benchmark_config.json @@ -0,0 +1,97 @@ +{ + "framework": "ignitia", + "tests": [ + { + "default": { + "dockerfile": "ignitia.dockerfile", + "docker_cmd": "/app/ignitia", + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8000, + "approach": "Realistic", + "classification": "Platform", + "database": "none", + "framework": "Ignitia", + "language": "Rust", + "flavor": "None", + "orm": "Raw", + "platform": "Rust", + "webserver": "Tokio", + "os": "Linux", + "database_os": "Linux", + "display_name": "Ignitia", + "notes": "Blazing fast Rust web framework with zero-copy optimizations", + "versus": "None" + }, + "pg": { + "dockerfile": "ignitia.dockerfile", + "docker_cmd": "/app/ignitia-pg", + "db_url": "/db", + "fortune_url": "/fortunes", + "query_url": "/queries?q=", + "update_url": "/updates?q=", + "port": 8000, + "approach": "Realistic", + "classification": "Fullstack", + "database": "postgres", + "framework": "Ignitia", + "language": "Rust", + "flavor": "None", + "orm": "Raw", + "platform": "Rust", + "webserver": "Tokio", + "os": "Linux", + "database_os": "Linux", + "display_name": "Ignitia [PostgreSQL]", + "notes": "PostgreSQL with tokio-postgres and prepared statements", + "versus": "None" + }, + "pg-pool": { + "dockerfile": "ignitia.dockerfile", + "docker_cmd": "/app/ignitia-pg-pool", + "db_url": "/db", + "query_url": "/queries?q=", + "update_url": "/updates?q=", + "fortune_url": "/fortunes", + "port": 8000, + "approach": "Realistic", + "classification": "Fullstack", + "database": "postgres", + "framework": "Ignitia", + "language": "Rust", + "flavor": "None", + "orm": "Raw", + "platform": "Rust", + "webserver": "Tokio", + "os": "Linux", + "database_os": "Linux", + "display_name": "Ignitia [PostgreSQL - deadpool]", + "notes": "PostgreSQL with deadpool connection pooling", + "versus": "None" + }, + "mongo": { + "dockerfile": "ignitia.dockerfile", + "docker_cmd": "/app/ignitia-mongo", + "db_url": "/db", + "query_url": "/queries?q=", + "fortune_url": "/fortunes", + "update_url": "/updates?q=", + "port": 8000, + "approach": "Realistic", + "classification": "Fullstack", + "database": "mongodb", + "framework": "Ignitia", + "language": "Rust", + "flavor": "None", + "orm": "Raw", + "platform": "Rust", + "webserver": "Tokio", + "os": "Linux", + "database_os": "Linux", + "display_name": "Ignitia [MongoDB]", + "notes": "MongoDB with native driver and compression", + "versus": "None" + } + } + ] +} diff --git a/frameworks/Rust/ignitia/config.toml b/frameworks/Rust/ignitia/config.toml new file mode 100644 index 00000000000..0e7b5718de6 --- /dev/null +++ b/frameworks/Rust/ignitia/config.toml @@ -0,0 +1,19 @@ +[framework] +name = "ignitia" + +[main] +urls.plaintext = "/plaintext" +urls.json = "/json" +urls.db = "/db" +urls.query = "/queries?q=" +urls.update = "/updates?q=" +urls.fortune = "/fortunes" +approach = "Realistic" +classification = "Fullstack" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "Rust" +webserver = "Tokio" +versus = "None" diff --git a/frameworks/Rust/ignitia/ignitia.dockerfile b/frameworks/Rust/ignitia/ignitia.dockerfile new file mode 100644 index 00000000000..98ad5cb3203 --- /dev/null +++ b/frameworks/Rust/ignitia/ignitia.dockerfile @@ -0,0 +1,49 @@ +FROM docker.io/rust:1.88-slim-bookworm AS builder + +# Install build dependencies +RUN apt-get update && apt-get install -y --no-install-recommends \ + pkg-config \ + libssl-dev \ + && rm -rf /var/lib/apt/lists/* + +# Set working directory +WORKDIR /build + +# Copy dependency files first for better caching +COPY ./Cargo.toml ./Cargo.lock /build/ + +# Fetch dependencies +RUN cargo fetch + +# Copy template files +COPY ./templates/ /build/templates/ + +# Copy source code +COPY ./src/ /build/src/ + +# Set Rust compilation flags for native CPU optimizations +ENV RUSTFLAGS="-C target-cpu=native" + +# Build all release binaries +RUN cargo build --release + +# Use distroless for minimal runtime image +FROM gcr.io/distroless/cc-debian12 + +# Set environment variables +ENV POSTGRES_URL=postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world +ENV POSTGRES_MIN_POOL_SIZE=56 +ENV POSTGRES_MAX_POOL_SIZE=56 +ENV MONGODB_URL=mongodb://tfb-database:27017 +ENV MONGODB_MIN_POOL_SIZE=56 +ENV MONGODB_MAX_POOL_SIZE=56 + +# Copy all compiled binaries from builder +COPY --from=builder /build/target/release/ignitia* /app/ + +# Expose port +EXPOSE 8000 + +# Default command (can be overridden by docker_cmd in benchmark_config.json) +CMD ["/app/ignitia"] + diff --git a/frameworks/Rust/ignitia/rustfmt.toml b/frameworks/Rust/ignitia/rustfmt.toml new file mode 100644 index 00000000000..e418c53afd2 --- /dev/null +++ b/frameworks/Rust/ignitia/rustfmt.toml @@ -0,0 +1,3 @@ +max_width = 100 +reorder_imports = true +edition = "2021" diff --git a/frameworks/Rust/ignitia/src/common/mod.rs b/frameworks/Rust/ignitia/src/common/mod.rs new file mode 100644 index 00000000000..bec23c4fed0 --- /dev/null +++ b/frameworks/Rust/ignitia/src/common/mod.rs @@ -0,0 +1,38 @@ +pub mod models; +pub mod utils; + +use rand::{Rng, RngCore, distr::Uniform, rngs::SmallRng}; +use std::{env, fmt::Debug, str::FromStr}; + +#[allow(dead_code)] +pub const SELECT_ALL_FORTUNES: &str = "SELECT * FROM fortune"; +#[allow(dead_code)] +pub const SELECT_WORLD_BY_ID: &str = "SELECT id, randomnumber FROM world WHERE id = $1 LIMIT 1"; +#[allow(dead_code)] +pub const UPDATE_WORLDS: &str = r#"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"#; + +#[allow(dead_code)] +pub fn get_env(key: &str) -> T +where + ::Err: Debug, +{ + env::var(key) + .unwrap_or_else(|_| panic!("{key} environment variable was not set")) + .parse::() + .unwrap_or_else(|_| panic!("could not parse {key}")) +} + +#[allow(dead_code)] +#[inline(always)] +pub fn random_id(rng: &mut impl RngCore) -> i32 { + rng.random_range(1..=10_000) as i32 +} + +#[allow(dead_code)] +#[inline(always)] +pub fn random_ids(rng: &mut SmallRng, count: usize) -> impl Iterator + use<'_> { + rng.sample_iter(Uniform::new_inclusive(1, 10_000).unwrap()) + .take(count) +} diff --git a/frameworks/Rust/ignitia/src/common/models.rs b/frameworks/Rust/ignitia/src/common/models.rs new file mode 100644 index 00000000000..1644447c3cd --- /dev/null +++ b/frameworks/Rust/ignitia/src/common/models.rs @@ -0,0 +1,25 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Serialize)] +pub struct Message { + pub message: &'static str, +} + +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] +pub struct Fortune { + pub id: i32, + pub message: String, +} + +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] +pub struct FortuneInfo { + pub id: i32, + pub message: String, +} + +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] +pub struct World { + pub id: i32, + #[serde(rename = "randomNumber")] + pub random_number: i32, +} diff --git a/frameworks/Rust/ignitia/src/common/utils.rs b/frameworks/Rust/ignitia/src/common/utils.rs new file mode 100644 index 00000000000..892b92e2ca3 --- /dev/null +++ b/frameworks/Rust/ignitia/src/common/utils.rs @@ -0,0 +1,37 @@ +use serde::{Deserialize, Deserializer}; + +#[allow(dead_code)] +#[derive(Debug, Deserialize)] +pub struct Params { + #[serde(default, deserialize_with = "deserialize_query_count")] + pub q: usize, +} + +// Custom deserializer that handles invalid values +fn deserialize_query_count<'de, D>(deserializer: D) -> Result +where + D: Deserializer<'de>, +{ + #[derive(Deserialize)] + #[serde(untagged)] + enum QueryValue { + Int(usize), + String(String), + } + + let value = Option::::deserialize(deserializer)?; + + let count = match value { + Some(QueryValue::Int(i)) => i, + Some(QueryValue::String(s)) => s.parse().unwrap_or(1), + None => 1, + }; + + Ok(count.clamp(1, 500)) +} + +#[allow(dead_code)] +#[inline(always)] +pub fn parse_params(params: Params) -> usize { + params.q +} diff --git a/frameworks/Rust/ignitia/src/main.rs b/frameworks/Rust/ignitia/src/main.rs new file mode 100644 index 00000000000..1695a348b18 --- /dev/null +++ b/frameworks/Rust/ignitia/src/main.rs @@ -0,0 +1,50 @@ +mod common; + +use common::models::Message; +use ignitia::{Response, Router, Server}; + +const HELLO_WORLD: &str = "Hello, World!"; + +#[inline(always)] +async fn plaintext() -> Response { + Response::text(HELLO_WORLD) + .with_header("Server", "Ignitia") + .with_header("Content-Type", "text/plain") + .with_header( + "Date", + httpdate::fmt_http_date(std::time::SystemTime::now()), + ) +} + +#[inline(always)] +async fn json() -> Response { + // Create new Message object for each request (no caching) + let message = Message { + message: HELLO_WORLD, + }; + + Response::json(message) + .with_header("Server", "Ignitia") + .with_header("Content-Type", "application/json") + .with_header( + "Date", + httpdate::fmt_http_date(std::time::SystemTime::now()), + ) +} + +#[tokio::main] +async fn main() { + dotenv::dotenv().ok(); + + let app = Router::new() + .get("/plaintext", plaintext) + .get("/json", json); + + println!("Starting Ignitia server on 0.0.0.0:8000"); + + Server::new(app, "0.0.0.0:8000".parse().unwrap()) + .with_performance_config(ignitia::PerformanceConfig::max_rps()) + .ignitia() + .await + .unwrap(); +} diff --git a/frameworks/Rust/ignitia/src/main_mongo.rs b/frameworks/Rust/ignitia/src/main_mongo.rs new file mode 100644 index 00000000000..35ca4914daa --- /dev/null +++ b/frameworks/Rust/ignitia/src/main_mongo.rs @@ -0,0 +1,156 @@ +mod common; +mod mongo; + +use common::{ + get_env, + models::{FortuneInfo, World}, + random_id, + utils::{Params, parse_params}, +}; +use ignitia::{Query, Response, Router, Server, State}; +use mongo::database::{fetch_fortunes, find_world_by_id, find_worlds, update_worlds}; +use mongodb::{ + Client, + options::{ClientOptions, Compressor}, +}; +use rand::{SeedableRng, rng, rngs::SmallRng}; +use std::time::Duration; +use yarte::Template; + +#[derive(Template)] +#[template(path = "fortunes.html.hbs")] +pub struct FortunesTemplate<'a> { + pub fortunes: &'a Vec, +} + +async fn db(State(db): State) -> Response { + let random_id = random_id(&mut rng()); + + match find_world_by_id(db, random_id).await { + Ok(world) => Response::json(world) + .with_header("Server", "Ignitia") + .with_header("Content-Type", "application/json") + .with_header( + "Date", + httpdate::fmt_http_date(std::time::SystemTime::now()), + ), + Err(_) => Response::internal_error() + .with_header("Server", "Ignitia") + .with_header("Date", httpdate::fmt_http_date(std::time::SystemTime::now())), + } +} + +async fn queries(State(db): State, Query(params): Query) -> Response { + let q = parse_params(params); + let mut rng = SmallRng::from_rng(&mut rng()); + + match find_worlds(db, &mut rng, q).await { + Ok(results) => Response::json(results) + .with_header("Server", "Ignitia") + .with_header("Content-Type", "application/json") + .with_header( + "Date", + httpdate::fmt_http_date(std::time::SystemTime::now()), + ), + Err(_) => Response::internal_error() + .with_header("Server", "Ignitia") + .with_header("Date", httpdate::fmt_http_date(std::time::SystemTime::now())), + } +} + +async fn updates(State(db): State, Query(params): Query) -> Response { + let q = parse_params(params); + let mut rng = SmallRng::from_rng(&mut rng()); + + match find_worlds(db.clone(), &mut rng, q).await { + Ok(worlds) => { + let mut updated_worlds: Vec = Vec::with_capacity(q); + + for mut world in worlds { + world.random_number = random_id(&mut rng); + updated_worlds.push(world); + } + + match update_worlds(db, updated_worlds.clone()).await { + Ok(_) => Response::json(updated_worlds) + .with_header("Server", "Ignitia") + .with_header("Content-Type", "application/json") + .with_header( + "Date", + httpdate::fmt_http_date(std::time::SystemTime::now()), + ), + Err(_) => Response::internal_error() + .with_header("Server", "Ignitia") + .with_header("Date", httpdate::fmt_http_date(std::time::SystemTime::now())), + } + } + Err(_) => Response::internal_error() + .with_header("Server", "Ignitia") + .with_header("Date", httpdate::fmt_http_date(std::time::SystemTime::now())), + } +} + +async fn fortunes(State(db): State) -> Response { + match fetch_fortunes(db).await { + Ok(fortune_infos) => { + let html = FortunesTemplate { + fortunes: &fortune_infos, + } + .call() + .expect("error rendering template"); + + Response::html(html) + .with_header("Server", "Ignitia") + .with_header("Content-Type", "text/html; charset=utf-8") + .with_header( + "Date", + httpdate::fmt_http_date(std::time::SystemTime::now()), + ) + } + Err(_) => Response::internal_error() + .with_header("Server", "Ignitia") + .with_header("Date", httpdate::fmt_http_date(std::time::SystemTime::now())), + } +} + +#[tokio::main] +async fn main() { + dotenv::dotenv().ok(); + + let database_url: String = get_env("MONGODB_URL"); + let max_pool_size: u32 = get_env("MONGODB_MAX_POOL_SIZE"); + let min_pool_size: u32 = get_env("MONGODB_MIN_POOL_SIZE"); + + let mut client_options = ClientOptions::parse(database_url).await.unwrap(); + + client_options.max_pool_size = Some(max_pool_size); + client_options.min_pool_size = Some(min_pool_size); + client_options.connect_timeout = Some(Duration::from_millis(200)); + client_options.compressors = Some(vec![ + Compressor::Snappy, + Compressor::Zlib { + level: Default::default(), + }, + Compressor::Zstd { + level: Default::default(), + }, + ]); + + let client = Client::with_options(client_options).unwrap(); + let database = client.database("hello_world"); + + let app = Router::new() + .get("/db", db) + .get("/queries", queries) + .get("/updates", updates) + .get("/fortunes", fortunes) + .state(database); + + println!("Starting Ignitia MongoDB server on 0.0.0.0:8000"); + + Server::new(app, "0.0.0.0:8000".parse().unwrap()) + .with_performance_config(ignitia::PerformanceConfig::max_rps()) + .ignitia() + .await + .unwrap(); +} diff --git a/frameworks/Rust/ignitia/src/main_pg.rs b/frameworks/Rust/ignitia/src/main_pg.rs new file mode 100644 index 00000000000..e58ceb965b9 --- /dev/null +++ b/frameworks/Rust/ignitia/src/main_pg.rs @@ -0,0 +1,113 @@ +mod common; +mod pg; + +use common::{ + get_env, random_id, + utils::{Params, parse_params}, +}; +use ignitia::{Query, Response, Router, Server, State}; +use pg::database::PgConnection; +use pg::models::Fortune; +use rand::rng; +use yarte::Template; + +#[derive(Template)] +#[template(path = "fortunes.html.hbs")] +pub struct FortunesTemplate<'a> { + pub fortunes: &'a Vec, +} + +async fn db(State(conn): State>) -> Response { + let id = random_id(&mut rng()); + match conn.fetch_world_by_id(id).await { + Ok(world) => Response::json(world) + .with_header("Server", "Ignitia") + .with_header("Content-Type", "application/json") + .with_header( + "Date", + httpdate::fmt_http_date(std::time::SystemTime::now()), + ), + Err(_) => Response::internal_error(), + } +} + +async fn queries( + State(conn): State>, + Query(params): Query, +) -> Response { + let q = parse_params(params); + match conn.fetch_random_worlds(q).await { + Ok(results) => Response::json(results) + .with_header("Server", "Ignitia") + .with_header("Content-Type", "application/json") + .with_header( + "Date", + httpdate::fmt_http_date(std::time::SystemTime::now()), + ), + Err(_) => Response::internal_error() + .with_header("Server", "Ignitia") + .with_header("Date", httpdate::fmt_http_date(std::time::SystemTime::now())), + } +} + +async fn fortunes(State(conn): State>) -> Response { + match conn.fetch_all_fortunes().await { + Ok(fortunes) => { + let html = FortunesTemplate { + fortunes: &fortunes, + } + .call() + .expect("error rendering template"); + Response::html(html) + .with_header("Server", "Ignitia") + .with_header("Content-Type", "text/html; charset=utf-8") + .with_header( + "Date", + httpdate::fmt_http_date(std::time::SystemTime::now()), + ) + } + Err(_) => Response::internal_error() + .with_header("Server", "Ignitia") + .with_header("Date", httpdate::fmt_http_date(std::time::SystemTime::now())), + } +} + +async fn updates( + State(conn): State>, + Query(params): Query, +) -> Response { + let q = parse_params(params); + match conn.update_worlds(q).await { + Ok(worlds) => Response::json(worlds) + .with_header("Server", "Ignitia") + .with_header("Content-Type", "application/json") + .with_header( + "Date", + httpdate::fmt_http_date(std::time::SystemTime::now()), + ), + Err(_) => Response::internal_error() + .with_header("Server", "Ignitia") + .with_header("Date", httpdate::fmt_http_date(std::time::SystemTime::now())), + } +} + +#[tokio::main] +async fn main() { + dotenv::dotenv().ok(); + + let database_url: String = get_env("POSTGRES_URL"); + let pg_connection = PgConnection::connect(database_url).await; + + let app = Router::new() + .get("/db", db) + .get("/queries", queries) + .get("/fortunes", fortunes) + .get("/updates", updates) + .state(pg_connection); + + Server::new(app, "0.0.0.0:8000".parse().unwrap()) + .with_performance_config(ignitia::PerformanceConfig::max_rps()) + .ignitia() + .await + .unwrap(); +} diff --git a/frameworks/Rust/ignitia/src/main_pg_pool.rs b/frameworks/Rust/ignitia/src/main_pg_pool.rs new file mode 100644 index 00000000000..4356101d566 --- /dev/null +++ b/frameworks/Rust/ignitia/src/main_pg_pool.rs @@ -0,0 +1,225 @@ +mod common; +mod pg_pool; + +use common::{ + SELECT_ALL_FORTUNES, SELECT_WORLD_BY_ID, UPDATE_WORLDS, get_env, random_id, random_ids, + utils::{Params, parse_params}, +}; +use futures_util::{TryStreamExt, stream::FuturesUnordered}; +use ignitia::{Query, Response, Router, Server, State}; +use pg_pool::database::{create_pool, fetch_all_fortunes, fetch_world_by_id}; +use pg_pool::models::{Fortune, World}; +use rand::{SeedableRng, rng, rngs::SmallRng}; +use yarte::Template; + +#[derive(Template)] +#[template(path = "fortunes.html.hbs")] +pub struct FortunesTemplate<'a> { + pub fortunes: &'a Vec, +} + +async fn db(State(pool): State) -> Response { + let random_id = random_id(&mut rng()); + + match pool.get().await { + Ok(client) => { + let select = client.prepare_cached(SELECT_WORLD_BY_ID).await.unwrap(); + match fetch_world_by_id(&client, random_id, &select).await { + Ok(world) => Response::json(world) + .with_header("Server", "Ignitia") + .with_header("Content-Type", "application/json") + .with_header( + "Date", + httpdate::fmt_http_date(std::time::SystemTime::now()), + ), + Err(_) => Response::internal_error() + .with_header("Server", "Ignitia") + .with_header( + "Date", + httpdate::fmt_http_date(std::time::SystemTime::now()), + ), + } + } + Err(_) => Response::internal_error() + .with_header("Server", "Ignitia") + .with_header( + "Date", + httpdate::fmt_http_date(std::time::SystemTime::now()), + ), + } +} + +async fn queries( + State(pool): State, + Query(params): Query, +) -> Response { + let q = parse_params(params); + let mut rng = SmallRng::from_rng(&mut rng()); + + match pool.get().await { + Ok(client) => { + let select = client.prepare_cached(SELECT_WORLD_BY_ID).await.unwrap(); + let future_worlds = FuturesUnordered::new(); + + for id in random_ids(&mut rng, q) { + future_worlds.push(fetch_world_by_id(&client, id, &select)); + } + + match future_worlds.try_collect::>().await { + Ok(results) => Response::json(results) + .with_header("Server", "Ignitia") + .with_header("Content-Type", "application/json") + .with_header( + "Date", + httpdate::fmt_http_date(std::time::SystemTime::now()), + ), + Err(_) => Response::internal_error() + .with_header("Server", "Ignitia") + .with_header( + "Date", + httpdate::fmt_http_date(std::time::SystemTime::now()), + ), + } + } + Err(_) => Response::internal_error() + .with_header("Server", "Ignitia") + .with_header( + "Date", + httpdate::fmt_http_date(std::time::SystemTime::now()), + ), + } +} + +async fn fortunes(State(pool): State) -> Response { + match pool.get().await { + Ok(client) => { + let select = client.prepare_cached(SELECT_ALL_FORTUNES).await.unwrap(); + + match fetch_all_fortunes(client, &select).await { + Ok(mut fortunes) => { + fortunes.push(Fortune { + id: 0, + message: "Additional fortune added at request time.".to_string(), + }); + + fortunes.sort_by(|a, b| a.message.cmp(&b.message)); + + let html = FortunesTemplate { + fortunes: &fortunes, + } + .call() + .expect("error rendering template"); + Response::html(html) + .with_header("Server", "Ignitia") + .with_header("Content-Type", "text/html; charset=utf-8") + .with_header( + "Date", + httpdate::fmt_http_date(std::time::SystemTime::now()), + ) + } + Err(_) => Response::internal_error() + .with_header("Server", "Ignitia") + .with_header( + "Date", + httpdate::fmt_http_date(std::time::SystemTime::now()), + ), + } + } + Err(_) => Response::internal_error() + .with_header("Server", "Ignitia") + .with_header( + "Date", + httpdate::fmt_http_date(std::time::SystemTime::now()), + ), + } +} + +async fn updates( + State(pool): State, + Query(params): Query, +) -> Response { + let q = parse_params(params); + let mut rng = SmallRng::from_rng(&mut rng()); + + match pool.get().await { + Ok(client) => { + let select = client.prepare_cached(SELECT_WORLD_BY_ID).await.unwrap(); + let update = client.prepare_cached(UPDATE_WORLDS).await.unwrap(); + + let future_worlds = FuturesUnordered::new(); + for id in random_ids(&mut rng, q) { + future_worlds.push(fetch_world_by_id(&client, id, &select)); + } + + match future_worlds.try_collect::>().await { + Ok(worlds) => { + let mut ids = Vec::with_capacity(q); + let mut nids = Vec::with_capacity(q); + + let worlds: Vec = worlds + .into_iter() + .map(|mut w| { + w.randomnumber = random_id(&mut rng); + ids.push(w.id); + nids.push(w.randomnumber); + w + }) + .collect(); + + match client.execute(&update, &[&ids, &nids]).await { + Ok(_) => Response::json(worlds) + .with_header("Server", "Ignitia") + .with_header("Content-Type", "application/json") + .with_header( + "Date", + httpdate::fmt_http_date(std::time::SystemTime::now()), + ), + Err(_) => Response::internal_error() + .with_header("Server", "Ignitia") + .with_header( + "Date", + httpdate::fmt_http_date(std::time::SystemTime::now()), + ), + } + } + Err(_) => Response::internal_error() + .with_header("Server", "Ignitia") + .with_header( + "Date", + httpdate::fmt_http_date(std::time::SystemTime::now()), + ), + } + } + Err(_) => Response::internal_error() + .with_header("Server", "Ignitia") + .with_header( + "Date", + httpdate::fmt_http_date(std::time::SystemTime::now()), + ), + } +} + +#[tokio::main] +async fn main() { + dotenv::dotenv().ok(); + + let database_url: String = get_env("POSTGRES_URL"); + let max_pool_size: u32 = get_env("POSTGRES_MAX_POOL_SIZE"); + + let pool = create_pool(database_url, max_pool_size).await; + + let app = Router::new() + .get("/db", db) + .get("/queries", queries) + .get("/fortunes", fortunes) + .get("/updates", updates) + .state(pool); + + println!("Starting Ignitia PostgreSQL (deadpool) server on 0.0.0.0:8000"); + + Server::new(app, "0.0.0.0:8000".parse().unwrap()) + .with_performance_config(ignitia::PerformanceConfig::max_rps()) + .ignitia() + .await + .unwrap(); +} diff --git a/frameworks/Rust/ignitia/src/mongo/database.rs b/frameworks/Rust/ignitia/src/mongo/database.rs new file mode 100644 index 00000000000..1017b44882d --- /dev/null +++ b/frameworks/Rust/ignitia/src/mongo/database.rs @@ -0,0 +1,103 @@ +use crate::common::{ + models::{Fortune, FortuneInfo, World}, + random_ids, +}; +use futures_util::{StreamExt, TryStreamExt, stream::FuturesUnordered}; +use mongodb::{Database, bson::doc}; +use rand::rngs::SmallRng; +use std::io; + +#[allow(dead_code)] +#[derive(Debug)] +pub enum MongoError { + Io(io::Error), + Mongo(mongodb::error::Error), +} + +impl From for MongoError { + fn from(err: io::Error) -> Self { + MongoError::Io(err) + } +} + +impl From for MongoError { + fn from(err: mongodb::error::Error) -> Self { + MongoError::Mongo(err) + } +} + +pub async fn find_world_by_id(db: Database, id: i32) -> Result { + let world_collection = db.collection::("world"); + let filter = doc! { "_id": id as f32 }; + + let world: World = world_collection + .find_one(filter) + .await + .unwrap() + .expect("expected world, found none"); + + Ok(world) +} + +pub async fn find_worlds( + db: Database, + rng: &mut SmallRng, + count: usize, +) -> Result, MongoError> { + let future_worlds = FuturesUnordered::new(); + + for id in random_ids(rng, count) { + future_worlds.push(find_world_by_id(db.clone(), id)); + } + + let worlds: Result, MongoError> = future_worlds.try_collect().await; + worlds +} + +pub async fn fetch_fortunes(db: Database) -> Result, MongoError> { + let fortune_collection = db.collection::("fortune"); + + let mut fortune_cursor = fortune_collection + .find(doc! {}) + .await + .expect("fortunes could not be loaded"); + + let mut fortunes: Vec = Vec::new(); + + while let Some(doc) = fortune_cursor.next().await { + let fortune = doc.expect("could not load fortune"); + fortunes.push(FortuneInfo { + id: fortune.id, + message: fortune.message, + }); + } + + fortunes.push(FortuneInfo { + id: 0, + message: "Additional fortune added at request time.".to_string(), + }); + + fortunes.sort_by(|a, b| a.message.cmp(&b.message)); + Ok(fortunes) +} + +pub async fn update_worlds(db: Database, worlds: Vec) -> Result { + let mut updates = Vec::new(); + + for world in worlds { + updates.push(doc! { + "q": { "id": world.id }, + "u": { "$set": { "randomNumber": world.random_number }} + }); + } + + db.run_command(doc! { + "update": "world", + "updates": updates, + "ordered": false + }) + .await + .expect("could not update worlds"); + + Ok(true) +} diff --git a/frameworks/Rust/ignitia/src/mongo/mod.rs b/frameworks/Rust/ignitia/src/mongo/mod.rs new file mode 100644 index 00000000000..8fd0a6be869 --- /dev/null +++ b/frameworks/Rust/ignitia/src/mongo/mod.rs @@ -0,0 +1 @@ +pub mod database; diff --git a/frameworks/Rust/ignitia/src/pg/database.rs b/frameworks/Rust/ignitia/src/pg/database.rs new file mode 100644 index 00000000000..6f40b31d599 --- /dev/null +++ b/frameworks/Rust/ignitia/src/pg/database.rs @@ -0,0 +1,104 @@ +use super::models::{Fortune, World}; +use crate::common::{random_id, random_ids}; +use futures::StreamExt; +use rand::{SeedableRng, rng, rngs::SmallRng}; +use std::{borrow::Cow, sync::Arc}; +use tokio::pin; +use tokio_postgres::{Client, NoTls, Statement, connect}; + +pub struct PgConnection { + client: Client, + fortune: Statement, + world: Statement, + updates: Statement, +} + +impl PgConnection { + pub async fn connect(db_url: String) -> Arc { + let (cl, conn) = connect(&db_url, NoTls) + .await + .expect("cannot connect to postgresql"); + + tokio::spawn(async move { + if let Err(error) = conn.await { + eprintln!("database connection error: {error}"); + } + }); + + let fortune = cl + .prepare(crate::common::SELECT_ALL_FORTUNES) + .await + .unwrap(); + let world = cl.prepare(crate::common::SELECT_WORLD_BY_ID).await.unwrap(); + let updates = cl.prepare(crate::common::UPDATE_WORLDS).await.unwrap(); + + Arc::new(PgConnection { + client: cl, + fortune, + world, + updates, + }) + } + + pub async fn fetch_world_by_id(&self, id: i32) -> Result { + self.client + .query_one(&self.world, &[&id]) + .await + .map(|row| World { + id: row.get(0), + randomnumber: row.get(1), + }) + } + + pub async fn fetch_random_worlds( + &self, + num: usize, + ) -> Result, tokio_postgres::Error> { + let mut rng = SmallRng::from_rng(&mut rng()); + let mut worlds = Vec::with_capacity(num); + + for id in random_ids(&mut rng, num) { + worlds.push(self.fetch_world_by_id(id).await?); + } + Ok(worlds) + } + + pub async fn update_worlds(&self, num: usize) -> Result, tokio_postgres::Error> { + let mut worlds = self.fetch_random_worlds(num).await?; + let mut rng = SmallRng::from_rng(&mut rng()); + let mut ids = Vec::with_capacity(num); + let mut nids = Vec::with_capacity(num); + + for w in &mut worlds { + w.randomnumber = random_id(&mut rng); + ids.push(&w.id); + nids.push(&w.randomnumber); + } + + self.client.execute(&self.updates, &[&ids, &nids]).await?; + Ok(worlds) + } + + pub async fn fetch_all_fortunes(&self) -> Result, tokio_postgres::Error> { + let mut fortunes = vec![Fortune { + id: 0, + message: Cow::Borrowed("Additional fortune added at request time."), + }]; + + let rows = self + .client + .query_raw::<_, _, &[i32; 0]>(&self.fortune, &[]) + .await?; + pin!(rows); + + while let Some(row) = rows.next().await.transpose()? { + fortunes.push(Fortune { + id: row.get(0), + message: Cow::Owned(row.get(1)), + }); + } + + fortunes.sort_by(|it, next| it.message.cmp(&next.message)); + Ok(fortunes) + } +} diff --git a/frameworks/Rust/ignitia/src/pg/mod.rs b/frameworks/Rust/ignitia/src/pg/mod.rs new file mode 100644 index 00000000000..c51e02d23d3 --- /dev/null +++ b/frameworks/Rust/ignitia/src/pg/mod.rs @@ -0,0 +1,2 @@ +pub mod database; +pub mod models; diff --git a/frameworks/Rust/ignitia/src/pg/models.rs b/frameworks/Rust/ignitia/src/pg/models.rs new file mode 100644 index 00000000000..2feb81f7d4f --- /dev/null +++ b/frameworks/Rust/ignitia/src/pg/models.rs @@ -0,0 +1,15 @@ +use serde::{Deserialize, Serialize}; +use std::borrow::Cow; + +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] +pub struct Fortune { + pub id: i32, + pub message: Cow<'static, str>, +} + +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] +pub struct World { + pub id: i32, + #[serde(rename = "randomNumber")] + pub randomnumber: i32, +} diff --git a/frameworks/Rust/ignitia/src/pg_pool/database.rs b/frameworks/Rust/ignitia/src/pg_pool/database.rs new file mode 100644 index 00000000000..09b5a09c822 --- /dev/null +++ b/frameworks/Rust/ignitia/src/pg_pool/database.rs @@ -0,0 +1,65 @@ +use deadpool_postgres::{Client, Manager, ManagerConfig, RecyclingMethod}; +use futures_util::StreamExt; +use std::io; +use tokio::pin; +use tokio_pg_mapper::FromTokioPostgresRow; +use tokio_postgres::{NoTls, Row, Statement}; + +use super::models::{Fortune, World}; + +#[allow(dead_code)] +#[derive(Debug)] +pub enum PgError { + Io(io::Error), + Pg(tokio_postgres::Error), +} + +impl From for PgError { + fn from(err: io::Error) -> Self { + PgError::Io(err) + } +} + +impl From for PgError { + fn from(err: tokio_postgres::Error) -> Self { + PgError::Pg(err) + } +} + +pub async fn create_pool(database_url: String, max_pool_size: u32) -> deadpool_postgres::Pool { + let pg_config: tokio_postgres::Config = database_url.parse().expect("invalid database url"); + + let mgr_config = ManagerConfig { + recycling_method: RecyclingMethod::Fast, + }; + + let mgr = Manager::from_config(pg_config, NoTls, mgr_config); + deadpool_postgres::Pool::builder(mgr) + .max_size(max_pool_size as usize) + .build() + .unwrap() +} + +pub async fn fetch_world_by_id( + client: &Client, + id: i32, + select: &Statement, +) -> Result { + let row: Row = client.query_one(select, &[&id]).await.unwrap(); + Ok(World::from_row(row).unwrap()) +} + +pub async fn fetch_all_fortunes( + client: Client, + select: &Statement, +) -> Result, PgError> { + let mut fortunes: Vec = Vec::new(); + let rows = client.query_raw::<_, _, &[i32; 0]>(select, &[]).await?; + pin!(rows); + + while let Some(row) = rows.next().await.transpose()? { + fortunes.push(Fortune::from_row(row).expect("could not convert row to fortune")); + } + + Ok(fortunes) +} diff --git a/frameworks/Rust/ignitia/src/pg_pool/mod.rs b/frameworks/Rust/ignitia/src/pg_pool/mod.rs new file mode 100644 index 00000000000..c51e02d23d3 --- /dev/null +++ b/frameworks/Rust/ignitia/src/pg_pool/mod.rs @@ -0,0 +1,2 @@ +pub mod database; +pub mod models; diff --git a/frameworks/Rust/ignitia/src/pg_pool/models.rs b/frameworks/Rust/ignitia/src/pg_pool/models.rs new file mode 100644 index 00000000000..61fe8dda977 --- /dev/null +++ b/frameworks/Rust/ignitia/src/pg_pool/models.rs @@ -0,0 +1,17 @@ +use serde::{Deserialize, Serialize}; +use tokio_pg_mapper_derive::PostgresMapper; + +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize, PostgresMapper)] +#[pg_mapper(table = "Fortune")] +pub struct Fortune { + pub id: i32, + pub message: String, +} + +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize, PostgresMapper)] +#[pg_mapper(table = "World")] +pub struct World { + pub id: i32, + #[serde(rename = "randomNumber")] + pub randomnumber: i32, +} diff --git a/frameworks/Rust/ignitia/templates/fortunes.html.hbs b/frameworks/Rust/ignitia/templates/fortunes.html.hbs new file mode 100644 index 00000000000..b9e25a52a8e --- /dev/null +++ b/frameworks/Rust/ignitia/templates/fortunes.html.hbs @@ -0,0 +1,5 @@ +Fortunes + {{~# each fortunes ~}} + + {{~/each ~}} +
idmessage
{{id}}{{message}}
diff --git a/frameworks/Rust/khttp/Cargo.lock b/frameworks/Rust/khttp/Cargo.lock new file mode 100644 index 00000000000..5278faf3a17 --- /dev/null +++ b/frameworks/Rust/khttp/Cargo.lock @@ -0,0 +1,701 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[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 = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[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.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" + +[[package]] +name = "cc" +version = "1.2.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d05d92f4b1fd76aad469d46cdd858ca761576082cd37df81416691e50199fb" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" + +[[package]] +name = "chrono" +version = "0.4.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-link", +] + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[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 = "dtoa" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6add3b8cff394282be81f3fc1a0605db594ed69890078ca6e2cab1c408bcf04" + +[[package]] +name = "find-msvc-tools" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0399f9d26e5191ce32c498bebd31e7a3ceabc2745f0ac54af3f335126c3f24b3" + +[[package]] +name = "iana-time-zone" +version = "0.1.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" +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 = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "js-sys" +version = "0.3.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "khttp" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81f065beacc9822de303c4a5c66c30044ed62023b5afe70407bdcf77a088b91e" +dependencies = [ + "libc", + "memchr", +] + +[[package]] +name = "khttp-techempower" +version = "0.1.0" +dependencies = [ + "khttp", + "mimalloc", + "pq-sys", + "yarte", +] + +[[package]] +name = "libc" +version = "0.2.176" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" + +[[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 = "log" +version = "0.4.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" + +[[package]] +name = "memchr" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "mimalloc" +version = "0.1.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1ee66a4b64c74f4ef288bcbb9192ad9c3feaad75193129ac8509af543894fd8" +dependencies = [ + "libmimalloc-sys", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "pq-sys" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "412a4cb9e93795c0594dab7c1c4ec1c8b42b514e1baf6e9f63d14aa376e5bd04" +dependencies = [ + "libc", + "pkg-config", + "vcpkg", +] + +[[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.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b5288124840bee7b386bc413c487869b360b2b4ec421ea56425128692f2a82c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "833eb9ce86d40ef33cb1306d8accf7bc8ec2bfea4355cbdebb3df68b40925cad" +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 = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[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 = "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.106", +] + +[[package]] +name = "serde_json" +version = "1.0.145" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", + "serde_core", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[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 = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + +[[package]] +name = "unicode-ident" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" + +[[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 = "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 = "wasm-bindgen" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn 2.0.106", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1" +dependencies = [ + "unicode-ident", +] + +[[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.106", +] + +[[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.106", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[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 = "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", + "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", +] diff --git a/frameworks/Rust/khttp/Cargo.toml b/frameworks/Rust/khttp/Cargo.toml new file mode 100644 index 00000000000..68af03b1cb8 --- /dev/null +++ b/frameworks/Rust/khttp/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "khttp-techempower" +version = "0.1.0" +edition = "2024" + +[dependencies] +khttp = { version = "0.2", features = ["epoll"] } +yarte = { version = "0.15", features = ["json"] } +pq-sys = "0.7" +mimalloc = "0.1" + +[profile.release] +opt-level = 3 +codegen-units = 1 +panic = 'abort' +lto = true +debug = false +incremental = false +overflow-checks = false diff --git a/frameworks/Rust/khttp/README.md b/frameworks/Rust/khttp/README.md new file mode 100755 index 00000000000..02671bc3d7f --- /dev/null +++ b/frameworks/Rust/khttp/README.md @@ -0,0 +1,18 @@ +# khttp Benchmarking Test + +Benchmark for [khttp](https://github.com/karlivory/khttp) - a low-level HTTP/1.1 micro-framework. + +### Test Type Implementation Source Code + +* [JSON](./src/main.rs) +* [FORTUNES](./src/main.rs) + +## Test URLs + +### JSON + +http://localhost:8080/json + +### FORTUNES + +http://localhost:8080/fortunes diff --git a/frameworks/Rust/khttp/benchmark_config.json b/frameworks/Rust/khttp/benchmark_config.json new file mode 100755 index 00000000000..dc1c39a912c --- /dev/null +++ b/frameworks/Rust/khttp/benchmark_config.json @@ -0,0 +1,26 @@ +{ + "framework": "khttp", + "tests": [ + { + "default": { + "json_url": "/json", + "fortune_url": "/fortunes", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "Postgres", + "framework": "khttp", + "language": "Rust", + "flavor": "None", + "orm": "raw", + "platform": "None", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "khttp", + "notes": "", + "versus": "None" + } + } + ] +} diff --git a/frameworks/Rust/khttp/khttp.dockerfile b/frameworks/Rust/khttp/khttp.dockerfile new file mode 100644 index 00000000000..85096783cfd --- /dev/null +++ b/frameworks/Rust/khttp/khttp.dockerfile @@ -0,0 +1,13 @@ +FROM docker.io/rust:1.88 + +RUN apt-get update -yqq && apt-get install -yqq cmake g++ + +ADD ./ /app +WORKDIR /app + +RUN cargo clean +RUN RUSTFLAGS="-C target-cpu=native" cargo build --release + +EXPOSE 8080 + +CMD ./target/release/khttp-techempower diff --git a/frameworks/Rust/khttp/src/main.rs b/frameworks/Rust/khttp/src/main.rs new file mode 100644 index 00000000000..8a147f21705 --- /dev/null +++ b/frameworks/Rust/khttp/src/main.rs @@ -0,0 +1,181 @@ +#[global_allocator] +static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; + +use khttp::{Headers, Method::*, RequestContext, ResponseHandle, Server, Status}; +use pq_sys::{ + ConnStatusType, ExecStatusType, PGconn, PQclear, PQconnectdb, PQerrorMessage, PQexecPrepared, + PQfinish, PQgetlength, PQgetvalue, PQntuples, PQprepare, PQresultStatus, PQstatus, +}; +use std::{ffi::CStr, io, ptr, sync::LazyLock}; +use yarte::{Serialize, ywrite_html}; + +#[derive(Serialize)] +struct HelloMessage { + message: &'static str, +} + +static JSON_HEADERS: LazyLock> = LazyLock::new(|| { + let mut headers = Headers::new(); + headers.add(Headers::CONTENT_TYPE, b"application/json"); + headers.add("server", b"khttp"); + headers +}); + +fn main() { + let mut app = Server::builder("0.0.0.0:8080").unwrap(); + + app.route(Get, "/json", |_ctx, res| { + // body + let msg = HelloMessage { + message: "Hello, World!", + }; + let mut buf = Vec::with_capacity(32); + msg.to_bytes_mut(&mut buf); + + // response + res.ok(&JSON_HEADERS, buf) + }); + + app.route(Get, "/fortunes", handle_fortunes); + + app.build().serve_epoll().unwrap(); +} + +// --------------------------------------------------------------------- +// GET /fortunes handler +// --------------------------------------------------------------------- + +fn handle_fortunes(_ctx: RequestContext, res: &mut ResponseHandle) -> io::Result<()> { + // headers + let mut headers = Headers::new(); + headers.add(Headers::CONTENT_TYPE, b"text/html; charset=utf-8"); + headers.add("server", b"khttp"); + + // response + match fetch_fortunes_html() { + Ok(body) => res.ok(&headers, body), + Err(_) => res.send0(&Status::INTERNAL_SERVER_ERROR, &headers), + } +} + +// --------------------------------------------------------------------- +// /fortunes query implementation using postgres (libpq) +// --------------------------------------------------------------------- + +const DB_CONNINFO: &CStr = c"postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world"; +const PG_FORTUNES_SQL: &CStr = c"SELECT id, message FROM fortune"; +const PG_FORTUNES_PREPARED_STMT: &CStr = c"s_fortunes"; + +#[derive(Serialize)] +struct Fortune<'a> { + id: i32, + message: &'a str, +} + +fn fetch_fortunes_html() -> Result, &'static str> { + PG_CONN.with(|pg| unsafe { + let res = PQexecPrepared( + pg.conn, + PG_FORTUNES_PREPARED_STMT.as_ptr(), // stmtName + 0, // nParams + ptr::null(), // paramValues + ptr::null(), // paramLengths + ptr::null(), // paramFormats + 1, // resultFormat = 1 (binary) + ); + if res.is_null() { + return Err("PQexecPrepared returned null"); + } + if PQresultStatus(res) != ExecStatusType::PGRES_TUPLES_OK { + PQclear(res); + return Err("PQexecPrepared non-ok result status"); + } + + let rows = PQntuples(res); + let mut fortunes = Vec::with_capacity(rows as usize + 1); + + for i in 0..rows { + // field 0: id (int) + let id_ptr = PQgetvalue(res, i, 0) as *const i32; + let id = i32::from_be(ptr::read_unaligned(id_ptr)); + + // field 1: message (text) + let msg_len = PQgetlength(res, i, 1) as usize; + let msg_ptr = PQgetvalue(res, i, 1) as *const u8; + let msg_slice = std::slice::from_raw_parts(msg_ptr, msg_len); + let message = std::str::from_utf8_unchecked(msg_slice); // message fields are stored in utf8 + + fortunes.push(Fortune { id, message }); + } + + // add extra fortune + fortunes.push(Fortune { + id: 0, + message: "Additional fortune added at request time.", + }); + + // sort + fortunes.sort_by(|a, b| a.message.cmp(b.message)); + + // render html template + let mut buf = Vec::with_capacity(2048); + ywrite_html!(buf, "{{> fortunes }}"); + + PQclear(res); + Ok(buf) + }) +} + +// TLS: connection per thread +thread_local! { + static PG_CONN: PgConnection = PgConnection::new(); +} + +struct PgConnection { + conn: *mut PGconn, +} + +impl PgConnection { + fn new() -> Self { + unsafe { + // connect + let conn = PQconnectdb(DB_CONNINFO.as_ptr()); + if PQstatus(conn) != ConnStatusType::CONNECTION_OK { + let err = get_pg_error_message(conn); + PQfinish(conn); + panic!("PQconnectdb failed: {err}"); + } + + // prepare fortunes statement + let res = PQprepare( + conn, + PG_FORTUNES_PREPARED_STMT.as_ptr(), + PG_FORTUNES_SQL.as_ptr(), + 0, + ptr::null(), + ); + if res.is_null() { + PQfinish(conn); + panic!("PQprepare returned null"); + } + let st = PQresultStatus(res); + PQclear(res); + if st != ExecStatusType::PGRES_COMMAND_OK { + let err = get_pg_error_message(conn); + PQfinish(conn); + panic!("prepare failed: {err}"); + } + + PgConnection { conn } + } + } +} + +#[cold] +fn get_pg_error_message(conn: *mut PGconn) -> String { + unsafe { + CStr::from_ptr(PQerrorMessage(conn)) + .to_string_lossy() + .into_owned() + } +} diff --git a/frameworks/Rust/khttp/templates/fortunes.hbs b/frameworks/Rust/khttp/templates/fortunes.hbs new file mode 100644 index 00000000000..7e535aad0d0 --- /dev/null +++ b/frameworks/Rust/khttp/templates/fortunes.hbs @@ -0,0 +1,5 @@ +Fortunes + {{~# each fortunes ~}} + + {{~/each ~}} +
idmessage
{{id}}{{message}}
diff --git a/frameworks/Rust/may-minihttp/Cargo.lock b/frameworks/Rust/may-minihttp/Cargo.lock new file mode 100644 index 00000000000..d5c50284a95 --- /dev/null +++ b/frameworks/Rust/may-minihttp/Cargo.lock @@ -0,0 +1,1420 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[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 = "atoi" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" +dependencies = [ + "num-traits", +] + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bitflags" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" + +[[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" +dependencies = [ + "bytes", +] + +[[package]] +name = "bumpalo" +version = "3.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee" + +[[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 = "cc" +version = "1.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc" +dependencies = [ + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chrono" +version = "0.4.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-link", +] + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "core_affinity" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a034b3a7b624016c6e13f5df875747cc25f884156aad2abd12b6c46797971342" +dependencies = [ + "libc", + "num_cpus", + "winapi", +] + +[[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 = "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.104", +] + +[[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 = "fallible-iterator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" + +[[package]] +name = "generator" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d18470a76cb7f8ff746cf1f7470914f900252ec36bbc40b569d74b1258446827" +dependencies = [ + "cc", + "cfg-if", + "libc", + "log", + "rustversion", + "windows", +] + +[[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.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi", +] + +[[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 = "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 = "iana-time-zone" +version = "0.1.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" +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 = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[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 = "libc" +version = "0.2.174" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" + +[[package]] +name = "libmimalloc-sys" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88cd67e9de251c1781dbe2f641a1a3ad66eaae831b8a2c38fbdc5ddae16d4d" +dependencies = [ + "cc", + "libc", +] + +[[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 = "log" +version = "0.4.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" + +[[package]] +name = "may" +version = "0.3.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a812e25193d07288695d0e12e30ec5cd52f9fefc3c55038b89f1ef906dcab078" +dependencies = [ + "cfg-if", + "core_affinity", + "crossbeam", + "generator", + "libc", + "log", + "may_queue", + "nix", + "num_cpus", + "parking_lot", + "rustversion", + "smallvec", + "socket2", + "windows-sys 0.59.0", +] + +[[package]] +name = "may-minihttp" +version = "0.1.0" +dependencies = [ + "atoi", + "buf-min", + "bytes", + "log", + "may", + "may_minihttp", + "may_postgres", + "mimalloc", + "nanorand", + "num_cpus", + "smallvec", + "yarte", +] + +[[package]] +name = "may_minihttp" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "710fda59b93aa204a26bfc7ba9c349d90035bd1b30df10df46d7c552d107291e" +dependencies = [ + "bytes", + "httparse", + "httpdate", + "itoa", + "log", + "may", + "once_cell", +] + +[[package]] +name = "may_postgres" +version = "0.1.0" +source = "git+https://github.com/Xudong-Huang/may_postgres.git?rev=917ed78#917ed788c31825b79d38e15ad8742369bec89761" +dependencies = [ + "byteorder", + "bytes", + "crossbeam", + "fallible-iterator", + "log", + "may", + "percent-encoding", + "phf", + "postgres-protocol", + "postgres-types", + "smallvec", + "spin", +] + +[[package]] +name = "may_queue" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7026ba39000f40c16ba8ea206967380471726dd26fc34f51491b47fba9d84a94" +dependencies = [ + "crossbeam-utils", + "rustversion", + "smallvec", +] + +[[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 = "mimalloc" +version = "0.1.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1791cbe101e95af5764f06f20f6760521f7158f69dbf9d6baf941ee1bf6bc40" +dependencies = [ + "libmimalloc-sys", +] + +[[package]] +name = "nanorand" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" + +[[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", + "memoffset", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[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 = "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", +] + +[[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.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 = "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", + "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 = "proc-macro2" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +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 = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "rand" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" +dependencies = [ + "rand_chacha", + "rand_core", +] + +[[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", +] + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom", +] + +[[package]] +name = "redox_syscall" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustversion" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[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.104", +] + +[[package]] +name = "serde_json" +version = "1.0.140" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[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 = "siphasher" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[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 = "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.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tinyvec" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" +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 = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + +[[package]] +name = "typenum" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" + +[[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 = "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 = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wasi" +version = "0.14.2+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] + +[[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.104", + "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.104", + "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 = "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" +version = "0.61.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" +dependencies = [ + "windows-collections", + "windows-core", + "windows-future", + "windows-link", + "windows-numerics", +] + +[[package]] +name = "windows-collections" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" +dependencies = [ + "windows-core", +] + +[[package]] +name = "windows-core" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-future" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" +dependencies = [ + "windows-core", + "windows-link", + "windows-threading", +] + +[[package]] +name = "windows-implement" +version = "0.60.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + +[[package]] +name = "windows-interface" +version = "0.59.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + +[[package]] +name = "windows-numerics" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" +dependencies = [ + "windows-core", + "windows-link", +] + +[[package]] +name = "windows-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +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", +] + +[[package]] +name = "windows-threading" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" +dependencies = [ + "windows-link", +] + +[[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.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[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.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[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.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +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-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags", +] + +[[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", + "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.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.104", +] diff --git a/frameworks/Rust/may-minihttp/Cargo.toml b/frameworks/Rust/may-minihttp/Cargo.toml index 17e2b1d92ee..9fc7760ff8e 100644 --- a/frameworks/Rust/may-minihttp/Cargo.toml +++ b/frameworks/Rust/may-minihttp/Cargo.toml @@ -18,8 +18,8 @@ yarte = { version = "0.15", features = ["bytes-buf", "json"] } buf-min = { version = "0.7", features = ["bytes"] } may = { version = "0.3", default-features = false } -may_minihttp = { git = "https://github.com/Xudong-Huang/may_minihttp.git", rev = "f8241e7", default-features = false } -may_postgres = { git = "https://github.com/Xudong-Huang/may_postgres.git", rev = "bf1d86e", default-features = false } +may_minihttp = { version = "0.1", default-features = false } +may_postgres = { git = "https://github.com/Xudong-Huang/may_postgres.git", rev = "917ed78", default-features = false } [profile.release] opt-level = 3 diff --git a/frameworks/Rust/may-minihttp/may-minihttp.dockerfile b/frameworks/Rust/may-minihttp/may-minihttp.dockerfile index bb614e239d5..160e563ac2c 100644 --- a/frameworks/Rust/may-minihttp/may-minihttp.dockerfile +++ b/frameworks/Rust/may-minihttp/may-minihttp.dockerfile @@ -1,4 +1,4 @@ -FROM rust:1.72 +FROM rust:1.79 RUN apt-get update -yqq && apt-get install -yqq cmake g++ diff --git a/frameworks/Rust/may-minihttp/src/main.rs b/frameworks/Rust/may-minihttp/src/main.rs index 7eab3409ed1..33b410b1c0f 100644 --- a/frameworks/Rust/may-minihttp/src/main.rs +++ b/frameworks/Rust/may-minihttp/src/main.rs @@ -7,7 +7,7 @@ use std::sync::Arc; use bytes::BytesMut; use may_minihttp::{HttpService, HttpServiceFactory, Request, Response}; -use may_postgres::{self, types::ToSql, Client, Statement}; +use may_postgres::{types::ToSql, Client, Statement}; use nanorand::{Rng, WyRand}; use smallvec::SmallVec; use yarte::{ywrite_html, Serialize}; @@ -49,7 +49,7 @@ struct PgConnectionPool { impl PgConnectionPool { fn new(db_url: &'static str, size: usize) -> PgConnectionPool { let clients = (0..size) - .map(|_| std::thread::spawn(move || PgConnection::new(db_url))) + .map(|_| may::go!(move || PgConnection::new(db_url))) .collect::>(); let mut clients: Vec<_> = clients.into_iter().map(|t| t.join().unwrap()).collect(); clients.sort_by(|a, b| (a.client.id() % size).cmp(&(b.client.id() % size))); @@ -59,6 +59,7 @@ impl PgConnectionPool { fn get_connection(&self, id: usize) -> PgConnection { let len = self.clients.len(); let connection = &self.clients[id % len]; + // assert_eq!(connection.client.id() % len, id % len); PgConnection { client: connection.client.clone(), statement: connection.statement.clone(), @@ -282,7 +283,7 @@ impl HttpServiceFactory for HttpServer { fn main() { may::config().set_pool_capacity(1000).set_stack_size(0x1000); - println!("Starting http server: 127.0.0.1:8080"); + println!("Starting http server: 0.0.0.1:8080"); let server = HttpServer { db_pool: PgConnectionPool::new( "postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world", diff --git a/frameworks/Rust/ntex/Cargo.toml b/frameworks/Rust/ntex/Cargo.toml index f14828040f7..a4baf02318f 100755 --- a/frameworks/Rust/ntex/Cargo.toml +++ b/frameworks/Rust/ntex/Cargo.toml @@ -1,6 +1,6 @@ [package] -name = "ntex" -version = "0.7.0" +name = "ntex-bench" +version = "2.1.0" edition = "2018" [[bin]] @@ -8,7 +8,15 @@ name = "ntex" path = "src/main.rs" [[bin]] -name = "ntex-astd" +name = "ntex-compio" +path = "src/main.rs" + +[[bin]] +name = "ntex-neon" +path = "src/main.rs" + +[[bin]] +name = "ntex-neon-uring" path = "src/main.rs" [[bin]] @@ -16,7 +24,15 @@ name = "ntex-db" path = "src/main_db.rs" [[bin]] -name = "ntex-db-astd" +name = "ntex-db-compio" +path = "src/main_db.rs" + +[[bin]] +name = "ntex-db-neon" +path = "src/main_db.rs" + +[[bin]] +name = "ntex-db-neon-uring" path = "src/main_db.rs" [[bin]] @@ -24,7 +40,15 @@ name = "ntex-plt" path = "src/main_plt.rs" [[bin]] -name = "ntex-plt-astd" +name = "ntex-plt-compio" +path = "src/main_plt.rs" + +[[bin]] +name = "ntex-plt-neon" +path = "src/main_plt.rs" + +[[bin]] +name = "ntex-plt-neon-uring" path = "src/main_plt.rs" [features] @@ -33,26 +57,39 @@ default = [] # tokio runtime tokio = ["ntex/tokio"] -# async-std runtime -async-std = ["ntex/async-std"] +# compio runtime +compio = ["ntex/compio"] + +# neon runtime +neon = ["ntex/neon"] + +# neon runtime +neon-uring = ["ntex/neon-uring"] [dependencies] -ntex = "0.7.2" -ntex-bytes = { version = "0.1.19", features=["simd"] } +ntex = "2.13" +ntex-compio = "0.3" +ntex-neon = "0.1.31" +ntex-net = "2.5.27" +ntex-bytes = { version = "0.1.21", 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"] } buf-min = { version = "0.7", features = ["ntex-bytes"] } -env_logger = "0.10" +env_logger = "0.11" nanorand = { version = "0.7", default-features = false, features = ["std", "wyrand", "tls"] } atoi = "2.0" -num_cpus = "1.16" -smallvec = "1.11" -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" +futures = "0.3" +sonic-rs = "0.5.1" +smallvec = "1.15" +serde = { version = "1", features = ["derive"] } +serde_json = "1" log = { version = "0.4", features = ["release_max_level_off"] } tok_io = {version = "1", package = "tokio" } -tokio-postgres = { git="https://github.com/fafhrd91/postgres.git" } +tokio-postgres = { git="https://github.com/fafhrd91/postgres.git", branch="ntex-2" } + +[target.'cfg(target_os = "linux")'.dependencies] +compio-driver = { version = "*", features = ["io-uring"]} [profile.release] opt-level = 3 diff --git a/frameworks/Rust/ntex/benchmark_config.json b/frameworks/Rust/ntex/benchmark_config.json index ab6fc091970..16615823f11 100755 --- a/frameworks/Rust/ntex/benchmark_config.json +++ b/frameworks/Rust/ntex/benchmark_config.json @@ -19,7 +19,7 @@ "notes": "", "versus": "" }, - "astd": { + "neon": { "json_url": "/json", "plaintext_url": "/plaintext", "port": 8080, @@ -33,7 +33,25 @@ "webserver": "ntex", "os": "Linux", "database_os": "Linux", - "display_name": "ntex [async-std]", + "display_name": "ntex [neon]", + "notes": "", + "versus": "" + }, + "neon-uring": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "Postgres", + "framework": "ntex", + "language": "Rust", + "orm": "Raw", + "platform": "None", + "webserver": "ntex", + "os": "Linux", + "database_os": "Linux", + "display_name": "ntex [neon(io-uring)]", "notes": "", "versus": "" }, @@ -57,7 +75,27 @@ "notes": "", "versus": "" }, - "db-astd": { + "db-neon": { + "fortune_url": "/fortunes", + "db_url": "/db", + "query_url": "/query?q=", + "update_url": "/update?q=", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "Postgres", + "framework": "ntex", + "language": "Rust", + "orm": "Raw", + "platform": "None", + "webserver": "ntex", + "os": "Linux", + "database_os": "Linux", + "display_name": "ntex [neon,db]", + "notes": "", + "versus": "" + }, + "db-neon-uring": { "fortune_url": "/fortunes", "db_url": "/db", "query_url": "/query?q=", @@ -73,7 +111,7 @@ "webserver": "ntex", "os": "Linux", "database_os": "Linux", - "display_name": "ntex [async-std,db]", + "display_name": "ntex [neon(io-uring),db]", "notes": "", "versus": "" }, @@ -95,7 +133,25 @@ "notes": "", "versus": "" }, - "plt-astd": { + "plt-neon": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Platform", + "database": "Postgres", + "framework": "ntex", + "language": "Rust", + "orm": "Raw", + "platform": "None", + "webserver": "ntex", + "os": "Linux", + "database_os": "Linux", + "display_name": "ntex [neon,platform]", + "notes": "", + "versus": "" + }, + "plt-neon-uring": { "json_url": "/json", "plaintext_url": "/plaintext", "port": 8080, @@ -109,7 +165,7 @@ "webserver": "ntex", "os": "Linux", "database_os": "Linux", - "display_name": "ntex [async-std,platform]", + "display_name": "ntex [neon(io-uring),platform]", "notes": "", "versus": "" } diff --git a/frameworks/Rust/ntex/config.toml b/frameworks/Rust/ntex/config.toml index 84527c12626..ad8a0276411 100644 --- a/frameworks/Rust/ntex/config.toml +++ b/frameworks/Rust/ntex/config.toml @@ -14,7 +14,33 @@ platform = "None" webserver = "ntex" versus = "" -[astd] +[compio] +urls.plaintext = "/plaintext" +urls.json = "/json" +approach = "Realistic" +classification = "Micro" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "None" +webserver = "ntex" +versus = "" + +[neon] +urls.plaintext = "/plaintext" +urls.json = "/json" +approach = "Realistic" +classification = "Micro" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "None" +webserver = "ntex" +versus = "" + +[neon-uring] urls.plaintext = "/plaintext" urls.json = "/json" approach = "Realistic" @@ -42,7 +68,37 @@ platform = "None" webserver = "ntex" versus = "" -[db-astd] +[db-compio] +urls.db = "/db" +urls.query = "/query?q=" +urls.update = "/update?q=" +urls.fortune = "/fortunes" +approach = "Realistic" +classification = "Micro" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "None" +webserver = "ntex" +versus = "" + +[db-neon] +urls.db = "/db" +urls.query = "/query?q=" +urls.update = "/update?q=" +urls.fortune = "/fortunes" +approach = "Realistic" +classification = "Micro" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "None" +webserver = "ntex" +versus = "" + +[db-neon-uring] urls.db = "/db" urls.query = "/query?q=" urls.update = "/update?q=" @@ -70,7 +126,33 @@ platform = "None" webserver = "ntex" versus = "" -[plt-astd] +[plt-compio] +urls.plaintext = "/plaintext" +urls.json = "/json" +approach = "Realistic" +classification = "Platform" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "None" +webserver = "ntex" +versus = "" + +[plt-neon] +urls.plaintext = "/plaintext" +urls.json = "/json" +approach = "Realistic" +classification = "Platform" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "None" +webserver = "ntex" +versus = "" + +[plt-neon-uring] urls.plaintext = "/plaintext" urls.json = "/json" approach = "Realistic" diff --git a/frameworks/Rust/ntex/ntex-astd.dockerfile b/frameworks/Rust/ntex/ntex-astd.dockerfile deleted file mode 100644 index be97758bbeb..00000000000 --- a/frameworks/Rust/ntex/ntex-astd.dockerfile +++ /dev/null @@ -1,16 +0,0 @@ -FROM rust:latest - -# Disable simd at jsonescape -# ENV CARGO_CFG_JSONESCAPE_DISABLE_AUTO_SIMD= - -RUN apt-get update -yqq && apt-get install -yqq cmake g++ - -ADD ./ /ntex -WORKDIR /ntex - -RUN cargo clean -RUN RUSTFLAGS="-C target-cpu=native" cargo build --release --features="async-std" - -EXPOSE 8080 - -CMD ./target/release/ntex-astd diff --git a/frameworks/Rust/ntex/ntex-compio.dockerfile b/frameworks/Rust/ntex/ntex-compio.dockerfile new file mode 100644 index 00000000000..c825e18078e --- /dev/null +++ b/frameworks/Rust/ntex/ntex-compio.dockerfile @@ -0,0 +1,16 @@ +FROM rust:latest + +# Disable simd at jsonescape +# ENV CARGO_CFG_JSONESCAPE_DISABLE_AUTO_SIMD= + +RUN apt-get update -yqq && apt-get install -yqq cmake g++ + +ADD ./ /ntex +WORKDIR /ntex + +RUN cargo clean +RUN RUSTFLAGS="-C target-cpu=native" cargo build --release --features="compio" + +EXPOSE 8080 + +CMD ./target/release/ntex-compio diff --git a/frameworks/Rust/ntex/ntex-db-astd.dockerfile b/frameworks/Rust/ntex/ntex-db-astd.dockerfile deleted file mode 100644 index e8717d37a50..00000000000 --- a/frameworks/Rust/ntex/ntex-db-astd.dockerfile +++ /dev/null @@ -1,16 +0,0 @@ -FROM rust:latest - -# Disable simd at jsonescape -# ENV CARGO_CFG_JSONESCAPE_DISABLE_AUTO_SIMD= - -RUN apt-get update -yqq && apt-get install -yqq cmake g++ - -ADD ./ /ntex -WORKDIR /ntex - -RUN cargo clean -RUN RUSTFLAGS="-C target-cpu=native" cargo build --release --features="async-std" - -EXPOSE 8080 - -CMD ./target/release/ntex-db-astd diff --git a/frameworks/Rust/ntex/ntex-db-compio.dockerfile b/frameworks/Rust/ntex/ntex-db-compio.dockerfile new file mode 100644 index 00000000000..c892bcdc9fc --- /dev/null +++ b/frameworks/Rust/ntex/ntex-db-compio.dockerfile @@ -0,0 +1,16 @@ +FROM rust:latest + +# Disable simd at jsonescape +# ENV CARGO_CFG_JSONESCAPE_DISABLE_AUTO_SIMD= + +RUN apt-get update -yqq && apt-get install -yqq cmake g++ + +ADD ./ /ntex +WORKDIR /ntex + +RUN cargo clean +RUN RUSTFLAGS="-C target-cpu=native" cargo build --release --features="compio" + +EXPOSE 8080 + +CMD ./target/release/ntex-db-compio diff --git a/frameworks/Rust/ntex/ntex-db-neon-uring.dockerfile b/frameworks/Rust/ntex/ntex-db-neon-uring.dockerfile new file mode 100644 index 00000000000..2b65aaa1556 --- /dev/null +++ b/frameworks/Rust/ntex/ntex-db-neon-uring.dockerfile @@ -0,0 +1,16 @@ +FROM rust:latest + +# Disable simd at jsonescape +# ENV CARGO_CFG_JSONESCAPE_DISABLE_AUTO_SIMD= + +RUN apt-get update -yqq && apt-get install -yqq cmake g++ + +ADD ./ /ntex +WORKDIR /ntex + +RUN cargo clean +RUN RUSTFLAGS="-C target-cpu=native" cargo build --release --features="neon-uring" + +EXPOSE 8080 + +CMD ./target/release/ntex-db-neon-uring diff --git a/frameworks/Rust/ntex/ntex-db-neon.dockerfile b/frameworks/Rust/ntex/ntex-db-neon.dockerfile new file mode 100644 index 00000000000..0bd30d7d49c --- /dev/null +++ b/frameworks/Rust/ntex/ntex-db-neon.dockerfile @@ -0,0 +1,16 @@ +FROM rust:latest + +# Disable simd at jsonescape +# ENV CARGO_CFG_JSONESCAPE_DISABLE_AUTO_SIMD= + +RUN apt-get update -yqq && apt-get install -yqq cmake g++ + +ADD ./ /ntex +WORKDIR /ntex + +RUN cargo clean +RUN RUSTFLAGS="-C target-cpu=native" cargo build --release --features="neon" + +EXPOSE 8080 + +CMD ./target/release/ntex-db-neon diff --git a/frameworks/Rust/ntex/ntex-neon-uring.dockerfile b/frameworks/Rust/ntex/ntex-neon-uring.dockerfile new file mode 100644 index 00000000000..f69e45e7f8d --- /dev/null +++ b/frameworks/Rust/ntex/ntex-neon-uring.dockerfile @@ -0,0 +1,16 @@ +FROM rust:latest + +# Disable simd at jsonescape +# ENV CARGO_CFG_JSONESCAPE_DISABLE_AUTO_SIMD= + +RUN apt-get update -yqq && apt-get install -yqq cmake g++ + +ADD ./ /ntex +WORKDIR /ntex + +RUN cargo clean +RUN RUSTFLAGS="-C target-cpu=native" cargo build --release --features="neon-uring" + +EXPOSE 8080 + +CMD ./target/release/ntex-neon-uring diff --git a/frameworks/Rust/ntex/ntex-neon.dockerfile b/frameworks/Rust/ntex/ntex-neon.dockerfile new file mode 100644 index 00000000000..91b0ac1acba --- /dev/null +++ b/frameworks/Rust/ntex/ntex-neon.dockerfile @@ -0,0 +1,16 @@ +FROM rust:latest + +# Disable simd at jsonescape +# ENV CARGO_CFG_JSONESCAPE_DISABLE_AUTO_SIMD= + +RUN apt-get update -yqq && apt-get install -yqq cmake g++ + +ADD ./ /ntex +WORKDIR /ntex + +RUN cargo clean +RUN RUSTFLAGS="-C target-cpu=native" cargo build --release --features="neon" + +EXPOSE 8080 + +CMD ./target/release/ntex-neon diff --git a/frameworks/Rust/ntex/ntex-plt-astd.dockerfile b/frameworks/Rust/ntex/ntex-plt-astd.dockerfile deleted file mode 100644 index 8ec6c7fe636..00000000000 --- a/frameworks/Rust/ntex/ntex-plt-astd.dockerfile +++ /dev/null @@ -1,16 +0,0 @@ -FROM rust:latest - -# Disable simd at jsonescape -# ENV CARGO_CFG_JSONESCAPE_DISABLE_AUTO_SIMD= - -RUN apt-get update -yqq && apt-get install -yqq cmake g++ - -ADD ./ /ntex -WORKDIR /ntex - -RUN cargo clean -RUN RUSTFLAGS="-C target-cpu=native" cargo build --release --features="async-std" - -EXPOSE 8080 - -CMD ./target/release/ntex-plt-astd diff --git a/frameworks/Rust/ntex/ntex-plt-compio.dockerfile b/frameworks/Rust/ntex/ntex-plt-compio.dockerfile new file mode 100644 index 00000000000..849e224994b --- /dev/null +++ b/frameworks/Rust/ntex/ntex-plt-compio.dockerfile @@ -0,0 +1,16 @@ +FROM rust:latest + +# Disable simd at jsonescape +# ENV CARGO_CFG_JSONESCAPE_DISABLE_AUTO_SIMD= + +RUN apt-get update -yqq && apt-get install -yqq cmake g++ + +ADD ./ /ntex +WORKDIR /ntex + +RUN cargo clean +RUN RUSTFLAGS="-C target-cpu=native" cargo build --release --features="compio" + +EXPOSE 8080 + +CMD ./target/release/ntex-plt-compio diff --git a/frameworks/Rust/ntex/ntex-plt-neon-uring.dockerfile b/frameworks/Rust/ntex/ntex-plt-neon-uring.dockerfile new file mode 100644 index 00000000000..943c6ef2373 --- /dev/null +++ b/frameworks/Rust/ntex/ntex-plt-neon-uring.dockerfile @@ -0,0 +1,16 @@ +FROM rust:latest + +# Disable simd at jsonescape +# ENV CARGO_CFG_JSONESCAPE_DISABLE_AUTO_SIMD= + +RUN apt-get update -yqq && apt-get install -yqq cmake g++ + +ADD ./ /ntex +WORKDIR /ntex + +RUN cargo clean +RUN RUSTFLAGS="-C target-cpu=native" cargo build --release --features="neon-uring" + +EXPOSE 8080 + +CMD ./target/release/ntex-plt-neon-uring diff --git a/frameworks/Rust/ntex/ntex-plt-neon.dockerfile b/frameworks/Rust/ntex/ntex-plt-neon.dockerfile new file mode 100644 index 00000000000..766886f6997 --- /dev/null +++ b/frameworks/Rust/ntex/ntex-plt-neon.dockerfile @@ -0,0 +1,16 @@ +FROM rust:latest + +# Disable simd at jsonescape +# ENV CARGO_CFG_JSONESCAPE_DISABLE_AUTO_SIMD= + +RUN apt-get update -yqq && apt-get install -yqq cmake g++ + +ADD ./ /ntex +WORKDIR /ntex + +RUN cargo clean +RUN RUSTFLAGS="-C target-cpu=native" cargo build --release --features="neon" + +EXPOSE 8080 + +CMD ./target/release/ntex-plt-neon diff --git a/frameworks/Rust/ntex/src/db.rs b/frameworks/Rust/ntex/src/db.rs index 578465a90e2..a85b137139c 100644 --- a/frameworks/Rust/ntex/src/db.rs +++ b/frameworks/Rust/ntex/src/db.rs @@ -1,24 +1,29 @@ -use std::{cell::RefCell, fmt::Write as FmtWrite}; +use std::{borrow::Cow, cell::RefCell}; use nanorand::{Rng, WyRand}; -use ntex::util::{BufMut, Bytes, BytesMut}; +use ntex::util::{Bytes, BytesMut}; use smallvec::SmallVec; -use tokio_postgres::types::ToSql; use tokio_postgres::{connect, Client, Statement}; -use yarte::{ywrite_html, Serialize}; +use yarte::TemplateBytesTrait; use super::utils; -#[derive(Copy, Clone, Serialize, Debug)] +#[derive(Copy, Clone, Debug, sonic_rs::Serialize)] pub struct World { pub id: i32, pub randomnumber: i32, } -#[derive(Serialize, Debug)] -pub struct Fortune<'a> { +#[derive(Debug, sonic_rs::Serialize)] +pub struct Fortune { pub id: i32, - pub message: &'a str, + pub message: Cow<'static, str>, +} + +#[derive(yarte::TemplateBytes)] +#[template(path = "fortune.hbs")] +pub struct FortunesTemplate<'a> { + pub fortunes: &'a Vec, } /// Postgres interface @@ -27,8 +32,9 @@ pub struct PgConnection { fortune: Statement, world: Statement, rng: WyRand, - updates: Vec, + updates: Statement, buf: RefCell, + fbuf: RefCell>, } impl PgConnection { @@ -41,28 +47,8 @@ impl PgConnection { }); let fortune = cl.prepare("SELECT * FROM fortune").await.unwrap(); - let mut updates = Vec::new(); - for num in 1..=500u16 { - let mut pl: u16 = 1; - let mut q = String::new(); - q.push_str("UPDATE world SET randomnumber = CASE id "); - for _ in 1..=num { - let _ = write!(&mut q, "when ${} then ${} ", pl, pl + 1); - pl += 2; - } - q.push_str("ELSE randomnumber END WHERE id IN ("); - for _ in 1..=num { - let _ = write!(&mut q, "${},", pl); - pl += 1; - } - q.pop(); - q.push(')'); - updates.push(cl.prepare(&q).await.unwrap()); - } - let world = cl - .prepare("SELECT id, randomnumber FROM world WHERE id=$1") - .await - .unwrap(); + let updates = cl.prepare("UPDATE world w SET randomnumber = u.new_val FROM (SELECT unnest($1::int[]) as id, unnest($2::int[]) as new_val) u WHERE w.id = u.id").await.unwrap(); + let world = cl.prepare("SELECT * FROM world WHERE id=$1").await.unwrap(); PgConnection { cl, @@ -70,7 +56,8 @@ impl PgConnection { world, updates, rng: WyRand::new(), - buf: RefCell::new(BytesMut::with_capacity(65535)), + buf: RefCell::new(BytesMut::with_capacity(10 * 1024 * 1024)), + fbuf: RefCell::new(Vec::with_capacity(64)), } } } @@ -82,24 +69,27 @@ impl PgConnection { let row = self.cl.query_one(&self.world, &[&random_id]).await.unwrap(); let mut body = self.buf.borrow_mut(); - utils::reserve(&mut body); - World { - id: row.get(0), - randomnumber: row.get(1), - } - .to_bytes_mut(&mut *body); + 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() } pub async fn get_worlds(&self, num: usize) -> Bytes { let mut rng = self.rng.clone(); - let mut queries = SmallVec::<[_; 32]>::new(); + let mut queries = Vec::with_capacity(num); (0..num).for_each(|_| { let w_id = (rng.generate::() % 10_000 + 1) as i32; queries.push(self.cl.query_one(&self.world, &[&w_id])); }); - let mut worlds = SmallVec::<[_; 32]>::new(); + let mut worlds = Vec::with_capacity(num); for fut in queries { let row = fut.await.unwrap(); worlds.push(World { @@ -109,73 +99,67 @@ impl PgConnection { } let mut body = self.buf.borrow_mut(); - utils::reserve(&mut body); - body.put_u8(b'['); - worlds.iter().for_each(|w| { - w.to_bytes_mut(&mut *body); - body.put_u8(b','); - }); - let idx = body.len() - 1; - body[idx] = b']'; + utils::reserve(&mut body, 2 * 1024); + sonic_rs::to_writer(utils::BytesWriter(&mut body), &worlds[..]).unwrap(); body.split().freeze() } pub async fn update(&self, num: usize) -> Bytes { let mut rng = nanorand::tls_rng(); + let mut ids = Vec::with_capacity(num); + let mut numbers = Vec::with_capacity(num); + let mut worlds = SmallVec::<[_; 32]>::new(); let mut queries = SmallVec::<[_; 32]>::new(); + (0..num).for_each(|_| { let w_id = (rng.generate::() % 10_000 + 1) as i32; - queries.push(self.cl.query_one(&self.world, &[&w_id])); + ids.push(w_id); + numbers.push((rng.generate::() % 10_000 + 1) as i32); }); + ids.sort(); - let mut worlds = SmallVec::<[_; 32]>::new(); - for fut in queries.into_iter() { - let row = fut.await.unwrap(); + (0..num).for_each(|idx| { worlds.push(World { - id: row.get(0), - randomnumber: (rng.generate::() % 10_000 + 1) as i32, + id: ids[idx], + randomnumber: numbers[idx], }); - } - - let mut params: Vec<&dyn ToSql> = Vec::with_capacity(num * 3); - for w in &worlds { - params.push(&w.id); - params.push(&w.randomnumber); - } - for w in &worlds { - params.push(&w.id); - } - let _ = self.cl.query(&self.updates[num - 1], ¶ms).await; + queries.push(self.cl.query_one(&self.world, &[&ids[idx]])); + }); + let _ = self + .cl + .query(&self.updates, &[&ids, &numbers]) + .await + .unwrap(); let mut body = self.buf.borrow_mut(); - utils::reserve(&mut body); - body.put_u8(b'['); - worlds.iter().for_each(|w| { - w.to_bytes_mut(&mut *body); - body.put_u8(b','); - }); - let idx = body.len() - 1; - body[idx] = b']'; + utils::reserve(&mut body, 2 * 1024); + sonic_rs::to_writer(utils::BytesWriter(&mut body), &worlds[..]).unwrap(); body.split().freeze() } pub async fn tell_fortune(&self) -> Bytes { let rows = self.cl.query_raw(&self.fortune, &[]).await.unwrap(); - let mut fortunes = Vec::with_capacity(rows.len() + 1); + let mut fortunes = self.fbuf.borrow_mut(); fortunes.push(Fortune { id: 0, - message: "Additional fortune added at request time.", + message: Cow::Borrowed("Additional fortune added at request time."), }); fortunes.extend(rows.iter().map(|row| Fortune { id: row.get(0), - message: row.get(1), + message: Cow::Owned(row.get(1)), })); - fortunes.sort_by(|it, next| it.message.cmp(next.message)); + 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); - ywrite_html!(body, "{{> fortune }}"); + utils::reserve(&mut body, 4 * 1024); + + FortunesTemplate { + fortunes: &fortunes, + } + .write_call(&mut body); + fortunes.clear(); + let result = body.split().freeze(); let _ = std::mem::replace(&mut *self.buf.borrow_mut(), body); result diff --git a/frameworks/Rust/ntex/src/main.rs b/frameworks/Rust/ntex/src/main.rs index c9220d83247..b0e53b3f05c 100644 --- a/frameworks/Rust/ntex/src/main.rs +++ b/frameworks/Rust/ntex/src/main.rs @@ -1,9 +1,9 @@ #[global_allocator] -static GLOBAL: snmalloc_rs::SnMalloc = snmalloc_rs::SnMalloc; +static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; use ntex::http::header::{CONTENT_TYPE, SERVER}; use ntex::{http, time::Seconds, util::BytesMut, util::PoolId, web}; -use yarte::Serialize; +use sonic_rs::Serialize; mod utils; @@ -15,10 +15,13 @@ pub struct Message { #[web::get("/json")] async fn json() -> web::HttpResponse { let mut body = BytesMut::with_capacity(utils::SIZE); - Message { - message: "Hello, World!", - } - .to_bytes_mut(&mut body); + sonic_rs::to_writer( + utils::BytesWriter(&mut body), + &Message { + message: "Hello, World!", + }, + ) + .unwrap(); let mut response = web::HttpResponse::with_body(http::StatusCode::OK, body.into()); response.headers_mut().insert(SERVER, utils::HDR_SERVER); @@ -48,6 +51,7 @@ async fn main() -> std::io::Result<()> { // start http server ntex::server::build() .backlog(1024) + .enable_affinity() .bind("techempower", "0.0.0.0:8080", |cfg| { cfg.memory_pool(PoolId::P1); PoolId::P1.set_read_params(65535, 2048); @@ -55,10 +59,11 @@ async fn main() -> std::io::Result<()> { http::HttpService::build() .keep_alive(http::KeepAlive::Os) - .client_timeout(Seconds(0)) + .client_timeout(Seconds::ZERO) + .headers_read_rate(Seconds::ZERO, Seconds::ZERO, 0) + .payload_read_rate(Seconds::ZERO, Seconds::ZERO, 0) .h1(web::App::new().service(json).service(plaintext).finish()) })? - .workers(num_cpus::get()) .run() .await } diff --git a/frameworks/Rust/ntex/src/main_db.rs b/frameworks/Rust/ntex/src/main_db.rs index 8354a41fd21..544921fb594 100644 --- a/frameworks/Rust/ntex/src/main_db.rs +++ b/frameworks/Rust/ntex/src/main_db.rs @@ -1,13 +1,12 @@ #[cfg(not(target_os = "macos"))] #[global_allocator] -static GLOBAL: snmalloc_rs::SnMalloc = snmalloc_rs::SnMalloc; -// static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; +static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; use ntex::http::header::{CONTENT_TYPE, SERVER}; use ntex::http::{HttpService, KeepAlive, Request, Response, StatusCode}; use ntex::service::{Service, ServiceCtx, ServiceFactory}; use ntex::web::{Error, HttpResponse}; -use ntex::{time::Seconds, util::BoxFuture, util::PoolId}; +use ntex::{time::Seconds, util::PoolId}; mod db; mod utils; @@ -17,52 +16,49 @@ struct App(db::PgConnection); impl Service for App { type Response = Response; type Error = Error; - type Future<'f> = BoxFuture<'f, Result> where Self: 'f; - fn call<'a>(&'a self, req: Request, _: ServiceCtx<'a, Self>) -> Self::Future<'a> { - Box::pin(async move { - match req.path() { - "/db" => { - let body = self.0.get_world().await; - let mut res = HttpResponse::with_body(StatusCode::OK, body.into()); - res.headers_mut().insert(SERVER, utils::HDR_SERVER); - res.headers_mut() - .insert(CONTENT_TYPE, utils::HDR_JSON_CONTENT_TYPE); - Ok(res) - } - "/fortunes" => { - let body = self.0.tell_fortune().await; - let mut res = HttpResponse::with_body(StatusCode::OK, body.into()); - res.headers_mut().insert(SERVER, utils::HDR_SERVER); - res.headers_mut() - .insert(CONTENT_TYPE, utils::HDR_HTML_CONTENT_TYPE); - Ok(res) - } - "/query" => { - let worlds = self - .0 - .get_worlds(utils::get_query_param(req.uri().query())) - .await; - let mut res = HttpResponse::with_body(StatusCode::OK, worlds.into()); - res.headers_mut().insert(SERVER, utils::HDR_SERVER); - res.headers_mut() - .insert(CONTENT_TYPE, utils::HDR_JSON_CONTENT_TYPE); - Ok(res) - } - "/update" => { - let worlds = self - .0 - .update(utils::get_query_param(req.uri().query())) - .await; - let mut res = HttpResponse::with_body(StatusCode::OK, worlds.into()); - res.headers_mut().insert(SERVER, utils::HDR_SERVER); - res.headers_mut() - .insert(CONTENT_TYPE, utils::HDR_JSON_CONTENT_TYPE); - Ok(res) - } - _ => Ok(Response::new(StatusCode::NOT_FOUND)), + async fn call(&self, req: Request, _: ServiceCtx<'_, Self>) -> Result { + match req.path() { + "/db" => { + let body = self.0.get_world().await; + let mut res = HttpResponse::with_body(StatusCode::OK, body.into()); + res.headers_mut().insert(SERVER, utils::HDR_SERVER); + res.headers_mut() + .insert(CONTENT_TYPE, utils::HDR_JSON_CONTENT_TYPE); + Ok(res) } - }) + "/fortunes" => { + let body = self.0.tell_fortune().await; + let mut res = HttpResponse::with_body(StatusCode::OK, body.into()); + res.headers_mut().insert(SERVER, utils::HDR_SERVER); + res.headers_mut() + .insert(CONTENT_TYPE, utils::HDR_HTML_CONTENT_TYPE); + Ok(res) + } + "/query" => { + let worlds = self + .0 + .get_worlds(utils::get_query_param(req.uri().query())) + .await; + let mut res = HttpResponse::with_body(StatusCode::OK, worlds.into()); + res.headers_mut().insert(SERVER, utils::HDR_SERVER); + res.headers_mut() + .insert(CONTENT_TYPE, utils::HDR_JSON_CONTENT_TYPE); + Ok(res) + } + "/update" => { + let worlds = self + .0 + .update(utils::get_query_param(req.uri().query())) + .await; + let mut res = HttpResponse::with_body(StatusCode::OK, worlds.into()); + res.headers_mut().insert(SERVER, utils::HDR_SERVER); + res.headers_mut() + .insert(CONTENT_TYPE, utils::HDR_JSON_CONTENT_TYPE); + Ok(res) + } + _ => Ok(Response::new(StatusCode::NOT_FOUND)), + } } } @@ -73,13 +69,12 @@ impl ServiceFactory for AppFactory { type Error = Error; type Service = App; type InitError = (); - type Future<'f> = BoxFuture<'f, Result>; - fn create(&self, _: ()) -> Self::Future<'_> { + async fn create(&self, _: ()) -> Result { const DB_URL: &str = "postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world"; - Box::pin(async move { Ok(App(db::PgConnection::connect(DB_URL).await)) }) + Ok(App(db::PgConnection::connect(DB_URL).await)) } } @@ -89,6 +84,7 @@ async fn main() -> std::io::Result<()> { ntex::server::build() .backlog(1024) + .enable_affinity() .bind("techempower", "0.0.0.0:8080", |cfg| { cfg.memory_pool(PoolId::P1); PoolId::P1.set_read_params(65535, 2048); @@ -97,9 +93,10 @@ async fn main() -> std::io::Result<()> { HttpService::build() .keep_alive(KeepAlive::Os) .client_timeout(Seconds(0)) + .headers_read_rate(Seconds::ZERO, Seconds::ZERO, 0) + .payload_read_rate(Seconds::ZERO, Seconds::ZERO, 0) .h1(AppFactory) })? - .workers(num_cpus::get()) .run() .await } diff --git a/frameworks/Rust/ntex/src/main_plt.rs b/frameworks/Rust/ntex/src/main_plt.rs index 4e9279d4ebf..e16070f0b63 100644 --- a/frameworks/Rust/ntex/src/main_plt.rs +++ b/frameworks/Rust/ntex/src/main_plt.rs @@ -1,9 +1,10 @@ #[global_allocator] -static GLOBAL: snmalloc_rs::SnMalloc = snmalloc_rs::SnMalloc; -use std::{future::Future, io, pin::Pin, task::Context, task::Poll}; +static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; -use ntex::{fn_service, http::h1, io::Io, io::RecvError, util::ready, util::PoolId}; -use yarte::Serialize; +use std::{future::Future, io, pin::Pin, task::ready, task::Context, task::Poll}; + +use ntex::{fn_service, http::h1, io::Io, io::RecvError, util::PoolId}; +use sonic_rs::Serialize; mod utils; @@ -35,16 +36,19 @@ impl Future for App { Ok((req, _)) => { let _ = this.io.with_write_buf(|buf| { buf.with_bytes_mut(|buf| { - utils::reserve(buf); + utils::reserve(buf, 2 * 1024); match req.path() { "/json" => { buf.extend_from_slice(JSON); this.codec.set_date_header(buf); - Message { - message: "Hello, World!", - } - .to_bytes_mut(buf); + sonic_rs::to_writer( + utils::BytesWriter(buf), + &Message { + message: "Hello, World!", + }, + ) + .unwrap(); } "/plaintext" => { buf.extend_from_slice(PLAIN); @@ -77,6 +81,7 @@ async fn main() -> io::Result<()> { // start http server ntex::server::build() .backlog(1024) + .enable_affinity() .bind("techempower", "0.0.0.0:8080", |cfg| { cfg.memory_pool(PoolId::P1); PoolId::P1.set_read_params(65535, 2048); @@ -87,7 +92,6 @@ async fn main() -> io::Result<()> { codec: h1::Codec::default(), }) })? - .workers(num_cpus::get()) .run() .await } diff --git a/frameworks/Rust/ntex/src/utils.rs b/frameworks/Rust/ntex/src/utils.rs index 5792506dd71..6fd48e6e265 100644 --- a/frameworks/Rust/ntex/src/utils.rs +++ b/frameworks/Rust/ntex/src/utils.rs @@ -1,8 +1,9 @@ #![allow(dead_code)] -use std::cmp; +use std::{cmp, io, io::Write, mem::MaybeUninit, slice::from_raw_parts_mut}; use atoi::FromRadix10; use ntex::{http::header::HeaderValue, util::BufMut, util::Bytes, util::BytesMut}; +use sonic_rs::writer::WriteExt; pub const HDR_SERVER: HeaderValue = HeaderValue::from_static("N"); pub const HDR_JSON_CONTENT_TYPE: HeaderValue = HeaderValue::from_static("application/json"); @@ -11,7 +12,6 @@ pub const HDR_HTML_CONTENT_TYPE: HeaderValue = HeaderValue::from_static("text/html; charset=utf-8"); pub const BODY_PLAIN_TEXT: Bytes = Bytes::from_static(b"Hello, World!"); -const LW: usize = 1024; const HW: usize = 128 * 1024; pub const SIZE: usize = 27; @@ -25,9 +25,43 @@ pub fn get_query_param(query: Option<&str>) -> usize { cmp::min(500, cmp::max(1, q) as usize) } -pub fn reserve(buf: &mut BytesMut) { +pub fn reserve(buf: &mut BytesMut, lw: usize) { let remaining = buf.remaining_mut(); - if remaining < LW { + if remaining < lw { buf.reserve(HW); } } + +pub struct BytesWriter<'a>(pub &'a mut BytesMut); + +impl Write for BytesWriter<'_> { + fn write(&mut self, src: &[u8]) -> Result { + self.0.extend_from_slice(src); + Ok(src.len()) + } + + fn flush(&mut self) -> Result<(), io::Error> { + Ok(()) + } +} + +impl WriteExt for BytesWriter<'_> { + #[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(from_raw_parts_mut(ptr, additional)) + } + } + + #[inline(always)] + unsafe fn flush_len(&mut self, additional: usize) -> io::Result<()> { + unsafe { + let new_len = self.0.len() + additional; + self.0.set_len(new_len); + } + Ok(()) + } +} diff --git a/frameworks/Rust/ntex/templates/fortune.hbs b/frameworks/Rust/ntex/templates/fortune.hbs index b9e25a52a8e..499ac5ae966 100644 --- a/frameworks/Rust/ntex/templates/fortune.hbs +++ b/frameworks/Rust/ntex/templates/fortune.hbs @@ -1,5 +1,5 @@ Fortunes - {{~# each fortunes ~}} - - {{~/each ~}} +{{~# each fortunes ~}} + +{{~/each ~}}
idmessage
{{id}}{{message}}
{{id}}{{message}}
diff --git a/frameworks/Rust/ntex/templates/fortune.html b/frameworks/Rust/ntex/templates/fortune.html deleted file mode 100644 index 7c448b9d999..00000000000 --- a/frameworks/Rust/ntex/templates/fortune.html +++ /dev/null @@ -1,12 +0,0 @@ - - - Fortunes - - - - {% for item in items %} - - {% endfor %} -
idmessage
{{item.id}}{{item.message}}
- - diff --git a/frameworks/Rust/ntex/templates/fortune.stpl b/frameworks/Rust/ntex/templates/fortune.stpl deleted file mode 100644 index 238f470a43d..00000000000 --- a/frameworks/Rust/ntex/templates/fortune.stpl +++ /dev/null @@ -1,10 +0,0 @@ - - - Fortunes - - - - <% for item in items { %><% } %> -
idmessage
<%= item.id %><%= &*item.message %>
- - diff --git a/frameworks/Rust/ohkami/.gitignore b/frameworks/Rust/ohkami/.gitignore index c41cc9e35e3..b60de5b5f2c 100644 --- a/frameworks/Rust/ohkami/.gitignore +++ b/frameworks/Rust/ohkami/.gitignore @@ -1 +1 @@ -/target \ No newline at end of file +**/target diff --git a/frameworks/Rust/ohkami/Cargo.lock b/frameworks/Rust/ohkami/Cargo.lock index 5b1aeabfc54..4760079eca4 100644 --- a/frameworks/Rust/ohkami/Cargo.lock +++ b/frameworks/Rust/ohkami/Cargo.lock @@ -1,301 +1,407 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +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.6" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" dependencies = [ - "getrandom", + "getrandom 0.2.16", "once_cell", "version_check", ] [[package]] name = "aho-corasick" -version = "0.7.20" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] [[package]] -name = "android_system_properties" -version = "0.1.5" +name = "annotate-snippets" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +checksum = "ccaf7e9dfbb6ab22c82e473cd1a8a7bd313c19a5b7e40970f3d89ef5a5c9e81e" dependencies = [ - "libc", + "unicode-width", + "yansi-term", ] [[package]] -name = "annotate-snippets" -version = "0.9.1" +name = "anysc-rustls" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3b9d411ecbaf79885c6df4d75fff75858d5995ff25385657a28af47e82f9c36" +checksum = "7b04ec47ea6da4486baee0d3d4b18fb4b8c89d777f1005d5235c4caf164fa6d1" dependencies = [ - "unicode-width", - "yansi-term", + "futures-rustls", + "tokio-rustls", ] [[package]] name = "async-channel" -version = "1.8.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf46fee83e5ccffc220104713af3292ff9bc7c64c7de289f66dae8e38d826833" +checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2" dependencies = [ - "concurrent-queue", - "event-listener", + "concurrent-queue 2.5.0", + "event-listener-strategy", "futures-core", + "pin-project-lite", ] [[package]] name = "async-executor" -version = "1.5.0" +version = "1.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17adb73da160dfb475c183343c8cccd80721ea5a605d3eb57125f0a7b7a92d0b" +checksum = "497c00e0fd83a72a79a39fcbd8e3e2f055d6f6c7e025f3b3d91f4f8e76527fb8" dependencies = [ - "async-lock", "async-task", - "concurrent-queue", - "fastrand", - "futures-lite", + "concurrent-queue 2.5.0", + "fastrand 2.3.0", + "futures-lite 2.6.1", + "pin-project-lite", "slab", ] [[package]] -name = "async-global-executor" -version = "2.3.1" +name = "async-fs" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1b6f5d7df27bd294849f8eec66ecfc63d11814df7a4f5d74168a2394467b776" +checksum = "09f7e37c0ed80b2a977691c47dae8625cfb21e205827106c64f7c588766b2e50" dependencies = [ - "async-channel", - "async-executor", - "async-io", "async-lock", "blocking", - "futures-lite", - "once_cell", + "futures-lite 2.6.1", ] [[package]] name = "async-io" -version = "1.12.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c374dda1ed3e7d8f0d9ba58715f924862c63eae6849c92d3a18e7fbde9e2794" +checksum = "19634d6336019ef220f09fd31168ce5c184b295cbf80345437cc36094ef223ca" dependencies = [ "async-lock", - "autocfg", - "concurrent-queue", - "futures-lite", - "libc", - "log", + "cfg-if", + "concurrent-queue 2.5.0", + "futures-io", + "futures-lite 2.6.1", "parking", "polling", + "rustix 1.0.8", "slab", - "socket2", - "waker-fn", - "windows-sys 0.42.0", + "windows-sys 0.60.2", ] [[package]] name = "async-lock" -version = "2.6.0" +version = "3.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8101efe8695a6c17e02911402145357e718ac92d3ff88ae8419e84b1707b685" +checksum = "5fd03604047cee9b6ce9de9f70c6cd540a0520c813cbd49bae61f33ab80ed1dc" dependencies = [ "event-listener", - "futures-lite", + "event-listener-strategy", + "pin-project-lite", ] [[package]] -name = "async-native-tls" -version = "0.4.0" +name = "async-net" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d57d4cec3c647232e1094dc013546c0b33ce785d8aeb251e1f20dfaf8a9a13fe" +checksum = "b948000fad4873c1c9339d60f2623323a0cfd3816e5181033c6a5cb68b2accf7" dependencies = [ - "futures-util", - "native-tls", - "thiserror", - "url", + "async-io", + "blocking", + "futures-lite 2.6.1", ] [[package]] name = "async-process" -version = "1.6.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6381ead98388605d0d9ff86371043b5aa922a3905824244de40dc263a14fcba4" +checksum = "65daa13722ad51e6ab1a1b9c01299142bc75135b337923cfa10e79bbbd669f00" dependencies = [ + "async-channel", "async-io", "async-lock", - "autocfg", + "async-signal", + "async-task", "blocking", "cfg-if", "event-listener", - "futures-lite", - "libc", - "signal-hook", - "windows-sys 0.42.0", + "futures-lite 2.6.1", + "rustix 1.0.8", ] [[package]] -name = "async-std" -version = "1.12.0" +name = "async-signal" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" +checksum = "f567af260ef69e1d52c2b560ce0ea230763e6fbb9214a85d768760a920e3e3c1" dependencies = [ - "async-channel", - "async-global-executor", "async-io", "async-lock", - "async-process", - "crossbeam-utils", - "futures-channel", + "atomic-waker", + "cfg-if", "futures-core", "futures-io", - "futures-lite", - "gloo-timers", - "kv-log-macro", - "log", - "memchr", - "once_cell", - "pin-project-lite", - "pin-utils", + "rustix 1.0.8", + "signal-hook-registry", "slab", - "wasm-bindgen-futures", + "windows-sys 0.60.2", ] [[package]] name = "async-task" -version = "4.3.0" +version = "4.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a40729d2133846d9ed0ea60a8b9541bccddab49cd30f0715a1da672fe9a2524" +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" [[package]] -name = "atoi" -version = "1.0.0" +name = "async-trait" +version = "0.1.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7c57d12312ff59c811c0643f4d80830505833c9ffaebd193d819392b265be8e" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ - "num-traits", + "proc-macro2", + "quote", + "syn 2.0.106", ] [[package]] name = "atomic-waker" -version = "1.0.0" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "065374052e7df7ee4047b1160cca5e1467a12351a40b3da123c870ba0b8eda2a" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "autocfg" -version = "1.1.0" +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 = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets 0.52.6", +] [[package]] name = "base64" -version = "0.13.1" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] -name = "bitflags" -version = "1.3.2" +name = "bindgen" +version = "0.69.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +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.4.1" +version = "2.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +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.3" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ "generic-array", ] [[package]] name = "blocking" -version = "1.3.0" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c67b173a56acffd6d2326fb7ab938ba0b00a71480e14902b2591c87bc5741e8" +checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21" dependencies = [ "async-channel", - "async-lock", "async-task", - "atomic-waker", - "fastrand", - "futures-lite", + "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.11.1" +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 = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" +checksum = "3aad623c0c9416ec94524edd23af3f3e2fd16d1ec7d41c940084c05f77e35c96" [[package]] name = "byteorder" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +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 = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" +checksum = "981520c98f422fcc584dc1a95c334e6953900b9106bc47a9839b81790009eb21" [[package]] name = "cc" -version = "1.0.78" +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 = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] [[package]] name = "cfg-if" -version = "1.0.0" +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 = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] -name = "chrono" -version = "0.4.23" +name = "clang-sys" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" dependencies = [ - "iana-time-zone", - "js-sys", - "num-integer", - "num-traits", - "time", - "wasm-bindgen", - "winapi", + "glob", + "libc", + "libloading", ] [[package]] -name = "codespan-reporting" -version = "0.11.1" +name = "cmake" +version = "0.1.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" dependencies = [ - "termcolor", - "unicode-width", + "cc", ] [[package]] name = "concurrent-queue" -version = "2.0.0" +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 = "bd7bef69dc86e3c610e4e7aed41035e2a7ed12e72dd7530f61327a6579a4390b" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" dependencies = [ "crossbeam-utils", ] @@ -307,63 +413,69 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" [[package]] -name = "core-foundation" -version = "0.9.3" +name = "cpufeatures" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" dependencies = [ - "core-foundation-sys", "libc", ] [[package]] -name = "core-foundation-sys" -version = "0.8.3" +name = "crossbeam" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" +checksum = "1137cd7e7fc0fb5d3c5a8678be38ec56e819125d8d7907411fe24ccb943faca8" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-epoch", + "crossbeam-queue", + "crossbeam-utils", +] [[package]] -name = "cpufeatures" -version = "0.2.5" +name = "crossbeam-channel" +version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" dependencies = [ - "libc", + "crossbeam-utils", ] [[package]] -name = "crc" -version = "3.0.0" +name = "crossbeam-deque" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53757d12b596c16c78b83458d732a5d1a17ab3f53f2f7412f6fb57cc8a140ab3" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" dependencies = [ - "crc-catalog", + "crossbeam-epoch", + "crossbeam-utils", ] [[package]] -name = "crc-catalog" -version = "2.1.0" +name = "crossbeam-epoch" +version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d0165d2900ae6778e36e80bbc4da3b5eefccee9ba939761f9c2882a5d9af3ff" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] [[package]] name = "crossbeam-queue" -version = "0.3.8" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" +checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" dependencies = [ - "cfg-if", "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.14" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f" -dependencies = [ - "cfg-if", -] +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crypto-common" @@ -376,165 +488,166 @@ dependencies = [ ] [[package]] -name = "ctor" -version = "0.1.26" +name = "ctrlc" +version = "3.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096" +checksum = "46f93780a459b7d656ef7f071fe699c4d3d2cb201c4b24d085b6ddc505276e73" dependencies = [ - "quote", - "syn", + "nix 0.30.1", + "windows-sys 0.59.0", ] [[package]] -name = "cxx" -version = "1.0.85" +name = "derive_more" +version = "0.99.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5add3fc1717409d029b20c5b6903fc0c0b02fa6741d820054f4a2efa5e5816fd" +checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f" dependencies = [ - "cc", - "cxxbridge-flags", - "cxxbridge-macro", - "link-cplusplus", + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.106", ] [[package]] -name = "cxx-build" -version = "1.0.85" +name = "digest" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4c87959ba14bc6fbc61df77c3fcfe180fc32b93538c4f1031dd802ccb5f2ff0" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "cc", - "codespan-reporting", - "once_cell", - "proc-macro2", - "quote", - "scratch", - "syn", + "block-buffer", + "crypto-common", + "subtle", ] [[package]] -name = "cxxbridge-flags" -version = "1.0.85" +name = "dtoa" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69a3e162fde4e594ed2b07d0f83c6c67b745e7f28ce58c6df5e6b6bef99dfb59" +checksum = "d6add3b8cff394282be81f3fc1a0605db594ed69890078ca6e2cab1c408bcf04" [[package]] -name = "cxxbridge-macro" -version = "1.0.85" +name = "dunce" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e7e2adeb6a0d4a282e581096b06e1791532b7d576dcde5ccd9382acf55db8e6" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" [[package]] -name = "derive_more" -version = "0.99.17" +name = "either" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" -dependencies = [ - "convert_case", - "proc-macro2", - "quote", - "rustc_version", - "syn", -] +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] -name = "digest" -version = "0.10.6" +name = "enclose" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" -dependencies = [ - "block-buffer", - "crypto-common", - "subtle", -] +checksum = "eef75b364b1baff88ff28dc34e4c7c0ebd138abd76f4e58e24e37d9b7f54b8f1" [[package]] -name = "dirs" -version = "4.0.0" +name = "errno" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" +checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" dependencies = [ - "dirs-sys", + "libc", + "windows-sys 0.60.2", ] [[package]] -name = "dirs-sys" -version = "0.3.7" +name = "event-listener" +version = "5.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" dependencies = [ - "libc", - "redox_users", - "winapi", + "concurrent-queue 2.5.0", + "parking", + "pin-project-lite", ] [[package]] -name = "dotenvy" -version = "0.15.6" +name = "event-listener-strategy" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03d8c417d7a8cb362e0c37e5d815f5eb7c37f79ff93707329d5a194e42e54ca0" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" +dependencies = [ + "event-listener", + "pin-project-lite", +] [[package]] -name = "dtoa" -version = "1.0.5" +name = "fallible-iterator" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c00704156a7de8df8da0911424e30c2049957b0a714542a44e05fe693dd85313" +checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" [[package]] -name = "either" -version = "1.8.0" +name = "fastrand" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] [[package]] -name = "event-listener" -version = "2.5.3" +name = "fastrand" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] -name = "fastrand" -version = "1.8.0" +name = "flume" +version = "0.10.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" +checksum = "1657b4441c3403d9f7b3409e47575237dac27b1b5726df654a6ecbf92f0f7577" dependencies = [ - "instant", + "futures-core", + "futures-sink", + "nanorand", + "pin-project", + "spin", ] [[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +name = "framework_benchmarks" +version = "0.24.0" dependencies = [ - "foreign-types-shared", + "futures-util", + "ohkami", + "rand 0.8.5", + "tokio", + "tokio-postgres", + "yarte", ] [[package]] -name = "foreign-types-shared" -version = "0.1.1" +name = "fs_extra" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" [[package]] -name = "form_urlencoded" -version = "1.1.0" +name = "futures" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ - "percent-encoding", + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", ] [[package]] name = "futures-channel" -version = "0.3.25" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -542,34 +655,34 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.25" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] -name = "futures-intrusive" -version = "0.4.2" +name = "futures-executor" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a604f7a68fbf8103337523b1fadc8ade7361ee3f112f7c680ad179651616aed5" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", - "lock_api", - "parking_lot", + "futures-task", + "futures-util", ] [[package]] name = "futures-io" -version = "0.3.25" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-lite" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7694489acd39452c77daa48516b894c153f192c3578d5a839b62c58099fcbf48" +checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" dependencies = [ - "fastrand", + "fastrand 1.9.0", "futures-core", "futures-io", "memchr", @@ -578,35 +691,60 @@ dependencies = [ "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.25" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn", + "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.25" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.25" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" -version = "0.3.25" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ + "futures-channel", "futures-core", "futures-io", "futures-macro", @@ -620,9 +758,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.6" +version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", @@ -630,68 +768,81 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.8" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", + "js-sys", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi 0.11.1+wasi-snapshot-preview1", + "wasm-bindgen", ] [[package]] -name = "gloo-timers" -version = "0.2.5" +name = "getrandom" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98c4a8d6391675c6b2ee1a6c8d06e8e2d03605c44cec1270675985a4c2a5500b" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ - "futures-channel", - "futures-core", - "js-sys", - "wasm-bindgen", + "cfg-if", + "libc", + "r-efi", + "wasi 0.14.3+wasi-0.2.4", ] [[package]] -name = "hashbrown" -version = "0.12.3" +name = "gimli" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" -dependencies = [ - "ahash", -] +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] -name = "hashlink" -version = "0.8.1" +name = "glob" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69fe1fcf8b4278d860ad0548329f892a3631fb63f82574df68275f34cdbe0ffa" -dependencies = [ - "hashbrown", -] +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" [[package]] -name = "heck" -version = "0.4.0" +name = "glommio" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" +checksum = "e1f8bc1fce949d18098dc0a4e861314e40351a0144ebf61e59bdb5254a2273b2" dependencies = [ - "unicode-segmentation", + "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 = "hex" -version = "0.4.3" +name = "hermit-abi" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "hkdf" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" -dependencies = [ - "hmac", -] +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" [[package]] name = "hmac" @@ -703,146 +854,209 @@ dependencies = [ ] [[package]] -name = "iana-time-zone" -version = "0.1.53" +name = "home" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765" +checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "winapi", + "windows-sys 0.59.0", ] [[package]] -name = "iana-time-zone-haiku" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" -dependencies = [ - "cxx", - "cxx-build", -] - -[[package]] -name = "idna" -version = "0.3.0" +name = "instant" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "cfg-if", ] [[package]] -name = "indexmap" -version = "1.9.2" +name = "intrusive-collections" +version = "0.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" +checksum = "189d0897e4cbe8c75efedf3502c18c887b05046e59d28404d4d8e46cbc4d1e86" dependencies = [ - "autocfg", - "hashbrown", + "memoffset", ] [[package]] -name = "instant" -version = "0.1.12" +name = "io-uring" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" dependencies = [ + "bitflags", "cfg-if", + "libc", ] [[package]] name = "itertools" -version = "0.10.5" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" dependencies = [ "either", ] [[package]] name = "itoa" -version = "1.0.5" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] -name = "js-sys" -version = "0.3.60" +name = "jobserver" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" dependencies = [ - "wasm-bindgen", + "getrandom 0.3.3", + "libc", ] [[package]] -name = "kv-log-macro" -version = "1.0.7" +name = "js-sys" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" dependencies = [ - "log", + "once_cell", + "wasm-bindgen", ] [[package]] name = "lazy_static" -version = "1.4.0" +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 = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.138" +version = "0.2.175" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8" +checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" [[package]] -name = "link-cplusplus" -version = "1.0.8" +name = "libloading" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" +checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" dependencies = [ - "cc", + "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.9" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" dependencies = [ "autocfg", "scopeguard", ] [[package]] -name = "log" -version = "0.4.17" +name = "lockfree" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +checksum = "74ee94b5ad113c7cb98c5a040f783d0952ee4fe100993881d1673c2cb002dd23" dependencies = [ - "cfg-if", - "value-bag", + "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.5" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6365506850d44bff6e2fbcb5176cf63650e48bd45ef2fe2665ae1570e0f4b9ca" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" dependencies = [ + "cfg-if", "digest", ] [[package]] name = "memchr" -version = "2.5.0" +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 = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +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" @@ -851,192 +1065,259 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] -name = "native-tls" -version = "0.2.11" +name = "miniz_oxide" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", +] + +[[package]] +name = "mio" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" dependencies = [ - "lazy_static", "libc", "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", + "wasi 0.11.1+wasi-snapshot-preview1", + "windows-sys 0.59.0", ] [[package]] -name = "nom" -version = "7.1.1" +name = "mpmc-channel" +version = "0.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" +checksum = "9184bf37b24a7fcdc91a9ca61efc4f3510276693f4693735556a77cc42cc342c" + +[[package]] +name = "nanorand" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" dependencies = [ - "memchr", - "minimal-lexical", + "getrandom 0.2.16", ] [[package]] -name = "nu-ansi-term" -version = "0.46.0" +name = "nio" +version = "0.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +checksum = "85c8716fafb666bc4100593e8dcbbf930480692f9cd7755b21279343ff52b8db" dependencies = [ - "overload", - "winapi", + "crossbeam-channel", + "futures", + "libc", + "mio", + "mpmc-channel", + "nio-macros", + "socket2 0.5.10", + "tokio", ] [[package]] -name = "num-integer" -version = "0.1.45" +name = "nio-macros" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +checksum = "4a67f7f91ca31eaa3fa95a2654d86f34ea912e3b0fec9f4a89e0890b64a4e33e" dependencies = [ - "autocfg", - "num-traits", + "quote2", + "syn 2.0.106", ] [[package]] -name = "num-traits" -version = "0.2.15" +name = "nix" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" dependencies = [ - "autocfg", + "bitflags", + "cfg-if", + "libc", + "memoffset", ] [[package]] -name = "ohkami" -version = "0.1.0" +name = "nix" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" dependencies = [ - "ohkami 0.3.3", - "rand", - "serde", - "sqlx", - "yarte", + "bitflags", + "cfg-if", + "cfg_aliases", + "libc", ] [[package]] -name = "ohkami" -version = "0.3.3" +name = "nom" +version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5865b230c6e90ca5146fc32495d8e6fc601756727affb1567d0a9d0096de6c0" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" dependencies = [ - "async-std", - "chrono", - "serde", - "serde_json", - "sqlx", - "tracing", - "tracing-subscriber", + "memchr", + "minimal-lexical", ] [[package]] -name = "once_cell" -version = "1.16.0" +name = "num_cpus" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" +dependencies = [ + "hermit-abi", + "libc", +] [[package]] -name = "openssl" -version = "0.10.60" +name = "object" +version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79a4c6c3a2b158f7f8f2a2fc5a969fa3a068df6fc9dbb4a43845436e3af7c800" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ - "bitflags 2.4.1", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", + "memchr", ] [[package]] -name = "openssl-macros" -version = "0.1.0" +name = "ohkami" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" +checksum = "82a18bebc444bf9ed43b2ae864b111da831d584fa46e88aa9fa26b72d3afaf4a" dependencies = [ - "proc-macro2", - "quote", - "syn", + "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 = "openssl-probe" -version = "0.1.5" +name = "ohkami_lib" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +checksum = "057e4f200cc0d0cc66a28d55fe371acc5a7c02f66ef13c0b41a84c8ff88d1025" +dependencies = [ + "byte_reader", + "percent-encoding", + "serde", +] [[package]] -name = "openssl-sys" -version = "0.9.96" +name = "ohkami_macros" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3812c071ba60da8b5677cc12bcb1d42989a65553772897a7e0355545a819838f" +checksum = "15df818179dd272de9c427c08b3d5eaf7511cfdf41e63b232ce99723d603be0c" dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", + "proc-macro2", + "quote", + "syn 2.0.106", ] [[package]] -name = "overload" -version = "0.1.1" +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 = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" +checksum = "30fceb411f9a12ff9222c5f824026be368ff15dc2f13468d850c7d3f502205d6" [[package]] name = "parking" -version = "2.0.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" -version = "0.11.2" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" dependencies = [ - "instant", "lock_api", "parking_lot_core", ] [[package]] name = "parking_lot_core" -version = "0.8.6" +version = "0.9.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" dependencies = [ "cfg-if", - "instant", "libc", "redox_syscall", "smallvec", - "winapi", + "windows-targets 0.52.6", ] [[package]] -name = "paste" -version = "1.0.11" +name = "percent-encoding" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d01a5bd0424d00070b0098dd17ebca6f961a959dead1dbcbbbc1d1cd8d3deeba" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] -name = "percent-encoding" -version = "2.2.0" +name = "phf" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" +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.9" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "pin-utils" @@ -1045,59 +1326,129 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] -name = "pkg-config" -version = "0.3.26" +name = "piper" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" +checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" +dependencies = [ + "atomic-waker", + "fastrand 2.3.0", + "futures-io", +] [[package]] name = "polling" -version = "2.5.2" +version = "3.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22122d5ec4f9fe1b3916419b76be1e80bcb93f618d071d2edf841b137b2a2bd6" +checksum = "b5bd19146350fe804f7cb2669c851c03d69da628803dab0d98018142aaa5d829" dependencies = [ - "autocfg", "cfg-if", - "libc", - "log", - "wepoll-ffi", - "windows-sys 0.42.0", + "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.17" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] [[package]] name = "prettyplease" -version = "0.1.22" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c8992a85d8e93a28bdf76137db888d3874e3b230dee5ed8bebac4c9f7617773" +checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" dependencies = [ "proc-macro2", - "syn", + "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.49" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.23" +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 = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +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" @@ -1105,8 +1456,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha", - "rand_core", + "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]] @@ -1116,7 +1477,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "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]] @@ -1125,34 +1496,44 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom", + "getrandom 0.2.16", ] [[package]] -name = "redox_syscall" -version = "0.2.16" +name = "rand_core" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "bitflags 1.3.2", + "getrandom 0.3.3", ] [[package]] -name = "redox_users" -version = "0.4.3" +name = "redox_syscall" +version = "0.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" dependencies = [ - "getrandom", - "redox_syscall", - "thiserror", + "bitflags", ] [[package]] name = "regex" -version = "1.7.0" +version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a" +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", @@ -1161,121 +1542,183 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.28" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" +checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" [[package]] -name = "remove_dir_all" -version = "0.5.3" +name = "ring" +version = "0.17.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ - "winapi", + "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.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ "semver", ] [[package]] -name = "ryu" -version = "1.0.12" +name = "rustix" +version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys 0.4.15", + "windows-sys 0.59.0", +] [[package]] -name = "schannel" -version = "0.1.20" +name = "rustix" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2" +checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8" dependencies = [ - "lazy_static", - "windows-sys 0.36.1", + "bitflags", + "errno", + "libc", + "linux-raw-sys 0.9.4", + "windows-sys 0.60.2", ] [[package]] -name = "scopeguard" -version = "1.1.0" +name = "rustls" +version = "0.23.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +checksum = "c0ebcbd2f03de0fc1122ad9bb24b127a5a6cd51d72604a3f3c50ac459762b6cc" +dependencies = [ + "aws-lc-rs", + "log", + "once_cell", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] [[package]] -name = "scratch" -version = "1.0.3" +name = "rustls-pki-types" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddccb15bcce173023b3fedd9436f882a0739b8dfb45e4f6b6002bee5929f61b2" +checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" +dependencies = [ + "zeroize", +] [[package]] -name = "security-framework" -version = "2.7.0" +name = "rustls-webpki" +version = "0.103.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bc1bb97804af6631813c55739f771071e0f2ed33ee20b68c86ec505d906356c" +checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc" dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", + "aws-lc-rs", + "ring", + "rustls-pki-types", + "untrusted", ] [[package]] -name = "security-framework-sys" -version = "2.6.1" +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 = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" -dependencies = [ - "core-foundation-sys", - "libc", -] +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "semver" -version = "1.0.16" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" [[package]] name = "serde" -version = "1.0.151" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97fed41fc1a24994d044e6db6935e69511a1153b52c15eb42493b26fa87feba0" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.151" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "255abe9a125a985c05190d687b320c12f9b1f0b99445e608c21ba0782c719ad8" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.106", ] [[package]] name = "serde_json" -version = "1.0.91" +version = "1.0.143" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" +checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] [[package]] name = "sha1" -version = "0.10.5" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", "cpufeatures", @@ -1284,9 +1727,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.6" +version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", "cpufeatures", @@ -1294,19 +1737,16 @@ dependencies = [ ] [[package]] -name = "sharded-slab" -version = "0.1.4" +name = "shlex" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" -dependencies = [ - "lazy_static", -] +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook" -version = "0.3.14" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a253b5e89e2698464fc26b545c9edceb338e18a89effeeecfea192c3025be29d" +checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2" dependencies = [ "libc", "signal-hook-registry", @@ -1314,159 +1754,115 @@ dependencies = [ [[package]] name = "signal-hook-registry" -version = "1.4.0" +version = "1.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b" dependencies = [ "libc", ] [[package]] -name = "slab" -version = "0.4.7" +name = "siphasher" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" -dependencies = [ - "autocfg", -] +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" [[package]] -name = "smallvec" -version = "1.10.0" +name = "sketches-ddsketch" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +checksum = "04d2ecae5fcf33b122e2e6bd520a57ccf152d2dde3b38c71039df1a6867264ee" [[package]] -name = "socket2" -version = "0.4.7" +name = "slab" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" -dependencies = [ - "libc", - "winapi", -] +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" [[package]] -name = "sqlformat" -version = "0.2.0" +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 = "f87e292b4291f154971a43c3774364e2cbcaec599d3f5bf6fa9d122885dbc38a" +checksum = "a33bd3e260892199c3ccfc487c88b2da2265080acb316cd920da72fdfd7c599f" dependencies = [ - "itertools", - "nom", - "unicode_categories", + "async-channel", + "async-executor", + "async-fs", + "async-io", + "async-lock", + "async-net", + "async-process", + "blocking", + "futures-lite 2.6.1", ] [[package]] -name = "sqlx" -version = "0.6.2" +name = "socket2" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9249290c05928352f71c077cc44a464d880c63f26f7534728cca008e135c0428" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" dependencies = [ - "sqlx-core", - "sqlx-macros", + "libc", + "winapi", ] [[package]] -name = "sqlx-core" -version = "0.6.2" +name = "socket2" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcbc16ddba161afc99e14d1713a453747a2b07fc097d2009f4c300ec99286105" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" dependencies = [ - "ahash", - "atoi", - "base64", - "bitflags 1.3.2", - "byteorder", - "bytes", - "crc", - "crossbeam-queue", - "dirs", - "dotenvy", - "either", - "event-listener", - "futures-channel", - "futures-core", - "futures-intrusive", - "futures-util", - "hashlink", - "hex", - "hkdf", - "hmac", - "indexmap", - "itoa", "libc", - "log", - "md-5", - "memchr", - "once_cell", - "paste", - "percent-encoding", - "rand", - "serde", - "serde_json", - "sha1", - "sha2", - "smallvec", - "sqlformat", - "sqlx-rt", - "stringprep", - "thiserror", - "url", - "whoami", + "windows-sys 0.52.0", ] [[package]] -name = "sqlx-macros" -version = "0.6.2" +name = "socket2" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b850fa514dc11f2ee85be9d055c512aa866746adfacd1cb42d867d68e6a5b0d9" +checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" dependencies = [ - "dotenvy", - "either", - "heck", - "once_cell", - "proc-macro2", - "quote", - "sha2", - "sqlx-core", - "sqlx-rt", - "syn", - "url", + "libc", + "windows-sys 0.59.0", ] [[package]] -name = "sqlx-rt" -version = "0.6.2" +name = "spin" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24c5b2d25fa654cc5f841750b8e1cdedbe21189bf9a9382ee90bfa9dd3562396" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" dependencies = [ - "async-native-tls", - "async-std", - "native-tls", + "lock_api", ] [[package]] name = "stringprep" -version = "0.1.2" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ee348cb74b87454fff4b551cbf727025810a004f88aeacae7f85b87f4e9a1c1" +checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" dependencies = [ "unicode-bidi", "unicode-normalization", + "unicode-properties", ] [[package]] name = "subtle" -version = "2.4.1" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "1.0.107" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", "quote", @@ -1474,99 +1870,112 @@ dependencies = [ ] [[package]] -name = "tempfile" -version = "3.3.0" +name = "syn" +version = "2.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" dependencies = [ - "cfg-if", - "fastrand", - "libc", - "redox_syscall", - "remove_dir_all", - "winapi", + "proc-macro2", + "quote", + "unicode-ident", ] [[package]] -name = "termcolor" -version = "1.1.3" +name = "tinyvec" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" dependencies = [ - "winapi-util", + "tinyvec_macros", ] [[package]] -name = "thiserror" -version = "1.0.38" +name = "tinyvec_macros" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" -dependencies = [ - "thiserror-impl", -] +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] -name = "thiserror-impl" -version = "1.0.38" +name = "tokio" +version = "1.47.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" +checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" dependencies = [ - "proc-macro2", - "quote", - "syn", + "backtrace", + "bytes", + "io-uring", + "libc", + "mio", + "pin-project-lite", + "slab", + "socket2 0.6.0", + "windows-sys 0.59.0", ] [[package]] -name = "thread_local" -version = "1.1.4" +name = "tokio-postgres" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" +checksum = "6c95d533c83082bb6490e0189acaa0bbeef9084e60471b696ca6988cd0541fb0" dependencies = [ - "once_cell", + "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 = "time" -version = "0.1.45" +name = "tokio-rustls" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" +checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" dependencies = [ - "libc", - "wasi 0.10.0+wasi-snapshot-preview1", - "winapi", + "rustls", + "tokio", ] [[package]] -name = "tinyvec" -version = "1.6.0" +name = "tokio-util" +version = "0.7.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5" dependencies = [ - "tinyvec_macros", + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", ] -[[package]] -name = "tinyvec_macros" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" - [[package]] name = "toml" -version = "0.5.10" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1333c76748e868a4d9d1017b5ab53171dfd095f70c712fdb4653a406547f598f" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" dependencies = [ "serde", ] [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ - "cfg-if", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -1574,110 +1983,89 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.23" +version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" +checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.106", ] [[package]] name = "tracing-core" -version = "0.1.30" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" dependencies = [ "once_cell", - "valuable", -] - -[[package]] -name = "tracing-log" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" -dependencies = [ - "lazy_static", - "log", - "tracing-core", ] [[package]] -name = "tracing-subscriber" -version = "0.3.16" +name = "typenum" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70" -dependencies = [ - "nu-ansi-term", - "sharded-slab", - "smallvec", - "thread_local", - "tracing-core", - "tracing-log", -] +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" [[package]] -name = "typenum" -version = "1.16.0" +name = "unicase" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" [[package]] name = "unicode-bidi" -version = "0.3.8" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" +checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" [[package]] name = "unicode-ident" -version = "1.0.6" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "unicode-normalization" -version = "0.1.22" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" dependencies = [ "tinyvec", ] [[package]] -name = "unicode-segmentation" -version = "1.10.0" +name = "unicode-properties" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fdbf052a0783de01e944a6ce7a8cb939e295b1e7be835a1112c3b9a7f047a5a" +checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" [[package]] name = "unicode-width" -version = "0.1.10" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "unicode-xid" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] -name = "unicode_categories" -version = "0.1.1" +name = "untrusted" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] -name = "url" -version = "2.3.1" +name = "uuid" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +checksum = "f33196643e165781c20a5ead5582283a7dacbb87855d867fbc2df3f81eddc1be" dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", + "js-sys", + "wasm-bindgen", ] [[package]] @@ -1687,7 +2075,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dd8b599d797eb038d0dde9a3860aacb6bbba3bffa4ac64f807c8673820cc9d9" dependencies = [ "regex", - "syn", + "syn 1.0.109", ] [[package]] @@ -1696,94 +2084,70 @@ version = "0.15.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e8257fbc510f0a46eb602c10215901938b5c2a7d5e70fc11483b1d3c9b5b18c" -[[package]] -name = "valuable" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" - -[[package]] -name = "value-bag" -version = "1.0.0-alpha.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2209b78d1249f7e6f3293657c9779fe31ced465df091bbd433a1cf88e916ec55" -dependencies = [ - "ctor", - "version_check", -] - -[[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.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "waker-fn" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" +checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" [[package]] name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +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 = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.83" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if", + "once_cell", + "rustversion", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.83" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" dependencies = [ "bumpalo", "log", - "once_cell", "proc-macro2", "quote", - "syn", + "syn 2.0.106", "wasm-bindgen-shared", ] -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - [[package]] name = "wasm-bindgen-macro" -version = "0.2.83" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1791,50 +2155,56 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.83" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.106", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.83" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] [[package]] name = "web-sys" -version = "0.3.60" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" dependencies = [ "js-sys", "wasm-bindgen", ] [[package]] -name = "wepoll-ffi" -version = "0.1.2" +name = "which" +version = "4.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d743fdedc5c64377b5fc2bc036b01c7fd642205a0d96356034ae3404d49eb7fb" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" dependencies = [ - "cc", + "either", + "home", + "once_cell", + "rustix 0.38.44", ] [[package]] name = "whoami" -version = "1.2.3" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6631b6a2fd59b1841b622e8f1a7ad241ef0a46f2d580464ce8140ac94cbd571" +checksum = "5d4a4db5077702ca3015d3d02d74974948aba2ad9e12ab7df718ee64ccd7e97d" dependencies = [ - "bumpalo", - "wasm-bindgen", + "libredox", + "wasite", "web-sys", ] @@ -1855,119 +2225,178 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] -name = "winapi-util" -version = "0.1.5" +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 = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "winapi", + "windows-targets 0.52.6", ] [[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" +name = "windows-sys" +version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] [[package]] name = "windows-sys" -version = "0.36.1" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows_aarch64_msvc 0.36.1", - "windows_i686_gnu 0.36.1", - "windows_i686_msvc 0.36.1", - "windows_x86_64_gnu 0.36.1", - "windows_x86_64_msvc 0.36.1", + "windows-targets 0.53.3", ] [[package]] -name = "windows-sys" -version = "0.42.0" +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 = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc 0.42.0", - "windows_i686_gnu 0.42.0", - "windows_i686_msvc 0.42.0", - "windows_x86_64_gnu 0.42.0", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc 0.42.0", + "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.42.0" +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 = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" [[package]] name = "windows_aarch64_msvc" -version = "0.36.1" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_aarch64_msvc" -version = "0.42.0" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" [[package]] name = "windows_i686_gnu" -version = "0.36.1" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnu" -version = "0.42.0" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" +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.36.1" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_i686_msvc" -version = "0.42.0" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" [[package]] name = "windows_x86_64_gnu" -version = "0.36.1" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnu" -version = "0.42.0" +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 = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.0" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" [[package]] name = "windows_x86_64_msvc" -version = "0.36.1" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "windows_x86_64_msvc" -version = "0.42.0" +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 = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" +checksum = "052283831dbae3d879dc7f51f3d92703a316ca49f91540417d38591826127814" [[package]] name = "yansi-term" @@ -1990,13 +2419,13 @@ dependencies = [ [[package]] name = "yarte_codegen" -version = "0.15.6" +version = "0.15.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1cf72076dbf4d39fe4779b58380d7213dcb3995d00666dd2d109f1b45879ea4" +checksum = "4a79312078b97a195de91a8c1457c2e0d7abd97e6e605f3cdeb01b3c105d2cff" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", "yarte_helpers", "yarte_hir", ] @@ -2009,7 +2438,7 @@ checksum = "b296edd7e1a81717b6f794baa2de8dfe89646050847161550b2d963b3ca6fe80" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", "yarte_codegen", "yarte_helpers", "yarte_hir", @@ -2018,15 +2447,15 @@ dependencies = [ [[package]] name = "yarte_helpers" -version = "0.15.7" +version = "0.15.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8dfe1ef3558dde14b4be5387bdd41e3bd45746570743521470ec3e9cd0826679" +checksum = "e0d1076f8cee9541ea5ffbecd9102f751252c91f085e7d30a18a3ce805ebd3ee" dependencies = [ "dtoa", "itoa", - "prettyplease", + "prettyplease 0.1.25", "serde", - "syn", + "syn 1.0.109", "toml", "v_htmlescape", ] @@ -2040,7 +2469,7 @@ dependencies = [ "derive_more", "proc-macro2", "quote", - "syn", + "syn 1.0.109", "v_eval", "v_htmlescape", "yarte_helpers", @@ -2058,7 +2487,33 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn", + "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 a521a7b4f08..c905f405235 100644 --- a/frameworks/Rust/ohkami/Cargo.toml +++ b/frameworks/Rust/ohkami/Cargo.toml @@ -1,11 +1,19 @@ [package] -name = "ohkami" -version = "0.1.0" -edition = "2021" +name = "framework_benchmarks" +version = "0.24.0" +edition = "2024" +authors = ["kanarus "] [dependencies] -ohkami = { version = "0.3.3", features = ["sqlx", "postgres"] } -serde = { version = "1.0", features = ["derive"] } -sqlx = "0.6" -rand = "0.8.5" -yarte = "0.15" +ohkami = { version = "0.24" } +tokio = { optional = true, version = "1.47", 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"] } + +[features] +rt_tokio = ["ohkami/rt_tokio", "tokio", "tokio-postgres", "yarte", "futures-util", "rand"] +rt_smol = ["ohkami/rt_smol"] +rt_glommio = ["ohkami/rt_glommio"] +rt_nio = ["ohkami/rt_nio"] diff --git a/frameworks/Rust/ohkami/README.md b/frameworks/Rust/ohkami/README.md index e234565d4b4..288c9fe1b1d 100644 --- a/frameworks/Rust/ohkami/README.md +++ b/frameworks/Rust/ohkami/README.md @@ -1,15 +1,33 @@ -# [ohkami](https://github.com/kana-rus/ohkami) web framework +# [Ohkami](https://github.com/ohkami-rs/ohkami) - A performant, declarative, and runtime-flexible web framework for Rust -## Description -ohkami is **simple** and **macro free** wen framework. +## Features -## Database -- PostgreSQL +> - *macro-less and type-safe* APIs for declarative, ergonomic code +> - *runtime-flexible* : `tokio`, `smol`, `nio`, `glommio` and `worker` (Cloudflare Workers), `lambda` (AWS Lambda) +> - good performance, no-network testing, well-structured middlewares, Server-Sent Events, WebSocket, highly integrated OpenAPI document generation, ... ## Test URLs -- JSON Encoding: [http://localhost:8080/json](http://localhost:8080/json) -- Single Row Query: [http://localhost:8080/db](http://localhost:8080/db) -- Multi Row Query: [http://localhost:8080/queries](http://localhost:8080/queries) -- Fortunes: [http://localhost:8080/fortunes](http://localhost:8080/fortunes) -- Update Query: [http://localhost:8080/updates](http://localhost:8080/updates) -- Plaintext: [http://localhost:8080/plaintext](http://localhost:8080/plaintext) \ No newline at end of file + +### 1. JSON Serialization + + http://localhost:8000/json + +### 2. Single Database Query + + http://localhost:8000/db + +### 3. Multiple Database Queries + + http://localhost:8000/queries?q={count} + +### 4. Fortunes + + http://localhost:8000/fortunes + +### 5. Database Updates + + http://localhost:8000/updates?q={count} + +### 6. Plaintext + + http://localhost:8000/plaintext diff --git a/frameworks/Rust/ohkami/benchmark_config.json b/frameworks/Rust/ohkami/benchmark_config.json index b80c54f8be3..ce44db39c24 100644 --- a/frameworks/Rust/ohkami/benchmark_config.json +++ b/frameworks/Rust/ohkami/benchmark_config.json @@ -3,25 +3,77 @@ "tests": [ { "default": { - "json_url": "/json", - "plaintext_url": "/plaintext", - "fortune_url": "/fortunes", - "db_url": "/db", - "query_url": "/queries?q=", - "update_url": "/updates?q=", - "port": 8080, - "approach": "Realistic", + "dockerfile": "rt_tokio.dockerfile", + "display_name": "Ohkami [tokio]", + "framework": "Ohkami", + "webserver": "Ohkami", + "language": "Rust", + "approach": "Realistic", "classification": "Micro", - "database": "Postgres", - "framework": "ohkami", - "language": "Rust", - "orm": "Raw", - "platform": "Rust", - "webserver": "ohkami", - "os": "Linux", - "database_os": "Linux", - "display_name": "ohkami" + "database": "Postgres", + "orm": "Raw", + "platform": "None", + "os": "Linux", + "database_os": "Linux", + "port": 8000, + "json_url": "/json", + "db_url": "/db", + "query_url": "/queries?q=", + "fortune_url": "/fortunes", + "update_url": "/updates?q=", + "plaintext_url": "/plaintext" + }, + "rt_smol": { + "dockerfile": "rt_smol.dockerfile", + "display_name": "Ohkami [smol]", + "framework": "Ohkami", + "webserver": "Ohkami", + "language": "Rust", + "approach": "Realistic", + "classification": "Micro", + "database": "Postgres", + "orm": "Raw", + "platform": "None", + "os": "Linux", + "database_os": "Linux", + "port": 8000, + "json_url": "/json", + "plaintext_url": "/plaintext" + }, + "rt_glommio": { + "dockerfile": "rt_glommio.dockerfile", + "display_name": "Ohkami [glommio]", + "framework": "Ohkami", + "webserver": "Ohkami", + "language": "Rust", + "approach": "Realistic", + "classification": "Micro", + "database": "Postgres", + "orm": "Raw", + "platform": "None", + "os": "Linux", + "database_os": "Linux", + "port": 8000, + "json_url": "/json", + "plaintext_url": "/plaintext" + }, + "rt_nio": { + "dockerfile": "rt_nio.dockerfile", + "display_name": "Ohkami [nio]", + "framework": "Ohkami", + "webserver": "Ohkami", + "language": "Rust", + "approach": "Realistic", + "classification": "Micro", + "database": "Postgres", + "orm": "Raw", + "platform": "None", + "os": "Linux", + "database_os": "Linux", + "port": 8000, + "json_url": "/json", + "plaintext_url": "/plaintext" } } ] -} \ No newline at end of file +} diff --git a/frameworks/Rust/ohkami/ohkami.dockerfile b/frameworks/Rust/ohkami/ohkami.dockerfile deleted file mode 100644 index ccecec92039..00000000000 --- a/frameworks/Rust/ohkami/ohkami.dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM rust:1.65 - -RUN apt update -yqq \ - && apt install -yqq cmake g++ - -ADD ./ /ohkami -WORKDIR /ohkami - -RUN cargo clean \ - && RUSTFLAGS="-C target-cpu=native" cargo build --release - -EXPOSE 8080 -CMD ./target/release/ohkami \ No newline at end of file diff --git a/frameworks/Rust/ohkami/rt_glommio.dockerfile b/frameworks/Rust/ohkami/rt_glommio.dockerfile new file mode 100644 index 00000000000..d8426468dec --- /dev/null +++ b/frameworks/Rust/ohkami/rt_glommio.dockerfile @@ -0,0 +1,23 @@ +FROM rust:1.89-slim-bookworm 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 +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 new file mode 100644 index 00000000000..0ef27d22413 --- /dev/null +++ b/frameworks/Rust/ohkami/rt_glommio/Cargo.lock @@ -0,0 +1,1062 @@ +# 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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + +[[package]] +name = "ahash" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[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 = "bitflags" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" + +[[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 = "buddy-alloc" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3240a4cb09cf0da6a51641bd40ce90e96ea6065e3a1adc46434029254bcc2d09" + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "byte_reader" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3aad623c0c9416ec94524edd23af3f3e2fd16d1ec7d41c940084c05f77e35c96" + +[[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.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13208fcbb66eaeffe09b99fffbe1af420f00a7b35aa99ad683dfc1aa76145229" +dependencies = [ + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[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 = "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.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471" +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.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90eeab0aa92f3f9b4e87f258c72b139c207d251f9cbc1080a0086b86a8870dd3" +dependencies = [ + "nix 0.29.0", + "windows-sys", +] + +[[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 = "enclose" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef4f6f904480430009ad8f22edc9573e26e4f137365f014d7ea998d5341639a" + +[[package]] +name = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + +[[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.21.0" +dependencies = [ + "ohkami", +] + +[[package]] +name = "framework_benchmarks-glommio" +version = "0.0.0" +dependencies = [ + "framework_benchmarks", + "glommio", + "num_cpus", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[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", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite", + "waker-fn", +] + +[[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-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", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + +[[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", + "crossbeam", + "enclose", + "flume", + "futures-lite", + "intrusive-collections", + "lazy_static", + "libc", + "lockfree", + "log", + "nix 0.27.1", + "pin-project-lite", + "rlimit", + "scoped-tls", + "scopeguard", + "signal-hook", + "sketches-ddsketch", + "smallvec", + "socket2", + "tracing", + "typenum", +] + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[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 = "itoa" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" + +[[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 = "libc" +version = "0.2.169" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" + +[[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 = "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.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[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.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21788e6e675e8f19754e8c520ed420977ebade2867e2ff8363357b68c2ef8e8a" +dependencies = [ + "base64", + "futures-util", + "glommio", + "sha1", +] + +[[package]] +name = "miniz_oxide" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8402cab7aefae129c6977bb0ff1b8fd9a04eb5b51efc50a70bea51cda0c7924" +dependencies = [ + "adler2", +] + +[[package]] +name = "nanorand" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" +dependencies = [ + "getrandom", +] + +[[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.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +dependencies = [ + "bitflags", + "cfg-if", + "cfg_aliases", + "libc", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +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.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37844b8da12eece89bd239e4d8cb7d7dad07978f6f20b3917d6fe7c289361f58" +dependencies = [ + "base64", + "byte_reader", + "ctrlc", + "futures-util", + "glommio", + "hmac", + "mews", + "num_cpus", + "ohkami_lib", + "ohkami_macros", + "serde", + "serde_json", + "sha2", +] + +[[package]] +name = "ohkami_lib" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e95fa8274aba0c04904453fdd847898faf86856f7e80180305a51a5636338ed8" +dependencies = [ + "byte_reader", + "percent-encoding", + "serde", +] + +[[package]] +name = "ohkami_macros" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f326ade375c9f24daa9c029f2f6019bff9157bb780239839a6e4ce9aa136178f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "once_cell" +version = "1.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + +[[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 = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pin-project" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e2ec53ad785f4d35dac0adea7f7dc6f1bb277ad84a680c7afefeae05d1f5916" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d56a66c0c55993aa927429d0f8a0abfd74f084e4d9c192cffed01e418d83eefb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[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 = "proc-macro2" +version = "1.0.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" +dependencies = [ + "proc-macro2", +] + +[[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.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[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 = "serde" +version = "1.0.217" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.217" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "930cfb6e6abf99298aaad7d29abbef7a9999a9a8806a40088f55f0dcec03146b" +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.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" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[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 = "sketches-ddsketch" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04d2ecae5fcf33b122e2e6bd520a57ccf152d2dde3b38c71039df1a6867264ee" + +[[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.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "2.0.96" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[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.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +dependencies = [ + "once_cell", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicode-ident" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11cd88e12b17c6494200a9c1b683a04fcac9573ed74cd1b62aeb2727c5592243" + +[[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.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[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", + "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", + "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", + "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 = "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-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +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", +] + +[[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.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[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.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[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.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/frameworks/Rust/ohkami/rt_glommio/Cargo.toml b/frameworks/Rust/ohkami/rt_glommio/Cargo.toml new file mode 100644 index 00000000000..78bc03f50b8 --- /dev/null +++ b/frameworks/Rust/ohkami/rt_glommio/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "framework_benchmarks-glommio" +version = "0.0.0" +edition = "2024" +authors = ["kanarus "] + +[profile.release] +lto = true +panic = "abort" +codegen-units = 1 + +[dependencies] +framework_benchmarks = { path = "..", features = ["rt_glommio"] } +glommio = { version = "0.9" } +num_cpus = { version = "1.17" } diff --git a/frameworks/Rust/ohkami/rt_glommio/src/main.rs b/frameworks/Rust/ohkami/rt_glommio/src/main.rs new file mode 100644 index 00000000000..965a47f4912 --- /dev/null +++ b/frameworks/Rust/ohkami/rt_glommio/src/main.rs @@ -0,0 +1,11 @@ +use glommio::{LocalExecutorPoolBuilder, PoolPlacement, CpuSet}; + +fn main() { + LocalExecutorPoolBuilder::new(PoolPlacement::MaxSpread(num_cpus::get(), CpuSet::online().ok())) + .on_all_shards(|| async { + framework_benchmarks::ohkami().await + .howl("0.0.0.0:8000").await + }) + .unwrap() + .join_all(); +} diff --git a/frameworks/Rust/ohkami/rt_nio.dockerfile b/frameworks/Rust/ohkami/rt_nio.dockerfile new file mode 100644 index 00000000000..af664d37c84 --- /dev/null +++ b/frameworks/Rust/ohkami/rt_nio.dockerfile @@ -0,0 +1,22 @@ +FROM rust:1.89-slim-bookworm AS builder + +RUN apt update && apt install -y --no-install-recommends \ + pkg-config \ + && rm -rf /var/lib/apt/lists/* + +COPY ./Cargo.toml /build/ +COPY ./src/ /build/src/ +COPY ./rt_nio/ /build/rt_nio/ + +WORKDIR /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 new file mode 100644 index 00000000000..0ffab198e12 --- /dev/null +++ b/frameworks/Rust/ohkami/rt_nio/Cargo.lock @@ -0,0 +1,773 @@ +# 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.0" +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" + +[[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 = "bitflags" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" + +[[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 = "byte_reader" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3aad623c0c9416ec94524edd23af3f3e2fd16d1ec7d41c940084c05f77e35c96" + +[[package]] +name = "bytes" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471" +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.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90eeab0aa92f3f9b4e87f258c72b139c207d251f9cbc1080a0086b86a8870dd3" +dependencies = [ + "nix", + "windows-sys 0.59.0", +] + +[[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 = "framework_benchmarks" +version = "0.21.0" +dependencies = [ + "ohkami", +] + +[[package]] +name = "framework_benchmarks-nio" +version = "0.0.0" +dependencies = [ + "framework_benchmarks", + "nio", +] + +[[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", +] + +[[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 = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "itoa" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" + +[[package]] +name = "libc" +version = "0.2.169" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" + +[[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.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "mews" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21788e6e675e8f19754e8c520ed420977ebade2867e2ff8363357b68c2ef8e8a" +dependencies = [ + "base64", + "nio", + "sha1", + "tokio", +] + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +dependencies = [ + "libc", + "log", + "wasi", + "windows-sys 0.52.0", +] + +[[package]] +name = "mpmc-channel" +version = "0.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9184bf37b24a7fcdc91a9ca61efc4f3510276693f4693735556a77cc42cc342c" + +[[package]] +name = "nio" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af5df74a05351a6e56595f76330c6dc0641452291d69f36e7541a949bbbc93eb" +dependencies = [ + "crossbeam-channel", + "futures", + "libc", + "mio", + "mpmc-channel", + "nio-macros", + "socket2", + "tokio", +] + +[[package]] +name = "nio-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a67f7f91ca31eaa3fa95a2654d86f34ea912e3b0fec9f4a89e0890b64a4e33e" +dependencies = [ + "quote2", + "syn", +] + +[[package]] +name = "nix" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +dependencies = [ + "bitflags", + "cfg-if", + "cfg_aliases", + "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.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37844b8da12eece89bd239e4d8cb7d7dad07978f6f20b3917d6fe7c289361f58" +dependencies = [ + "base64", + "byte_reader", + "ctrlc", + "hmac", + "mews", + "nio", + "ohkami_lib", + "ohkami_macros", + "serde", + "serde_json", + "sha2", + "tokio", +] + +[[package]] +name = "ohkami_lib" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e95fa8274aba0c04904453fdd847898faf86856f7e80180305a51a5636338ed8" +dependencies = [ + "byte_reader", + "percent-encoding", + "serde", +] + +[[package]] +name = "ohkami_macros" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f326ade375c9f24daa9c029f2f6019bff9157bb780239839a6e4ce9aa136178f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[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", + "smallvec", + "windows-targets", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[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 = "proc-macro2" +version = "1.0.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" +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 = "redox_syscall" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" +dependencies = [ + "bitflags", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "serde" +version = "1.0.217" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.217" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "930cfb6e6abf99298aaad7d29abbef7a9999a9a8806a40088f55f0dcec03146b" +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.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[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 = "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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "2.0.96" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tokio" +version = "1.43.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e" +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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicode-ident" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11cd88e12b17c6494200a9c1b683a04fcac9573ed74cd1b62aeb2727c5592243" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +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", +] + +[[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.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[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.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[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.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/frameworks/Rust/ohkami/rt_nio/Cargo.toml b/frameworks/Rust/ohkami/rt_nio/Cargo.toml new file mode 100644 index 00000000000..a159e3e829f --- /dev/null +++ b/frameworks/Rust/ohkami/rt_nio/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "framework_benchmarks-nio" +version = "0.0.0" +edition = "2024" +authors = ["kanarus "] + +[profile.release] +lto = true +panic = "abort" +codegen-units = 1 + +[dependencies] +framework_benchmarks = { path = "..", features = ["rt_nio"] } +nio = { version = "0.0" } diff --git a/frameworks/Rust/ohkami/rt_nio/src/main.rs b/frameworks/Rust/ohkami/rt_nio/src/main.rs new file mode 100644 index 00000000000..ffaeee65b1a --- /dev/null +++ b/frameworks/Rust/ohkami/rt_nio/src/main.rs @@ -0,0 +1,5 @@ +#[nio::main] +async fn main() { + framework_benchmarks::ohkami().await + .howl("0.0.0.0:8000").await +} diff --git a/frameworks/Rust/ohkami/rt_smol.dockerfile b/frameworks/Rust/ohkami/rt_smol.dockerfile new file mode 100644 index 00000000000..935e4d09f93 --- /dev/null +++ b/frameworks/Rust/ohkami/rt_smol.dockerfile @@ -0,0 +1,22 @@ +FROM rust:1.89-slim-bookworm AS builder + +RUN apt update && apt install -y --no-install-recommends \ + pkg-config \ + && rm -rf /var/lib/apt/lists/* + +COPY ./Cargo.toml /build/ +COPY ./src/ /build/src/ +COPY ./rt_smol/ /build/rt_smol/ + +WORKDIR /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 new file mode 100644 index 00000000000..59625d44ce8 --- /dev/null +++ b/frameworks/Rust/ohkami/rt_smol/Cargo.lock @@ -0,0 +1,754 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "async-channel" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" +dependencies = [ + "concurrent-queue", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-executor" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand", + "futures-lite", + "slab", +] + +[[package]] +name = "async-fs" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebcd09b382f40fcd159c2d695175b2ae620ffa5f3bd6f664131efff4e8b9e04a" +dependencies = [ + "async-lock", + "blocking", + "futures-lite", +] + +[[package]] +name = "async-io" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a2b323ccce0a1d90b449fd71f2a06ca7faa7c54c2751f06c9bd851fc061059" +dependencies = [ + "async-lock", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite", + "parking", + "polling", + "rustix", + "slab", + "tracing", + "windows-sys", +] + +[[package]] +name = "async-lock" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" +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", +] + +[[package]] +name = "async-process" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63255f1dc2381611000436537bbedfe83183faa303a5a0edaf191edef06526bb" +dependencies = [ + "async-channel", + "async-io", + "async-lock", + "async-signal", + "async-task", + "blocking", + "cfg-if", + "event-listener", + "futures-lite", + "rustix", + "tracing", +] + +[[package]] +name = "async-signal" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "637e00349800c0bdf8bfc21ebbc0b6524abea702b0da4168ac00d070d0c0b9f3" +dependencies = [ + "async-io", + "async-lock", + "atomic-waker", + "cfg-if", + "futures-core", + "futures-io", + "rustix", + "signal-hook-registry", + "slab", + "windows-sys", +] + +[[package]] +name = "async-task" +version = "4.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" + +[[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.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bitflags" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" + +[[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.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" +dependencies = [ + "async-channel", + "async-task", + "futures-io", + "futures-lite", + "piper", +] + +[[package]] +name = "byte_reader" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3aad623c0c9416ec94524edd23af3f3e2fd16d1ec7d41c940084c05f77e35c96" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[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 = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[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.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90eeab0aa92f3f9b4e87f258c72b139c207d251f9cbc1080a0086b86a8870dd3" +dependencies = [ + "nix", + "windows-sys", +] + +[[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 = "errno" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "event-listener" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3e4e0dd3673c1139bf041f3008816d9cf2946bbfac2945c09e523b8d7b05b2" +dependencies = [ + "event-listener", + "pin-project-lite", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "framework_benchmarks" +version = "0.21.0" +dependencies = [ + "ohkami", +] + +[[package]] +name = "framework_benchmarks-smol" +version = "0.0.0" +dependencies = [ + "framework_benchmarks", + "smol", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[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 = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5edaec856126859abb19ed65f39e90fea3a9574b9707f13539acf4abf7eb532" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "parking", + "pin-project-lite", +] + +[[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-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 = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "itoa" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" + +[[package]] +name = "libc" +version = "0.2.169" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" + +[[package]] +name = "linux-raw-sys" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "mews" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21788e6e675e8f19754e8c520ed420977ebade2867e2ff8363357b68c2ef8e8a" +dependencies = [ + "base64", + "sha1", + "smol", +] + +[[package]] +name = "nix" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +dependencies = [ + "bitflags", + "cfg-if", + "cfg_aliases", + "libc", +] + +[[package]] +name = "ohkami" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37844b8da12eece89bd239e4d8cb7d7dad07978f6f20b3917d6fe7c289361f58" +dependencies = [ + "base64", + "byte_reader", + "ctrlc", + "futures-util", + "hmac", + "mews", + "ohkami_lib", + "ohkami_macros", + "serde", + "serde_json", + "sha2", + "smol", +] + +[[package]] +name = "ohkami_lib" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e95fa8274aba0c04904453fdd847898faf86856f7e80180305a51a5636338ed8" +dependencies = [ + "byte_reader", + "percent-encoding", + "serde", +] + +[[package]] +name = "ohkami_macros" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f326ade375c9f24daa9c029f2f6019bff9157bb780239839a6e4ce9aa136178f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[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", + "futures-io", +] + +[[package]] +name = "polling" +version = "3.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f" +dependencies = [ + "cfg-if", + "concurrent-queue", + "hermit-abi", + "pin-project-lite", + "rustix", + "tracing", + "windows-sys", +] + +[[package]] +name = "proc-macro2" +version = "1.0.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" +dependencies = [ + "proc-macro2", +] + +[[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", +] + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "serde" +version = "1.0.217" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.217" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "930cfb6e6abf99298aaad7d29abbef7a9999a9a8806a40088f55f0dcec03146b" +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.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[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 = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[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", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "2.0.96" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicode-ident" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11cd88e12b17c6494200a9c1b683a04fcac9573ed74cd1b62aeb2727c5592243" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +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", +] + +[[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.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[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.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[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.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/frameworks/Rust/ohkami/rt_smol/Cargo.toml b/frameworks/Rust/ohkami/rt_smol/Cargo.toml new file mode 100644 index 00000000000..2484a598d18 --- /dev/null +++ b/frameworks/Rust/ohkami/rt_smol/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "framework_benchmarks-smol" +version = "0.0.0" +edition = "2024" +authors = ["kanarus "] + +[profile.release] +lto = true +panic = "abort" +codegen-units = 1 + +[dependencies] +framework_benchmarks = { path = "..", features = ["rt_smol"] } +smol = { version = "2.0" } diff --git a/frameworks/Rust/ohkami/rt_smol/src/main.rs b/frameworks/Rust/ohkami/rt_smol/src/main.rs new file mode 100644 index 00000000000..68d594b664a --- /dev/null +++ b/frameworks/Rust/ohkami/rt_smol/src/main.rs @@ -0,0 +1,6 @@ +fn main() { + smol::block_on(async { + framework_benchmarks::ohkami().await + .howl("0.0.0.0:8000").await + }) +} diff --git a/frameworks/Rust/ohkami/rt_tokio.dockerfile b/frameworks/Rust/ohkami/rt_tokio.dockerfile new file mode 100644 index 00000000000..35359c9a9bf --- /dev/null +++ b/frameworks/Rust/ohkami/rt_tokio.dockerfile @@ -0,0 +1,26 @@ +FROM rust:1.89-slim-bookworm AS builder + +RUN apt update && apt install -y --no-install-recommends \ + pkg-config \ + libpq-dev libssl-dev \ + && rm -rf /var/lib/apt/lists/* + +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 +CMD [ "/app/framework_benchmarks-tokio" ] diff --git a/frameworks/Rust/ohkami/rt_tokio/Cargo.lock b/frameworks/Rust/ohkami/rt_tokio/Cargo.lock new file mode 100644 index 00000000000..4a5fe5e8bf6 --- /dev/null +++ b/frameworks/Rust/ohkami/rt_tokio/Cargo.lock @@ -0,0 +1,1770 @@ +# 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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + +[[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-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 = "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" +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.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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" + +[[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 = "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.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" + +[[package]] +name = "cc" +version = "1.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13208fcbb66eaeffe09b99fffbe1af420f00a7b35aa99ad683dfc1aa76145229" +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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[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 = "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 = "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.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90eeab0aa92f3f9b4e87f258c72b139c207d251f9cbc1080a0086b86a8870dd3" +dependencies = [ + "nix", + "windows-sys 0.59.0", +] + +[[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.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.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653" + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "errno" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "fallible-iterator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" + +[[package]] +name = "framework_benchmarks" +version = "0.24.0" +dependencies = [ + "futures-util", + "ohkami", + "rand 0.8.5", + "tokio", + "tokio-postgres", + "yarte", +] + +[[package]] +name = "framework_benchmarks-tokio" +version = "0.0.0" +dependencies = [ + "framework_benchmarks", + "num_cpus", + "tokio", +] + +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + +[[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-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.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-core", + "futures-macro", + "futures-sink", + "futures-task", + "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 0.11.0+wasi-snapshot-preview1", +] + +[[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 = "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 = "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.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" + +[[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", +] + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" + +[[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 = "mews" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8554a5554e9be00776567382b100a89e550a6031fc76356455157d230caca7a5" +dependencies = [ + "base64", + "futures-util", + "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 = "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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +dependencies = [ + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.52.0", +] + +[[package]] +name = "nix" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +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", + "hmac", + "mews", + "mime_guess", + "ohkami_lib", + "ohkami_macros", + "serde", + "serde_json", + "sha2", + "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.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + +[[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", + "smallvec", + "windows-targets", +] + +[[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.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-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 = "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.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 = "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.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" +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.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.15", +] + +[[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.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[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.15", + "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" +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", + "windows-sys 0.59.0", +] + +[[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.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[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.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f79dfe2d285b0488816f30e700a7438c5a73d816b5b7d3ac72fbc48b0d185e03" + +[[package]] +name = "serde" +version = "1.0.217" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.217" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "serde_json" +version = "1.0.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "930cfb6e6abf99298aaad7d29abbef7a9999a9a8806a40088f55f0dcec03146b" +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.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 = "siphasher" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" +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 = "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.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "022db8904dfa342efe721985167e9fcd16c29b226db4397ed752a761cfce81e8" +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", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "slab", + "socket2 0.6.0", + "tokio-macros", + "windows-sys 0.59.0", +] + +[[package]] +name = "tokio-macros" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[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.8", + "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 = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[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.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11cd88e12b17c6494200a9c1b683a04fcac9573ed74cd1b62aeb2727c5592243" + +[[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 = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[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", +] + +[[package]] +name = "whoami" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "372d5b87f58ec45c384ba03563b03544dc5fadc3983e434b286913f5b4a9bb6d" +dependencies = [ + "redox_syscall", + "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-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +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", +] + +[[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.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[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.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[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.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +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.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.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.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/rt_tokio/Cargo.toml b/frameworks/Rust/ohkami/rt_tokio/Cargo.toml new file mode 100644 index 00000000000..8f464cad8b9 --- /dev/null +++ b/frameworks/Rust/ohkami/rt_tokio/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "framework_benchmarks-tokio" +version = "0.0.0" +edition = "2024" +authors = ["kanarus "] + +[profile.release] +lto = true +panic = "abort" +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 new file mode 100644 index 00000000000..8a801fa838e --- /dev/null +++ b/frameworks/Rust/ohkami/rt_tokio/src/main.rs @@ -0,0 +1,39 @@ +fn runtime() -> tokio::runtime::Runtime { + tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .unwrap() +} + +async fn serve( + server: impl FnOnce(tokio::net::TcpListener) -> ServeFuture, +) -> std::io::Result<()> { + println!("start serving !"); + + let socket = tokio::net::TcpSocket::new_v4()?; + socket.set_reuseport(true)?; + socket.set_reuseaddr(true)?; + socket.set_nodelay(true)?; + + socket.bind("0.0.0.0:8000".parse().unwrap())?; + server(socket.listen(4096)?).await; + + Ok(()) +} + +fn main() { + for _ in 0..(num_cpus::get() - 1/*for main thread*/) { + std::thread::spawn(|| { + runtime().block_on(async { + serve(|listener| async { + framework_benchmarks::ohkami().await.howl(listener).await + }).await.expect("serving error") + }) + }); + } + runtime().block_on(async { + serve(|listener| async { + framework_benchmarks::ohkami().await.howl(listener).await + }).await.expect("serving error") + }); +} diff --git a/frameworks/Rust/ohkami/src/components.rs b/frameworks/Rust/ohkami/src/components.rs deleted file mode 100644 index 7fab61e573b..00000000000 --- a/frameworks/Rust/ohkami/src/components.rs +++ /dev/null @@ -1,60 +0,0 @@ -pub(crate) mod consts { - use std::ops::RangeInclusive; - - pub const RAND_RANGE: RangeInclusive = 1..=10000; - pub const DB_URL: &'static str = "postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world?sslmode=disable"; - pub const MAX_CONNECTIONS: u32 = 10000; -} - -pub(crate) mod models { - use serde::Serialize; - use sqlx::FromRow; - use yarte::Template; - - #[derive(FromRow, Serialize)] - pub struct World { - id: i32, - randomnumber: i32, - } impl World { - pub fn set_randomnumber(&mut self, new_randomnumber: i32) { - self.randomnumber = new_randomnumber - } - } - - #[derive(FromRow, Serialize)] - pub struct Fortune { - pub id: i32, - pub message: String, - } - #[derive(Template)] - #[template(path = "fortunes.hbs")] - pub(crate) struct FortunesTemplate { - pub(crate) fortunes: Vec - } -} - -pub(crate) mod functions { - use ohkami::{prelude::Body, result::{Result, ElseResponseWithErr}, response::Response}; - use rand::Rng; - use yarte::Template; - use super::{models::{Fortune, FortunesTemplate}, consts::RAND_RANGE}; - - pub fn random_i32() -> i32 { - rand::thread_rng().gen_range(RAND_RANGE) as i32 - } - pub fn random_i32s(n: usize) -> std::vec::IntoIter { - let mut generator = rand::thread_rng(); - let mut i32s = Vec::with_capacity(n); - for _ in 0..n { - i32s.push(generator.gen_range(RAND_RANGE) as i32) - } - i32s.into_iter() - } - pub fn render_html(fortunes: Vec) -> Result { - Response::OK(Body::html( - FortunesTemplate {fortunes} - .call() - ._else(|_| Response::InternalServerError("failed to render template"))? - )) - } -} diff --git a/frameworks/Rust/ohkami/src/fangs.rs b/frameworks/Rust/ohkami/src/fangs.rs new file mode 100644 index 00000000000..f7592303d63 --- /dev/null +++ b/frameworks/Rust/ohkami/src/fangs.rs @@ -0,0 +1,10 @@ +use ohkami::prelude::*; + +#[derive(Clone)] +pub struct SetServer; +impl FangAction for SetServer { + #[inline(always)] + async fn back<'a>(&'a self, res: &'a mut ohkami::Response) { + res.headers.set().server("ohkami"); + } +} diff --git a/frameworks/Rust/ohkami/src/lib.rs b/frameworks/Rust/ohkami/src/lib.rs new file mode 100644 index 00000000000..aa289a822d5 --- /dev/null +++ b/frameworks/Rust/ohkami/src/lib.rs @@ -0,0 +1,85 @@ +mod fangs; +mod models; +#[cfg(feature = "rt_tokio")] mod postgres; +#[cfg(feature = "rt_tokio")] mod templates; + +use { + fangs::SetServer, + models::Message, + ohkami::prelude::*, +}; +#[cfg(feature = "rt_tokio")] use { + models::{Fortune, World, WorldsMeta}, + postgres::Postgres, + templates::FortunesTemplate, +}; + +pub async fn ohkami() -> Ohkami { + Ohkami::new(( + SetServer, + #[cfg(feature = "rt_tokio")] + Context::new(Postgres::new().await), + + "/plaintext".GET(plaintext), + "/json".GET(json_serialization), + #[cfg(feature = "rt_tokio")] + "/db".GET(single_database_query), + #[cfg(feature = "rt_tokio")] + "/queries".GET(multiple_database_query), + #[cfg(feature = "rt_tokio")] + "/fortunes".GET(fortunes), + #[cfg(feature = "rt_tokio")] + "/updates".GET(database_updates), + )) +} + +async fn plaintext() -> &'static str { + "Hello, World!" +} + +async fn json_serialization() -> Json { + Json(Message { + message: "Hello, World!" + }) +} + +#[cfg(feature = "rt_tokio")] +async fn single_database_query( + Context(db): Context<'_, Postgres>, +) -> Json { + let world = db.select_random_world().await; + Json(world) +} + +#[cfg(feature = "rt_tokio")] +async fn multiple_database_query( + Query(q): Query>, + Context(db): Context<'_, Postgres>, +) -> Json> { + let n = q.parse(); + let worlds = db.select_n_random_worlds(n).await; + Json(worlds) +} + +#[cfg(feature = "rt_tokio")] +async fn fortunes( + Context(db): Context<'_, Postgres>, +) -> FortunesTemplate { + 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 } +} + +#[cfg(feature = "rt_tokio")] +async fn database_updates( + Query(q): Query>, + Context(db): Context<'_, Postgres>, +) -> Json> { + let n = q.parse(); + let worlds = db.update_randomnumbers_of_n_worlds(n).await; + Json(worlds) +} diff --git a/frameworks/Rust/ohkami/src/main.rs b/frameworks/Rust/ohkami/src/main.rs deleted file mode 100644 index de77651f067..00000000000 --- a/frameworks/Rust/ohkami/src/main.rs +++ /dev/null @@ -1,97 +0,0 @@ -use ohkami::{prelude::*, json}; -use sqlx::postgres::PgPoolOptions; -mod components; use components::{ - consts::{DB_URL, MAX_CONNECTIONS}, - models::{World, Fortune}, - functions::{random_i32, random_i32s, render_html}, -}; - -fn main() -> Result<()> { - let config = Config { - db_profile: DBprofile { - pool_options: PgPoolOptions::new().max_connections(MAX_CONNECTIONS), - url: DB_URL, - }, - log_subscribe: None, - ..Default::default() - }; - - Server::setup_with(config) - .GET("/json", || async {Response::OK(json!("message": "Hello, World!"))}) - .GET("/plaintext", || async {Response::OK("Hello, World!")}) - .GET("/db", handle_db) - .GET("/fortunes", handle_fortunes) - .GET("/queries", handle_queries) - .GET("/updates", handle_updates) - .serve_on(":8080") -} - -async fn handle_db(ctx: Context) -> Result { - let id = random_i32(); - let world = sqlx::query_as::<_, World>( - "SELECT id, randomnumber FROM world WHERE id = $1" - ).bind(id) - .fetch_one(ctx.pool()) - .await?; - Response::OK(json(&world)?) -} - -async fn handle_fortunes(ctx: Context) -> Result { - let mut fortunes = sqlx::query_as::<_, Fortune>( - "SELECT id, message FROM fortune" - ) - .fetch_all(ctx.pool()) - .await?; - fortunes.push(Fortune { - id: 0, - message: "Additional fortune added at request time.".into(), - }); - fortunes.sort_unstable_by(|it, next| it.message.cmp(&next.message)); - render_html(fortunes) -} - -async fn handle_queries(ctx: Context) -> Result { - let count = { - let queries = ctx.query::<&str>("q").unwrap_or("1").parse::().unwrap_or(1); - if queries < 1 {1} else if 500 < queries {500} else {queries} - }; - let mut worlds = Vec::with_capacity(count); - for id in random_i32s(count) { - worlds.push( - sqlx::query_as::<_, World>( - "SELECT id, randomnumber FROM world WHERE id = $1" - ).bind(id) - .fetch_one(ctx.pool()) - .await? - ) - } - Response::OK(json(&worlds)?) -} - -async fn handle_updates(ctx: Context) -> Result { - let count = { - let queries = ctx.query::<&str>("q").unwrap_or("1").parse::().unwrap_or(1); - if queries < 1 {1} else if 500 < queries {500} else {queries} - }; - let mut worlds = Vec::with_capacity(count); - let mut new_randomnumbers = random_i32s(count); - for id in random_i32s(count) { - let mut world = sqlx::query_as::<_, World>( - "SELECT id, randomnumber FROM world WHERE id = $1" - ).bind(id) - .fetch_one(ctx.pool()) - .await?; - - let new_randomnumber = new_randomnumbers.next().unwrap(); - world.set_randomnumber(new_randomnumber); - - sqlx::query("UPDATE world SET randomnumber = $1 WHERE id = $2") - .bind(new_randomnumber) - .bind(id) - .execute(ctx.pool()) - .await?; - - worlds.push(world) - } - Response::OK(json(&worlds)?) -} diff --git a/frameworks/Rust/ohkami/src/models.rs b/frameworks/Rust/ohkami/src/models.rs new file mode 100644 index 00000000000..45120b3d7f4 --- /dev/null +++ b/frameworks/Rust/ohkami/src/models.rs @@ -0,0 +1,41 @@ +use ohkami::serde; + +#[derive(serde::Serialize)] +pub struct Message { + pub message: &'static str, +} + +#[cfg(feature = "rt_tokio")] +pub use db::*; +#[cfg(feature = "rt_tokio")] +mod db { + use super::*; + + pub struct Fortune { + pub id: i32, + pub message: String, + } + + #[derive(serde::Serialize)] + #[allow(non_snake_case)] + pub struct World { + pub id: i32, + #[serde(rename = "randomNumber")] + pub randomnumber: i32, + } + + #[derive(serde::Deserialize)] + pub struct WorldsMeta<'req> { + q: Option<&'req str>, + } + impl WorldsMeta<'_> { + #[inline(always)] + pub fn parse(self) -> usize { + match self.q.unwrap_or("1").parse::().unwrap_or(1) { + n @ 1..=500 => n, + 0 => 1, + 501.. => 500, + } + } + } +} diff --git a/frameworks/Rust/ohkami/src/postgres.rs b/frameworks/Rust/ohkami/src/postgres.rs new file mode 100644 index 00000000000..b9a402cc50f --- /dev/null +++ b/frameworks/Rust/ohkami/src/postgres.rs @@ -0,0 +1,131 @@ +#![cfg(feature = "rt_tokio")] + +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}; + +#[derive(Clone)] +pub struct Postgres { + client: Arc, + statements: TechEmpowerStatements, +} + +#[derive(Clone)] +struct TechEmpowerStatements { + select_world_by_id: tokio_postgres::Statement, + select_all_fortunes: tokio_postgres::Statement, + update_worlds: tokio_postgres::Statement, +} + +impl Postgres { + pub async fn new() -> Self { + let (client, connection) = tokio_postgres::connect( + &std::env::var("DATABASE_URL").unwrap(), + tokio_postgres::NoTls + ).await.expect("failed to connect database"); + + tokio::spawn(async { + if let Err(e) = connection.await { + eprintln!("error in database connection: {e}"); + } + }); + + let statements = TechEmpowerStatements { + select_world_by_id: client + .prepare("SELECT id, randomnumber FROM world WHERE id = $1 LIMIT 1") + .await + .unwrap(), + select_all_fortunes: client + .prepare("SELECT id, message FROM fortune") + .await + .unwrap(), + update_worlds: client + .prepare("\ + UPDATE world SET randomnumber = new.randomnumber FROM ( \ + SELECT * FROM UNNEST($1::int[], $2::int[]) AS v(id, randomnumber) \ + ) AS new WHERE world.id = new.id \ + ") + .await + .unwrap(), + }; + + Self { client: Arc::new(client), statements } + } +} + +impl Postgres { + const ID_RANGE: std::ops::Range = 1..10001; + + async fn select_random_world_by_id(&self, id: i32) -> World { + let row = self.client + .query_one(&self.statements.select_world_by_id, &[&id]) + .await + .expect("failed to fetch a world"); + + 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_n_random_worlds(&self, n: usize) -> Vec { + let rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); + + let selects = FuturesUnordered::new(); + for id in rng.sample_iter(Uniform::new(Self::ID_RANGE.start, Self::ID_RANGE.end)).take(n) { + selects.push(self.select_random_world_by_id(id)) + } + + selects.collect::>().await + } + + pub async fn select_all_fortunes(&self) -> Vec { + let mut rows = std::pin::pin!(self + .client + .query_raw::<_, _, &[i32; 0]>(&self.statements.select_all_fortunes, &[]) + .await + .expect("failed to fetch fortunes") + ); + + let mut fortunes = Vec::new(); + while let Some(row) = rows.next().await.transpose().unwrap() { + fortunes.push(Fortune { + id: row.get(0), + message: row.get(1), + }); + } + + fortunes + } + + pub async fn update_randomnumbers_of_n_worlds(&self, n: usize) -> Vec { + let rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); + + 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)) + .take(n) + .collect::>(); + for i in 0..n { + worlds[i].randomnumber = new_randomnumbers[i]; + ids.push(worlds[i].id); + } + + self.client + .execute(&self.statements.update_worlds, &[&ids, &new_randomnumbers]) + .await + .expect("failed to update worlds"); + + worlds + } +} diff --git a/frameworks/Rust/ohkami/src/templates.rs b/frameworks/Rust/ohkami/src/templates.rs new file mode 100644 index 00000000000..486d3dd901f --- /dev/null +++ b/frameworks/Rust/ohkami/src/templates.rs @@ -0,0 +1,27 @@ +#![cfg(feature = "rt_tokio")] + +use ohkami::{IntoResponse, Response}; +use yarte::Template; +use crate::models::Fortune; + +#[derive(Template)] +#[template(src = r#" +Fortunes + {{~# each fortunes ~}} + + {{~/each ~}} +
idmessage
{{id}}{{message}}
+"#)] +pub struct FortunesTemplate { + pub fortunes: Vec, +} + +impl IntoResponse for FortunesTemplate { + #[inline] + fn into_response(self) -> Response { + match Template::call(&self) { + Ok(template) => Response::OK().with_html(template), + Err(_) => Response::InternalServerError(), + } + } +} diff --git a/frameworks/Rust/ohkami/templates/fortunes.hbs b/frameworks/Rust/ohkami/templates/fortunes.hbs deleted file mode 100644 index 988cf4fbe93..00000000000 --- a/frameworks/Rust/ohkami/templates/fortunes.hbs +++ /dev/null @@ -1,5 +0,0 @@ -Fortunes - {{~# each fortunes ~}} - - {{~/each ~}} -
idmessage
{{id}}{{message}}
\ No newline at end of file diff --git a/frameworks/Rust/pavex/Cargo.lock b/frameworks/Rust/pavex/Cargo.lock index 55bef569ece..d9f8310b9d6 100644 --- a/frameworks/Rust/pavex/Cargo.lock +++ b/frameworks/Rust/pavex/Cargo.lock @@ -81,6 +81,12 @@ dependencies = [ "cc", ] +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "fnv" version = "1.0.7" @@ -147,9 +153,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.18" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17f8a914c2987b688368b5138aa05321db91f4090cf26118185672ad588bce21" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" dependencies = [ "bytes", "fnv", @@ -157,7 +163,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap", + "indexmap 2.1.0", "slab", "tokio", "tokio-util", @@ -170,6 +176,12 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + [[package]] name = "hermit-abi" version = "0.2.6" @@ -244,10 +256,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.12.3", "serde", ] +[[package]] +name = "indexmap" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +dependencies = [ + "equivalent", + "hashbrown 0.14.3", +] + [[package]] name = "itoa" version = "1.0.6" @@ -256,9 +278,9 @@ checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" [[package]] name = "libc" -version = "0.2.142" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a987beff54b60ffa6d51982e1aa1146bc42f19bd26be28b0586f252fccf5317" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "lock_api" @@ -293,14 +315,14 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "mio" -version = "0.8.6" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", "log", "wasi", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -339,7 +361,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] @@ -350,7 +372,7 @@ dependencies = [ "anyhow", "fs-err", "http", - "indexmap", + "indexmap 1.9.3", "pavex_runtime", "ron", "serde", @@ -585,7 +607,7 @@ dependencies = [ "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] @@ -695,7 +717,16 @@ version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" dependencies = [ - "windows-targets", + "windows-targets 0.42.2", +] + +[[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]] @@ -704,13 +735,28 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "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.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]] @@ -719,38 +765,80 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" +[[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_msvc" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + [[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.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + [[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.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + [[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.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + [[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.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + [[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.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" diff --git a/frameworks/Rust/pavex/benchmark_config.json b/frameworks/Rust/pavex/benchmark_config.json index e9decbdcdd9..1a4bc1856a7 100755 --- a/frameworks/Rust/pavex/benchmark_config.json +++ b/frameworks/Rust/pavex/benchmark_config.json @@ -18,6 +18,7 @@ "database_os": "Linux", "display_name": "pavex", "notes": "", + "tags": ["broken"], "versus": "None" } } diff --git a/frameworks/Rust/rama/.gitignore b/frameworks/Rust/rama/.gitignore new file mode 100644 index 00000000000..b7f7b51783c --- /dev/null +++ b/frameworks/Rust/rama/.gitignore @@ -0,0 +1,2 @@ +.env +target/ diff --git a/frameworks/Rust/rama/Cargo.lock b/frameworks/Rust/rama/Cargo.lock new file mode 100644 index 00000000000..c31e2852e02 --- /dev/null +++ b/frameworks/Rust/rama/Cargo.lock @@ -0,0 +1,4825 @@ +# 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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "getrandom 0.2.15", + "once_cell", + "version_check", + "zerocopy 0.7.35", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[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 = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[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-compression" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59a194f9d963d8099596278594b3107448656ba73831c9d8c783e613ce86da64" +dependencies = [ + "brotli 7.0.0", + "flate2", + "futures-core", + "memchr", + "pin-project-lite", + "tokio", + "zstd 0.13.3", + "zstd-safe 7.2.1", +] + +[[package]] +name = "async-recursion" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.91", +] + +[[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.91", +] + +[[package]] +name = "async-trait" +version = "0.1.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.91", +] + +[[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.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[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 0.52.6", +] + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[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 = "bindgen" +version = "0.71.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3" +dependencies = [ + "bitflags 2.9.0", + "cexpr", + "clang-sys", + "itertools 0.13.0", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.91", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +dependencies = [ + "serde", +] + +[[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 = "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.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad8646f98db542e39fc66e68a20b2144f6a732636df7c2354e74645faaa433ce" +dependencies = [ + "cfg_aliases", +] + +[[package]] +name = "brotli" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc97b8f16f944bba54f0433f07e30be199b6dc2bd25937444bbad560bcea29bd" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor 4.0.2", +] + +[[package]] +name = "brotli" +version = "8.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9991eea70ea4f293524138648e41ee89b0b2b12ddef3b255effa43c8056e0e0d" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor 5.0.0", +] + +[[package]] +name = "brotli-decompressor" +version = "4.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74fa05ad7d803d413eb8380983b092cbbaf9a85f151b871360e7b00cd7060b37" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + +[[package]] +name = "brotli-decompressor" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + +[[package]] +name = "bson" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af8113ff51309e2779e8785a246c10fb783e8c2452f134d6257fd71cc03ccd6c" +dependencies = [ + "ahash", + "base64 0.22.1", + "bitvec", + "getrandom 0.2.15", + "getrandom 0.3.2", + "hex", + "indexmap 2.7.0", + "js-sys", + "once_cell", + "rand 0.9.0", + "serde", + "serde_bytes", + "serde_json", + "time", + "uuid", +] + +[[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.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" + +[[package]] +name = "cc" +version = "1.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31a0499c1dc64f458ad13872de75c0eb7e3fdb0e67964610c914b034fc5956e" +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 7.1.3", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chrono" +version = "0.4.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-targets 0.52.6", +] + +[[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 = "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 = "const-random" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" +dependencies = [ + "const-random-macro", +] + +[[package]] +name = "const-random-macro" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" +dependencies = [ + "getrandom 0.2.15", + "once_cell", + "tiny-keccak", +] + +[[package]] +name = "const_format" +version = "0.2.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "126f97965c8ad46d6d9163268ff28432e8f6a1196a55578867832e3049df63dd" +dependencies = [ + "const_format_proc_macros", +] + +[[package]] +name = "const_format_proc_macros" +version = "0.2.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[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.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" +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 = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + +[[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-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 = "crunchy" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" + +[[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 = "csv" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acdc4883a9c96732e4733212c01447ebd805833b7275a73ca3ee080fd77afdaf" +dependencies = [ + "csv-core", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d02f3b0da4c6504f86e9cd789d8dbafab48c2321be74e9987593de5a894d93d" +dependencies = [ + "memchr", +] + +[[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.91", +] + +[[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.91", +] + +[[package]] +name = "data-encoding" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" + +[[package]] +name = "deadpool" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ed5957ff93768adf7a65ab167a17835c3d2c3c50d084fe305174c112f468e2f" +dependencies = [ + "deadpool-runtime", + "num_cpus", + "serde", + "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.15", + "serde", + "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 = "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", + "serde", +] + +[[package]] +name = "derive-syn-parse" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d65d7ce8132b7c0e54497a4d9a55a1c2a0912a0d786cf894472ba818fba45762" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.91", +] + +[[package]] +name = "derive-where" +version = "1.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62d671cc41a825ebabc75757b62d3d168c577f9149b2d49ece1dad1f72119d25" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.91", +] + +[[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.91", +] + +[[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.91", +] + +[[package]] +name = "dotenv" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" + +[[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.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 = "endian-type" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" + +[[package]] +name = "enum-as-inner" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.91", +] + +[[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.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +dependencies = [ + "libc", + "windows-sys 0.59.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 = "5.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" +dependencies = [ + "concurrent-queue", + "parking", + "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 = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "flate2" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "float-cmp" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b09cf3155332e944990140d967ff5eceb70df778b34f77d8075db46e4704e6d8" +dependencies = [ + "num-traits", +] + +[[package]] +name = "flume" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" +dependencies = [ + "futures-core", + "futures-sink", + "nanorand", + "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.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" +dependencies = [ + "foreign-types-macros", + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-macros" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.91", +] + +[[package]] +name = "foreign-types-shared" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" + +[[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 = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + +[[package]] +name = "fslock" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04412b8935272e3a9bae6f48c7bfff74c2911f60525404edfdd28e49884c3bfb" +dependencies = [ + "libc", + "winapi", +] + +[[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-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-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-lite" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5edaec856126859abb19ed65f39e90fea3a9574b9707f13539acf4abf7eb532" +dependencies = [ + "fastrand", + "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.91", +] + +[[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 = "generator" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc6bd114ceda131d3b1d665eba35788690ad37f5916457286b32ab6fd3c438dd" +dependencies = [ + "cfg-if", + "libc", + "log", + "rustversion", + "windows", +] + +[[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", + "js-sys", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", + "wasm-bindgen", +] + +[[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.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" + +[[package]] +name = "h2" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccae279728d634d083c00f6099cb58f01cc99c145b84b8be2f6c74618d79922e" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http", + "indexmap 2.7.0", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "halfbrown" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2c385c6df70fd180bbb673d93039dbd2cd34e41d782600bdf6e1ca7bce39aa" +dependencies = [ + "hashbrown 0.15.2", + "serde", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] + +[[package]] +name = "hashlink" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" +dependencies = [ + "hashbrown 0.15.2", +] + +[[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.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 = "hickory-proto" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ad3d6d98c648ed628df039541a5577bee1a7c83e9e16fe3dbedeea4cdfeb971" +dependencies = [ + "async-trait", + "cfg-if", + "data-encoding", + "enum-as-inner", + "futures-channel", + "futures-io", + "futures-util", + "idna", + "ipnet", + "once_cell", + "rand 0.8.5", + "thiserror 1.0.69", + "tinyvec", + "tokio", + "tracing", + "url", +] + +[[package]] +name = "hickory-proto" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d844af74f7b799e41c78221be863bade11c430d46042c3b49ca8ae0c6d27287" +dependencies = [ + "async-recursion", + "async-trait", + "cfg-if", + "critical-section", + "data-encoding", + "enum-as-inner", + "futures-channel", + "futures-io", + "futures-util", + "idna", + "ipnet", + "once_cell", + "rand 0.9.0", + "ring", + "thiserror 2.0.12", + "tinyvec", + "tokio", + "tracing", + "url", +] + +[[package]] +name = "hickory-resolver" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a2e2aba9c389ce5267d31cf1e4dace82390ae276b0b364ea55630b1fa1b44b4" +dependencies = [ + "cfg-if", + "futures-util", + "hickory-proto 0.24.3", + "ipconfig", + "lru-cache", + "once_cell", + "parking_lot", + "rand 0.8.5", + "resolv-conf", + "smallvec", + "thiserror 1.0.69", + "tokio", + "tracing", +] + +[[package]] +name = "hickory-resolver" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a128410b38d6f931fcc6ca5c107a3b02cabd6c05967841269a4ad65d23c44331" +dependencies = [ + "cfg-if", + "futures-util", + "hickory-proto 0.25.1", + "ipconfig", + "moka", + "once_cell", + "parking_lot", + "rand 0.9.0", + "resolv-conf", + "smallvec", + "thiserror 2.0.12", + "tokio", + "tracing", +] + +[[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.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "hostname" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" +dependencies = [ + "libc", + "match_cfg", + "winapi", +] + +[[package]] +name = "http" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" +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 = "http-range-header" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9171a2ea8a68358193d15dd5d70c1c10a2afc3e7e4c5bc92bc9f025cebd7359c" + +[[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 = "iana-time-zone" +version = "0.1.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core 0.52.0", +] + +[[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 = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.91", +] + +[[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.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "indexmap" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" +dependencies = [ + "equivalent", + "hashbrown 0.15.2", + "serde", +] + +[[package]] +name = "ipconfig" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" +dependencies = [ + "socket2", + "widestring", + "windows-sys 0.48.0", + "winreg", +] + +[[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.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" + +[[package]] +name = "jobserver" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +dependencies = [ + "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" +dependencies = [ + "spin", +] + +[[package]] +name = "libc" +version = "0.2.171" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" + +[[package]] +name = "libloading" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" +dependencies = [ + "cfg-if", + "windows-targets 0.52.6", +] + +[[package]] +name = "libm" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" + +[[package]] +name = "libmimalloc-sys" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b20daca3a4ac14dbdc753c5e90fc7b490a48a9131daed3c9a9ced7b2defd37b" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "libsqlite3-sys" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" +dependencies = [ + "pkg-config", + "vcpkg", +] + +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "litemap" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" + +[[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 = "loom" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca" +dependencies = [ + "cfg-if", + "generator", + "pin-utils", + "scoped-tls", + "serde", + "serde_json", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "lru-cache" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" +dependencies = [ + "linked-hash-map", +] + +[[package]] +name = "macro_magic" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc33f9f0351468d26fbc53d9ce00a096c8522ecb42f19b50f34f2c422f76d21d" +dependencies = [ + "macro_magic_core", + "macro_magic_macros", + "quote", + "syn 2.0.91", +] + +[[package]] +name = "macro_magic_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1687dc887e42f352865a393acae7cf79d98fab6351cde1f58e9e057da89bf150" +dependencies = [ + "const-random", + "derive-syn-parse", + "macro_magic_core_macros", + "proc-macro2", + "quote", + "syn 2.0.91", +] + +[[package]] +name = "macro_magic_core_macros" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b02abfe41815b5bd98dbd4260173db2c116dda171dc0fe7838cb206333b83308" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.91", +] + +[[package]] +name = "macro_magic_macros" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73ea28ee64b88876bf45277ed9a5817c1817df061a74f2b988971a12570e5869" +dependencies = [ + "macro_magic_core", + "quote", + "syn 2.0.91", +] + +[[package]] +name = "match_cfg" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" + +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + +[[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 = "md5" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "mimalloc" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03cb1f88093fe50061ca1195d336ffec131347c7b833db31f9ab62a2d1b7925f" +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 = "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.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" +dependencies = [ + "adler2", +] + +[[package]] +name = "mio" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +dependencies = [ + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.52.0", +] + +[[package]] +name = "moka" +version = "0.12.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9321642ca94a4282428e6ea4af8cc2ca4eac48ac7a6a4ea8f33f76d0ce70926" +dependencies = [ + "crossbeam-channel", + "crossbeam-epoch", + "crossbeam-utils", + "loom", + "parking_lot", + "portable-atomic", + "rustc_version", + "smallvec", + "tagptr", + "thiserror 1.0.69", + "uuid", +] + +[[package]] +name = "mongodb" +version = "3.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdf4261933e5113914caec01c4bb16a7502bdaa9cf80fd87191765e7d9ff16b2" +dependencies = [ + "async-trait", + "base64 0.13.1", + "bitflags 1.3.2", + "bson", + "chrono", + "derive-where", + "derive_more", + "flate2", + "futures-core", + "futures-executor", + "futures-io", + "futures-util", + "hex", + "hickory-proto 0.24.3", + "hickory-resolver 0.24.2", + "hmac", + "macro_magic", + "md-5", + "mongodb-internal-macros", + "once_cell", + "pbkdf2", + "percent-encoding", + "rand 0.8.5", + "rustc_version_runtime", + "rustls 0.21.12", + "rustls-pemfile 1.0.4", + "serde", + "serde_bytes", + "serde_with", + "sha-1", + "sha2", + "snap", + "socket2", + "stringprep", + "strsim", + "take_mut", + "thiserror 1.0.69", + "tokio", + "tokio-rustls", + "tokio-util", + "typed-builder", + "uuid", + "webpki-roots 0.25.4", + "zstd 0.11.2+zstd.1.5.2", +] + +[[package]] +name = "mongodb-internal-macros" +version = "3.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "619176c99deef0d50be51ce3193e9efd6a56ab0f4e6a38d5fd614880d148c7ae" +dependencies = [ + "macro_magic", + "proc-macro2", + "quote", + "syn 2.0.91", +] + +[[package]] +name = "nanoid" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ffa00dec017b5b1a8b7cf5e2c008bfda1aa7e0697ac1508b491fdf2622fb4d8" +dependencies = [ + "rand 0.8.5", +] + +[[package]] +name = "nanorand" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" +dependencies = [ + "getrandom 0.2.15", +] + +[[package]] +name = "nibble_vec" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43" +dependencies = [ + "smallvec", +] + +[[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 = "nom" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405" +dependencies = [ + "memchr", +] + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + +[[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 0.8.5", + "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 = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +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 = "once_cell" +version = "1.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +dependencies = [ + "critical-section", + "portable-atomic", +] + +[[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.91", +] + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[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.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", + "smallvec", + "windows-targets 0.52.6", +] + +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest", +] + +[[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.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" + +[[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.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" + +[[package]] +name = "portable-atomic" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" + +[[package]] +name = "postgres-protocol" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76ff0abab4a9b844b93ef7b81f1efc0a366062aaef2cd702c76256b5dc075c54" +dependencies = [ + "base64 0.22.1", + "byteorder", + "bytes", + "fallible-iterator", + "hmac", + "md-5", + "memchr", + "rand 0.9.0", + "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 = "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 0.7.35", +] + +[[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.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "psl" +version = "2.1.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70295efe3fd3db60e81f452e2eacc407b4e6c2e1ff7f763424ae6e16105cee26" +dependencies = [ + "psl-types", +] + +[[package]] +name = "psl-types" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33cb294fe86a74cbcf50d4445b37da762029549ebeea341421c7c70370f86cac" + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quick_cache" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f8ed0655cbaf18a26966142ad23b95d8ab47221c50c4f73a1db7d0d2d6e3da8" +dependencies = [ + "ahash", + "equivalent", + "hashbrown 0.15.2", + "parking_lot", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "radix_trie" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd" +dependencies = [ + "endian-type", + "nibble_vec", +] + +[[package]] +name = "rama" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbfc04ce5f0295c6674d37d22ca388d4d2fd7cc1a7afef33a5ed0a3f3ae098f0" +dependencies = [ + "rama-core", + "rama-dns", + "rama-http", + "rama-http-backend", + "rama-http-core", + "rama-net", + "rama-tcp", + "rama-tls-boring", + "rama-tower", + "rama-ua", + "rama-utils", + "rustversion", +] + +[[package]] +name = "rama-boring" +version = "0.2.0-alpha.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f9f292c90071be607788a32902eb469aa700cbedb3a7ff89f9e7aea4748a50f" +dependencies = [ + "bitflags 2.9.0", + "foreign-types", + "libc", + "openssl-macros", + "rama-boring-sys", +] + +[[package]] +name = "rama-boring-sys" +version = "0.2.0-alpha.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4d21214d5d8f7fadddfed54a23ebcbf1c9b7d48bf330866973e6a125e0ff731" +dependencies = [ + "autocfg", + "bindgen", + "cmake", + "fs_extra", + "fslock", +] + +[[package]] +name = "rama-boring-tokio" +version = "0.2.0-alpha.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad64d69fd3d8a3e02c58bf2869d1dd549fa99bef763cf50839113aa3a9c5e121" +dependencies = [ + "rama-boring", + "rama-boring-sys", + "tokio", +] + +[[package]] +name = "rama-core" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94bc95e260be6953d91b4dca39a16498424f20ba4cc7516eb4971ed0b083bb42" +dependencies = [ + "futures-lite", + "parking_lot", + "rama-error", + "rama-macros", + "rama-utils", + "tokio", + "tokio-graceful", + "tracing", +] + +[[package]] +name = "rama-dns" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bb7832d151b5c08aefab1302cd8a7d1250ce1cc523cb0e7721f64c2f10b1f86" +dependencies = [ + "hickory-resolver 0.25.1", + "rama-core", + "rama-net", + "rama-utils", + "serde", + "tokio", +] + +[[package]] +name = "rama-error" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afef8edf9f08e7602d2f724b69a7b8fe6fd791e1dc2ca51fa4aa92ebe47963c" + +[[package]] +name = "rama-http" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b10c0565cfef10e41c5d92f7e244c6749098c3a3a8df539e70e5e576cb53a17b" +dependencies = [ + "async-compression", + "base64 0.22.1", + "bitflags 2.9.0", + "bytes", + "chrono", + "const_format", + "csv", + "futures-lite", + "http-range-header", + "httpdate", + "iri-string", + "matchit", + "mime", + "mime_guess", + "nanoid", + "percent-encoding", + "pin-project-lite", + "radix_trie", + "rama-core", + "rama-http-headers", + "rama-http-types", + "rama-macros", + "rama-net", + "rama-ua", + "rama-utils", + "regex", + "serde", + "serde_html_form", + "serde_json", + "smol_str", + "tokio", + "tokio-util", + "tracing", + "uuid", +] + +[[package]] +name = "rama-http-backend" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852edae14b952453a0de0c71d5f0868457cdb9e3ec2d35fa620309180eec15bb" +dependencies = [ + "const_format", + "futures", + "h2", + "rama-core", + "rama-http", + "rama-http-core", + "rama-http-headers", + "rama-http-types", + "rama-net", + "rama-tcp", + "rama-utils", + "tokio", + "tracing", +] + +[[package]] +name = "rama-http-core" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89eab20977f04fa72249831d349cdd6d49c2ffc08d2d07571809dd219fca1f48" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-channel", + "futures-core", + "futures-sink", + "futures-util", + "httparse", + "httpdate", + "indexmap 2.7.0", + "itoa", + "pin-project-lite", + "rama-core", + "rama-http", + "rama-http-types", + "rama-utils", + "slab", + "smallvec", + "tokio", + "tokio-test", + "tokio-util", + "tracing", + "want", +] + +[[package]] +name = "rama-http-headers" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2679fadfd104128546d537cc15cbdff2ce3c4b49d6facb4b09308d8ebb32ce2" +dependencies = [ + "base64 0.22.1", + "bytes", + "httpdate", + "mime", + "rama-core", + "rama-error", + "rama-http-types", + "rama-macros", + "rama-net", + "rama-utils", + "serde", + "sha1", + "tracing", +] + +[[package]] +name = "rama-http-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22d5ffcadbc046d7e137ae70e92e0bc139893ede6c8f40d9754c7788d64ef1c5" +dependencies = [ + "bytes", + "const_format", + "csv", + "futures-core", + "futures-lite", + "headers", + "http", + "http-body", + "http-body-util", + "mime", + "mime_guess", + "pin-project-lite", + "rama-core", + "rama-error", + "rama-macros", + "rama-utils", + "serde", + "serde_html_form", + "serde_json", + "smallvec", + "sync_wrapper", + "tracing", +] + +[[package]] +name = "rama-macros" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41ba53ab8aa7a42286422e8cb6bdc211ebfa584309e994b0d8a06e17b3ab5c73" + +[[package]] +name = "rama-net" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "216e40781e2b0e23cd1ddec4cb5424b5068c54512e20e4c77fad2ba14f06801e" +dependencies = [ + "base64 0.22.1", + "bytes", + "const_format", + "flume", + "futures-lite", + "headers", + "hex", + "ipnet", + "itertools 0.14.0", + "md5", + "nom 8.0.0", + "parking_lot", + "pin-project-lite", + "psl", + "rama-core", + "rama-http-types", + "rama-macros", + "rama-utils", + "serde", + "sha2", + "smol_str", + "socket2", + "tokio", + "tracing", +] + +[[package]] +name = "rama-tcp" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8541541a5b97e1c4f9caf9a1e6dbdf25d3576fed0d58952ce8f98adf6b90cfc6" +dependencies = [ + "rama-core", + "rama-dns", + "rama-http-types", + "rama-net", + "rama-utils", + "tokio", + "tracing", +] + +[[package]] +name = "rama-techempower" +version = "0.2.0" +dependencies = [ + "bytes", + "deadpool", + "deadpool-postgres", + "dotenv", + "futures", + "futures-util", + "mimalloc", + "mime", + "mongodb", + "num_cpus", + "quick_cache", + "rama", + "rand 0.9.0", + "serde", + "serde_json", + "serde_path_to_error", + "simd-json", + "sqlx", + "tokio", + "tokio-pg-mapper", + "tokio-pg-mapper-derive", + "tokio-postgres", + "yarte", +] + +[[package]] +name = "rama-tls-boring" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3aa8aea06efa5fec804d4a6971046e457cd6e26b88e0d86e02bb76fd5dc6e618" +dependencies = [ + "brotli 8.0.1", + "flate2", + "flume", + "itertools 0.14.0", + "moka", + "parking_lot", + "pin-project-lite", + "rama-boring", + "rama-boring-tokio", + "rama-core", + "rama-net", + "rama-utils", + "tokio", + "tracing", +] + +[[package]] +name = "rama-tower" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b17056fb6e6d2a9cf64d71d59580732902bbd6480894c566e950335f5fc6effb" +dependencies = [ + "rama-core", + "rama-http-types", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "rama-ua" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65a8650461ae628954a2ffe288879ed4de81518ea2d49f7bbf2f32eb56f539db" +dependencies = [ + "itertools 0.14.0", + "rama-core", + "rama-http-headers", + "rama-http-types", + "rama-net", + "rama-utils", + "rand 0.9.0", + "serde", + "serde_json", + "tracing", +] + +[[package]] +name = "rama-utils" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5f721b2f7d9b3d5016b1720551500216b56eb513faf70d0fc64ebd002694297" +dependencies = [ + "parking_lot", + "pin-project-lite", + "rama-macros", + "serde", + "tokio", +] + +[[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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.3", + "zerocopy 0.8.24", +] + +[[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.15", +] + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom 0.3.2", +] + +[[package]] +name = "redox_syscall" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" +dependencies = [ + "bitflags 2.9.0", +] + +[[package]] +name = "ref-cast" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf0a6f84d5f1d581da8b41b47ec8600871962f2a528115b542b362d4b744931" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcc303e793d3734489387d205e9b186fac9c6cfacedd98cbb2e8a5943595f3e6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.91", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata 0.4.9", + "regex-syntax 0.8.5", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.5", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "resolv-conf" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00" +dependencies = [ + "hostname", + "quick-error", +] + +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.15", + "libc", + "spin", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rsa" +version = "0.9.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47c75d7c5c6b673e58bf54d8544a9f432e3a925b0e80f7cd3602ab5c50c55519" +dependencies = [ + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core 0.6.4", + "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-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustc_version_runtime" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dd18cd2bae1820af0b6ad5e54f4a51d0f3fcc53b05f845675074efcc7af071d" +dependencies = [ + "rustc_version", + "semver", +] + +[[package]] +name = "rustix" +version = "0.38.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" +dependencies = [ + "bitflags 2.9.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustls" +version = "0.21.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" +dependencies = [ + "log", + "ring", + "rustls-webpki 0.101.7", + "sct", +] + +[[package]] +name = "rustls" +version = "0.23.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5065c3f250cbd332cd894be57c40fa52387247659b14a2d6041d121547903b1b" +dependencies = [ + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki 0.102.8", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.7", +] + +[[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.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2bf47e6ff922db3825eb750c4e2ff784c6ff8fb9e13046ef6a1d1c5401b0b37" + +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "rustls-webpki" +version = "0.102.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[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 = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "semver" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba" + +[[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_bytes" +version = "0.11.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "387cc504cb06bb40a96c8e04e951fe01854cf6bc921053c954e4a606d9675c6a" +dependencies = [ + "serde", +] + +[[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.91", +] + +[[package]] +name = "serde_html_form" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d2de91cf02bbc07cde38891769ccd5d4f073d22a40683aa4bc7a95781aaa2c4" +dependencies = [ + "form_urlencoded", + "indexmap 2.7.0", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_json" +version = "1.0.140" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +dependencies = [ + "indexmap 2.7.0", + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_path_to_error" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59fab13f937fa393d08645bf3a84bdfe86e296747b506ada67bb15f10f218b2a" +dependencies = [ + "itoa", + "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 = "serde_with" +version = "3.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e28bdad6db2b8340e449f7108f020b3b092e8583a9e3fb82713e1d4e71fe817" +dependencies = [ + "base64 0.22.1", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.7.0", + "serde", + "serde_derive", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d846214a9854ef724f3da161b426242d8de7c1fc7de2f89bb1efcb154dca79d" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.91", +] + +[[package]] +name = "sha-1" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[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 = "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.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 0.6.4", +] + +[[package]] +name = "simd-json" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10b5602e4f1f7d358956f94cac1eff59220f34cf9e26d49f5fde5acef851cbed" +dependencies = [ + "getrandom 0.3.2", + "halfbrown", + "ref-cast", + "serde", + "serde_json", + "simdutf8", + "value-trait", +] + +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + +[[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.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" +dependencies = [ + "serde", +] + +[[package]] +name = "smol_str" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9676b89cd56310a87b93dec47b11af744f34d5fc9f367b829474eec0a891350d" +dependencies = [ + "borsh", + "serde", +] + +[[package]] +name = "snap" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b6b67fb9a61334225b5b790716f609cd58395f895b3fe8b328786812a40bc3b" + +[[package]] +name = "socket2" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" +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 = "sqlx" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4410e73b3c0d8442c5f99b425d7a435b5ee0ae4167b3196771dd3f7a01be745f" +dependencies = [ + "sqlx-core", + "sqlx-macros", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", +] + +[[package]] +name = "sqlx-core" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a007b6936676aa9ab40207cde35daab0a04b823be8ae004368c0793b96a61e0" +dependencies = [ + "bytes", + "crc", + "crossbeam-queue", + "either", + "event-listener", + "futures-core", + "futures-intrusive", + "futures-io", + "futures-util", + "hashbrown 0.15.2", + "hashlink", + "indexmap 2.7.0", + "log", + "memchr", + "once_cell", + "percent-encoding", + "rustls 0.23.20", + "rustls-pemfile 2.2.0", + "serde", + "serde_json", + "sha2", + "smallvec", + "thiserror 2.0.12", + "tokio", + "tokio-stream", + "tracing", + "url", + "webpki-roots 0.26.7", +] + +[[package]] +name = "sqlx-macros" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3112e2ad78643fef903618d78cf0aec1cb3134b019730edb039b69eaf531f310" +dependencies = [ + "proc-macro2", + "quote", + "sqlx-core", + "sqlx-macros-core", + "syn 2.0.91", +] + +[[package]] +name = "sqlx-macros-core" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e9f90acc5ab146a99bf5061a7eb4976b573f560bc898ef3bf8435448dd5e7ad" +dependencies = [ + "dotenvy", + "either", + "heck", + "hex", + "once_cell", + "proc-macro2", + "quote", + "serde", + "serde_json", + "sha2", + "sqlx-core", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", + "syn 2.0.91", + "tempfile", + "tokio", + "url", +] + +[[package]] +name = "sqlx-mysql" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4560278f0e00ce64938540546f59f590d60beee33fffbd3b9cd47851e5fff233" +dependencies = [ + "atoi", + "base64 0.22.1", + "bitflags 2.9.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 0.8.5", + "rsa", + "serde", + "sha1", + "sha2", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror 2.0.12", + "tracing", + "whoami", +] + +[[package]] +name = "sqlx-postgres" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5b98a57f363ed6764d5b3a12bfedf62f07aa16e1856a7ddc2a0bb190a959613" +dependencies = [ + "atoi", + "base64 0.22.1", + "bitflags 2.9.0", + "byteorder", + "crc", + "dotenvy", + "etcetera", + "futures-channel", + "futures-core", + "futures-util", + "hex", + "hkdf", + "hmac", + "home", + "itoa", + "log", + "md-5", + "memchr", + "once_cell", + "rand 0.8.5", + "serde", + "serde_json", + "sha2", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror 2.0.12", + "tracing", + "whoami", +] + +[[package]] +name = "sqlx-sqlite" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f85ca71d3a5b24e64e1d08dd8fe36c6c95c339a896cc33068148906784620540" +dependencies = [ + "atoi", + "flume", + "futures-channel", + "futures-core", + "futures-executor", + "futures-intrusive", + "futures-util", + "libsqlite3-sys", + "log", + "percent-encoding", + "serde", + "serde_urlencoded", + "sqlx-core", + "tracing", + "url", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[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.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d53cbcb5a243bd33b7858b1d7f4aca2153490815872d86d955d6ea29f743c035" +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" + +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.91", +] + +[[package]] +name = "tagptr" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" + +[[package]] +name = "take_mut" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "tempfile" +version = "3.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" +dependencies = [ + "cfg-if", + "fastrand", + "once_cell", + "rustix", + "windows-sys 0.59.0", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +dependencies = [ + "thiserror-impl 2.0.12", +] + +[[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.91", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.91", +] + +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "time" +version = "0.3.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" +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.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "022db8904dfa342efe721985167e9fcd16c29b226db4397ed752a761cfce81e8" +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.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2513ca694ef9ede0fb23fe71a4ee4107cb102b9dc1930f6d0fd77aae068ae165" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.52.0", +] + +[[package]] +name = "tokio-graceful" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45740b38b48641855471cd402922e89156bdfbd97b69b45eeff170369cc18c7d" +dependencies = [ + "loom", + "pin-project-lite", + "slab", + "tokio", + "tracing", +] + +[[package]] +name = "tokio-macros" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.91", +] + +[[package]] +name = "tokio-pg-mapper" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93f2b78f3566383ffabc553c72bbb2f129962a54886c5c4d8e8c706f84eceab8" +dependencies = [ + "tokio-postgres", +] + +[[package]] +name = "tokio-pg-mapper-derive" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8548f756cd6eb4069c5af0fb0cec57001fb42bd1fb7330d8f24067ee3fa62608" +dependencies = [ + "quote", + "syn 1.0.109", + "tokio-postgres", +] + +[[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.0", + "socket2", + "tokio", + "tokio-util", + "whoami", +] + +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls 0.21.12", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-test" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2468baabc3311435b55dd935f702f42cd1b8abb7e754fb7dfb16bd36aa88f9f7" +dependencies = [ + "async-stream", + "bytes", + "futures-core", + "tokio", + "tokio-stream", +] + +[[package]] +name = "tokio-util" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" +dependencies = [ + "bytes", + "futures-core", + "futures-io", + "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 = "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.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.91", +] + +[[package]] +name = "tracing-core" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +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-subscriber" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "typed-builder" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89851716b67b937e393b3daa8423e67ddfc4bbbf1654bcf05488e95e0828db0c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[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.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" + +[[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 = "url" +version = "2.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "uuid" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9" +dependencies = [ + "getrandom 0.3.2", + "js-sys", + "serde", + "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 = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "value-trait" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0508fce11ad19e0aab49ce20b6bec7f8f82902ded31df1c9fc61b90f0eb396b8" +dependencies = [ + "float-cmp", + "halfbrown", + "itoa", + "ryu", +] + +[[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.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasi" +version = "0.14.2+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] + +[[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.91", + "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.91", + "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 = "webpki-roots" +version = "0.25.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" + +[[package]] +name = "webpki-roots" +version = "0.26.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d642ff16b7e79272ae451b7322067cdc17cadf68c23264be9d94a32319efe7e" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "whoami" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "372d5b87f58ec45c384ba03563b03544dc5fadc3983e434b286913f5b4a9bb6d" +dependencies = [ + "redox_syscall", + "wasite", + "web-sys", +] + +[[package]] +name = "widestring" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311" + +[[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" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" +dependencies = [ + "windows-core 0.58.0", + "windows-targets 0.52.6", +] + +[[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-core" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-result", + "windows-strings", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-implement" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.91", +] + +[[package]] +name = "windows-interface" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.91", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result", + "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 = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags 2.9.0", +] + +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[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", + "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 = "yoke" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.91", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive 0.7.35", +] + +[[package]] +name = "zerocopy" +version = "0.8.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879" +dependencies = [ + "zerocopy-derive 0.8.24", +] + +[[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.91", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.91", +] + +[[package]] +name = "zerofrom" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.91", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.91", +] + +[[package]] +name = "zstd" +version = "0.11.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +dependencies = [ + "zstd-safe 5.0.2+zstd.1.5.2", +] + +[[package]] +name = "zstd" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" +dependencies = [ + "zstd-safe 7.2.1", +] + +[[package]] +name = "zstd-safe" +version = "5.0.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-safe" +version = "7.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54a3ab4db68cea366acc5c897c7b4d4d1b8994a9cd6e6f841f8964566a419059" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.13+zstd.1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/frameworks/Rust/rama/Cargo.toml b/frameworks/Rust/rama/Cargo.toml new file mode 100644 index 00000000000..1c4ce26a247 --- /dev/null +++ b/frameworks/Rust/rama/Cargo.toml @@ -0,0 +1,74 @@ +[package] +name = "rama-techempower" +version = "0.2.0" +authors = ["Glen Henri J. De Cauwsemaecker "] +edition = "2024" + +[[bin]] +name = "rama" +path = "src/main.rs" + +[[bin]] +name = "rama-sqlx" +path = "src/main_sqlx.rs" + +[[bin]] +name = "rama-pg-pool" +path = "src/main_pg_pool.rs" + +[[bin]] +name = "rama-mongo" +path = "src/main_mongo.rs" + +[[bin]] +name = "rama-mongo-raw" +path = "src/main_mongo_raw.rs" + +[[bin]] +name = "rama-pg" +path = "src/main_pg.rs" + +[features] +default = [] +simd-json = ["dep:simd-json", "dep:mime", "dep:serde_path_to_error"] + +[dependencies] +rama = { version = "0.2.0", default-features = false, features = ["http-full"] } +deadpool = { version = "0.12", features = ["rt_tokio_1", "serde", "managed"] } +deadpool-postgres = { version = "0.14", features = ["rt_tokio_1", "serde"] } +dotenv = "0.15" +futures = "0.3" +futures-util = "0.3" +mongodb = { version = "3.2", features = [ + "zstd-compression", + "snappy-compression", + "zlib-compression", +] } +num_cpus = "1.16" +rand = { version = "0.9", features = ["small_rng"] } +serde = { version = "1", features = ["derive"] } +serde_json = "1" +sqlx = { version = "0.8", features = [ + "postgres", + "macros", + "runtime-tokio", + "tls-rustls", +] } +tokio = { version = "1.44", features = ["full"] } +tokio-pg-mapper = { version = "0.2" } +tokio-pg-mapper-derive = { version = "0.2" } +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" } +serde_path_to_error = { version = "0.1", optional = true } +quick_cache = "0.6" +mimalloc = "0.1" + + +[profile.release] +lto = "fat" +codegen-units = 1 +strip = true +opt-level = 3 diff --git a/frameworks/Rust/rama/README.md b/frameworks/Rust/rama/README.md new file mode 100755 index 00000000000..a3a50725739 --- /dev/null +++ b/frameworks/Rust/rama/README.md @@ -0,0 +1,43 @@ +# [Rama](https://github.com/plabayo/rama) + +## Description + +Rama (ラマ) is a modular service framework for the Rust language +to move and transform your network packets. + +- [User Guide](https://ramaproxy.org/book/preface.html) +- [API Documentation](https://docs.rs/rama/latest/rama/) +- [Cargo Package (`rama`)](https://crates.io/crates/rama) + +## Variants + +- PostgreSQL using `SQLx`, `tokio_postgres`, and `deadpool`. +- MongoDB with `mongodb`. + +## Test URLs + +- Plaintext: http://localhost:8000/plaintext +- JSON Encoding: http://localhost:8000/json +- Single Row Query: http://localhost:8000/db +- Multi Row Query: http://localhost:8000/queries?q=20 +- Fortunes: http://localhost:8000/fortunes +- Update Query: http://localhost:8000/updates?q=20 +- Cached Query: http://localhost:8000/cached-queries?q=20 + +## Notable Points (both performance and build) + +- Use of `async`. +- Use of the most recent versions of Rust, `rama` and dependencies. +- (Disabled by default) Compile-time swap-in of `simd-json` instead of `serde_json` for faster JSON serialization. +- Release binaries are stripped and compiled with CPU native. +- Sockets configured with `TCP_NODELAY` and to support an increased number of pending connections. +- For very simple benchmarks, use of a separate, single-threaded Tokio runtime for each thread. +- Server configured to serve HTTP/1 only, with no need for websockets. +- Separation of build and deployment containers using multi-stage builds. +- Deployment into Google's minimal `distroless-cc` container. +- Use of pipelined database queries (where supported). +- Streaming database queries (where supported). +- Use of PostgreSQL prepared statements cache (where supported). +- Use of PostgreSQL arrays to execute multi-row database updates with a single `UPDATE` query. + - This is permitted by the [test requirements](https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview#database-updates), step (ix). +- Use of a fast PRNG diff --git a/frameworks/Rust/rama/benchmark_config.json b/frameworks/Rust/rama/benchmark_config.json new file mode 100755 index 00000000000..8b196c76997 --- /dev/null +++ b/frameworks/Rust/rama/benchmark_config.json @@ -0,0 +1,141 @@ +{ + "framework": "rama", + "tests": [ + { + "default": { + "dockerfile": "rama.dockerfile", + "docker_cmd": "/app/rama", + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8000, + "approach": "Realistic", + "classification": "Platform", + "database": "none", + "framework": "Rama", + "language": "Rust", + "flavor": "None", + "orm": "Raw", + "platform": "Rust", + "webserver": "Rama", + "os": "Linux", + "database_os": "Linux", + "display_name": "Rama", + "notes": "", + "versus": "None" + }, + "sqlx": { + "dockerfile": "rama.dockerfile", + "docker_cmd": "/app/rama-sqlx", + "db_url": "/db", + "fortune_url": "/fortunes", + "cached_query_url": "/cached-queries?q=", + "port": 8000, + "approach": "Realistic", + "classification": "Fullstack", + "database": "postgres", + "framework": "Rama", + "language": "Rust", + "flavor": "None", + "orm": "Raw", + "platform": "Rust", + "webserver": "Rama", + "os": "Linux", + "database_os": "Linux", + "display_name": "Rama [Postgresql - sqlx]", + "notes": "", + "versus": "None" + }, + "pg": { + "dockerfile": "rama.dockerfile", + "docker_cmd": "/app/rama-pg", + "db_url": "/db", + "fortune_url": "/fortunes", + "query_url": "/queries?q=", + "update_url": "/updates?q=", + "port": 8000, + "approach": "Realistic", + "classification": "Fullstack", + "database": "postgres", + "framework": "Rama", + "language": "Rust", + "flavor": "None", + "orm": "Raw", + "platform": "Rust", + "webserver": "Rama", + "os": "Linux", + "database_os": "Linux", + "display_name": "Rama [Postgresql]", + "notes": "", + "versus": "None" + }, + "pg-pool": { + "dockerfile": "rama.dockerfile", + "docker_cmd": "/app/rama-pg-pool", + "db_url": "/db", + "query_url": "/queries?q=", + "update_url": "/updates?q=", + "fortune_url": "/fortunes", + "port": 8000, + "approach": "Realistic", + "classification": "Fullstack", + "database": "postgres", + "framework": "Rama", + "language": "Rust", + "flavor": "None", + "orm": "Raw", + "platform": "Rust", + "webserver": "Rama", + "os": "Linux", + "database_os": "Linux", + "display_name": "Rama [Postgresql - deadpool]", + "notes": "", + "versus": "None" + }, + "mongo": { + "dockerfile": "rama.dockerfile", + "docker_cmd": "/app/rama-mongo", + "db_url": "/db", + "query_url": "/queries?q=", + "fortune_url": "/fortunes", + "update_url": "/updates?q=", + "port": 8000, + "approach": "Realistic", + "classification": "Fullstack", + "database": "mongodb", + "framework": "Rama", + "language": "Rust", + "flavor": "None", + "orm": "Raw", + "platform": "Rust", + "webserver": "Rama", + "os": "Linux", + "database_os": "Linux", + "display_name": "Rama [Mongodb]", + "notes": "", + "versus": "None" + }, + "mongo-raw": { + "dockerfile": "rama.dockerfile", + "docker_cmd": "/app/rama-mongo-raw", + "db_url": "/db", + "query_url": "/queries?q=", + "update_url": "/updates?q=", + "port": 8000, + "approach": "Realistic", + "classification": "Fullstack", + "database": "mongodb", + "framework": "Rama", + "language": "Rust", + "flavor": "None", + "orm": "Raw", + "platform": "Rust", + "webserver": "Rama", + "os": "Linux", + "database_os": "Linux", + "display_name": "Rama [Mongodb raw]", + "notes": "", + "versus": "None" + } + } + ] +} diff --git a/frameworks/Rust/rama/config.toml b/frameworks/Rust/rama/config.toml new file mode 100644 index 00000000000..8216c65bea2 --- /dev/null +++ b/frameworks/Rust/rama/config.toml @@ -0,0 +1,20 @@ +[framework] +name = "rama" + +[main] +urls.plaintext = "/plaintext" +urls.json = "/json" +urls.db = "/db" +urls.query = "/queries?q=" +urls.update = "/updates?q=" +urls.fortune = "/fortunes" +urls.cached_query = "/cached-queries?q=" +approach = "Realistic" +classification = "Fullstack" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "Rust" +webserver = "Rama" +versus = "None" diff --git a/frameworks/Rust/rama/rama.dockerfile b/frameworks/Rust/rama/rama.dockerfile new file mode 100644 index 00000000000..c61848fb9fb --- /dev/null +++ b/frameworks/Rust/rama/rama.dockerfile @@ -0,0 +1,24 @@ +FROM docker.io/rust:1.86-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 ./Cargo.toml ./Cargo.lock /build/ +RUN cargo fetch +COPY ./templates/ /build/templates +COPY ./src/ /build/src +ENV RUSTFLAGS "-C target-cpu=native" +RUN cargo build --release + +FROM gcr.io/distroless/cc-debian12 +ENV POSTGRES_URL=postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world +ENV POSTGRES_MIN_POOL_SIZE=56 +ENV POSTGRES_MAX_POOL_SIZE=56 +ENV MONGODB_URL=mongodb://tfb-database:27017 +ENV MONGODB_MIN_POOL_SIZE=28 +ENV MONGODB_MAX_POOL_SIZE=28 +COPY --from=builder /build/target/release/rama* /app/ +EXPOSE 8000 +CMD ["/app/rama"] diff --git a/frameworks/Rust/rama/run.sh b/frameworks/Rust/rama/run.sh new file mode 100644 index 00000000000..9d90dcd73be --- /dev/null +++ b/frameworks/Rust/rama/run.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +./target/release/rama-techempower diff --git a/frameworks/Rust/rama/rustfmt.toml b/frameworks/Rust/rama/rustfmt.toml new file mode 100644 index 00000000000..94bd11d51d7 --- /dev/null +++ b/frameworks/Rust/rama/rustfmt.toml @@ -0,0 +1,2 @@ +max_width = 89 +reorder_imports = true diff --git a/frameworks/Rust/rama/src/common/mod.rs b/frameworks/Rust/rama/src/common/mod.rs new file mode 100644 index 00000000000..f3488fbab9b --- /dev/null +++ b/frameworks/Rust/rama/src/common/mod.rs @@ -0,0 +1,49 @@ +use std::{env, str::FromStr}; + +use core::fmt::Debug; +use rand::{distr::Uniform, rngs::SmallRng, Rng, RngCore}; +pub mod models; +pub mod utils; + +#[cfg(feature = "simd-json")] +pub mod simd_json; + +#[allow(dead_code)] +pub const SELECT_ALL_FORTUNES: &str = "SELECT * FROM fortune"; +#[allow(dead_code)] +pub const SELECT_WORLD_BY_ID: &str = + "SELECT id, randomnumber FROM world WHERE id = $1 LIMIT 1"; +#[allow(dead_code)] +pub const SELECT_ALL_CACHED_WORLDS: &str = + "SELECT id, randomnumber FROM world ORDER BY id"; +#[allow(dead_code)] +pub const UPDATE_WORLDS: &str = r#"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"#; + +/// Return the value of an environment variable. +#[allow(dead_code)] +pub fn get_env(key: &str) -> T +where + ::Err: Debug, +{ + env::var(key) + .unwrap_or_else(|_| panic!("{key} environment variable was not set")) + .parse::() + .unwrap_or_else(|_| panic!("could not parse {key}")) +} + +/// Generate a single integer in the range 1 to 10,000 (inclusive) +#[allow(dead_code)] +#[inline(always)] +pub fn random_id(rng: &mut impl RngCore) -> i32 { + rng.random_range(1..=10_000) +} + +/// Generate an iterator of integers in the range 1 to 10,000 (inclusive) +#[allow(dead_code)] +#[inline(always)] +pub fn random_ids(rng: &mut SmallRng, count: usize) -> impl Iterator + use<'_> { + rng.sample_iter(Uniform::new_inclusive(1, 10_000).unwrap()) + .take(count) +} \ No newline at end of file diff --git a/frameworks/Rust/rama/src/common/models.rs b/frameworks/Rust/rama/src/common/models.rs new file mode 100644 index 00000000000..1644447c3cd --- /dev/null +++ b/frameworks/Rust/rama/src/common/models.rs @@ -0,0 +1,25 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Serialize)] +pub struct Message { + pub message: &'static str, +} + +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] +pub struct Fortune { + pub id: i32, + pub message: String, +} + +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] +pub struct FortuneInfo { + pub id: i32, + pub message: String, +} + +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] +pub struct World { + pub id: i32, + #[serde(rename = "randomNumber")] + pub random_number: i32, +} diff --git a/frameworks/Rust/rama/src/common/simd_json.rs b/frameworks/Rust/rama/src/common/simd_json.rs new file mode 100644 index 00000000000..a1cb766eb07 --- /dev/null +++ b/frameworks/Rust/rama/src/common/simd_json.rs @@ -0,0 +1,151 @@ +#![allow(dead_code)] + +use bytes::{BufMut, BytesMut}; +use rama::http::{ + HeaderMap, HeaderValue, Request, Response, StatusCode, header, + service::web::extract::{ + Bytes, FromRequest, + body::{BytesRejection, InvalidJsonContentType, JsonRejection}, + }, + service::web::response::IntoResponse, +}; +use serde::{Serialize, de::DeserializeOwned}; +use simd_json; + +#[derive(Debug, Clone, Copy, Default)] +pub struct Json(pub T); + +pub enum SimdJsonRejection { + Json(JsonRejection), + Bytes(BytesRejection), + Simd(String), +} + +impl IntoResponse for SimdJsonRejection { + fn into_response(self) -> Response { + todo!() + } +} + +impl From for SimdJsonRejection { + fn from(err: JsonRejection) -> Self { + SimdJsonRejection::Json(err) + } +} + +impl From for SimdJsonRejection { + fn from(err: BytesRejection) -> Self { + SimdJsonRejection::Bytes(err) + } +} + +impl From for SimdJsonRejection { + fn from(err: simd_json::Error) -> Self { + SimdJsonRejection::Simd(err.to_string()) + } +} + +impl FromRequest for Json +where + T: DeserializeOwned + Send + Sync + 'static, +{ + type Rejection = SimdJsonRejection; + + async fn from_request(req: Request) -> Result { + if json_content_type(req.headers()) { + let bytes = Bytes::from_request(req).await?; + Self::from_bytes(&bytes) + } else { + Err(SimdJsonRejection::Json( + InvalidJsonContentType::default().into(), + )) + } + } +} + +fn json_content_type(headers: &HeaderMap) -> bool { + let content_type = if let Some(content_type) = headers.get(header::CONTENT_TYPE) { + content_type + } else { + return false; + }; + + let content_type = if let Ok(content_type) = content_type.to_str() { + content_type + } else { + return false; + }; + + let mime = if let Ok(mime) = content_type.parse::() { + mime + } else { + return false; + }; + + let is_json_content_type = mime.type_() == "application" + && (mime.subtype() == "json" + || mime.suffix().is_some_and(|name| name == "json")); + + is_json_content_type +} + +rama::utils::macros::impl_deref!(Json); + +impl From for Json { + fn from(inner: T) -> Self { + Self(inner) + } +} + +impl Json +where + T: DeserializeOwned, +{ + /// Construct a `Json` from a byte slice. Most users should prefer to use the `FromRequest` impl + /// but special cases may require first extracting a `Request` into `Bytes` then optionally + /// constructing a `Json`. + pub fn from_bytes(bytes: &[u8]) -> Result { + let body = &mut bytes.to_owned(); + let deserializer = simd_json::from_slice::(body); + + let value = match deserializer { + Ok(v) => v, + Err(err) => { + let rejection = { SimdJsonRejection::from(err) }; + return Err(rejection); + } + }; + + Ok(Json(value)) + } +} + +impl IntoResponse for Json +where + T: Serialize, +{ + fn into_response(self) -> Response { + // Use a small initial capacity of 128 bytes like serde_json::to_vec + // https://docs.rs/serde_json/1.0.82/src/serde_json/ser.rs.html#2189 + let mut buf = BytesMut::with_capacity(128).writer(); + match simd_json::to_writer(&mut buf, &self.0) { + Ok(()) => ( + [( + header::CONTENT_TYPE, + HeaderValue::from_static(mime::APPLICATION_JSON.as_ref()), + )], + buf.into_inner().freeze(), + ) + .into_response(), + Err(err) => ( + StatusCode::INTERNAL_SERVER_ERROR, + [( + header::CONTENT_TYPE, + HeaderValue::from_static(mime::TEXT_PLAIN_UTF_8.as_ref()), + )], + err.to_string(), + ) + .into_response(), + } + } +} diff --git a/frameworks/Rust/rama/src/common/utils.rs b/frameworks/Rust/rama/src/common/utils.rs new file mode 100644 index 00000000000..23b29110b04 --- /dev/null +++ b/frameworks/Rust/rama/src/common/utils.rs @@ -0,0 +1,27 @@ +use rama::http::StatusCode; +use serde::Deserialize; + +#[derive(Debug, Deserialize)] +pub struct Params { + q: Option, +} + +#[allow(dead_code)] +#[inline(always)] +pub fn parse_params(params: Params) -> usize { + params + .q + .and_then(|q| q.parse().ok()) + .unwrap_or(1) + .clamp(1, 500) +} + +/// Utility function for mapping any error into a `500 Internal Server Error` +/// response. +#[allow(dead_code)] +pub fn internal_error(err: E) -> (StatusCode, String) +where + E: std::error::Error, +{ + (StatusCode::INTERNAL_SERVER_ERROR, err.to_string()) +} diff --git a/frameworks/Rust/rama/src/main.rs b/frameworks/Rust/rama/src/main.rs new file mode 100644 index 00000000000..d018215254f --- /dev/null +++ b/frameworks/Rust/rama/src/main.rs @@ -0,0 +1,47 @@ +mod common; +mod server; + +use common::models::Message; +use dotenv::dotenv; +use mimalloc::MiMalloc; + +#[global_allocator] +static GLOBAL: MiMalloc = MiMalloc; + +#[cfg(feature = "simd-json")] +use common::simd_json::Json; +#[cfg(not(feature = "simd-json"))] +use rama::http::service::web::response::Json; +use rama::http::{ + StatusCode, + service::web::{Router, response::IntoResponse}, +}; + +/// Return a plaintext static string. +#[inline(always)] +pub async fn plaintext() -> &'static str { + "Hello, World!" +} + +/// Return a JSON message. +#[inline(always)] +pub async fn json() -> impl IntoResponse { + let message = Message { + message: "Hello, World!", + }; + + (StatusCode::OK, Json(message)) +} + +fn main() { + dotenv().ok(); + server::start_tokio(serve_app) +} + +async fn serve_app() { + let app = Router::new() + .get("/plaintext", plaintext) + .get("/json", json); + + server::serve((), app, Some(8000)).await; +} diff --git a/frameworks/Rust/rama/src/main_mongo.rs b/frameworks/Rust/rama/src/main_mongo.rs new file mode 100644 index 00000000000..c31023205a5 --- /dev/null +++ b/frameworks/Rust/rama/src/main_mongo.rs @@ -0,0 +1,155 @@ +mod common; +mod mongo; +mod server; + +use std::time::Duration; + +#[cfg(feature = "simd-json")] +use common::simd_json::Json; +use common::{ + models::{FortuneInfo, World}, + random_id, +}; +use dotenv::dotenv; +use mimalloc::MiMalloc; +use mongodb::{ + Client, + options::{ClientOptions, Compressor}, +}; +#[cfg(not(feature = "simd-json"))] +use rama::http::service::web::response::Json; +use rama::http::{ + StatusCode, + service::web::{ + Router, + extract::Query, + response::{Html, IntoResponse}, + }, +}; +use rand::{SeedableRng, rng, rngs::SmallRng}; +use yarte::Template; + +#[global_allocator] +static GLOBAL: MiMalloc = MiMalloc; + +use common::{ + get_env, + utils::{Params, parse_params}, +}; +use mongo::database::{ + DatabaseConnection, fetch_fortunes, find_world_by_id, find_worlds, update_worlds, +}; + +#[derive(Template)] +#[template(path = "fortunes.html.hbs")] +pub struct FortunesTemplate<'a> { + pub fortunes: &'a Vec, +} + +async fn db(DatabaseConnection(db): DatabaseConnection) -> impl IntoResponse { + let random_id = random_id(&mut rng()); + + let world = find_world_by_id(db, random_id) + .await + .expect("world could not be found"); + + (StatusCode::OK, Json(world)) +} + +async fn queries( + DatabaseConnection(db): DatabaseConnection, + Query(params): Query, +) -> impl IntoResponse { + let q = parse_params(params); + + let mut rng = SmallRng::from_rng(&mut rng()); + let worlds = find_worlds(db, &mut rng, q).await; + let results = worlds.expect("worlds could not be retrieved"); + + (StatusCode::OK, Json(results)) +} + +async fn updates( + DatabaseConnection(db): DatabaseConnection, + Query(params): Query, +) -> impl IntoResponse { + let q = parse_params(params); + + let mut rng = SmallRng::from_rng(&mut rng()); + + let worlds = find_worlds(db.clone(), &mut rng, q) + .await + .expect("worlds could not be retrieved"); + let mut updated_worlds: Vec = Vec::with_capacity(q); + + for mut world in worlds { + world.random_number = random_id(&mut rng); + updated_worlds.push(world); + } + + update_worlds(db.clone(), updated_worlds.clone()) + .await + .expect("could not update worlds"); + + (StatusCode::OK, Json(updated_worlds.clone())) +} + +async fn fortunes(DatabaseConnection(db): DatabaseConnection) -> impl IntoResponse { + let fortunes = fetch_fortunes(db).await.expect("could not fetch fortunes"); + + let fortune_infos: Vec = fortunes + .iter() + .map(|f| FortuneInfo { + id: f.id, + message: f.message.clone(), + }) + .collect(); + + Html( + FortunesTemplate { + fortunes: &fortune_infos, + } + .call() + .expect("error rendering template"), + ) +} + +fn main() { + dotenv().ok(); + server::start_tokio(serve_app) +} + +async fn serve_app() { + let database_url: String = get_env("MONGODB_URL"); + let max_pool_size: u32 = get_env("MONGODB_MAX_POOL_SIZE"); + let min_pool_size: u32 = get_env("MONGODB_MIN_POOL_SIZE"); + + let mut client_options = ClientOptions::parse(database_url).await.unwrap(); + + // setup connection pool + client_options.max_pool_size = Some(max_pool_size); + client_options.min_pool_size = Some(min_pool_size); + client_options.connect_timeout = Some(Duration::from_millis(200)); + + // the server will select the algorithm it supports from the list provided by the driver + client_options.compressors = Some(vec![ + Compressor::Snappy, + Compressor::Zlib { + level: Default::default(), + }, + Compressor::Zstd { + level: Default::default(), + }, + ]); + + let client = Client::with_options(client_options).unwrap(); + let database = client.database("hello_world"); + + let app = Router::new() + .get("/fortunes", fortunes) + .get("/db", db) + .get("/queries", queries) + .get("/updates", updates); + + server::serve(database, app, Some(8000)).await; +} diff --git a/frameworks/Rust/rama/src/main_mongo_raw.rs b/frameworks/Rust/rama/src/main_mongo_raw.rs new file mode 100644 index 00000000000..839d2b8ae4a --- /dev/null +++ b/frameworks/Rust/rama/src/main_mongo_raw.rs @@ -0,0 +1,122 @@ +mod common; +mod mongo_raw; +mod server; + +use common::{models::World, random_id}; +use mongo_raw::database::{ + DatabaseConnection, find_world_by_id, find_worlds, update_worlds, +}; + +use common::{ + get_env, + utils::{Params, parse_params}, +}; +use rama::http::{ + StatusCode, + service::web::{Router, extract::Query, response::IntoResponse}, +}; +use std::time::Duration; + +use mimalloc::MiMalloc; + +#[global_allocator] +static GLOBAL: MiMalloc = MiMalloc; + +#[cfg(feature = "simd-json")] +use common::simd_json::Json; +#[cfg(not(feature = "simd-json"))] +use rama::http::service::web::response::Json; + +use dotenv::dotenv; +use mongodb::{ + Client, + options::{ClientOptions, Compressor}, +}; +use rand::{SeedableRng, rng, rngs::SmallRng}; + +async fn db(DatabaseConnection(db): DatabaseConnection) -> impl IntoResponse { + let random_id = random_id(&mut rng()); + + let world = find_world_by_id(db, random_id) + .await + .expect("world could not be found"); + + (StatusCode::OK, Json(world)) +} + +async fn queries( + DatabaseConnection(db): DatabaseConnection, + Query(params): Query, +) -> impl IntoResponse { + let q = parse_params(params); + + let mut rng = SmallRng::from_rng(&mut rng()); + let worlds = find_worlds(db, &mut rng, q).await; + let results = worlds.expect("worlds could not be retrieved"); + + (StatusCode::OK, Json(results)) +} + +async fn updates( + DatabaseConnection(db): DatabaseConnection, + Query(params): Query, +) -> impl IntoResponse { + let q = parse_params(params); + + let mut rng = SmallRng::from_rng(&mut rng()); + + let worlds = find_worlds(db.clone(), &mut rng, q) + .await + .expect("worlds could not be retrieved"); + let mut updated_worlds: Vec = Vec::with_capacity(q); + + for mut world in worlds { + world.random_number = random_id(&mut rng); + updated_worlds.push(world); + } + + update_worlds(db.clone(), updated_worlds.clone()) + .await + .expect("could not update worlds"); + + (StatusCode::OK, Json(updated_worlds.clone())) +} + +fn main() { + dotenv().ok(); + server::start_tokio(serve_app) +} + +async fn serve_app() { + let database_url: String = get_env("MONGODB_URL"); + let max_pool_size: u32 = get_env("MONGODB_MAX_POOL_SIZE"); + let min_pool_size: u32 = get_env("MONGODB_MIN_POOL_SIZE"); + + let mut client_options = ClientOptions::parse(database_url).await.unwrap(); + + // setup connection pool + client_options.max_pool_size = Some(max_pool_size); + client_options.min_pool_size = Some(min_pool_size); + client_options.connect_timeout = Some(Duration::from_millis(200)); + + // the server will select the algorithm it supports from the list provided by the driver + client_options.compressors = Some(vec![ + Compressor::Snappy, + Compressor::Zlib { + level: Default::default(), + }, + Compressor::Zstd { + level: Default::default(), + }, + ]); + + let client = Client::with_options(client_options).unwrap(); + let database = client.database("hello_world"); + + let app = Router::new() + .get("/db", db) + .get("/queries", queries) + .get("/updates", updates); + + server::serve(database, app, Some(8000)).await; +} diff --git a/frameworks/Rust/rama/src/main_pg.rs b/frameworks/Rust/rama/src/main_pg.rs new file mode 100644 index 00000000000..74072b1bf3b --- /dev/null +++ b/frameworks/Rust/rama/src/main_pg.rs @@ -0,0 +1,107 @@ +mod common; +mod pg; + +use dotenv::dotenv; +use mimalloc::MiMalloc; +use rama::http::{ + StatusCode, + service::web::{ + Router, + extract::Query, + response::{Html, IntoResponse}, + }, +}; +use rand::rng; +use yarte::Template; + +#[global_allocator] +static GLOBAL: MiMalloc = MiMalloc; + +#[cfg(feature = "simd-json")] +use common::simd_json::Json; +#[cfg(not(feature = "simd-json"))] +use rama::http::service::web::response::Json; + +mod server; + +use common::{ + get_env, random_id, + utils::{Params, parse_params}, +}; +use pg::database::{DatabaseConnection, PgConnection}; +use pg::models::Fortune; + +#[derive(Template)] +#[template(path = "fortunes.html.hbs")] +pub struct FortunesTemplate<'a> { + pub fortunes: &'a Vec, +} + +async fn db(DatabaseConnection(conn): DatabaseConnection) -> impl IntoResponse { + let id = random_id(&mut rng()); + let world = conn + .fetch_world_by_id(id) + .await + .expect("error loading world"); + + (StatusCode::OK, Json(world)) +} + +async fn queries( + DatabaseConnection(conn): DatabaseConnection, + Query(params): Query, +) -> impl IntoResponse { + let q = parse_params(params); + + let results = conn + .fetch_random_worlds(q) + .await + .expect("error loading worlds"); + + (StatusCode::OK, Json(results)) +} + +async fn fortunes(DatabaseConnection(conn): DatabaseConnection) -> impl IntoResponse { + let fortunes: Vec = conn + .fetch_all_fortunes() + .await + .expect("error loading fortunes"); + + Html( + FortunesTemplate { + fortunes: &fortunes, + } + .call() + .expect("error rendering template"), + ) +} + +async fn updates( + DatabaseConnection(conn): DatabaseConnection, + Query(params): Query, +) -> impl IntoResponse { + let q = parse_params(params); + let worlds = conn.update_worlds(q).await.expect("error updating worlds"); + + (StatusCode::OK, Json(worlds)) +} + +fn main() { + dotenv().ok(); + server::start_tokio(serve_app) +} + +async fn serve_app() { + let database_url: String = get_env("POSTGRES_URL"); + + // Create shared database connection + let pg_connection = PgConnection::connect(database_url).await; + + let app = Router::new() + .get("/fortunes", fortunes) + .get("/db", db) + .get("/queries", queries) + .get("/updates", updates); + + server::serve(pg_connection, app, Some(8000)).await; +} diff --git a/frameworks/Rust/rama/src/main_pg_pool.rs b/frameworks/Rust/rama/src/main_pg_pool.rs new file mode 100644 index 00000000000..cf894b155a7 --- /dev/null +++ b/frameworks/Rust/rama/src/main_pg_pool.rs @@ -0,0 +1,149 @@ +mod common; +mod pg_pool; + +#[cfg(feature = "simd-json")] +use common::simd_json::Json; +#[cfg(not(feature = "simd-json"))] +use rama::http::service::web::response::Json; + +use common::{SELECT_ALL_FORTUNES, SELECT_WORLD_BY_ID, UPDATE_WORLDS, random_ids}; +use dotenv::dotenv; +use futures_util::{TryStreamExt, stream::FuturesUnordered}; +use mimalloc::MiMalloc; +use rama::http::{ + StatusCode, + service::web::{ + Router, + extract::Query, + response::{Html, IntoResponse}, + }, +}; +use rand::{SeedableRng, rng, rngs::SmallRng}; +use yarte::Template; + +#[global_allocator] +static GLOBAL: MiMalloc = MiMalloc; + +mod server; + +use common::{ + get_env, random_id, + utils::{Params, parse_params}, +}; +use pg_pool::database::{ + DatabaseClient, PgError, create_pool, fetch_all_fortunes, fetch_world_by_id, +}; +use pg_pool::models::{Fortune, World}; + +#[derive(Template)] +#[template(path = "fortunes.html.hbs")] +pub struct FortunesTemplate<'a> { + pub fortunes: &'a Vec, +} + +async fn db(DatabaseClient(client): DatabaseClient) -> impl IntoResponse { + let random_id = random_id(&mut rng()); + + let select = &client.prepare_cached(SELECT_WORLD_BY_ID).await.unwrap(); + let world = fetch_world_by_id(&client, random_id, select) + .await + .expect("could not fetch world"); + + (StatusCode::OK, Json(world)) +} + +async fn queries( + DatabaseClient(client): DatabaseClient, + Query(params): Query, +) -> impl IntoResponse { + let q = parse_params(params); + + let mut rng = SmallRng::from_rng(&mut rng()); + let select = &client.prepare_cached(SELECT_WORLD_BY_ID).await.unwrap(); + let future_worlds = FuturesUnordered::new(); + + for id in random_ids(&mut rng, q) { + future_worlds.push(fetch_world_by_id(&client, id, select)); + } + + let worlds: Result, PgError> = future_worlds.try_collect().await; + let results = worlds.expect("worlds could not be retrieved"); + + (StatusCode::OK, Json(results)) +} + +async fn fortunes(DatabaseClient(client): DatabaseClient) -> impl IntoResponse { + let select = &client.prepare_cached(SELECT_ALL_FORTUNES).await.unwrap(); + + let mut fortunes = fetch_all_fortunes(client, select) + .await + .expect("could not fetch fortunes"); + + fortunes.push(Fortune { + id: 0, + message: "Additional fortune added at request time.".to_string(), + }); + + fortunes.sort_by(|a, b| a.message.cmp(&b.message)); + + Html( + FortunesTemplate { + fortunes: &fortunes, + } + .call() + .expect("error rendering template"), + ) +} + +async fn updates( + DatabaseClient(client): DatabaseClient, + Query(params): Query, +) -> impl IntoResponse { + let q = parse_params(params); + + let mut rng = SmallRng::from_rng(&mut rng()); + let select = &client.prepare_cached(SELECT_WORLD_BY_ID).await.unwrap(); + let update = &client.prepare_cached(UPDATE_WORLDS).await.unwrap(); + + // Select the random worlds. + let future_worlds = FuturesUnordered::new(); + for id in random_ids(&mut rng, q) { + future_worlds.push(fetch_world_by_id(&client, id, select)); + } + let worlds: Vec = future_worlds.try_collect().await.unwrap(); + + let mut ids = Vec::with_capacity(q); + let mut nids = Vec::with_capacity(q); + let worlds: Vec = worlds + .into_iter() + .map(|mut w| { + w.randomnumber = random_id(&mut rng); + ids.push(w.id); + nids.push(w.randomnumber); + w + }) + .collect(); + + // Update the random worlds in the database. + client.execute(update, &[&ids, &nids]).await.unwrap(); + + (StatusCode::OK, Json(worlds)) +} + +#[tokio::main] +async fn main() { + dotenv().ok(); + + let database_url: String = get_env("POSTGRES_URL"); + let max_pool_size: u32 = get_env("POSTGRES_MAX_POOL_SIZE"); + + let pool = create_pool(database_url, max_pool_size).await; + + let app = Router::new() + .get("/fortunes", fortunes) + .get("/db", db) + .get("/queries", queries) + .get("/updates", updates); + + server::serve(pool, app, Some(8000)).await; +} diff --git a/frameworks/Rust/rama/src/main_sqlx.rs b/frameworks/Rust/rama/src/main_sqlx.rs new file mode 100644 index 00000000000..6fcef78c110 --- /dev/null +++ b/frameworks/Rust/rama/src/main_sqlx.rs @@ -0,0 +1,166 @@ +mod common; +mod sqlx; + +use std::sync::Arc; + +use ::sqlx::PgPool; +use dotenv::dotenv; +use mimalloc::MiMalloc; +use quick_cache::sync::Cache; +use rama::{ + Context, + http::{ + StatusCode, + service::web::{ + Router, + extract::Query, + response::{Html, IntoResponse}, + }, + }, +}; +use rand::{SeedableRng, rng, rngs::SmallRng}; +use sqlx::models::World; +use yarte::Template; + +#[global_allocator] +static GLOBAL: MiMalloc = MiMalloc; + +#[cfg(not(feature = "simd-json"))] +use rama::http::service::web::response::Json; +#[cfg(feature = "simd-json")] +use rama::http::service::web::response::Json; + +mod server; + +use common::{ + get_env, random_id, random_ids, + utils::{Params, parse_params}, +}; +use sqlx::database::create_pool; +use sqlx::models::Fortune; + +#[derive(Template)] +#[template(path = "fortunes.html.hbs")] +pub struct FortunesTemplate<'a> { + pub fortunes: &'a Vec, +} + +async fn db(ctx: Context) -> impl IntoResponse { + let db = ctx.state().db.clone(); + + let id = random_id(&mut rng()); + let world: World = ::sqlx::query_as(common::SELECT_WORLD_BY_ID) + .bind(id) + .fetch_one(&mut *db.acquire().await.unwrap()) + .await + .expect("error loading world"); + + (StatusCode::OK, Json(world)) +} + +async fn queries( + Query(params): Query, + ctx: Context, +) -> impl IntoResponse { + let db = ctx.state().db.clone(); + + let mut rng = SmallRng::from_rng(&mut rng()); + let count = parse_params(params); + let mut worlds: Vec = Vec::with_capacity(count); + + for id in random_ids(&mut rng, count) { + let world: World = ::sqlx::query_as(common::SELECT_WORLD_BY_ID) + .bind(id) + .fetch_one(&mut *db.acquire().await.unwrap()) + .await + .expect("error loading world"); + worlds.push(world); + } + + (StatusCode::OK, Json(worlds)) +} + +async fn fortunes(ctx: Context) -> impl IntoResponse { + let db = ctx.state().db.clone(); + + let mut fortunes: Vec = ::sqlx::query_as(common::SELECT_ALL_FORTUNES) + .fetch_all(&mut *db.acquire().await.unwrap()) + .await + .expect("error loading Fortunes"); + + fortunes.push(Fortune { + id: 0, + message: "Additional fortune added at request time.".to_string(), + }); + + fortunes.sort_by(|a, b| a.message.cmp(&b.message)); + + Html( + FortunesTemplate { + fortunes: &fortunes, + } + .call() + .expect("error rendering template"), + ) +} + +async fn cache( + Query(params): Query, + ctx: Context, +) -> impl IntoResponse { + let count = parse_params(params); + let mut rng = SmallRng::from_rng(&mut rng()); + let mut worlds: Vec = Vec::with_capacity(count); + + for id in random_ids(&mut rng, count) { + if let Some(world) = ctx.state().cache.get(&id) { + worlds.push(world); + } + } + + (StatusCode::OK, Json(worlds)) +} + +/// Pre-load the cache with all worlds. +async fn preload_cache(AppState { db, cache }: &AppState) { + let worlds: Vec = ::sqlx::query_as(common::SELECT_ALL_CACHED_WORLDS) + .fetch_all(&mut *db.acquire().await.unwrap()) + .await + .expect("error loading worlds"); + + for world in worlds { + cache.insert(world.id, world); + } +} + +/// Application state +#[derive(Clone)] +struct AppState { + db: PgPool, + cache: Arc>, +} + +#[tokio::main] +async fn main() { + dotenv().ok(); + + let database_url: String = get_env("POSTGRES_URL"); + let max_pool_size: u32 = get_env("POSTGRES_MAX_POOL_SIZE"); + let min_pool_size: u32 = get_env("POSTGRES_MIN_POOL_SIZE"); + + let state = AppState { + db: create_pool(database_url, max_pool_size, min_pool_size).await, + cache: Arc::new(Cache::new(10_000)), + }; + + // Prime the cache with CachedWorld objects + preload_cache(&state).await; + + let app = Router::new() + .get("/fortunes", fortunes) + .get("/db", db) + .get("/queries", queries) + .get("/cached-queries", cache); + + server::serve(state, app, Some(8000)).await; +} diff --git a/frameworks/Rust/rama/src/mongo/database.rs b/frameworks/Rust/rama/src/mongo/database.rs new file mode 100644 index 00000000000..f072046fa95 --- /dev/null +++ b/frameworks/Rust/rama/src/mongo/database.rs @@ -0,0 +1,116 @@ +use std::{convert::Infallible, io}; + +use futures_util::{StreamExt, TryStreamExt, stream::FuturesUnordered}; +use mongodb::{Database, bson::doc}; +use rama::{ + Context, + http::{dep::http::request, service::web::extract::FromRequestContextRefPair}, +}; +use rand::rngs::SmallRng; + +use crate::common::{ + models::{Fortune, World}, + random_ids, +}; + +pub struct DatabaseConnection(pub Database); + +impl FromRequestContextRefPair for DatabaseConnection { + type Rejection = Infallible; + + async fn from_request_context_ref_pair( + ctx: &Context, + _parts: &request::Parts, + ) -> Result { + Ok(Self(ctx.state_clone())) + } +} + +#[derive(Debug)] +#[allow(dead_code)] +pub enum MongoError { + Io(io::Error), + Mongo(mongodb::error::Error), +} + +impl From for MongoError { + fn from(err: io::Error) -> Self { + MongoError::Io(err) + } +} + +impl From for MongoError { + fn from(err: mongodb::error::Error) -> Self { + MongoError::Mongo(err) + } +} + +pub async fn find_world_by_id(db: Database, id: i32) -> Result { + let world_collection = db.collection::("world"); + + let filter = doc! { "_id": id as f32 }; + + let world: World = world_collection + .find_one(filter) + .await + .unwrap() + .expect("expected world, found none"); + Ok(world) +} + +pub async fn find_worlds( + db: Database, + rng: &mut SmallRng, + count: usize, +) -> Result, MongoError> { + let future_worlds = FuturesUnordered::new(); + + for id in random_ids(rng, count) { + future_worlds.push(find_world_by_id(db.clone(), id)); + } + + let worlds: Result, MongoError> = future_worlds.try_collect().await; + worlds +} + +pub async fn fetch_fortunes(db: Database) -> Result, MongoError> { + let fortune_collection = db.collection::("fortune"); + + let mut fortune_cursor = fortune_collection + .find(doc! {}) + .await + .expect("fortunes could not be loaded"); + + let mut fortunes: Vec = Vec::new(); + + while let Some(doc) = fortune_cursor.next().await { + fortunes.push(doc.expect("could not load fortune")); + } + + fortunes.push(Fortune { + id: 0, + message: "Additional fortune added at request time.".to_string(), + }); + + fortunes.sort_by(|a, b| a.message.cmp(&b.message)); + Ok(fortunes) +} + +pub async fn update_worlds( + db: Database, + worlds: Vec, +) -> Result { + let mut updates = Vec::new(); + + for world in worlds { + updates.push(doc! { + "q": { "id": world.id }, "u": { "$set": { "randomNumber": world.random_number }} + }); + } + + db.run_command(doc! {"update": "world", "updates": updates, "ordered": false}) + .await + .expect("could not update worlds"); + + Ok(true) +} diff --git a/frameworks/Rust/rama/src/mongo/mod.rs b/frameworks/Rust/rama/src/mongo/mod.rs new file mode 100644 index 00000000000..8fd0a6be869 --- /dev/null +++ b/frameworks/Rust/rama/src/mongo/mod.rs @@ -0,0 +1 @@ +pub mod database; diff --git a/frameworks/Rust/rama/src/mongo_raw/database.rs b/frameworks/Rust/rama/src/mongo_raw/database.rs new file mode 100644 index 00000000000..60625b063d4 --- /dev/null +++ b/frameworks/Rust/rama/src/mongo_raw/database.rs @@ -0,0 +1,107 @@ +use std::{convert::Infallible, io}; + +use futures_util::{TryStreamExt, stream::FuturesUnordered}; +use mongodb::{ + Database, + bson::{RawDocumentBuf, doc}, +}; +use rama::{ + Context, + http::{dep::http::request, service::web::extract::FromRequestContextRefPair}, +}; +use rand::rngs::SmallRng; + +use crate::common::{models::World, random_ids}; + +pub struct DatabaseConnection(pub Database); + +impl FromRequestContextRefPair for DatabaseConnection { + type Rejection = Infallible; + + async fn from_request_context_ref_pair( + ctx: &Context, + _parts: &request::Parts, + ) -> Result { + Ok(Self(ctx.state_clone())) + } +} + +#[derive(Debug)] +#[allow(dead_code)] +pub enum MongoError { + Io(io::Error), + Mongo(mongodb::error::Error), +} + +impl From for MongoError { + fn from(err: io::Error) -> Self { + MongoError::Io(err) + } +} + +impl From for MongoError { + fn from(err: mongodb::error::Error) -> Self { + MongoError::Mongo(err) + } +} + +pub async fn find_world_by_id(db: Database, id: i32) -> Result { + let world_collection = db.collection::("world"); + + let filter = doc! { "_id": id as f32 }; + + let raw: RawDocumentBuf = world_collection + .find_one(filter) + .await + .unwrap() + .expect("expected world, found none"); + + Ok(World { + id: raw + .get("id") + .expect("expected to parse world id") + .expect("could not get world id") + .as_i32() + .expect("could not extract world id"), + random_number: raw + .get("id") + .expect("expected to parse world id") + .expect("could not get world id") + .as_i32() + .expect("could not extract world id"), + }) +} + +pub async fn find_worlds( + db: Database, + rng: &mut SmallRng, + count: usize, +) -> Result, MongoError> { + let future_worlds = FuturesUnordered::new(); + + for id in random_ids(rng, count) { + future_worlds.push(find_world_by_id(db.clone(), id)); + } + + let worlds: Result, MongoError> = future_worlds.try_collect().await; + worlds +} + +pub async fn update_worlds( + db: Database, + worlds: Vec, +) -> Result { + let mut updates = Vec::new(); + + for world in worlds { + updates.push(doc! { + "q": { "id": world.id }, "u": { "$set": { "randomNumber": world.random_number }} + }); + } + + db.run_command(doc! {"update": "world", "updates": updates, "ordered": false}) + .await + .expect("could not update worlds"); + + Ok(true) +} diff --git a/frameworks/Rust/rama/src/mongo_raw/mod.rs b/frameworks/Rust/rama/src/mongo_raw/mod.rs new file mode 100644 index 00000000000..8fd0a6be869 --- /dev/null +++ b/frameworks/Rust/rama/src/mongo_raw/mod.rs @@ -0,0 +1 @@ +pub mod database; diff --git a/frameworks/Rust/rama/src/pg/database.rs b/frameworks/Rust/rama/src/pg/database.rs new file mode 100644 index 00000000000..ea4a90b257d --- /dev/null +++ b/frameworks/Rust/rama/src/pg/database.rs @@ -0,0 +1,154 @@ +use std::{convert::Infallible, io, sync::Arc}; + +use futures::{StreamExt, TryStreamExt, stream::futures_unordered::FuturesUnordered}; +use rama::{ + Context, + http::{dep::http::request, service::web::extract::FromRequestContextRefPair}, +}; +use rand::{SeedableRng, rng, rngs::SmallRng}; +use tokio::pin; +use tokio_postgres::{Client, NoTls, Statement, connect}; + +use crate::common::{self, random_id, random_ids}; + +use super::models::{Fortune, World}; + +#[derive(Debug)] +#[allow(dead_code)] +pub enum PgError { + Io(io::Error), + Pg(tokio_postgres::Error), +} + +impl From for PgError { + fn from(err: io::Error) -> Self { + PgError::Io(err) + } +} + +impl From for PgError { + fn from(err: tokio_postgres::Error) -> Self { + PgError::Pg(err) + } +} + +/// Postgres interface +pub struct PgConnection { + client: Client, + fortune: Statement, + world: Statement, + updates: Statement, +} + +impl PgConnection { + pub async fn connect(db_url: String) -> Arc { + let (cl, conn) = connect(&db_url, NoTls) + .await + .expect("cannot connect to postgresql."); + + // Spawn connection + tokio::spawn(async move { + if let Err(error) = conn.await { + eprintln!("database connection error: {error}"); + } + }); + + // Prepare statements for the connection. + let fortune = cl.prepare(common::SELECT_ALL_FORTUNES).await.unwrap(); + let world = cl.prepare(common::SELECT_WORLD_BY_ID).await.unwrap(); + let updates = cl.prepare(common::UPDATE_WORLDS).await.unwrap(); + + Arc::new(PgConnection { + client: cl, + fortune, + world, + updates, + }) + } +} + +impl PgConnection { + pub async fn fetch_world_by_id(&self, id: i32) -> Result { + self.client + .query_one(&self.world, &[&id]) + .await + .map(|row| { + Ok(World { + id: row.get(0), + randomnumber: row.get(1), + }) + })? + } + + pub async fn fetch_random_worlds(&self, num: usize) -> Result, PgError> { + let mut rng = SmallRng::from_rng(&mut rng()); + + let futures = FuturesUnordered::new(); + + for id in random_ids(&mut rng, num) { + futures.push(self.fetch_world_by_id(id)); + } + + futures.try_collect().await + } + + pub async fn update_worlds(&self, num: usize) -> Result, PgError> { + let mut worlds = self.fetch_random_worlds(num).await?; + + // Update the worlds with new random numbers + let mut rng = SmallRng::from_rng(&mut rng()); + let mut ids = Vec::with_capacity(num); + let mut nids = Vec::with_capacity(num); + + for w in &mut worlds { + w.randomnumber = random_id(&mut rng); + ids.push(w.id); + nids.push(w.randomnumber); + } + + // Update the random worlds in the database. + self.client + .execute(&self.updates, &[&ids, &nids]) + .await + .unwrap(); + + Ok(worlds) + } + + pub async fn fetch_all_fortunes(&self) -> Result, PgError> { + let mut fortunes = vec![Fortune { + id: 0, + message: "Additional fortune added at request time.".parse().unwrap(), + }]; + + let rows = self + .client + .query_raw::<_, _, &[i32; 0]>(&self.fortune, &[]) + .await?; + + pin!(rows); + + while let Some(row) = rows.next().await.transpose()? { + fortunes.push(Fortune { + id: row.get(0), + message: row.get(1), + }); + } + + fortunes.sort_by(|it, next| it.message.cmp(&next.message)); + Ok(fortunes) + } +} + +pub struct DatabaseConnection(pub Arc); + +impl FromRequestContextRefPair> for DatabaseConnection { + type Rejection = Infallible; + + async fn from_request_context_ref_pair( + ctx: &Context>, + _parts: &request::Parts, + ) -> Result { + Ok(Self(ctx.state_clone())) + } +} diff --git a/frameworks/Rust/rama/src/pg/mod.rs b/frameworks/Rust/rama/src/pg/mod.rs new file mode 100644 index 00000000000..c51e02d23d3 --- /dev/null +++ b/frameworks/Rust/rama/src/pg/mod.rs @@ -0,0 +1,2 @@ +pub mod database; +pub mod models; diff --git a/frameworks/Rust/axum/src/models_pg.rs b/frameworks/Rust/rama/src/pg/models.rs similarity index 100% rename from frameworks/Rust/axum/src/models_pg.rs rename to frameworks/Rust/rama/src/pg/models.rs diff --git a/frameworks/Rust/rama/src/pg_pool/database.rs b/frameworks/Rust/rama/src/pg_pool/database.rs new file mode 100644 index 00000000000..df3af5a7eba --- /dev/null +++ b/frameworks/Rust/rama/src/pg_pool/database.rs @@ -0,0 +1,95 @@ +use std::io; + +use crate::{ + common::utils::internal_error, + pg_pool::models::{Fortune, World}, +}; +use deadpool_postgres::{Client, Manager, ManagerConfig, RecyclingMethod}; +use futures_util::StreamExt; +use rama::{ + Context, + http::{ + StatusCode, dep::http::request, service::web::extract::FromRequestContextRefPair, + }, +}; +use tokio::pin; +use tokio_pg_mapper::FromTokioPostgresRow; +use tokio_postgres::{NoTls, Row, Statement}; + +#[derive(Debug)] +#[allow(dead_code)] +pub enum PgError { + Io(io::Error), + Pg(tokio_postgres::Error), +} + +impl From for PgError { + fn from(err: io::Error) -> Self { + PgError::Io(err) + } +} + +impl From for PgError { + fn from(err: tokio_postgres::Error) -> Self { + PgError::Pg(err) + } +} + +pub async fn create_pool( + database_url: String, + max_pool_size: u32, +) -> deadpool_postgres::Pool { + let pg_config: tokio_postgres::Config = + database_url.parse().expect("invalid database url"); + + let mgr_config = ManagerConfig { + recycling_method: RecyclingMethod::Fast, + }; + let mgr = Manager::from_config(pg_config, NoTls, mgr_config); + let pool: deadpool_postgres::Pool = deadpool_postgres::Pool::builder(mgr) + .max_size(max_pool_size as usize) + .build() + .unwrap(); + + pool +} + +pub struct DatabaseClient(pub Client); + +impl FromRequestContextRefPair for DatabaseClient { + type Rejection = (StatusCode, String); + + async fn from_request_context_ref_pair( + ctx: &Context, + _parts: &request::Parts, + ) -> Result { + let conn = ctx.state().get().await.map_err(internal_error)?; + Ok(Self(conn)) + } +} + +pub async fn fetch_world_by_id( + client: &Client, + id: i32, + select: &Statement, +) -> Result { + let row: Row = client.query_one(select, &[&id]).await.unwrap(); + + Ok(World::from_row(row).unwrap()) +} + +pub async fn fetch_all_fortunes( + client: Client, + select: &Statement, +) -> Result, PgError> { + let mut fortunes: Vec = Vec::new(); + let rows = client.query_raw::<_, _, &[i32; 0]>(select, &[]).await?; + pin!(rows); + + while let Some(row) = rows.next().await.transpose()? { + fortunes + .push(Fortune::from_row(row).expect("could not convert row to fortune.")); + } + + Ok(fortunes) +} diff --git a/frameworks/Rust/rama/src/pg_pool/mod.rs b/frameworks/Rust/rama/src/pg_pool/mod.rs new file mode 100644 index 00000000000..c51e02d23d3 --- /dev/null +++ b/frameworks/Rust/rama/src/pg_pool/mod.rs @@ -0,0 +1,2 @@ +pub mod database; +pub mod models; diff --git a/frameworks/Rust/rama/src/pg_pool/models.rs b/frameworks/Rust/rama/src/pg_pool/models.rs new file mode 100644 index 00000000000..7dce3021eed --- /dev/null +++ b/frameworks/Rust/rama/src/pg_pool/models.rs @@ -0,0 +1,19 @@ +use serde::{Deserialize, Serialize}; +use tokio_pg_mapper_derive::PostgresMapper; + +#[allow(non_snake_case)] +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize, PostgresMapper)] +#[pg_mapper(table = "Fortune")] +pub struct Fortune { + pub id: i32, + pub message: String, +} + +#[allow(non_snake_case)] +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize, PostgresMapper)] +#[pg_mapper(table = "World")] +pub struct World { + pub id: i32, + #[serde(rename = "randomNumber")] + pub randomnumber: i32, +} diff --git a/frameworks/Rust/rama/src/server.rs b/frameworks/Rust/rama/src/server.rs new file mode 100644 index 00000000000..013656e6307 --- /dev/null +++ b/frameworks/Rust/rama/src/server.rs @@ -0,0 +1,77 @@ +use std::{ + future::Future, + io, + net::{Ipv4Addr, SocketAddr}, +}; + +use rama::{ + Layer, + http::{ + layer::required_header::AddRequiredResponseHeadersLayer, server::HttpServer, + service::web::Router, + }, + net::socket::{Domain, Socket, Type}, + rt::Executor, + tcp::server::TcpListener, +}; + +/// Reuse an existing listener, ensuring that the socket `backlog` +/// is set to enable a higher number of pending connections. +fn set_socket_options(addr: SocketAddr) -> io::Result> { + let socket = match addr { + SocketAddr::V4(_) => Socket::new(Domain::IPV4, Type::STREAM, None)?, + SocketAddr::V6(_) => Socket::new(Domain::IPV6, Type::STREAM, None)?, + }; + + socket.set_reuse_port(true)?; + socket.set_reuse_address(true)?; + socket.set_nonblocking(true)?; + socket.set_nodelay(true)?; + socket.bind(&addr.into())?; + socket.listen(4096)?; + + socket.try_into() +} + +/// Build a Rama server with consistent configuration, using the high-level API exposed +/// by rama 0.2. This is intended for convenience and intentionally does not provide much +/// customisability. +#[allow(dead_code)] +pub async fn serve( + state: State, + app: Router, + port: Option, +) { + let port = port.unwrap_or(8000); + let addr = SocketAddr::from((Ipv4Addr::UNSPECIFIED, port)); + let listener = set_socket_options(addr).expect("couldn't bind to address"); + println!("started rama server on port: {port}"); + + let app = AddRequiredResponseHeadersLayer::default().layer(app); + let http_service = HttpServer::auto(Executor::default()).service(app); + + listener.with_state(state).serve(http_service).await; +} + +/// Start a single-threaded tokio runtime on multiple threads. +#[allow(dead_code)] +pub fn start_tokio(f: fn() -> Fut) +where + Fut: Future + 'static, +{ + let rt = tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .unwrap(); + + for _ in 1..num_cpus::get() { + std::thread::spawn(move || { + let rt = tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .unwrap(); + rt.block_on(f()); + }); + } + rt.block_on(f()); +} diff --git a/frameworks/Rust/rama/src/sqlx/database.rs b/frameworks/Rust/rama/src/sqlx/database.rs new file mode 100644 index 00000000000..1d824144696 --- /dev/null +++ b/frameworks/Rust/rama/src/sqlx/database.rs @@ -0,0 +1,36 @@ +use std::io; + +use sqlx::{postgres::PgPoolOptions, PgPool}; + +#[derive(Debug)] +#[allow(dead_code)] +pub enum PgError { + Io(io::Error), + Pg(sqlx::Error), +} + +impl From for PgError { + fn from(err: io::Error) -> Self { + PgError::Io(err) + } +} + +impl From for PgError { + fn from(err: sqlx::Error) -> Self { + PgError::Pg(err) + } +} + +pub async fn create_pool( + database_url: String, + max_pool_size: u32, + min_pool_size: u32, +) -> PgPool { + PgPoolOptions::new() + .max_connections(max_pool_size) + .min_connections(min_pool_size) + .test_before_acquire(false) + .connect(&database_url) + .await + .unwrap() +} diff --git a/frameworks/Rust/rama/src/sqlx/mod.rs b/frameworks/Rust/rama/src/sqlx/mod.rs new file mode 100644 index 00000000000..c51e02d23d3 --- /dev/null +++ b/frameworks/Rust/rama/src/sqlx/mod.rs @@ -0,0 +1,2 @@ +pub mod database; +pub mod models; diff --git a/frameworks/Rust/axum/src/models_sqlx.rs b/frameworks/Rust/rama/src/sqlx/models.rs similarity index 100% rename from frameworks/Rust/axum/src/models_sqlx.rs rename to frameworks/Rust/rama/src/sqlx/models.rs diff --git a/frameworks/Rust/rama/templates/fortunes.html.hbs b/frameworks/Rust/rama/templates/fortunes.html.hbs new file mode 100644 index 00000000000..b9e25a52a8e --- /dev/null +++ b/frameworks/Rust/rama/templates/fortunes.html.hbs @@ -0,0 +1,5 @@ +Fortunes + {{~# each fortunes ~}} + + {{~/each ~}} +
idmessage
{{id}}{{message}}
diff --git a/frameworks/Rust/roa/.env b/frameworks/Rust/roa/.env deleted file mode 100644 index 3a9b68230d3..00000000000 --- a/frameworks/Rust/roa/.env +++ /dev/null @@ -1 +0,0 @@ -DATABASE_URL="postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world" \ No newline at end of file diff --git a/frameworks/Rust/roa/Cargo.toml b/frameworks/Rust/roa/Cargo.toml deleted file mode 100644 index d65ecf208b8..00000000000 --- a/frameworks/Rust/roa/Cargo.toml +++ /dev/null @@ -1,46 +0,0 @@ -[package] -name = "roa-techempower" -version = "0.1.0" -edition = "2018" -publish = false - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[[bin]] -name = "roa" -path = "src/main.rs" - -[[bin]] -name = "roa-db" -path = "src/main-db.rs" - -[[bin]] -name = "roa-core" -path = "src/main-core.rs" - -[dependencies] -roa = { version = "0.5.0", features = ["json", "template", "router"] } -roa-diesel = { version = "0.5.0", optional = true } -roa-pg = { version = "0.5.0", optional = true } -roa-tokio = { version = "0.5.0", optional = true } -async-std = { version = "1.5", features = ["attributes"] } -askama = "0.9" -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" -rand = { version = "0.7", features = ["small_rng"] } -bytes = "0.5.3" -futures = "0.3.4" -http = "0.2" -lazy_static = "1.4.0" -dotenv_codegen = "0.15.0" - -tokio = { version = "0.2.13", features = ["full"], optional = true } -diesel = { version = "1.4.3", features = ["postgres"], optional = true } -sqlx = { version = "0.2", features = ["postgres"], optional = true } -#hyper = "0.13" - -[features] -orm = ["diesel", "roa-diesel"] -pg = ["roa-pg"] -sqlx-pg = ["sqlx"] -tokio_rt = ["tokio", "roa-tokio"] diff --git a/frameworks/Rust/roa/README.md b/frameworks/Rust/roa/README.md deleted file mode 100755 index 4653b4c3dba..00000000000 --- a/frameworks/Rust/roa/README.md +++ /dev/null @@ -1,111 +0,0 @@ -
-

Roa

-

Roa is an async web framework inspired by koajs, lightweight but powerful.

-

- -[![Stable Test](https://github.com/Hexilee/roa/workflows/Stable%20Test/badge.svg)](https://github.com/Hexilee/roa/actions) -[![codecov](https://codecov.io/gh/Hexilee/roa/branch/master/graph/badge.svg)](https://codecov.io/gh/Hexilee/roa) -[![wiki](https://img.shields.io/badge/roa-wiki-purple.svg)](https://github.com/Hexilee/roa/wiki) -[![Rust Docs](https://docs.rs/roa/badge.svg)](https://docs.rs/roa) -[![Crate version](https://img.shields.io/crates/v/roa.svg)](https://crates.io/crates/roa) -[![Download](https://img.shields.io/crates/d/roa.svg)](https://crates.io/crates/roa) -[![Version](https://img.shields.io/badge/rustc-1.40+-lightgray.svg)](https://blog.rust-lang.org/2019/12/19/Rust-1.40.0.html) -[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/Hexilee/roa/blob/master/LICENSE) - -

- -

- Examples - | - Guide - | - Cookbook -

-
-
- - -#### Feature highlights - -- A lightweight, solid and well extensible core. - - Supports HTTP/1.x and HTTP/2.0 protocols. - - Full streaming. - - Highly extensible middleware system. - - Based on [`hyper`](https://github.com/hyperium/hyper), runtime-independent, you can chose async runtime as you like. -- Many useful extensions. - - Official runtime schemes: - - [async-std](https://github.com/async-rs/async-std) runtime and TcpStream; - - [tokio](https://github.com/tokio-rs/tokio) runtime and TcpStream. - - Transparent content compression (br, gzip, deflate, zstd). - - Configurable and nestable router. - - Named uri parameters(query and router parameter). - - Cookie and jwt support. - - HTTPS support. - - WebSocket support. - - Asynchronous multipart form support. - - Other middlewares(logger, CORS .etc). -- Integrations - - roa-diesel, integration with [diesel](https://github.com/diesel-rs/diesel). - - roa-juniper, integration with [juniper](https://github.com/graphql-rust/juniper). - - roa-pg, integration with [tokio-postgres](https://crates.io/crates/tokio-postgres). -- Works on stable Rust. - -#### Get start - -```text -# Cargo.toml - -[dependencies] -roa = "0.5.0" -async-std = { version = "1.5", features = ["attributes"] } -``` - -```rust,no_run -use roa::App; -use roa::preload::*; -use std::error::Error as StdError; - -#[async_std::main] -async fn main() -> Result<(), Box> { - let app = App::new().end("Hello, World"); - app.listen("127.0.0.1:8000", |addr| { - println!("Server is listening on {}", addr) - })? - .await?; - Ok(()) -} -``` -Refer to [wiki](https://github.com/Hexilee/roa/wiki) for more details. - -## Database - -PostgreSQL. - -* [diesel](http://diesel.rs) \/ [tokio-postgres](https://crates.io/crates/tokio-postgres) \/ [sqlx](https://github.com/launchbadge/sqlx) - -## 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/fortune - -### Test 5: Update Query - - http://localhost:8080/updates?q=20 - -### Test 6: Plaintext - - http://localhost:8080/plaintext - diff --git a/frameworks/Rust/roa/benchmark_config.json b/frameworks/Rust/roa/benchmark_config.json deleted file mode 100755 index b60fbac4858..00000000000 --- a/frameworks/Rust/roa/benchmark_config.json +++ /dev/null @@ -1,119 +0,0 @@ -{ - "framework": "roa", - "tests": [{ - "default": { - "json_url": "/json", - "plaintext_url": "/plaintext", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "Postgres", - "framework": "roa", - "language": "Rust", - "orm": "Raw", - "platform": "None", - "webserver": "hyper", - "os": "Linux", - "database_os": "Linux", - "display_name": "Roa", - "notes": "", - "versus": "" - }, - "core": { - "json_url": "/json", - "plaintext_url": "/plaintext", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "Postgres", - "framework": "roa", - "language": "Rust", - "orm": "Raw", - "platform": "None", - "webserver": "hyper", - "os": "Linux", - "database_os": "Linux", - "display_name": "Roa [Core]", - "notes": "", - "versus": "" - }, - "tokio": { - "json_url": "/json", - "plaintext_url": "/plaintext", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "Postgres", - "framework": "roa", - "language": "Rust", - "orm": "Raw", - "platform": "None", - "webserver": "hyper", - "os": "Linux", - "database_os": "Linux", - "display_name": "Roa [Tokio]", - "notes": "", - "versus": "" - }, - "diesel": { - "db_url": "/db", - "fortune_url": "/fortunes", - "query_url": "/queries?q=", - "update_url": "/updates?q=", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "Postgres", - "framework": "roa", - "language": "Rust", - "orm": "Full", - "platform": "None", - "webserver": "hyper", - "os": "Linux", - "database_os": "Linux", - "display_name": "Roa [Diesel]", - "notes": "", - "versus": "" - }, - "pg": { - "db_url": "/db", - "fortune_url": "/fortunes", - "query_url": "/queries?q=", - "update_url": "/updates?q=", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "Postgres", - "framework": "roa", - "language": "Rust", - "orm": "Raw", - "platform": "None", - "webserver": "hyper", - "os": "Linux", - "database_os": "Linux", - "display_name": "Roa [Postgres]", - "notes": "", - "versus": "" - }, - "sqlx": { - "db_url": "/db", - "fortune_url": "/fortunes", - "query_url": "/queries?q=", - "update_url": "/updates?q=", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "Postgres", - "framework": "roa", - "language": "Rust", - "orm": "Raw", - "platform": "None", - "webserver": "hyper", - "os": "Linux", - "database_os": "Linux", - "display_name": "Roa [Sqlx]", - "notes": "", - "versus": "" - } - }] -} \ No newline at end of file diff --git a/frameworks/Rust/roa/config.toml b/frameworks/Rust/roa/config.toml deleted file mode 100644 index 196983fba0a..00000000000 --- a/frameworks/Rust/roa/config.toml +++ /dev/null @@ -1,86 +0,0 @@ -[framework] -name = "roa" - -[sqlx] -urls.db = "/db" -urls.query = "/queries?q=" -urls.update = "/updates?q=" -urls.fortune = "/fortune" -approach = "Realistic" -classification = "Micro" -database = "Postgres" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "None" -webserver = "hyper" -versus = "" - -[core] -urls.plaintext = "/plaintext" -urls.json = "/json" -approach = "Realistic" -classification = "Micro" -database = "Postgres" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "None" -webserver = "hyper" -versus = "" - -[main] -urls.plaintext = "/plaintext" -urls.json = "/json" -approach = "Realistic" -classification = "Micro" -database = "Postgres" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "None" -webserver = "hyper" -versus = "" - -[diesel] -urls.db = "/db" -urls.query = "/queries?q=" -urls.update = "/updates?q=" -urls.fortune = "/fortune" -approach = "Realistic" -classification = "Micro" -database = "Postgres" -database_os = "Linux" -os = "Linux" -orm = "Full" -platform = "None" -webserver = "hyper" -versus = "" - -[pg] -urls.db = "/db" -urls.query = "/queries?q=" -urls.update = "/updates?q=" -urls.fortune = "/fortune" -approach = "Realistic" -classification = "Micro" -database = "Postgres" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "None" -webserver = "hyper" -versus = "" - -[tokio] -urls.plaintext = "/plaintext" -urls.json = "/json" -approach = "Realistic" -classification = "Micro" -database = "Postgres" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "None" -webserver = "hyper" -versus = "" diff --git a/frameworks/Rust/roa/roa-core.dockerfile b/frameworks/Rust/roa/roa-core.dockerfile deleted file mode 100644 index e77098a5a32..00000000000 --- a/frameworks/Rust/roa/roa-core.dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM rust:1.73 - -RUN apt-get update -yqq && apt-get install -yqq cmake g++ - -ADD ./ /roa -WORKDIR /roa - -RUN cargo clean -RUN RUSTFLAGS="-C target-cpu=native" cargo build --release --bin roa-core - -EXPOSE 8080 - -CMD ./target/release/roa-core diff --git a/frameworks/Rust/roa/roa-diesel.dockerfile b/frameworks/Rust/roa/roa-diesel.dockerfile deleted file mode 100644 index 35d7aa3507a..00000000000 --- a/frameworks/Rust/roa/roa-diesel.dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM rust:1.73 - -RUN apt-get update -yqq && apt-get install -yqq cmake g++ - -ADD ./ /roa -WORKDIR /roa - -RUN cargo clean -RUN RUSTFLAGS="-C target-cpu=native" cargo build --release --bin roa-db --features "orm" - -EXPOSE 8080 - -CMD ./target/release/roa-db diff --git a/frameworks/Rust/roa/roa-pg.dockerfile b/frameworks/Rust/roa/roa-pg.dockerfile deleted file mode 100644 index beb9d673858..00000000000 --- a/frameworks/Rust/roa/roa-pg.dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM rust:1.73 - -RUN apt-get update -yqq && apt-get install -yqq cmake g++ - -ADD ./ /roa -WORKDIR /roa - -RUN cargo clean -RUN RUSTFLAGS="-C target-cpu=native" cargo build --release --bin roa-db --features "pg" - -EXPOSE 8080 - -CMD ./target/release/roa-db diff --git a/frameworks/Rust/roa/roa-sqlx.dockerfile b/frameworks/Rust/roa/roa-sqlx.dockerfile deleted file mode 100644 index f14a42dc735..00000000000 --- a/frameworks/Rust/roa/roa-sqlx.dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM rust:1.73 - -RUN apt-get update -yqq && apt-get install -yqq cmake g++ - -ADD ./ /roa -WORKDIR /roa - -RUN cargo clean -RUN RUSTFLAGS="-C target-cpu=native" cargo build --release --bin roa-db --features "sqlx-pg" - -EXPOSE 8080 - -CMD ./target/release/roa-db diff --git a/frameworks/Rust/roa/roa-tokio.dockerfile b/frameworks/Rust/roa/roa-tokio.dockerfile deleted file mode 100644 index 38f3b9fa381..00000000000 --- a/frameworks/Rust/roa/roa-tokio.dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM rust:1.73 - -RUN apt-get update -yqq && apt-get install -yqq cmake g++ - -ADD ./ /roa -WORKDIR /roa - -RUN cargo clean -RUN RUSTFLAGS="-C target-cpu=native" cargo build --release --bin roa-core --features "tokio_rt" - -EXPOSE 8080 - -CMD ./target/release/roa-core diff --git a/frameworks/Rust/roa/roa.dockerfile b/frameworks/Rust/roa/roa.dockerfile deleted file mode 100644 index 29ed4e2200f..00000000000 --- a/frameworks/Rust/roa/roa.dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM rust:1.73 - -RUN apt-get update -yqq && apt-get install -yqq cmake g++ - -ADD ./ /roa -WORKDIR /roa - -RUN cargo clean -RUN RUSTFLAGS="-C target-cpu=native" cargo build --release --bin roa - -EXPOSE 8080 - -CMD ./target/release/roa diff --git a/frameworks/Rust/roa/rustfmt.toml b/frameworks/Rust/roa/rustfmt.toml deleted file mode 100644 index 30e2708ff60..00000000000 --- a/frameworks/Rust/roa/rustfmt.toml +++ /dev/null @@ -1,2 +0,0 @@ -max_width = 89 -reorder_imports = true \ No newline at end of file diff --git a/frameworks/Rust/roa/src/db_diesel.rs b/frameworks/Rust/roa/src/db_diesel.rs deleted file mode 100644 index 9a311adf00a..00000000000 --- a/frameworks/Rust/roa/src/db_diesel.rs +++ /dev/null @@ -1,97 +0,0 @@ -use diesel::pg::PgConnection; -use diesel::prelude::*; -use diesel::r2d2::ConnectionManager; -use roa::http::StatusCode; -use roa_diesel::preload::*; -use roa_diesel::Pool; - -use rand::rngs::SmallRng; -use rand::{Rng, SeedableRng}; - -use crate::models::Fortune; -use crate::{async_trait, throw, Context, Result, Service, StdResult, World}; -use futures::stream::{FuturesUnordered, TryStreamExt}; - -#[derive(Clone)] -pub struct State { - pool: Pool, - rng: SmallRng, -} - -impl AsRef> for State { - #[inline] - fn as_ref(&self) -> &Pool { - &self.pool - } -} - -impl State { - pub async fn bind(pg_url: &str) -> StdResult { - let pool = Pool::builder() - .max_size(50) - .build(ConnectionManager::::new(pg_url))?; - Ok(Self { - pool, - rng: SmallRng::from_entropy(), - }) - } -} - -#[async_trait(?Send)] -impl Service for Context { - #[inline] - fn random_id(&mut self) -> i32 { - self.rng.gen_range(0, 10_001) - } - - #[inline] - fn get_queries(&self) -> usize { - use std::cmp::{max, min}; - let query = self.uri().query(); - let nums = query - .and_then(|query| Some((query, query.find("q")?))) - .and_then(|(query, pos)| query.split_at(pos + 2).1.parse().ok()) - .unwrap_or(1); - min(500, max(1, nums)) - } - - #[inline] - async fn query_world(&self, wid: i32) -> Result { - use crate::schema::world::dsl::*; - let data = self.first(world.filter(id.eq(wid))).await?; - match data { - None => throw!(StatusCode::NOT_FOUND), - Some(item) => Ok(item), - } - } - - #[inline] - async fn fortunes(&self) -> Result> { - use crate::schema::fortune::dsl::*; - Ok(self.load_data(fortune).await?) - } - - #[inline] - async fn update_worlds(&mut self) -> Result> { - let worlds = FuturesUnordered::new(); - let random_ids: Vec<_> = - (0..self.get_queries()).map(|_| self.random_id()).collect(); - for wid in random_ids { - worlds.push(update_world(self, wid)); - } - worlds.try_collect().await - } -} - -async fn update_world(ctx: &Context, wid: i32) -> Result { - use crate::schema::world::dsl::*; - let mut data = ctx.query_world(wid).await?; - data.randomnumber = wid; - ctx.execute( - diesel::update(world) - .filter(id.eq(wid)) - .set(randomnumber.eq(wid)), - ) - .await?; - Ok(data) -} diff --git a/frameworks/Rust/roa/src/db_pg.rs b/frameworks/Rust/roa/src/db_pg.rs deleted file mode 100644 index e2e3435af5a..00000000000 --- a/frameworks/Rust/roa/src/db_pg.rs +++ /dev/null @@ -1,126 +0,0 @@ -use crate::models::Fortune; -use crate::{async_trait, throw, Context, Result, Service, StdResult, World}; -use rand::rngs::SmallRng; -use rand::{Rng, SeedableRng}; -use roa::http::StatusCode; -use roa_pg::types::ToSql; -use roa_pg::{connect, Client, Statement}; -use std::collections::HashMap; -use std::fmt::Write; -use std::sync::Arc; - -#[derive(Clone)] -pub struct State { - client: Arc, - queries: Arc, - rng: SmallRng, -} - -pub struct Queries { - fortune: Statement, - world: Statement, - updates: HashMap, -} - -impl State { - pub async fn bind(url: &str) -> StdResult { - let (client, conn) = connect(&url.parse()?).await?; - - async_std::task::spawn(conn); - - let fortune = client.prepare("SELECT * FROM fortune").await?; - let world = client.prepare("SELECT * FROM world WHERE id=$1").await?; - let mut updates = HashMap::new(); - for num in 1..=500 { - let mut pl = 1; - let mut q = String::new(); - q.push_str("UPDATE world SET randomnumber = CASE id "); - for _ in 1..=num { - write!(&mut q, "when ${} then ${} ", pl, pl + 1)?; - pl += 2; - } - q.push_str("ELSE randomnumber END WHERE id IN ("); - for _ in 1..=num { - write!(&mut q, "${},", pl)?; - pl += 1; - } - q.pop(); - q.push(')'); - updates.insert(num, client.prepare(&q).await?); - } - Ok(State { - client: Arc::new(client), - queries: Arc::new(Queries { - fortune, - world, - updates, - }), - rng: SmallRng::from_entropy(), - }) - } -} - -#[async_trait(?Send)] -impl Service for Context { - #[inline] - fn random_id(&mut self) -> i32 { - self.rng.gen_range(0, 10_001) - } - - #[inline] - fn get_queries(&self) -> usize { - use std::cmp::{max, min}; - let query = self.uri().query(); - let nums = query - .and_then(|query| Some((query, query.find("q")?))) - .and_then(|(query, pos)| query.split_at(pos + 2).1.parse().ok()) - .unwrap_or(1); - min(500, max(1, nums)) - } - - #[inline] - async fn query_world(&self, wid: i32) -> Result { - match self.client.query_opt(&self.queries.world, &[&wid]).await? { - None => throw!(StatusCode::NOT_FOUND), - Some(row) => Ok(World { - id: row.get(0), - randomnumber: row.get(1), - }), - } - } - - #[inline] - async fn fortunes(&self) -> Result> { - let fortunes = self - .client - .query(&self.queries.fortune, &[]) - .await? - .iter() - .map(|row| Fortune { - id: row.get(0), - message: row.get(1), - }) - .collect(); - Ok(fortunes) - } - - #[inline] - async fn update_worlds(&mut self) -> Result> { - let mut worlds = self.query_worlds().await?; - let nums = worlds.len(); - let mut params: Vec<&(dyn ToSql + Sync)> = Vec::with_capacity(nums * 3); - for w in worlds.iter_mut() { - w.randomnumber = w.id; - } - for w in &worlds { - params.push(&w.id); - params.push(&w.randomnumber); - } - for w in &worlds { - params.push(&w.id); - } - let statement = &self.queries.updates[&nums]; - self.client.execute(statement, ¶ms).await?; - Ok(worlds) - } -} diff --git a/frameworks/Rust/roa/src/db_sqlx.rs b/frameworks/Rust/roa/src/db_sqlx.rs deleted file mode 100644 index 731f3dd7445..00000000000 --- a/frameworks/Rust/roa/src/db_sqlx.rs +++ /dev/null @@ -1,108 +0,0 @@ -use crate::models::Fortune; -use crate::{async_trait, throw, Context, Result, Service, StdResult, World}; -use futures::TryStreamExt; -use rand::rngs::SmallRng; -use rand::{Rng, SeedableRng}; -use roa::http::StatusCode; -use sqlx::{PgPool, Row}; -use std::collections::HashMap; -use std::fmt::Write; -use std::sync::Arc; - -#[derive(Clone)] -pub struct State { - client: PgPool, - updates: Arc>, - rng: SmallRng, -} - -impl State { - pub async fn bind(url: &str) -> StdResult { - let client = PgPool::new(url).await?; - let mut updates = HashMap::new(); - for num in 1..=500 { - let mut pl = 1; - let mut q = String::new(); - q.push_str("UPDATE world SET randomnumber = CASE id "); - for _ in 1..=num { - write!(&mut q, "when ${} then ${} ", pl, pl + 1)?; - pl += 2; - } - q.push_str("ELSE randomnumber END WHERE id IN ("); - for _ in 1..=num { - write!(&mut q, "${},", pl)?; - pl += 1; - } - q.pop(); - q.push(')'); - updates.insert(num, q); - } - Ok(State { - client, - updates: Arc::new(updates), - rng: SmallRng::from_entropy(), - }) - } -} - -#[async_trait(?Send)] -impl Service for Context { - #[inline] - fn random_id(&mut self) -> i32 { - self.rng.gen_range(0, 10_001) - } - - #[inline] - fn get_queries(&self) -> usize { - use std::cmp::{max, min}; - let query = self.uri().query(); - let nums = query - .and_then(|query| Some((query, query.find("q")?))) - .and_then(|(query, pos)| query.split_at(pos + 2).1.parse().ok()) - .unwrap_or(1); - min(500, max(1, nums)) - } - - #[inline] - async fn query_world(&self, wid: i32) -> Result { - match sqlx::query("SELECT * FROM world WHERE id=$1") - .bind(wid) - .fetch_optional(&mut &self.client) - .await? - { - None => throw!(StatusCode::NOT_FOUND), - Some(row) => Ok(World { - id: row.get(0), - randomnumber: row.get(1), - }), - } - } - - #[inline] - async fn fortunes(&self) -> Result> { - let fortunes: Vec<_> = sqlx::query("SELECT * FROM fortune") - .fetch(&mut &self.client) - .map_ok(|row| Fortune { - id: row.get(0), - message: row.get(1), - }) - .try_collect() - .await?; - Ok(fortunes) - } - - #[inline] - async fn update_worlds(&mut self) -> Result> { - let mut worlds = self.query_worlds().await?; - let mut query = sqlx::query(&self.updates[&worlds.len()]); - for w in worlds.iter_mut() { - w.randomnumber = w.id; - query = query.bind(w.id).bind(w.randomnumber); - } - for w in &worlds { - query = query.bind(w.id); - } - query.execute(&mut &self.client).await?; - Ok(worlds) - } -} diff --git a/frameworks/Rust/roa/src/endpoints.rs b/frameworks/Rust/roa/src/endpoints.rs deleted file mode 100644 index 1d5363d3cce..00000000000 --- a/frameworks/Rust/roa/src/endpoints.rs +++ /dev/null @@ -1,23 +0,0 @@ -use crate::utils::{Message, JSON_LEN, PLAINTEXT_LEN}; -use roa::http::header::CONTENT_LENGTH; -use roa::preload::*; -use roa::{Context, Result}; - -static HELLO_WORLD: &str = "Hello, World!"; - -#[inline] -pub async fn json(ctx: &mut Context) -> Result { - ctx.resp.headers.insert(CONTENT_LENGTH, JSON_LEN.clone()); - ctx.write_json(&Message { - message: HELLO_WORLD, - }) -} - -#[inline] -pub async fn plaintext(ctx: &mut Context) -> Result { - ctx.resp - .headers - .insert(CONTENT_LENGTH, PLAINTEXT_LEN.clone()); - ctx.write(HELLO_WORLD); - Ok(()) -} diff --git a/frameworks/Rust/roa/src/main-core.rs b/frameworks/Rust/roa/src/main-core.rs deleted file mode 100644 index fb82662a47b..00000000000 --- a/frameworks/Rust/roa/src/main-core.rs +++ /dev/null @@ -1,44 +0,0 @@ -use roa::http::header::SERVER; -use roa::{App, Context, Result}; -use std::error::Error as StdError; -use std::result::Result as StdResult; - -pub mod endpoints; -pub mod utils; -use endpoints::{json, plaintext}; -use utils::SERVER_HEADER; - -#[inline] -async fn endpoint(ctx: &mut Context<()>) -> Result { - // avoid to re-allocate a header map - ctx.resp.headers = std::mem::take(&mut ctx.req.headers); - ctx.resp.headers.clear(); - ctx.resp.headers.insert(SERVER, SERVER_HEADER.clone()); - match ctx.uri().path() { - "/plaintext" => plaintext(ctx).await, - _ => json(ctx).await, - } -} - -#[cfg(not(feature = "tokio_rt"))] -#[async_std::main] -async fn main() -> StdResult<(), Box> { - use roa::preload::*; - let app = App::new().end(endpoint); - app.listen("0.0.0.0:8080", |addr| { - println!("Server listen on {}...", addr); - })? - .await?; - Ok(()) -} - -#[cfg(feature = "tokio_rt")] -#[tokio::main] -async fn main() -> StdResult<(), Box> { - use roa_tokio::{Exec, TcpIncoming}; - let app = App::with_exec((), Exec).end(endpoint); - let incoming = TcpIncoming::bind("0.0.0.0:8080")?; - println!("Server listen on {}...", incoming.local_addr()); - app.accept(incoming).await?; - Ok(()) -} diff --git a/frameworks/Rust/roa/src/main-db.rs b/frameworks/Rust/roa/src/main-db.rs deleted file mode 100644 index acb702c17fd..00000000000 --- a/frameworks/Rust/roa/src/main-db.rs +++ /dev/null @@ -1,118 +0,0 @@ -#[cfg(feature = "orm")] -#[macro_use] -extern crate diesel; - -#[cfg(feature = "orm")] -mod db_diesel; - -#[cfg(feature = "orm")] -mod schema; - -#[cfg(feature = "orm")] -use db_diesel::State; - -#[cfg(feature = "pg")] -mod db_pg; - -#[cfg(feature = "pg")] -use db_pg::State; - -#[cfg(feature = "sqlx-pg")] -mod db_sqlx; - -#[cfg(feature = "sqlx-pg")] -use db_sqlx::State; - -use futures::stream::{FuturesUnordered, TryStreamExt}; -use roa::http::header::SERVER; -use roa::preload::*; -use roa::router::{get, RouteTable, Router}; -use roa::{async_trait, throw, App, Context, Next, Result}; -mod models; -pub mod utils; -use dotenv_codegen::dotenv; -use models::*; -use utils::SERVER_HEADER; - -type StdResult = std::result::Result>; - -#[async_trait(?Send)] -trait Service { - fn random_id(&mut self) -> i32; - fn get_queries(&self) -> usize; - async fn query_world(&self, wid: i32) -> Result; - async fn fortunes(&self) -> Result>; - async fn update_worlds(&mut self) -> Result>; - async fn query_worlds(&mut self) -> Result> { - let worlds = FuturesUnordered::new(); - let random_ids: Vec<_> = - (0..self.get_queries()).map(|_| self.random_id()).collect(); - for id in random_ids { - worlds.push(self.query_world(id)); - } - worlds.try_collect().await - } -} - -#[inline] -async fn gate(ctx: &mut Context, next: Next<'_>) -> Result { - // avoid to re-allocate a header map - ctx.resp.headers = std::mem::take(&mut ctx.req.headers); - ctx.resp.headers.clear(); - ctx.resp.headers.insert(SERVER, SERVER_HEADER.clone()); - next.await -} - -#[inline] -async fn db(ctx: &mut Context) -> Result { - let id = ctx.random_id(); - let data = ctx.query_world(id).await?; - ctx.write_json(&data)?; - Ok(()) -} - -#[inline] -async fn queries(ctx: &mut Context) -> Result { - let data = ctx.query_worlds().await?; - ctx.write_json(&data)?; - Ok(()) -} - -#[inline] -async fn fortune(ctx: &mut Context) -> Result { - let mut fortunes = ctx.fortunes().await?; - fortunes.push(Fortune { - id: 0, - message: "Additional fortune added at request time.".to_owned(), - }); - fortunes.sort_by(|it, next| it.message.cmp(&next.message)); - ctx.render(&Fortunes { items: &fortunes }) -} - -#[inline] -async fn updates(ctx: &mut Context) -> Result { - let data = ctx.update_worlds().await?; - ctx.write_json(&data)?; - Ok(()) -} - -fn routes(prefix: &'static str) -> StdResult> { - Router::new() - .gate(gate) - .on("/db", get(db)) - .on("/queries", get(queries)) - .on("/fortunes", get(fortune)) - .on("/updates", get(updates)) - .routes(prefix) - .map_err(Into::into) -} - -#[async_std::main] -async fn main() -> StdResult<()> { - let app = App::state(State::bind(dotenv!("DATABASE_URL")).await?).end(routes("/")?); - app.listen("0.0.0.0:8080", |addr| { - println!("Server listen on {}...", addr); - })? - .await?; - Ok(()) -} diff --git a/frameworks/Rust/roa/src/main.rs b/frameworks/Rust/roa/src/main.rs deleted file mode 100644 index af49219fe74..00000000000 --- a/frameworks/Rust/roa/src/main.rs +++ /dev/null @@ -1,34 +0,0 @@ -use roa::http::header::SERVER; -use roa::preload::*; -use roa::router::{get, Router}; -use roa::{App, Context, Next, Result}; -use std::error::Error; -use std::result::Result as StdResult; - -pub mod endpoints; -pub mod utils; -use endpoints::{json, plaintext}; -use utils::SERVER_HEADER; - -#[inline] -async fn gate(ctx: &mut Context<()>, next: Next<'_>) -> Result { - // avoid to re-allocate a header map - ctx.resp.headers = std::mem::take(&mut ctx.req.headers); - ctx.resp.headers.clear(); - ctx.resp.headers.insert(SERVER, SERVER_HEADER.clone()); - next.await -} - -#[async_std::main] -async fn main() -> StdResult<(), Box> { - let router = Router::new() - .gate(gate) - .on("/json", get(json)) - .on("/plaintext", get(plaintext)); - let app = App::new().end(router.routes("/")?); - app.listen("0.0.0.0:8080", |addr| { - println!("Server listen on {}...", addr); - })? - .await?; - Ok(()) -} diff --git a/frameworks/Rust/roa/src/models.rs b/frameworks/Rust/roa/src/models.rs deleted file mode 100644 index b45713d536c..00000000000 --- a/frameworks/Rust/roa/src/models.rs +++ /dev/null @@ -1,30 +0,0 @@ -#![allow(dead_code)] - -use askama::Template; -use serde::Serialize; - -#[derive(Serialize)] -pub struct Message { - pub message: &'static str, -} - -#[cfg_attr(feature = "orm", derive(Queryable))] -#[allow(non_snake_case)] -#[derive(Serialize, Debug)] -pub struct World { - pub id: i32, - pub randomnumber: i32, -} - -#[cfg_attr(feature = "orm", derive(Queryable))] -#[derive(Serialize, Debug)] -pub struct Fortune { - pub id: i32, - pub message: String, -} - -#[derive(Template)] -#[template(path = "fortune.html")] -pub struct Fortunes<'a> { - pub items: &'a [Fortune], -} diff --git a/frameworks/Rust/roa/src/utils.rs b/frameworks/Rust/roa/src/utils.rs deleted file mode 100644 index 34c00037fbc..00000000000 --- a/frameworks/Rust/roa/src/utils.rs +++ /dev/null @@ -1,20 +0,0 @@ -use lazy_static::lazy_static; -use roa::http::header::HeaderValue; -use serde::{Deserialize, Serialize}; - -lazy_static! { - pub static ref SERVER_HEADER: HeaderValue = HeaderValue::from_static("roa"); - pub static ref JSON_LEN: HeaderValue = HeaderValue::from_static("27"); - pub static ref PLAINTEXT_LEN: HeaderValue = HeaderValue::from_static("13"); -} - -#[derive(Serialize, Debug)] -pub struct Fortune { - pub id: i32, - pub message: String, -} - -#[derive(Serialize, Deserialize)] -pub struct Message { - pub message: &'static str, -} diff --git a/frameworks/Rust/roa/templates/fortune.html b/frameworks/Rust/roa/templates/fortune.html deleted file mode 100644 index 7c448b9d999..00000000000 --- a/frameworks/Rust/roa/templates/fortune.html +++ /dev/null @@ -1,12 +0,0 @@ - - - Fortunes - - - - {% for item in items %} - - {% endfor %} -
idmessage
{{item.id}}{{item.message}}
- - diff --git a/frameworks/Rust/rocket/.gitignore b/frameworks/Rust/rocket/.gitignore index 2eea525d885..b153885fd09 100644 --- a/frameworks/Rust/rocket/.gitignore +++ b/frameworks/Rust/rocket/.gitignore @@ -1 +1,3 @@ -.env \ No newline at end of file +.env + +Cargo.lock diff --git a/frameworks/Rust/rocket/Cargo.lock b/frameworks/Rust/rocket/Cargo.lock index 4f45a3f3f13..3e193d9a3eb 100644 --- a/frameworks/Rust/rocket/Cargo.lock +++ b/frameworks/Rust/rocket/Cargo.lock @@ -1,131 +1,115 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] -name = "aead" -version = "0.5.1" +name = "addr2line" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c192eb8f11fc081b0fe4259ba5af04217d4e0faddd02417310a927911abd7c8" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" dependencies = [ - "crypto-common", - "generic-array", -] - -[[package]] -name = "aes" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "433cfd6710c9986c576a25ca913c39d66a6474107b406f34f91d4a8923395241" -dependencies = [ - "cfg-if 1.0.0", - "cipher", - "cpufeatures", + "gimli", ] [[package]] -name = "aes-gcm" -version = "0.10.1" +name = "adler" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e1366e0c69c9f927b1fa5ce2c7bf9eafc8f9268c0b9800729e8b267612447c" -dependencies = [ - "aead", - "aes", - "cipher", - "ctr", - "ghash", - "subtle", -] +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "ahash" -version = "0.7.6" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +checksum = "d713b3834d76b85304d4d525563c1276e2e30dc97cc67bfb4585a4a29fc2c89f" dependencies = [ + "cfg-if", "getrandom", "once_cell", "version_check", + "zerocopy", ] [[package]] name = "aho-corasick" -version = "0.7.20" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" dependencies = [ "memchr", ] [[package]] -name = "annotate-snippets" -version = "0.9.1" +name = "allocator-api2" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3b9d411ecbaf79885c6df4d75fff75858d5995ff25385657a28af47e82f9c36" -dependencies = [ - "unicode-width", - "yansi-term", -] +checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" [[package]] name = "async-stream" -version = "0.3.3" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dad5c83079eae9969be7fadefe640a1c566901f05ff91ab221de4b6f68d9507e" +checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" dependencies = [ "async-stream-impl", "futures-core", + "pin-project-lite", ] [[package]] name = "async-stream-impl" -version = "0.3.3" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10f203db73a71dfa2fb6dd22763990fa26f3d2625a6da2da900d23b87d26be27" +checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.50", ] [[package]] name = "async-trait" -version = "0.1.61" +version = "0.1.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "705339e0e4a9690e2908d2b3d049d85682cf19fbd5782494498fbf7003a6a282" +checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.50", ] [[package]] name = "atoi" -version = "0.4.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616896e05fc0e2649463a93a15183c6a16bf03413a7af88ef1285ddedfa9cda5" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" dependencies = [ "num-traits", ] [[package]] name = "atomic" -version = "0.5.1" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59bdb34bc650a32731b31bd8f0829cc15d24a708ee31559e0bb34f2bc320cba" + +[[package]] +name = "atomic" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b88d82667eca772c4aa12f0f1348b3ae643424c8876448f3f7bd5787032e234c" +checksum = "8d818003e740b63afc82337e3160717f4f63078720a810b7b903e70a5d1d2994" dependencies = [ - "autocfg", + "bytemuck", ] [[package]] -name = "atty" -version = "0.2.14" +name = "atomic-write-file" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +checksum = "edcdbedc2236483ab103a53415653d6b4442ea6141baf1ffa85df29635e88436" dependencies = [ - "hermit-abi 0.1.19", - "libc", - "winapi 0.3.9", + "nix", + "rand", ] [[package]] @@ -135,16 +119,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] -name = "base64" -version = "0.13.1" +name = "backtrace" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] [[package]] name = "base64" -version = "0.20.0" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64ct" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ea22880d78093b0cbe17c89f64a7d457941e65759157ec6cb31a31d652b05e5" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" [[package]] name = "binascii" @@ -158,44 +157,50 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" +dependencies = [ + "serde", +] + [[package]] name = "block-buffer" -version = "0.10.3" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ "generic-array", ] [[package]] -name = "bumpalo" -version = "3.11.1" +name = "bytemuck" +version = "1.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" +checksum = "a2ef034f05691a48569bd920a96c81b9d91bbad1ab5ac7c4616c1f6ef36cb79f" [[package]] name = "byteorder" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.3.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "cc" -version = "1.0.78" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d" - -[[package]] -name = "cfg-if" -version = "0.1.10" +version = "1.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c" +dependencies = [ + "shlex", +] [[package]] name = "cfg-if" @@ -204,82 +209,70 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] -name = "cipher" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1873270f8f7942c191139cb8a40fd228da6c3fd2fc376d7e92d47aa14aeb59e" -dependencies = [ - "crypto-common", - "inout", -] - -[[package]] -name = "convert_case" -version = "0.4.0" +name = "const-oid" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "cookie" -version = "0.16.2" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb" +checksum = "3cd91cf61412820176e137621345ee43b3f4423e589e7ae4e50d601d93e35ef8" dependencies = [ - "aes-gcm", - "base64 0.20.0", - "hkdf", - "hmac", "percent-encoding", - "rand", - "sha2", - "subtle", "time", "version_check", ] [[package]] name = "cpufeatures" -version = "0.2.5" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" dependencies = [ "libc", ] [[package]] name = "crc" -version = "2.1.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49fc9a695bca7f35f5f4c15cddc84415f66a74ea78eef08e90c5024f2b540e23" +checksum = "86ec7a15cbe22e59248fc7eadb1907dab5ba09372595da4d73dd805ed4417dfe" dependencies = [ "crc-catalog", ] [[package]] name = "crc-catalog" -version = "1.1.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccaeedb56da03b09f598226e25e80088cb4cd25f316e6e4df7d695f0feeb1403" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" [[package]] -name = "crossbeam-queue" -version = "0.3.8" +name = "crossbeam-channel" +version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" dependencies = [ - "cfg-if 1.0.0", "crossbeam-utils", ] [[package]] -name = "crossbeam-utils" -version = "0.8.14" +name = "crossbeam-queue" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f" +checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" dependencies = [ - "cfg-if 1.0.0", + "crossbeam-utils", ] +[[package]] +name = "crossbeam-utils" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" + [[package]] name = "crypto-common" version = "0.1.6" @@ -287,37 +280,34 @@ 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" +name = "der" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" dependencies = [ - "cipher", + "const-oid", + "pem-rfc7468", + "zeroize", ] [[package]] -name = "derive_more" -version = "0.99.17" +name = "deranged" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" dependencies = [ - "convert_case", - "proc-macro2", - "quote", - "rustc_version", - "syn", + "powerfmt", ] [[package]] name = "devise" -version = "0.3.1" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50c7580b072f1c8476148f16e0a0d5dedddab787da98d86c5082c5e9ed8ab595" +checksum = "d6eacefd3f541c66fc61433d65e54e0e46e0a029a819a7dbbc7a7b489e8a85f8" dependencies = [ "devise_codegen", "devise_core", @@ -325,9 +315,9 @@ dependencies = [ [[package]] name = "devise_codegen" -version = "0.3.1" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "123c73e7a6e51b05c75fe1a1b2f4e241399ea5740ed810b0e3e6cacd9db5e7b2" +checksum = "9c8cf4b8dd484ede80fd5c547592c46c3745a617c8af278e2b72bea86b2dfed6" dependencies = [ "devise_core", "quote", @@ -335,97 +325,78 @@ dependencies = [ [[package]] name = "devise_core" -version = "0.3.1" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841ef46f4787d9097405cac4e70fb8644fc037b526e8c14054247c0263c400d0" +checksum = "35b50dba0afdca80b187392b24f2499a88c336d5a8493e4b4ccfb608708be56a" dependencies = [ - "bitflags", + "bitflags 2.4.2", "proc-macro2", "proc-macro2-diagnostics", "quote", - "syn", -] - -[[package]] -name = "diesel" -version = "1.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b28135ecf6b7d446b43e27e225622a038cc4e2930a1022f51cdb97ada19b8e4d" -dependencies = [ - "bitflags", - "byteorder", - "diesel_derives", - "pq-sys", - "r2d2", -] - -[[package]] -name = "diesel_derives" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45f5098f628d02a7a0f68ddba586fb61e80edec3bdc1be3b921f4ceec60858d3" -dependencies = [ - "proc-macro2", - "quote", - "syn", + "syn 2.0.50", ] [[package]] name = "digest" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", + "const-oid", "crypto-common", "subtle", ] [[package]] -name = "dirs" -version = "4.0.0" +name = "dotenvy" +version = "0.15.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" -dependencies = [ - "dirs-sys", -] +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" [[package]] -name = "dirs-sys" -version = "0.3.7" +name = "either" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" +checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" dependencies = [ - "libc", - "redox_users", - "winapi 0.3.9", + "serde", ] [[package]] -name = "dotenv" -version = "0.15.0" +name = "encoding_rs" +version = "0.8.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +dependencies = [ + "cfg-if", +] [[package]] -name = "dtoa" -version = "1.0.5" +name = "equivalent" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c00704156a7de8df8da0911424e30c2049957b0a714542a44e05fe693dd85313" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] -name = "either" -version = "1.8.0" +name = "errno" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] [[package]] -name = "encoding_rs" -version = "0.8.31" +name = "etcetera" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" +checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", + "home", + "windows-sys 0.48.0", ] [[package]] @@ -436,20 +407,17 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "fastrand" -version = "1.8.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" -dependencies = [ - "instant", -] +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" [[package]] name = "figment" -version = "0.10.8" +version = "0.10.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e56602b469b2201400dec66a66aec5a9b8761ee97cd1b8c96ab2483fcc16cc9" +checksum = "2b6e5bc7bd59d60d0d45a6ccab6cf0f4ce28698fb4e81e750ddf229c9b824026" dependencies = [ - "atomic", + "atomic 0.6.0", "pear", "serde", "toml", @@ -459,75 +427,65 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.19" +version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e884668cd0c7480504233e951174ddc3b382f7c2666e3b7310b5c4e7b0c37f9" +checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "redox_syscall", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] -name = "fnv" -version = "1.0.7" +name = "finl_unicode" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +checksum = "8fcfdc7a0362c9f4444381a9e697c79d435fe65b52a37466fc2c1184cee9edc6" [[package]] -name = "form_urlencoded" -version = "1.1.0" +name = "flume" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" dependencies = [ - "percent-encoding", + "futures-core", + "futures-sink", + "spin 0.9.8", ] [[package]] -name = "fsevent" -version = "0.4.0" +name = "fnv" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ab7d1bd1bd33cc98b0889831b72da23c0aa4df9cec7e0702f46ecea04b35db6" -dependencies = [ - "bitflags", - "fsevent-sys", -] +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] -name = "fsevent-sys" -version = "2.0.1" +name = "form_urlencoded" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f41b048a94555da0f42f1d632e2e19510084fb8e303b0daa2816e733fb3644a0" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ - "libc", + "percent-encoding", ] [[package]] -name = "fuchsia-zircon" -version = "0.3.3" +name = "fsevent-sys" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" +checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2" dependencies = [ - "bitflags", - "fuchsia-zircon-sys", + "libc", ] -[[package]] -name = "fuchsia-zircon-sys" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" - [[package]] name = "futures" -version = "0.3.25" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" dependencies = [ "futures-channel", "futures-core", - "futures-executor", "futures-io", "futures-sink", "futures-task", @@ -536,9 +494,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.25" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" dependencies = [ "futures-core", "futures-sink", @@ -546,15 +504,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.25" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" [[package]] name = "futures-executor" -version = "0.3.25" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7acc85df6714c176ab5edf386123fafe217be88c0840ec11f199441134a074e2" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" dependencies = [ "futures-core", "futures-task", @@ -563,54 +521,42 @@ dependencies = [ [[package]] name = "futures-intrusive" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a604f7a68fbf8103337523b1fadc8ade7361ee3f112f7c680ad179651616aed5" +checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" dependencies = [ "futures-core", "lock_api", - "parking_lot 0.11.2", + "parking_lot", ] [[package]] name = "futures-io" -version = "0.3.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb" - -[[package]] -name = "futures-macro" -version = "0.3.25" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" [[package]] name = "futures-sink" -version = "0.3.25" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" [[package]] name = "futures-task" -version = "0.3.25" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" [[package]] name = "futures-util" -version = "0.3.25" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ "futures-channel", "futures-core", "futures-io", - "futures-macro", "futures-sink", "futures-task", "memchr", @@ -621,9 +567,9 @@ dependencies = [ [[package]] name = "generator" -version = "0.7.2" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d266041a359dfa931b370ef684cceb84b166beb14f7f0421f4a6a3d0c446d12e" +checksum = "5cc16584ff22b460a382b7feec54b23d2908d858152e5739a120b949293bd74e" dependencies = [ "cc", "libc", @@ -634,9 +580,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.6" +version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", @@ -644,24 +590,20 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.8" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "wasi", ] [[package]] -name = "ghash" -version = "0.5.0" +name = "gimli" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d930750de5717d2dd0b8c0d42c076c0e884c81a73e6cab859bbd2339c71e3e40" -dependencies = [ - "opaque-debug", - "polyval", -] +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" [[package]] name = "glob" @@ -671,9 +613,9 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "h2" -version = "0.3.15" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f9f29bc9dda355256b2916cf526ab02ce0aeaaaf2bad60d65ef3f12f11dd0f4" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" dependencies = [ "bytes", "fnv", @@ -690,9 +632,9 @@ dependencies = [ [[package]] name = "handlebars" -version = "4.3.6" +version = "4.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "035ef95d03713f2c347a72547b7cd38cbc9af7cd51e6099fb62d586d4a6dee3a" +checksum = "faa67bab9ff362228eb3d00bd024a4965d8231bbb7921167f0cfa66c6626b225" dependencies = [ "log", "pest", @@ -704,54 +646,37 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.11.2" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" dependencies = [ "ahash", + "allocator-api2", ] -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - [[package]] name = "hashlink" -version = "0.7.0" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7249a3129cbc1ffccd74857f81464a323a152173cdb134e0fd81bc803b29facf" +checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" dependencies = [ - "hashbrown 0.11.2", + "hashbrown", ] [[package]] name = "heck" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" dependencies = [ "unicode-segmentation", ] [[package]] name = "hermit-abi" -version = "0.1.19" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - -[[package]] -name = "hermit-abi" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" -dependencies = [ - "libc", -] +checksum = "bd5256b483761cd23699d0da46cc6fd2ee3be420bbe6d020ae4a091e70b7e9fd" [[package]] name = "hex" @@ -761,9 +686,9 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "hkdf" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" dependencies = [ "hmac", ] @@ -777,11 +702,20 @@ 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 = "0.2.8" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" +checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" dependencies = [ "bytes", "fnv", @@ -790,9 +724,9 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", "http", @@ -807,15 +741,15 @@ checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" [[package]] name = "httpdate" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "0.14.23" +version = "0.14.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "034711faac9d2166cb1baf1a2fb0b60b1f277f8492fd72176c17f3515e1abd3c" +checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" dependencies = [ "bytes", "futures-channel", @@ -837,9 +771,9 @@ dependencies = [ [[package]] name = "idna" -version = "0.3.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -847,12 +781,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.9.2" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" +checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177" dependencies = [ - "autocfg", - "hashbrown 0.12.3", + "equivalent", + "hashbrown", "serde", ] @@ -864,11 +798,11 @@ checksum = "c8fae54786f62fb2918dcfae3d568594e50eb9b5c25bf04371af6fe7516452fb" [[package]] name = "inotify" -version = "0.7.1" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4816c66d2c8ae673df83366c18341538f234a26d65a9ecea5c348b453ac1d02f" +checksum = "f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff" dependencies = [ - "bitflags", + "bitflags 1.3.2", "inotify-sys", "libc", ] @@ -883,64 +817,49 @@ dependencies = [ ] [[package]] -name = "inout" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" -dependencies = [ - "generic-array", -] - -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if 1.0.0", -] - -[[package]] -name = "iovec" -version = "0.1.4" +name = "is-terminal" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" +checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" dependencies = [ + "hermit-abi", "libc", + "windows-sys 0.52.0", ] [[package]] name = "itertools" -version = "0.10.5" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" dependencies = [ "either", ] [[package]] name = "itoa" -version = "1.0.5" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] -name = "js-sys" -version = "0.3.60" +name = "kqueue" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" +checksum = "7447f1ca1b7b563588a205fe93dea8df60fd981423a768bc1c0ded35ed147d0c" dependencies = [ - "wasm-bindgen", + "kqueue-sys", + "libc", ] [[package]] -name = "kernel32-sys" -version = "0.2.2" +name = "kqueue-sys" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +checksum = "ed9625ffda8729b85e45cf04090035ac368927b8cebc34898e7c120f52e4838b" dependencies = [ - "winapi 0.2.8", - "winapi-build", + "bitflags 1.3.2", + "libc", ] [[package]] @@ -948,24 +867,44 @@ name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin 0.5.2", +] [[package]] -name = "lazycell" -version = "1.3.0" +name = "libc" +version = "0.2.170" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" +checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828" [[package]] -name = "libc" -version = "0.2.139" +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[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.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" [[package]] name = "lock_api" -version = "0.4.9" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" dependencies = [ "autocfg", "scopeguard", @@ -973,12 +912,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.17" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if 1.0.0", -] +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "loom" @@ -986,7 +922,7 @@ version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "generator", "scoped-tls", "serde", @@ -1001,29 +937,30 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" dependencies = [ - "regex-automata", + "regex-automata 0.1.10", ] [[package]] name = "md-5" -version = "0.10.5" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6365506850d44bff6e2fbcb5176cf63650e48bd45ef2fe2665ae1570e0f4b9ca" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" dependencies = [ + "cfg-if", "digest", ] [[package]] name = "memchr" -version = "2.5.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" [[package]] name = "mime" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "minimal-lexical" @@ -1032,65 +969,42 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] -name = "mio" -version = "0.6.23" +name = "miniz_oxide" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4" +checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" dependencies = [ - "cfg-if 0.1.10", - "fuchsia-zircon", - "fuchsia-zircon-sys", - "iovec", - "kernel32-sys", - "libc", - "log", - "miow", - "net2", - "slab", - "winapi 0.2.8", + "adler", ] [[package]] name = "mio" -version = "0.8.5" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" +checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" dependencies = [ "libc", "log", "wasi", - "windows-sys", -] - -[[package]] -name = "mio-extras" -version = "2.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52403fe290012ce777c4626790c8951324a2b9e3316b3143779c72b029742f19" -dependencies = [ - "lazycell", - "log", - "mio 0.6.23", - "slab", + "windows-sys 0.48.0", ] [[package]] -name = "miow" -version = "0.2.2" +name = "mio" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ - "kernel32-sys", - "net2", - "winapi 0.2.8", - "ws2_32-sys", + "libc", + "wasi", + "windows-sys 0.52.0", ] [[package]] name = "multer" -version = "2.0.4" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed4198ce7a4cbd2a57af78d28c6fbb57d81ac5f1d6ad79ac6c5587419cbdf22" +checksum = "01acbdc23469fd8fe07ab135923371d5f5a422fbf9c522158677c8eb15bc51c2" dependencies = [ "bytes", "encoding_rs", @@ -1100,28 +1014,28 @@ dependencies = [ "log", "memchr", "mime", - "spin 0.9.4", + "spin 0.9.8", "tokio", "tokio-util", "version_check", ] [[package]] -name = "net2" -version = "0.2.38" +name = "nix" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d0df99cfcd2530b2e694f6e17e7f37b8e26bb23983ac530c0c97408837c631" +checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" dependencies = [ - "cfg-if 0.1.10", + "bitflags 2.4.2", + "cfg-if", "libc", - "winapi 0.3.9", ] [[package]] name = "nom" -version = "7.1.2" +version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5507769c4919c998e69e49c839d9dc6e693ede4cc4290d6ad8b41d4f09c548c" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" dependencies = [ "memchr", "minimal-lexical", @@ -1129,29 +1043,30 @@ dependencies = [ [[package]] name = "normpath" -version = "0.3.2" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04aaf5e9cb0fbf883cc0423159eacdf96a9878022084b35c462c428cab73bcaf" +checksum = "5831952a9476f2fed74b77d74182fa5ddc4d21c72ec45a333b250e3ed0272804" dependencies = [ - "winapi 0.3.9", + "windows-sys 0.52.0", ] [[package]] name = "notify" -version = "4.0.17" +version = "6.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae03c8c853dba7bfd23e571ff0cff7bc9dceb40a4cd684cd1681824183f45257" +checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d" dependencies = [ - "bitflags", + "bitflags 2.4.2", + "crossbeam-channel", "filetime", - "fsevent", "fsevent-sys", "inotify", + "kqueue", "libc", - "mio 0.6.23", - "mio-extras", + "log", + "mio 0.8.10", "walkdir", - "winapi 0.3.9", + "windows-sys 0.48.0", ] [[package]] @@ -1161,57 +1076,93 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" dependencies = [ "overload", - "winapi 0.3.9", + "winapi", ] [[package]] -name = "num-traits" -version = "0.2.15" +name = "num-bigint-dig" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" dependencies = [ - "autocfg", + "byteorder", + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand", + "smallvec", + "zeroize", ] [[package]] -name = "num_cpus" -version = "1.15.0" +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 = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ - "hermit-abi 0.2.6", - "libc", + "num-traits", ] [[package]] -name = "once_cell" -version = "1.17.0" +name = "num-iter" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" +checksum = "d869c01cc0c455284163fd0092f1f93835385ccab5a98a0dcc497b2f8bf055a9" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] [[package]] -name = "opaque-debug" -version = "0.3.0" +name = "num-traits" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +dependencies = [ + "autocfg", + "libm", +] [[package]] -name = "overload" -version = "0.1.1" +name = "num_cpus" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] [[package]] -name = "parking_lot" -version = "0.11.2" +name = "object" +version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" dependencies = [ - "instant", - "lock_api", - "parking_lot_core 0.8.6", + "memchr", ] +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + [[package]] name = "parking_lot" version = "0.12.1" @@ -1219,47 +1170,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", - "parking_lot_core 0.9.5", -] - -[[package]] -name = "parking_lot_core" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" -dependencies = [ - "cfg-if 1.0.0", - "instant", - "libc", - "redox_syscall", - "smallvec", - "winapi 0.3.9", + "parking_lot_core", ] [[package]] name = "parking_lot_core" -version = "0.9.5" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ff9f3fef3968a3ec5945535ed654cb38ff72d7495a25619e2247fb15a2ed9ba" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-sys", + "windows-targets 0.48.5", ] [[package]] name = "paste" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d01a5bd0424d00070b0098dd17ebca6f961a959dead1dbcbbbc1d1cd8d3deeba" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" [[package]] name = "pear" -version = "0.2.3" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15e44241c5e4c868e3eaa78b7c1848cadd6344ed4f54d029832d32b415a58702" +checksum = "4ccca0f6c17acc81df8e242ed473ec144cbf5c98037e69aa6d144780aad103c8" dependencies = [ "inlinable_string", "pear_codegen", @@ -1268,37 +1205,47 @@ dependencies = [ [[package]] name = "pear_codegen" -version = "0.2.3" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82a5ca643c2303ecb740d506539deba189e16f2754040a42901cd8105d0282d0" +checksum = "2e22670e8eb757cff11d6c199ca7b987f352f0346e0be4dd23869ec72cb53c77" dependencies = [ "proc-macro2", "proc-macro2-diagnostics", "quote", - "syn", + "syn 2.0.50", +] + +[[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.2.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.5.6" +version = "2.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cbd939b234e95d72bc393d51788aec68aeeb5d51e748ca08ff3aad58cb722f7" +checksum = "219c0dcc30b6a27553f9cc242972b67f75b60eb0db71f0b5462f38b058c41546" dependencies = [ + "memchr", "thiserror", "ucd-trie", ] [[package]] name = "pest_derive" -version = "2.5.6" +version = "2.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a81186863f3d0a27340815be8f2078dd8050b14cd71913db9fbda795e5f707d7" +checksum = "22e1288dbd7786462961e69bfd4df7848c1e37e8b74303dbdab82c3a9cdd2809" dependencies = [ "pest", "pest_generator", @@ -1306,22 +1253,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.5.6" +version = "2.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75a1ef20bf3193c15ac345acb32e26b3dc3223aff4d77ae4fc5359567683796b" +checksum = "1381c29a877c6d34b8c176e734f35d7f7f5b3adaefe940cb4d1bb7af94678e2e" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn", + "syn 2.0.50", ] [[package]] name = "pest_meta" -version = "2.5.6" +version = "2.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e3b284b1f13a20dc5ebc90aff59a51b8d7137c221131b52a7260c08cbc1cc80" +checksum = "d0934d6907f148c22a3acbda520c7eed243ad7487a30f51f6ce52b58b7077a8a" dependencies = [ "once_cell", "pest", @@ -1330,9 +1277,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.9" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] name = "pin-utils" @@ -1341,84 +1288,75 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] -name = "polyval" -version = "0.6.0" +name = "pkcs1" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef234e08c11dfcb2e56f79fd70f6f2eb7f025c0ce2333e82f4f0518ecad30c6" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" dependencies = [ - "cfg-if 1.0.0", - "cpufeatures", - "opaque-debug", - "universal-hash", + "der", + "pkcs8", + "spki", ] [[package]] -name = "ppv-lite86" -version = "0.2.17" +name = "pkcs8" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] [[package]] -name = "pq-sys" -version = "0.4.7" +name = "pkg-config" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b845d6d8ec554f972a2c5298aad68953fd64e7441e846075450b44656a016d1" -dependencies = [ - "vcpkg", -] +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] -name = "prettyplease" -version = "0.1.23" +name = "powerfmt" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e97e3215779627f01ee256d2fad52f3d95e8e1c11e9fc6fd08f7cd455d5d5c78" -dependencies = [ - "proc-macro2", - "syn", -] +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.51" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" dependencies = [ "unicode-ident", ] [[package]] name = "proc-macro2-diagnostics" -version = "0.9.1" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bf29726d67464d49fa6224a1d07936a8c08bb3fba727c7493f6cf1616fdaada" +checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.50", "version_check", "yansi", ] [[package]] name = "quote" -version = "1.0.23" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] -[[package]] -name = "r2d2" -version = "0.8.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51de85fb3fb6524929c8a2eb85e6b6d363de4e8c48f9e2c2eac4944abc181c93" -dependencies = [ - "log", - "parking_lot 0.12.1", - "scheduled-thread-pool", -] - [[package]] name = "rand" version = "0.8.5" @@ -1451,53 +1389,43 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags", -] - -[[package]] -name = "redox_users" -version = "0.4.3" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ - "getrandom", - "redox_syscall", - "thiserror", + "bitflags 1.3.2", ] [[package]] name = "ref-cast" -version = "1.0.14" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c78fb8c9293bcd48ef6fce7b4ca950ceaf21210de6e105a883ee280c0f7b9ed" +checksum = "c4846d4c50d1721b1a3bef8af76924eef20d5e723647333798c1b519b3a9473f" dependencies = [ "ref-cast-impl", ] [[package]] name = "ref-cast-impl" -version = "1.0.14" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f9c0c92af03644e4806106281fe2e068ac5bc0ae74a707266d06ea27bccee5f" +checksum = "5fddb4f8d99b0a2ebafc65a87a69a7b9875e4b1ae1f00db265d300ef7f28bccc" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.50", ] [[package]] name = "regex" -version = "1.7.0" +version = "1.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a" +checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" dependencies = [ "aho-corasick", "memchr", - "regex-syntax", + "regex-automata 0.4.5", + "regex-syntax 0.8.2", ] [[package]] @@ -1506,49 +1434,55 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" dependencies = [ - "regex-syntax", + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-automata" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.2", ] [[package]] name = "regex-syntax" -version = "0.6.28" +version = "0.6.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] -name = "remove_dir_all" -version = "0.5.3" +name = "regex-syntax" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" -dependencies = [ - "winapi 0.3.9", -] +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "ring" -version = "0.16.20" +version = "0.17.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +checksum = "70ac5d832aa16abd7d1def883a8545280c20a60f523a370aa3a9617c2b8550ee" dependencies = [ "cc", + "cfg-if", + "getrandom", "libc", - "once_cell", - "spin 0.5.2", "untrusted", - "web-sys", - "winapi 0.3.9", + "windows-sys 0.52.0", ] [[package]] name = "rocket" -version = "0.5.0-rc.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98ead083fce4a405feb349cf09abdf64471c6077f14e0ce59364aa90d4b99317" +checksum = "9e7bb57ccb26670d73b6a47396c83139447b9e7878cab627fdfe9ea8da489150" dependencies = [ "async-stream", "async-trait", - "atomic", - "atty", + "atomic 0.5.3", "binascii", "bytes", "either", @@ -1559,7 +1493,7 @@ dependencies = [ "memchr", "multer", "num_cpus", - "parking_lot 0.12.1", + "parking_lot", "pin-project-lite", "rand", "ref-cast", @@ -1580,9 +1514,9 @@ dependencies = [ [[package]] name = "rocket_codegen" -version = "0.5.0-rc.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6aeb6bb9c61e9cd2c00d70ea267bf36f76a4cc615e5908b349c2f9d93999b47" +checksum = "a2238066abf75f21be6cd7dc1a09d5414a671f4246e384e49fe3f8a4936bd04c" dependencies = [ "devise", "glob", @@ -1590,15 +1524,16 @@ dependencies = [ "proc-macro2", "quote", "rocket_http", - "syn", + "syn 2.0.50", "unicode-xid", + "version_check", ] [[package]] name = "rocket_db_pools" -version = "0.1.0-rc.2" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bc154f4f4985a136e2d59c336474a56da02103993f5e637e3a5424971ee4eff" +checksum = "f0ebde3e24cbe917062b862136fd532d1ace80e0377a2f5fed541fadd764f1e5" dependencies = [ "rocket", "rocket_db_pools_codegen", @@ -1608,9 +1543,9 @@ dependencies = [ [[package]] name = "rocket_db_pools_codegen" -version = "0.1.0-rc.2" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0aa8f9b37bb1d4827aa5cca400d74e91d30f4352713cb65d6e7427bafe21336c" +checksum = "184a6f59eed0bf3d1cccb091960a2a1c89efa829b8a41158b269985a9c1bee95" dependencies = [ "devise", "quote", @@ -1618,22 +1553,22 @@ dependencies = [ [[package]] name = "rocket_dyn_templates" -version = "0.1.0-rc.2" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab13df598440527c200f46fb944dc55d8d67a1818b617eb5a3981dcd8b63fd2" +checksum = "04bfc006e547e4f72b760ab861f5943b688aed8a82c4977b5500c98f5d17dbfa" dependencies = [ - "glob", "handlebars", "normpath", "notify", "rocket", + "walkdir", ] [[package]] name = "rocket_http" -version = "0.5.0-rc.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ded65d127954de3c12471630bf4b81a2792f065984461e65b91d0fdaafc17a2" +checksum = "37a1663694d059fe5f943ea5481363e48050acedd241d46deb2e27f71110389e" dependencies = [ "cookie", "either", @@ -1657,86 +1592,96 @@ dependencies = [ ] [[package]] -name = "rocket_sync_db_pools" -version = "0.1.0-rc.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fa48b6ab25013e9812f1b0c592741900b3a2a83c0936292e0565c0ac842f558" +name = "rocket_techempower" +version = "0.5.0" dependencies = [ - "diesel", - "r2d2", + "rand", "rocket", - "rocket_sync_db_pools_codegen", - "serde", - "tokio", + "rocket_db_pools", + "rocket_dyn_templates", + "sqlx", ] [[package]] -name = "rocket_sync_db_pools_codegen" -version = "0.1.0-rc.2" +name = "rsa" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "280ef2d232923e69cb93da156972eb5476a7cce5ba44843f6608f46a4abf7aab" +checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc" dependencies = [ - "devise", - "quote", + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core", + "signature", + "spki", + "subtle", + "zeroize", ] [[package]] -name = "rocket_techempower" -version = "0.4.0" -dependencies = [ - "async-stream", - "async-trait", - "diesel", - "dotenv", - "figment", - "futures", - "futures-util", - "proc-macro2", - "rand", - "rocket", - "rocket_db_pools", - "rocket_dyn_templates", - "rocket_sync_db_pools", - "serde", - "serde_derive", - "serde_json", - "sqlx", - "yarte", -] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] -name = "rustc_version" -version = "0.4.0" +name = "rustix" +version = "0.38.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" dependencies = [ - "semver", + "bitflags 2.4.2", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", ] [[package]] name = "rustls" -version = "0.19.1" +version = "0.21.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" +checksum = "7fecbfb7b1444f477b345853b1fce097a2c6fb637b2bfb87e6bc5db0f043fae4" dependencies = [ - "base64 0.13.1", - "log", "ring", + "rustls-webpki", "sct", - "webpki", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64", +] + +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring", + "untrusted", ] [[package]] name = "rustversion" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" [[package]] name = "ryu" -version = "1.0.12" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" [[package]] name = "same-file" @@ -1747,15 +1692,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "scheduled-thread-pool" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cbc66816425a074528352f5789333ecff06ca41b36b0b0efdfbb29edc391a19" -dependencies = [ - "parking_lot 0.12.1", -] - [[package]] name = "scoped-tls" version = "1.0.1" @@ -1764,51 +1700,45 @@ checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" [[package]] name = "scopeguard" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "sct" -version = "0.6.1" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ "ring", "untrusted", ] -[[package]] -name = "semver" -version = "1.0.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a" - [[package]] name = "serde" -version = "1.0.152" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.152" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.50", ] [[package]] name = "serde_json" -version = "1.0.91" +version = "1.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" +checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" dependencies = [ "itoa", "ryu", @@ -1816,68 +1746,93 @@ dependencies = [ ] [[package]] -name = "sha-1" -version = "0.10.1" +name = "serde_spanned" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" +dependencies = [ + "serde", +] + +[[package]] +name = "sha1" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "cpufeatures", "digest", ] [[package]] name = "sha2" -version = "0.10.6" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "cpufeatures", "digest", ] [[package]] name = "sharded-slab" -version = "0.1.4" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +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.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" 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 = "slab" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] [[package]] name = "smallvec" -version = "1.10.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" [[package]] name = "socket2" -version = "0.4.7" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" +checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" dependencies = [ "libc", - "winapi 0.3.9", + "windows-sys 0.48.0", ] [[package]] @@ -1888,15 +1843,28 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" [[package]] name = "spin" -version = "0.9.4" +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 = "7f6002a767bff9e83f8eeecf883ecb8011875a21ae8da43bffb817a57e78cc09" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] [[package]] name = "sqlformat" -version = "0.1.8" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4b7922be017ee70900be125523f38bdd644f4f06a1b16e8fa5a8ee8c34bffd4" +checksum = "ce81b7bd7c4493975347ef60d8c7e8b742d4694f4c49f93e0a12ea263938176c" dependencies = [ "itertools", "nom", @@ -1905,99 +1873,207 @@ dependencies = [ [[package]] name = "sqlx" -version = "0.5.13" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "551873805652ba0d912fec5bbb0f8b4cdd96baf8e2ebf5970e5671092966019b" +checksum = "dba03c279da73694ef99763320dea58b51095dfe87d001b1d4b5fe78ba8763cf" dependencies = [ "sqlx-core", "sqlx-macros", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", ] [[package]] name = "sqlx-core" -version = "0.5.13" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e48c61941ccf5ddcada342cd59e3e5173b007c509e1e8e990dafc830294d9dc5" +checksum = "d84b0a3c3739e220d94b3239fd69fb1f74bc36e16643423bd99de3b43c21bfbd" dependencies = [ "ahash", "atoi", - "base64 0.13.1", - "bitflags", "byteorder", "bytes", "crc", "crossbeam-queue", - "dirs", + "dotenvy", "either", "event-listener", "futures-channel", "futures-core", "futures-intrusive", + "futures-io", "futures-util", "hashlink", "hex", - "hkdf", - "hmac", "indexmap", - "itoa", - "libc", "log", - "md-5", "memchr", "once_cell", "paste", "percent-encoding", - "rand", "rustls", + "rustls-pemfile", "serde", "serde_json", - "sha-1", "sha2", "smallvec", "sqlformat", - "sqlx-rt", - "stringprep", "thiserror", + "tokio", "tokio-stream", + "tracing", "url", - "webpki", "webpki-roots", - "whoami", ] [[package]] name = "sqlx-macros" -version = "0.5.13" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc0fba2b0cae21fc00fe6046f8baa4c7fcb49e379f0f592b04696607f69ed2e1" +checksum = "89961c00dc4d7dffb7aee214964b065072bff69e36ddb9e2c107541f75e4f2a5" dependencies = [ - "dotenv", - "either", - "heck", - "once_cell", "proc-macro2", "quote", - "sha2", "sqlx-core", - "sqlx-rt", - "syn", - "url", + "sqlx-macros-core", + "syn 1.0.109", ] [[package]] -name = "sqlx-rt" -version = "0.5.13" +name = "sqlx-macros-core" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4db708cd3e459078f85f39f96a00960bd841f66ee2a669e90bf36907f5a79aae" +checksum = "d0bd4519486723648186a08785143599760f7cc81c52334a55d6a83ea1e20841" dependencies = [ + "atomic-write-file", + "dotenvy", + "either", + "heck", + "hex", "once_cell", + "proc-macro2", + "quote", + "serde", + "serde_json", + "sha2", + "sqlx-core", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", + "syn 1.0.109", + "tempfile", "tokio", - "tokio-rustls", + "url", ] [[package]] -name = "stable-pattern" -version = "0.1.0" +name = "sqlx-mysql" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e37195395df71fd068f6e2082247891bc11e3289624bbc776a0cdfa1ca7f1ea4" +dependencies = [ + "atoi", + "base64", + "bitflags 2.4.2", + "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.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6ac0ac3b7ccd10cc96c7ab29791a7dd236bd94021f31eec7ba3d46a74aa1c24" +dependencies = [ + "atoi", + "base64", + "bitflags 2.4.2", + "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", + "sha1", + "sha2", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror", + "tracing", + "whoami", +] + +[[package]] +name = "sqlx-sqlite" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "210976b7d948c7ba9fced8ca835b11cbb2d677c59c79de41ac0d397e14547490" +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 = "stable-pattern" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4564168c00635f88eaed410d5efa8131afa8d8699a612c80c455a0ba05c21045" dependencies = [ @@ -2006,34 +2082,46 @@ dependencies = [ [[package]] name = "state" -version = "0.5.3" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbe866e1e51e8260c9eed836a042a5e7f6726bb2b411dffeaa712e19c388f23b" +checksum = "2b8c4a4445d81357df8b1a650d0d0d6fbbbfe99d064aa5e02f3e4022061476d8" dependencies = [ "loom", ] [[package]] name = "stringprep" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ee348cb74b87454fff4b551cbf727025810a004f88aeacae7f85b87f4e9a1c1" +checksum = "bb41d74e231a107a1b4ee36bd1214b11285b77768d2e3824aedafa988fd36ee6" dependencies = [ + "finl_unicode", "unicode-bidi", "unicode-normalization", ] [[package]] name = "subtle" -version = "2.4.1" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + +[[package]] +name = "syn" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] [[package]] name = "syn" -version = "1.0.107" +version = "2.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" +checksum = "74f1bdc9872430ce9b75da68329d1c1746faf50ffac5f19e02b71e37ff881ffb" dependencies = [ "proc-macro2", "quote", @@ -2042,54 +2130,56 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.3.0" +version = "3.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +checksum = "a365e8cd18e44762ef95d87f284f4b5cd04107fec2ff3052bd6a3e6069669e67" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "fastrand", - "libc", - "redox_syscall", - "remove_dir_all", - "winapi 0.3.9", + "rustix", + "windows-sys 0.52.0", ] [[package]] name = "thiserror" -version = "1.0.38" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" +checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.38" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" +checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.50", ] [[package]] name = "thread_local" -version = "1.1.4" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" dependencies = [ + "cfg-if", "once_cell", ] [[package]] name = "time" -version = "0.3.17" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376" +checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749" dependencies = [ + "deranged", "itoa", + "num-conv", + "powerfmt", "serde", "time-core", "time-macros", @@ -2097,16 +2187,17 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.0" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.6" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d967f99f534ca7e495c575c62638eebc2898a8c84c119b89e250477bc4ba16b2" +checksum = "7ba3a3ef41e6672a2f0f001392bb5dcd3ff0a9992d618ca761a11c3121547774" dependencies = [ + "num-conv", "time-core", ] @@ -2121,56 +2212,43 @@ dependencies = [ [[package]] name = "tinyvec_macros" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.24.1" +version = "1.44.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d9f76183f91ecfb55e1d7d5602bd1d979e38a3a522fe900241cf195624d67ae" +checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48" dependencies = [ - "autocfg", + "backtrace", "bytes", "libc", - "memchr", - "mio 0.8.5", - "num_cpus", + "mio 1.0.3", "pin-project-lite", "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] name = "tokio-macros" -version = "1.8.2" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", - "syn", -] - -[[package]] -name = "tokio-rustls" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6" -dependencies = [ - "rustls", - "tokio", - "webpki", + "syn 2.0.50", ] [[package]] name = "tokio-stream" -version = "0.1.11" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d660770404473ccd7bc9f8b28494a811bc18542b915c0855c51e8f419d5223ce" +checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" dependencies = [ "futures-core", "pin-project-lite", @@ -2179,9 +2257,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.4" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" dependencies = [ "bytes", "futures-core", @@ -2193,11 +2271,36 @@ dependencies = [ [[package]] name = "toml" -version = "0.5.10" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1333c76748e868a4d9d1017b5ab53171dfd095f70c712fdb4653a406547f598f" +checksum = "9a9aad4a3066010876e8dcf5a8a06e70a558751117a145c6ce2b82c2e2054290" dependencies = [ "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c1b5fd4128cc8d3e0cb74d4ed9a9cc7c7284becd4df68f5f940e1ad123606f6" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", ] [[package]] @@ -2208,11 +2311,11 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "cfg-if 1.0.0", + "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -2220,20 +2323,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.23" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.50", ] [[package]] name = "tracing-core" -version = "0.1.30" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", "valuable", @@ -2241,20 +2344,20 @@ dependencies = [ [[package]] name = "tracing-log" -version = "0.1.3" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" dependencies = [ - "lazy_static", "log", + "once_cell", "tracing-core", ] [[package]] name = "tracing-subscriber" -version = "0.3.16" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ "matchers", "nu-ansi-term", @@ -2270,36 +2373,36 @@ dependencies = [ [[package]] name = "try-lock" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "typenum" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "ubyte" -version = "0.10.3" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c81f0dae7d286ad0d9366d7679a77934cfc3cf3a8d67e82669794412b2368fe6" +checksum = "f720def6ce1ee2fc44d40ac9ed6d3a59c361c80a75a7aa8e75bb9baed31cf2ea" dependencies = [ "serde", ] [[package]] name = "ucd-trie" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" [[package]] name = "uncased" -version = "0.9.7" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09b01702b0fd0b3fadcf98e098780badda8742d4f4a7676615cad90e8ac73622" +checksum = "e1b88fcfe09e89d3866a5c11019378088af2d24c3fbd4f0543f96b479ec90697" dependencies = [ "serde", "version_check", @@ -2307,36 +2410,30 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.8" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-ident" -version = "1.0.6" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" dependencies = [ "tinyvec", ] [[package]] name = "unicode-segmentation" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fdbf052a0783de01e944a6ce7a8cb939e295b1e7be835a1112c3b9a7f047a5a" - -[[package]] -name = "unicode-width" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" [[package]] name = "unicode-xid" @@ -2350,27 +2447,17 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" -[[package]] -name = "universal-hash" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d3160b73c9a19f7e2939a2fdad446c57c1bbbbf4d919d3213ff1267a580d8b5" -dependencies = [ - "crypto-common", - "subtle", -] - [[package]] name = "untrusted" -version = "0.7.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.3.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" dependencies = [ "form_urlencoded", "idna", @@ -2378,20 +2465,10 @@ dependencies = [ ] [[package]] -name = "v_eval" -version = "0.6.0" +name = "urlencoding" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd8b599d797eb038d0dde9a3860aacb6bbba3bffa4ac64f807c8673820cc9d9" -dependencies = [ - "regex", - "syn", -] - -[[package]] -name = "v_htmlescape" -version = "0.15.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e8257fbc510f0a46eb602c10215901938b5c2a7d5e70fc11483b1d3c9b5b18c" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" [[package]] name = "valuable" @@ -2413,9 +2490,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "walkdir" -version = "2.3.3" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" +checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" dependencies = [ "same-file", "winapi-util", @@ -2423,11 +2500,10 @@ dependencies = [ [[package]] name = "want" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" dependencies = [ - "log", "try-lock", ] @@ -2438,347 +2514,229 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] -name = "wasm-bindgen" -version = "0.2.83" +name = "webpki-roots" +version = "0.25.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" -dependencies = [ - "cfg-if 1.0.0", - "wasm-bindgen-macro", -] +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] -name = "wasm-bindgen-backend" -version = "0.2.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.83" +name = "whoami" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] +checksum = "22fc3756b8a9133049b26c7f61ab35416c130e8c09b660f5b3958b446f52cc50" [[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.83" +name = "winapi" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-backend", - "wasm-bindgen-shared", + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", ] [[package]] -name = "wasm-bindgen-shared" -version = "0.2.83" +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] -name = "web-sys" -version = "0.3.60" +name = "winapi-util" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" dependencies = [ - "js-sys", - "wasm-bindgen", + "winapi", ] [[package]] -name = "webpki" -version = "0.21.4" +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea" -dependencies = [ - "ring", - "untrusted", -] +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] -name = "webpki-roots" -version = "0.21.1" +name = "windows" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aabe153544e473b775453675851ecc86863d2a81d786d741f6b76778f2a48940" +checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" dependencies = [ - "webpki", + "windows-targets 0.48.5", ] [[package]] -name = "whoami" -version = "1.3.0" +name = "windows-sys" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45dbc71f0cdca27dc261a9bd37ddec174e4a0af2b900b890f378460f745426e3" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "wasm-bindgen", - "web-sys", + "windows-targets 0.48.5", ] [[package]] -name = "winapi" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" - -[[package]] -name = "winapi" -version = "0.3.9" +name = "windows-sys" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", + "windows-targets 0.52.0", ] [[package]] -name = "winapi-build" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" - -[[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-util" -version = "0.1.5" +name = "windows-targets" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "winapi 0.3.9", + "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 = "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" -version = "0.39.0" +name = "windows-targets" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1c4bd0a50ac6020f65184721f758dba47bb9fbc2133df715ec74a237b26794a" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" dependencies = [ - "windows_aarch64_msvc 0.39.0", - "windows_i686_gnu 0.39.0", - "windows_i686_msvc 0.39.0", - "windows_x86_64_gnu 0.39.0", - "windows_x86_64_msvc 0.39.0", + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", ] [[package]] -name = "windows-sys" -version = "0.42.0" +name = "windows_aarch64_gnullvm" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc 0.42.0", - "windows_i686_gnu 0.42.0", - "windows_i686_msvc 0.42.0", - "windows_x86_64_gnu 0.42.0", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc 0.42.0", -] +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.0" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" [[package]] name = "windows_aarch64_msvc" -version = "0.39.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec7711666096bd4096ffa835238905bb33fb87267910e154b18b44eaabb340f2" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.42.0" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" [[package]] name = "windows_i686_gnu" -version = "0.39.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "763fc57100a5f7042e3057e7e8d9bdd7860d330070251a73d003563a3bb49e1b" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.42.0" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" [[package]] name = "windows_i686_msvc" -version = "0.39.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bc7cbfe58828921e10a9f446fcaaf649204dcfe6c1ddd712c5eebae6bda1106" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.42.0" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" [[package]] name = "windows_x86_64_gnu" -version = "0.39.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6868c165637d653ae1e8dc4d82c25d4f97dd6605eaa8d784b5c6e0ab2a252b65" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.42.0" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] -name = "windows_x86_64_msvc" -version = "0.39.0" +name = "windows_x86_64_gnullvm" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e4d40883ae9cae962787ca76ba76390ffa29214667a111db9e0a1ad8377e809" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" [[package]] name = "windows_x86_64_msvc" -version = "0.42.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] -name = "ws2_32-sys" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" -dependencies = [ - "winapi 0.2.8", - "winapi-build", -] - -[[package]] -name = "yansi" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" - -[[package]] -name = "yansi-term" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe5c30ade05e61656247b2e334a031dfd0cc466fadef865bdcdea8d537951bf1" -dependencies = [ - "winapi 0.3.9", -] - -[[package]] -name = "yarte" -version = "0.15.7" +name = "windows_x86_64_msvc" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfce1df93f3b16e5272221a559e60bbbaaa71dbc042a43996d223e51a690aab2" -dependencies = [ - "yarte_derive", - "yarte_helpers", -] +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] -name = "yarte_codegen" -version = "0.15.6" +name = "winnow" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1cf72076dbf4d39fe4779b58380d7213dcb3995d00666dd2d109f1b45879ea4" +checksum = "7a4191c47f15cc3ec71fcb4913cb83d58def65dd3787610213c649283b5ce178" dependencies = [ - "proc-macro2", - "quote", - "syn", - "yarte_helpers", - "yarte_hir", + "memchr", ] [[package]] -name = "yarte_derive" -version = "0.15.6" +name = "yansi" +version = "1.0.0-rc.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b296edd7e1a81717b6f794baa2de8dfe89646050847161550b2d963b3ca6fe80" +checksum = "1367295b8f788d371ce2dbc842c7b709c73ee1364d30351dd300ec2203b12377" dependencies = [ - "proc-macro2", - "quote", - "syn", - "yarte_codegen", - "yarte_helpers", - "yarte_hir", - "yarte_parser", + "is-terminal", ] [[package]] -name = "yarte_helpers" -version = "0.15.7" +name = "zerocopy" +version = "0.7.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8dfe1ef3558dde14b4be5387bdd41e3bd45746570743521470ec3e9cd0826679" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" dependencies = [ - "dtoa", - "itoa", - "prettyplease", - "serde", - "syn", - "toml", - "v_htmlescape", + "zerocopy-derive", ] [[package]] -name = "yarte_hir" -version = "0.15.6" +name = "zerocopy-derive" +version = "0.7.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee42d2f704a3b1d8bc111d47a705d1302a0943d85e4c230f4e8300ee0dde4a6" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ - "derive_more", "proc-macro2", "quote", - "syn", - "v_eval", - "v_htmlescape", - "yarte_helpers", - "yarte_parser", + "syn 2.0.50", ] [[package]] -name = "yarte_parser" -version = "0.15.2" +name = "zeroize" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "538f72049cf7104e12d5c444048d112cb8fc788a31308afd912442a381ba860c" -dependencies = [ - "annotate-snippets", - "derive_more", - "proc-macro2", - "quote", - "serde", - "syn", - "unicode-xid", - "yarte_helpers", -] +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" diff --git a/frameworks/Rust/rocket/Cargo.toml b/frameworks/Rust/rocket/Cargo.toml index 1863cbf4f12..9fc55725ba2 100644 --- a/frameworks/Rust/rocket/Cargo.toml +++ b/frameworks/Rust/rocket/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rocket_techempower" -version = "0.4.0" +version = "0.5.0" authors = [ "Marcelo Barbosa ", "Brendan Hansknecht ", @@ -17,27 +17,15 @@ opt-level = 3 name = "rocket" path = "src/main.rs" -[[bin]] -name = "rocket-diesel" -path = "rocket-diesel/main.rs" +# The Diesel version is broken +#[[bin]] +#name = "rocket-diesel" +#path = "rocket-diesel/main.rs" [dependencies] -diesel = { version = "1.4", features = ["postgres"] } -rocket_sync_db_pools = { version = "0.1.0-rc.2", default-features = false, features = ["diesel_postgres_pool"] } -rocket_dyn_templates = { version = "0.1.0-rc.2", features = ["handlebars"] } -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" -serde_derive = "1.0" -dotenv = "0.15.0" -figment = "0.10.6" +#rocket_sync_db_pools = { version = "0.1.0", default-features = false, features = ["diesel_postgres_pool"] } rand = { version = "0.8", features = ["small_rng"] } -rocket = { version = "0.5.0-rc.2", features = [ "json" ] } -rocket_db_pools = { version = "0.1.0-rc.2", features = [ "sqlx_postgres" ] } -sqlx = { version = "0.5.13", features = [ "postgres", "macros" ] } -yarte = "0.15.6" -# temp issue https://github.com/SergioBenitez/Rocket/issues/2491 -proc-macro2 = "= 1.0.51" -async-stream = "0.3.3" -async-trait = "0.1.53" -futures = "0.3.21" -futures-util = "0.3.21" +rocket = { version = "0.5.0", features = [ "json" ] } +rocket_db_pools = { version = "0.1.0", features = [ "sqlx_postgres" ] } +rocket_dyn_templates = { version = "0.1.0", features = ["handlebars"] } +sqlx = { version = "0.7", features = ["macros"] } diff --git a/frameworks/Rust/rocket/Rocket.toml b/frameworks/Rust/rocket/Rocket.toml new file mode 100644 index 00000000000..cc0ff76b043 --- /dev/null +++ b/frameworks/Rust/rocket/Rocket.toml @@ -0,0 +1,8 @@ +[default] +address = "0.0.0.0" +port = 8000 +log_level = "off" + +[default.databases.hello_world] +url = "postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world" +connect_timeout = 5 diff --git a/frameworks/Rust/rocket/benchmark_config.json b/frameworks/Rust/rocket/benchmark_config.json index e4643fe6c08..fb37d7377e9 100755 --- a/frameworks/Rust/rocket/benchmark_config.json +++ b/frameworks/Rust/rocket/benchmark_config.json @@ -1,53 +1,55 @@ { "framework": "rocket", "tests": [{ - "default": { - "json_url": "/json", - "plaintext_url": "/plaintext", - "db_url": "/db", - "fortune_url": "/fortunes", - "query_url": "/queries?q=", - "update_url": "/updates?q=", - "port": 8000, - "approach": "Realistic", - "classification": "Fullstack", - "database": "Postgres", - "framework": "Rocket", - "language": "Rust", - "flavor": "None", - "orm": "Full", - "platform": "Rust", - "webserver": "Hyper", - "os": "Linux", - "database_os": "Linux", - "display_name": "Rocket", - "notes": "", - "versus": "None", - "tags": ["broken"] - }, - "diesel": { - "json_url": "/json", - "plaintext_url": "/plaintext", - "db_url": "/db", - "fortune_url": "/fortunes", - "query_url": "/queries?q=", - "update_url": "/updates?q=", - "port": 8000, - "approach": "Realistic", - "classification": "Fullstack", - "database": "Postgres", - "framework": "Rocket", - "language": "Rust", - "flavor": "None", - "orm": "Full", - "platform": "Rust", - "webserver": "Hyper", - "os": "Linux", - "database_os": "Linux", - "display_name": "Rocket (Diesel)", - "notes": "", - "versus": "None", - "tags": ["broken"] - } - }] + "default": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "db_url": "/db", + "fortune_url": "/fortunes", + "query_url": "/queries?q=", + "update_url": "/updates?q=", + "port": 8000, + "approach": "Realistic", + "classification": "Fullstack", + "database": "Postgres", + "framework": "Rocket", + "language": "Rust", + "flavor": "None", + "orm": "Full", + "platform": "Rust", + "webserver": "Hyper", + "os": "Linux", + "database_os": "Linux", + "display_name": "Rocket", + "notes": "", + "tags": ["broken"], + "versus": "None" + }, + "diesel": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "db_url": "/db", + "fortune_url": "/fortunes", + "query_url": "/queries?q=", + "update_url": "/updates?q=", + "port": 8000, + "approach": "Realistic", + "classification": "Fullstack", + "database": "Postgres", + "framework": "Rocket", + "language": "Rust", + "flavor": "None", + "orm": "Full", + "platform": "Rust", + "webserver": "Hyper", + "os": "Linux", + "database_os": "Linux", + "display_name": "Rocket (Diesel)", + "notes": "", + "versus": "None", + "tags": [ + "broken" + ] + } + }] } diff --git a/frameworks/Rust/rocket/rocket-diesel.dockerfile b/frameworks/Rust/rocket/rocket-diesel.dockerfile index a64eeb4fd37..e7cb90c8a3a 100644 --- a/frameworks/Rust/rocket/rocket-diesel.dockerfile +++ b/frameworks/Rust/rocket/rocket-diesel.dockerfile @@ -1,4 +1,4 @@ -FROM rust:1.63 +FROM rust:1.76-slim ENV ROCKET_BENCHMARK_DATABASE_URL=postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world diff --git a/frameworks/Rust/rocket/rocket.dockerfile b/frameworks/Rust/rocket/rocket.dockerfile index 1d5cba3cd5a..c351f586c26 100644 --- a/frameworks/Rust/rocket/rocket.dockerfile +++ b/frameworks/Rust/rocket/rocket.dockerfile @@ -1,10 +1,4 @@ -FROM rust:1.60-slim - -ENV ROCKET_BENCHMARK_DATABASE_URL=postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world - -RUN apt-get update && apt-get install -y --no-install-recommends \ - libpq-dev \ -&& rm -rf /var/lib/apt/lists/* +FROM rust:1.76 ADD ./ /rocket WORKDIR /rocket diff --git a/frameworks/Rust/rocket/rust-toolchain.toml b/frameworks/Rust/rocket/rust-toolchain.toml deleted file mode 100644 index 292fe499e3b..00000000000 --- a/frameworks/Rust/rocket/rust-toolchain.toml +++ /dev/null @@ -1,2 +0,0 @@ -[toolchain] -channel = "stable" diff --git a/frameworks/Rust/rocket/src/main.rs b/frameworks/Rust/rocket/src/main.rs index 6bcbb9e8bfe..017bf8bc026 100644 --- a/frameworks/Rust/rocket/src/main.rs +++ b/frameworks/Rust/rocket/src/main.rs @@ -1,24 +1,14 @@ -#[macro_use] -extern crate rocket; -extern crate dotenv; -extern crate serde_derive; - mod database; mod models; -use std::env; -use std::net::{IpAddr, Ipv4Addr}; +use std::fmt::Write; -use dotenv::dotenv; -use figment::Figment; use rand::{self, Rng}; -use rocket::{Build, Rocket}; -use rocket::config::{Config, LogLevel}; -use rocket::response::content::RawHtml; +use rocket::{launch, get, routes}; use rocket::serde::json::Json; -use rocket_db_pools::{sqlx, Connection, Database}; -use sqlx::Acquire; -use yarte::Template; +use rocket_db_pools::{Connection, Database}; +use rocket_db_pools::sqlx; +use rocket_dyn_templates::{Template, context}; use database::HelloWorld; use models::{Fortune, Message, World}; @@ -28,12 +18,11 @@ fn plaintext() -> &'static str { "Hello, World!" } +const MESSAGE: Message = Message { message: "Hello, World!" }; + #[get("/json")] fn json() -> Json { - let message = Message { - message: "Hello, World!".into(), - }; - Json(message) + Json(MESSAGE) } fn random_id() -> i32 { @@ -42,16 +31,18 @@ fn random_id() -> i32 { rng.gen_range(1..=10_000) } +async fn query_random_world(db: &mut Connection) -> World { + let world_id = random_id(); + sqlx::query_as("SELECT id, randomnumber FROM World WHERE id = $1") + .bind(world_id) + .fetch_one(db.as_mut()) + .await + .expect("Error querying world") +} + #[get("/db")] async fn db(mut db: Connection) -> Json { - let number = random_id(); - let result: World = sqlx::query_as("SELECT id, randomnumber FROM World WHERE id = $1") - .bind(number) - .fetch_one(&mut *db) - .await - .ok() - .expect("error loading world"); - Json(result) + Json(query_random_world(&mut db).await) } #[get("/queries")] @@ -65,31 +56,19 @@ async fn queries(mut db: Connection, q: u16) -> Json> { let mut results = Vec::with_capacity(q.into()); for _ in 0..q { - let query_id = random_id(); - let result: World = sqlx::query_as("SELECT * FROM World WHERE id = $1") - .bind(query_id) - .fetch_one(&mut *db) - .await - .ok() - .expect("error loading world"); - results.push(result); + let world = query_random_world(&mut db).await; + + results.push(world); } Json(results) } -#[derive(Template)] -#[template(path = "fortunes.html.hbs")] -pub struct FortunesTemplate<'a> { - pub fortunes: &'a Vec, -} - #[get("/fortunes")] -async fn fortunes(mut db: Connection) -> RawHtml { +async fn fortunes(mut db: Connection) -> Template { let mut fortunes: Vec = sqlx::query_as("SELECT * FROM Fortune") - .fetch_all(&mut *db) + .fetch_all(db.as_mut()) .await - .ok() .expect("Could not load Fortunes"); fortunes.push(Fortune { @@ -99,13 +78,9 @@ async fn fortunes(mut db: Connection) -> RawHtml { fortunes.sort_by(|a, b| a.message.cmp(&b.message)); - RawHtml( - FortunesTemplate { - fortunes: &fortunes, - } - .call() - .expect("error rendering template"), - ) + Template::render("fortunes", context! { + fortunes: fortunes + }) } #[get("/updates")] @@ -119,70 +94,57 @@ async fn updates(mut db: Connection, q: u16) -> Json> { let mut results = Vec::with_capacity(q.into()); for _ in 0..q { - let query_id = random_id(); - let mut result: World = sqlx::query_as("SELECT * FROM World WHERE id = $1") - .bind(query_id) - .fetch_one(&mut *db) - .await - .ok() - .expect("World was not found"); - - result.random_number = random_id(); - results.push(result); + let mut world = query_random_world(&mut db).await; + + world.random_number = random_id(); + results.push(world); } - let mut pool = db.into_inner(); - let mut tx = pool - .begin() - .await - .ok() - .expect("could not start transaction"); + let query_string = { + let mut query = String::new(); + + query.push_str("UPDATE World SET randomnumber = CASE id "); + + let mut pl = 1; + + for _ in 1..=q { + let _ = write!(query, "when ${pl} then ${} ", pl + 1); + pl += 2; + } + + query.push_str("ELSE randomnumber END WHERE id IN ("); + + for _ in 1..=q { + let _ = write!(query, "${pl},"); + pl += 1; + } + + query.pop(); + query.push(')'); + + query + }; + + let mut query = sqlx::query(&query_string); for w in &results { - sqlx::query("UPDATE World SET randomnumber = $1 WHERE id = $2") - .bind(w.random_number) - .bind(w.id) - .execute(&mut tx) - .await - .ok() - .expect("Could not update World"); + query = query.bind(w.id).bind(w.random_number); } - tx.commit().await.ok().expect("could not update worlds"); + for w in &results { + query = query.bind(w.id); + } + + query.execute(db.as_mut()) + .await + .expect("Could not update worlds"); Json(results) } #[launch] -pub fn launch() -> Rocket { - if cfg!(not(test)) { - dotenv().ok(); - } - - let config = Config { - address: IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), - port: 8000, - keep_alive: 0, - log_level: LogLevel::Off, - ..Default::default() - }; - - let database_url = env::var("ROCKET_BENCHMARK_DATABASE_URL") - .ok() - .expect("ROCKET_BENCHMARK_DATABASE_URL environment variable was not set"); - - let figment = Figment::from(config).merge(( - "databases.hello_world", - rocket_db_pools::Config { - url: database_url, - min_connections: None, - max_connections: 100, - connect_timeout: 3, - idle_timeout: None, - }, - )); - - rocket::custom(figment) +pub fn launch() -> _ { + rocket::build() .mount( "/", routes![ @@ -197,4 +159,5 @@ pub fn launch() -> Rocket { ], ) .attach(HelloWorld::init()) + .attach(Template::fairing()) } diff --git a/frameworks/Rust/rocket/src/models.rs b/frameworks/Rust/rocket/src/models.rs index 2e9f5b3f3bf..9f4184985ba 100644 --- a/frameworks/Rust/rocket/src/models.rs +++ b/frameworks/Rust/rocket/src/models.rs @@ -1,13 +1,12 @@ use rocket::serde::{Deserialize, Serialize}; -use sqlx::FromRow; -use std::borrow::Cow; +use rocket_db_pools::sqlx::FromRow; #[derive(Serialize)] +#[serde(crate = "rocket::serde")] pub struct Message { - pub message: Cow<'static, str>, + pub message: &'static str, } -#[allow(non_snake_case)] #[derive(Clone, Debug, PartialEq, Deserialize, Serialize, FromRow)] #[serde(crate = "rocket::serde")] pub struct Fortune { @@ -15,7 +14,6 @@ pub struct Fortune { pub message: String, } -#[allow(non_snake_case)] #[derive(Clone, Debug, PartialEq, Deserialize, Serialize, FromRow)] #[serde(crate = "rocket::serde")] pub struct World { diff --git a/frameworks/Rust/salvo/Cargo.toml b/frameworks/Rust/salvo/Cargo.toml index 82b6107eb70..58fa4a6a315 100644 --- a/frameworks/Rust/salvo/Cargo.toml +++ b/frameworks/Rust/salvo/Cargo.toml @@ -40,16 +40,16 @@ anyhow = "1" async-trait = "0.1" bytes = "1" diesel = { version = "2", features = ["postgres", "r2d2"] } -deadpool = { version = "0.9", features = ["rt_tokio_1", "serde", "async-trait", "managed"] } -deadpool-postgres = "0.10" +deadpool = { version = "0.12", features = ["rt_tokio_1", "serde", "managed"] } +deadpool-postgres = "0.14" futures-util = "0.3" -lru = "0.11.0" -markup = "0.13" +lru = "0.12" +markup = "0.15" # mimalloc = { version = "0.1", default-features = false } -mongodb = { version = "2.4.0", features = ["zstd-compression", "snappy-compression", "zlib-compression"] } +mongodb = { version = "2", features = ["zstd-compression", "snappy-compression", "zlib-compression"] } once_cell = "1" rand = { version = "0.8", features = ["min_const_gen", "small_rng"] } -salvo = { version = "0.55", default-features = false, features = ["anyhow", "http1", "affix"] } +salvo = { version = "0.74", default-features = false, features = ["anyhow", "server", "http1", "affix-state"] } serde = { version = "1", features = ["derive"] } serde_json = "1" # smallvec = "1" @@ -60,11 +60,8 @@ tokio-pg-mapper = "0.2.0" tokio-pg-mapper-derive = "0.2.0" tokio-postgres = "0.7" v_htmlescape = "0.15" -dotenv = "0.15.0" +dotenvy = "0.15" [profile.release] lto = true -opt-level = 3 codegen-units = 1 -panic = "abort" - diff --git a/frameworks/Rust/salvo/benchmark_config.json b/frameworks/Rust/salvo/benchmark_config.json index 2890085bf66..d5f4d1f91a0 100644 --- a/frameworks/Rust/salvo/benchmark_config.json +++ b/frameworks/Rust/salvo/benchmark_config.json @@ -19,6 +19,7 @@ "database_os": "Linux", "display_name": "Salvo", "notes": "", + "tags": ["broken"], "versus": "None" }, "diesel": { @@ -39,6 +40,7 @@ "database_os": "Linux", "display_name": "Salvo [postgres-diesel]", "notes": "", + "tags": ["broken"], "versus": "None" }, "pg": { @@ -59,6 +61,7 @@ "database_os": "Linux", "display_name": "Salvo [postgres]", "notes": "", + "tags": ["broken"], "versus": "None" }, "pg-pool": { @@ -79,6 +82,7 @@ "database_os": "Linux", "display_name": "Salvo [postgres-deadpool]", "notes": "", + "tags": ["broken"], "versus": "None" }, "mongo": { @@ -99,6 +103,7 @@ "database_os": "Linux", "display_name": "Salvo [mongodb]", "notes": "", + "tags": ["broken"], "versus": "None" }, "mongo-raw": { @@ -118,6 +123,7 @@ "database_os": "Linux", "display_name": "Salvo [mongodb-raw]", "notes": "", + "tags": ["broken"], "versus": "None" }, "sqlx": { @@ -136,6 +142,7 @@ "database_os": "Linux", "display_name": "Salvo [postgres-sqlx]", "notes": "", + "tags": ["broken"], "versus": "None" }, "lru": { @@ -153,6 +160,7 @@ "database_os": "Linux", "display_name": "Salvo [lru]", "notes": "", + "tags": ["broken"], "versus": "None" } } diff --git a/frameworks/Rust/salvo/salvo-diesel.dockerfile b/frameworks/Rust/salvo/salvo-diesel.dockerfile index 9a1538291c4..0943b3af73a 100644 --- a/frameworks/Rust/salvo/salvo-diesel.dockerfile +++ b/frameworks/Rust/salvo/salvo-diesel.dockerfile @@ -1,4 +1,4 @@ -FROM rust:1.72 +FROM rust:1.83 ENV TECHEMPOWER_POSTGRES_URL=postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world ENV TECHEMPOWER_MAX_POOL_SIZE=28 diff --git a/frameworks/Rust/salvo/salvo-lru.dockerfile b/frameworks/Rust/salvo/salvo-lru.dockerfile index 6c21d0630d7..4dd1d4511be 100644 --- a/frameworks/Rust/salvo/salvo-lru.dockerfile +++ b/frameworks/Rust/salvo/salvo-lru.dockerfile @@ -1,4 +1,4 @@ -FROM rust:1.72 +FROM rust:1.83 ENV TECHEMPOWER_POSTGRES_URL=postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world diff --git a/frameworks/Rust/salvo/salvo-mongo-raw.dockerfile b/frameworks/Rust/salvo/salvo-mongo-raw.dockerfile index 93d580b6098..2f15faea13c 100644 --- a/frameworks/Rust/salvo/salvo-mongo-raw.dockerfile +++ b/frameworks/Rust/salvo/salvo-mongo-raw.dockerfile @@ -1,4 +1,4 @@ -FROM rust:1.72 +FROM rust:1.83 ENV TECHEMPOWER_MONGODB_URL=mongodb://tfb-database:27017 ENV TECHEMPOWER_MAX_POOL_SIZE=28 diff --git a/frameworks/Rust/salvo/salvo-mongo.dockerfile b/frameworks/Rust/salvo/salvo-mongo.dockerfile index fe92c417c15..2eccf7dd4be 100644 --- a/frameworks/Rust/salvo/salvo-mongo.dockerfile +++ b/frameworks/Rust/salvo/salvo-mongo.dockerfile @@ -1,4 +1,4 @@ -FROM rust:1.72 +FROM rust:1.83 ENV TECHEMPOWER_MONGODB_URL=mongodb://tfb-database:27017 ENV TECHEMPOWER_MAX_POOL_SIZE=28 diff --git a/frameworks/Rust/salvo/salvo-pg-pool.dockerfile b/frameworks/Rust/salvo/salvo-pg-pool.dockerfile index 4ce679efee2..bb4f4dba212 100644 --- a/frameworks/Rust/salvo/salvo-pg-pool.dockerfile +++ b/frameworks/Rust/salvo/salvo-pg-pool.dockerfile @@ -1,4 +1,4 @@ -FROM rust:1.72 +FROM rust:1.83 ENV TECHEMPOWER_POSTGRES_URL=postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world ENV TECHEMPOWER_MAX_POOL_SIZE=28 diff --git a/frameworks/Rust/salvo/salvo-pg.dockerfile b/frameworks/Rust/salvo/salvo-pg.dockerfile index a694661fc8c..da1009087e1 100644 --- a/frameworks/Rust/salvo/salvo-pg.dockerfile +++ b/frameworks/Rust/salvo/salvo-pg.dockerfile @@ -1,4 +1,4 @@ -FROM rust:1.72 +FROM rust:1.83 ENV TECHEMPOWER_POSTGRES_URL=postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world diff --git a/frameworks/Rust/salvo/salvo-sqlx.dockerfile b/frameworks/Rust/salvo/salvo-sqlx.dockerfile index a947139d101..6da69983675 100644 --- a/frameworks/Rust/salvo/salvo-sqlx.dockerfile +++ b/frameworks/Rust/salvo/salvo-sqlx.dockerfile @@ -1,4 +1,4 @@ -FROM rust:1.72 +FROM rust:1.83 ENV TECHEMPOWER_POSTGRES_URL=postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world ENV TECHEMPOWER_MAX_POOL_SIZE=56 diff --git a/frameworks/Rust/salvo/salvo.dockerfile b/frameworks/Rust/salvo/salvo.dockerfile index 1e88321d350..11553801801 100644 --- a/frameworks/Rust/salvo/salvo.dockerfile +++ b/frameworks/Rust/salvo/salvo.dockerfile @@ -1,4 +1,4 @@ -FROM rust:1.72 +FROM rust:1.83 ADD ./ /salvo WORKDIR /salvo diff --git a/frameworks/Rust/salvo/src/db_pg_pool.rs b/frameworks/Rust/salvo/src/db_pg_pool.rs index bc1f546e922..064dc34cdae 100644 --- a/frameworks/Rust/salvo/src/db_pg_pool.rs +++ b/frameworks/Rust/salvo/src/db_pg_pool.rs @@ -1,10 +1,9 @@ use deadpool_postgres::{Client, Manager, ManagerConfig, RecyclingMethod}; use tokio_pg_mapper::FromTokioPostgresRow; -use tokio_postgres::{NoTls, Row, Error, Statement}; +use tokio_postgres::{Error, NoTls, Row, Statement}; use crate::{Fortune, World}; - pub async fn create_pool(database_url: String, max_pool_size: u32) -> deadpool_postgres::Pool { let pg_config: tokio_postgres::Config = database_url.parse().expect("invalid database url"); diff --git a/frameworks/Rust/salvo/src/db_sqlx.rs b/frameworks/Rust/salvo/src/db_sqlx.rs index 64ab3696da8..73e5f82afe3 100644 --- a/frameworks/Rust/salvo/src/db_sqlx.rs +++ b/frameworks/Rust/salvo/src/db_sqlx.rs @@ -1,7 +1,7 @@ use sqlx::{ pool::PoolConnection, postgres::{PgArguments, PgPoolOptions}, - Arguments, PgPool, Postgres, Error + Arguments, Error, PgPool, Postgres, }; use crate::{Fortune, World}; diff --git a/frameworks/Rust/salvo/src/main.rs b/frameworks/Rust/salvo/src/main.rs index db6c6d704d0..63e2ca12cd2 100644 --- a/frameworks/Rust/salvo/src/main.rs +++ b/frameworks/Rust/salvo/src/main.rs @@ -2,6 +2,7 @@ // static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; use std::sync::Arc; +use std::thread::available_parallelism; use bytes::Bytes; use salvo::conn::tcp::TcpAcceptor; @@ -12,6 +13,7 @@ use serde::Serialize; mod utils; + #[derive(Serialize)] pub struct Message { pub message: &'static str, @@ -36,8 +38,7 @@ fn plaintext(res: &mut Response) { headers.insert(header::CONTENT_TYPE, HeaderValue::from_static("text/plain")); res.body(ResBody::Once(Bytes::from_static(b"Hello, world!"))); } -#[tokio::main] -async + fn main() { let router = Arc::new( Router::new() @@ -45,11 +46,27 @@ fn main() { .push(Router::with_path("json").get(json)), ); + let thread_count = available_parallelism().map(|n| n.get()).unwrap_or(16); + let rt = tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .unwrap(); + for _ in 1..thread_count { + let router = router.clone(); + std::thread::spawn(move || { + let rt = tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .unwrap(); + rt.block_on(serve(router)); + }); + } println!("Started http server: 127.0.0.1:8080"); - serve(router).await; + rt.block_on(serve(router)); } async fn serve(router: Arc) { + // let acceptor: TcpAcceptor = utils::reuse_listener().unwrap().try_into().unwrap(); let acceptor: TcpAcceptor = utils::reuse_listener().unwrap().try_into().unwrap(); let mut server = Server::new(acceptor); let http1 = server.http1_mut(); diff --git a/frameworks/Rust/salvo/src/main_diesel.rs b/frameworks/Rust/salvo/src/main_diesel.rs index 063b814e191..12e8bdc283a 100644 --- a/frameworks/Rust/salvo/src/main_diesel.rs +++ b/frameworks/Rust/salvo/src/main_diesel.rs @@ -15,6 +15,7 @@ use std::thread::available_parallelism; use anyhow::Error; use diesel::prelude::*; use diesel::r2d2::{ConnectionManager, Pool, PoolError, PooledConnection}; +use dotenvy::dotenv; use once_cell::sync::OnceCell; use rand::rngs::SmallRng; use rand::{Rng, SeedableRng}; @@ -22,7 +23,6 @@ use salvo::conn::tcp::TcpAcceptor; use salvo::http::header::{self, HeaderValue}; use salvo::http::ResBody; use salvo::prelude::*; -use dotenv::dotenv; mod models_diesel; mod schema; @@ -135,7 +135,10 @@ async fn fortunes(res: &mut Response) -> Result<(), Error> { let headers = res.headers_mut(); headers.insert(header::SERVER, HeaderValue::from_static("salvo")); - headers.insert(header::CONTENT_TYPE, HeaderValue::from_static("text/html; charset=utf-8")); + headers.insert( + header::CONTENT_TYPE, + HeaderValue::from_static("text/html; charset=utf-8"), + ); res.body(ResBody::Once(Bytes::from(data))); Ok(()) } @@ -164,14 +167,11 @@ markup::define! { fn main() { dotenv().ok(); - + let db_url: String = utils::get_env_var("TECHEMPOWER_POSTGRES_URL"); let max_pool_size: u32 = utils::get_env_var("TECHEMPOWER_MAX_POOL_SIZE"); DB_POOL - .set( - create_pool(&db_url, max_pool_size) - .unwrap_or_else(|_| panic!("Error connecting to {}", &db_url)), - ) + .set(create_pool(&db_url, max_pool_size).unwrap_or_else(|_| panic!("Error connecting to {}", &db_url))) .ok(); let router = Arc::new( diff --git a/frameworks/Rust/salvo/src/main_lru.rs b/frameworks/Rust/salvo/src/main_lru.rs index 77186e58ba9..0f4abcceefc 100644 --- a/frameworks/Rust/salvo/src/main_lru.rs +++ b/frameworks/Rust/salvo/src/main_lru.rs @@ -10,7 +10,7 @@ use std::thread::available_parallelism; use anyhow::Error; use bytes::Bytes; -use dotenv::dotenv; +use dotenvy::dotenv; use lru::LruCache; use once_cell::sync::OnceCell; use rand::rngs::SmallRng; diff --git a/frameworks/Rust/salvo/src/main_mongo.rs b/frameworks/Rust/salvo/src/main_mongo.rs index 46db9bf847c..54dfca1b183 100644 --- a/frameworks/Rust/salvo/src/main_mongo.rs +++ b/frameworks/Rust/salvo/src/main_mongo.rs @@ -10,7 +10,7 @@ use std::time::Duration; use anyhow::Error; use bytes::Bytes; -use dotenv::dotenv; +use dotenvy::dotenv; use mongodb::{ options::{ClientOptions, Compressor}, Client, Database, @@ -102,7 +102,10 @@ async fn fortunes(res: &mut Response, depot: &mut Depot) -> Result<(), Error> { let headers = res.headers_mut(); headers.insert(header::SERVER, HeaderValue::from_static("salvo")); - headers.insert(header::CONTENT_TYPE, HeaderValue::from_static("text/html; charset=utf-8")); + headers.insert( + header::CONTENT_TYPE, + HeaderValue::from_static("text/html; charset=utf-8"), + ); res.body(ResBody::Once(Bytes::from(data))); Ok(()) } @@ -174,7 +177,7 @@ async fn serve() { let database = client.database("hello_world"); let router = Router::new() - .hoop(salvo::affix::inject(database)) + .hoop(salvo::affix_state::inject(database)) .push(Router::with_path("db").get(world_row)) .push(Router::with_path("fortunes").get(fortunes)) .push(Router::with_path("queries").get(queries)) diff --git a/frameworks/Rust/salvo/src/main_mongo_raw.rs b/frameworks/Rust/salvo/src/main_mongo_raw.rs index 8c4e5af5efb..ba575dc33bc 100644 --- a/frameworks/Rust/salvo/src/main_mongo_raw.rs +++ b/frameworks/Rust/salvo/src/main_mongo_raw.rs @@ -9,7 +9,7 @@ use std::time::Duration; use anyhow::Error; use bytes::Bytes; -use dotenv::dotenv; +use dotenvy::dotenv; use mongodb::{ options::{ClientOptions, Compressor}, Client, Database, @@ -140,7 +140,7 @@ async fn serve() { let database = client.database("hello_world"); let router = Router::new() - .hoop(salvo::affix::inject(database)) + .hoop(salvo::affix_state::inject(database)) .push(Router::with_path("db").get(world_row)) .push(Router::with_path("queries").get(queries)) .push(Router::with_path("updates").get(updates)); diff --git a/frameworks/Rust/salvo/src/main_pg.rs b/frameworks/Rust/salvo/src/main_pg.rs index 0d54a192004..af04bf4b718 100644 --- a/frameworks/Rust/salvo/src/main_pg.rs +++ b/frameworks/Rust/salvo/src/main_pg.rs @@ -9,7 +9,7 @@ use std::thread::available_parallelism; use async_trait::async_trait; use bytes::Bytes; -use dotenv::dotenv; +use dotenvy::dotenv; use salvo::conn::tcp::TcpAcceptor; use salvo::http::header::{self, HeaderValue}; use salvo::http::ResBody; @@ -36,13 +36,7 @@ impl WorldHandler { } #[async_trait] impl Handler for WorldHandler { - async fn handle( - &self, - _req: &mut Request, - _depot: &mut Depot, - res: &mut Response, - _ctrl: &mut FlowCtrl, - ) { + async fn handle(&self, _req: &mut Request, _depot: &mut Depot, res: &mut Response, _ctrl: &mut FlowCtrl) { let world = self.conn.get_world().await.unwrap(); let data = serde_json::to_vec(&world).unwrap(); let headers = res.headers_mut(); @@ -66,13 +60,7 @@ impl WorldsHandler { } #[async_trait] impl Handler for WorldsHandler { - async fn handle( - &self, - req: &mut Request, - _depot: &mut Depot, - res: &mut Response, - _ctrl: &mut FlowCtrl, - ) { + async fn handle(&self, req: &mut Request, _depot: &mut Depot, res: &mut Response, _ctrl: &mut FlowCtrl) { let count = req.query::("q").unwrap_or(1); let count = cmp::min(500, cmp::max(1, count)); let worlds = self.conn.get_worlds(count).await.unwrap(); @@ -99,13 +87,7 @@ impl UpdatesHandler { } #[async_trait] impl Handler for UpdatesHandler { - async fn handle( - &self, - req: &mut Request, - _depot: &mut Depot, - res: &mut Response, - _ctrl: &mut FlowCtrl, - ) { + async fn handle(&self, req: &mut Request, _depot: &mut Depot, res: &mut Response, _ctrl: &mut FlowCtrl) { let count = req.query::("q").unwrap_or(1); let count = cmp::min(500, cmp::max(1, count)); let worlds = self.conn.update(count).await.unwrap(); @@ -132,19 +114,16 @@ impl FortunesHandler { } #[async_trait] impl Handler for FortunesHandler { - async fn handle( - &self, - _req: &mut Request, - _depot: &mut Depot, - res: &mut Response, - _ctrl: &mut FlowCtrl, - ) { + async fn handle(&self, _req: &mut Request, _depot: &mut Depot, res: &mut Response, _ctrl: &mut FlowCtrl) { let mut data = String::new(); write!(&mut data, "{}", self.conn.tell_fortune().await.unwrap()).unwrap(); let headers = res.headers_mut(); headers.insert(header::SERVER, HeaderValue::from_static("salvo")); - headers.insert(header::CONTENT_TYPE, HeaderValue::from_static("text/html; charset=utf-8")); + headers.insert( + header::CONTENT_TYPE, + HeaderValue::from_static("text/html; charset=utf-8"), + ); res.body(ResBody::Once(Bytes::from(data))); } } diff --git a/frameworks/Rust/salvo/src/main_pg_pool.rs b/frameworks/Rust/salvo/src/main_pg_pool.rs index 75078c42ff1..1e5d6c0b6ec 100644 --- a/frameworks/Rust/salvo/src/main_pg_pool.rs +++ b/frameworks/Rust/salvo/src/main_pg_pool.rs @@ -11,6 +11,7 @@ use std::thread::available_parallelism; use anyhow::Error; use bytes::Bytes; use deadpool_postgres::Pool; +use dotenvy::dotenv; use futures_util::{stream::FuturesUnordered, TryStreamExt}; use once_cell::sync::OnceCell; use rand::rngs::SmallRng; @@ -19,7 +20,6 @@ use salvo::conn::tcp::TcpAcceptor; use salvo::http::header::{self, HeaderValue}; use salvo::http::ResBody; use salvo::prelude::*; -use dotenv::dotenv; mod db_pg_pool; mod models_pg_pool; @@ -129,7 +129,10 @@ async fn fortunes(res: &mut Response) -> Result<(), Error> { let headers = res.headers_mut(); headers.insert(header::SERVER, HeaderValue::from_static("salvo")); - headers.insert(header::CONTENT_TYPE, HeaderValue::from_static("text/html; charset=utf-8")); + headers.insert( + header::CONTENT_TYPE, + HeaderValue::from_static("text/html; charset=utf-8"), + ); res.body(ResBody::Once(Bytes::from(data))); Ok(()) } @@ -158,7 +161,7 @@ markup::define! { fn main() { dotenv().ok(); - + let db_url: String = utils::get_env_var("TECHEMPOWER_POSTGRES_URL"); let max_pool_size: u32 = utils::get_env_var("TECHEMPOWER_MAX_POOL_SIZE"); let rt = tokio::runtime::Builder::new_current_thread() diff --git a/frameworks/Rust/salvo/src/main_sqlx.rs b/frameworks/Rust/salvo/src/main_sqlx.rs index 2dca03f4e31..ca52a8e6b61 100644 --- a/frameworks/Rust/salvo/src/main_sqlx.rs +++ b/frameworks/Rust/salvo/src/main_sqlx.rs @@ -9,6 +9,7 @@ use std::thread::available_parallelism; use anyhow::Error; use bytes::Bytes; +use dotenvy::dotenv; use once_cell::sync::OnceCell; use rand::rngs::SmallRng; use rand::{Rng, SeedableRng}; @@ -17,7 +18,6 @@ use salvo::http::header::{self, HeaderValue}; use salvo::http::ResBody; use salvo::prelude::*; use sqlx::PgPool; -use dotenv::dotenv; mod db_sqlx; mod models_sqlx; @@ -62,7 +62,10 @@ async fn fortunes(res: &mut Response) -> Result<(), Error> { let headers = res.headers_mut(); headers.insert(header::SERVER, HeaderValue::from_static("salvo")); - headers.insert(header::CONTENT_TYPE, HeaderValue::from_static("text/html; charset=utf-8")); + headers.insert( + header::CONTENT_TYPE, + HeaderValue::from_static("text/html; charset=utf-8"), + ); res.body(ResBody::Once(Bytes::from(data))); Ok(()) } diff --git a/frameworks/Rust/sib/Cargo.toml b/frameworks/Rust/sib/Cargo.toml new file mode 100644 index 00000000000..1358100f450 --- /dev/null +++ b/frameworks/Rust/sib/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "sib-techempower" +version = "0.0.1" +authors = ["mail@pooya.ai"] +description = "A high-performance, secure, and cross-platform modules optimized for efficiency, scalability, and reliability." +documentation = "https://docs.rs/sib" +edition = "2024" +keywords = ["sib", "networking", "real-time", "streaming", "web"] +license = "Apache-2.0" +repository = "https://github.com/PooyaEimandar/sib" +categories = ["development-tools"] +readme = "README.md" + +[dependencies] +sib = { version = "0.0.15", 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 } +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 = [ + "std", +] } + +[profile.release] +opt-level = 3 +codegen-units = 1 diff --git a/frameworks/Rust/sib/README.md b/frameworks/Rust/sib/README.md new file mode 100644 index 00000000000..2903a7a11ec --- /dev/null +++ b/frameworks/Rust/sib/README.md @@ -0,0 +1,15 @@ +# [SIB](https://github.com/pooyaeimandar/sib) web framework + +## Description + +Sib supports HTTP/1.1, HTTP/2, and HTTP/3. It uses coroutines and io_uring, along with zero-copy request/response handling, to achieve the lowest possible overhead. + +## Test URLs + +### Test 1: JSON Encoding + + http://localhost:8080/json + +### Test 2: Plaintext + + http://localhost:8080/plaintext diff --git a/frameworks/Rust/sib/benchmark_config.json b/frameworks/Rust/sib/benchmark_config.json new file mode 100644 index 00000000000..55316d46a37 --- /dev/null +++ b/frameworks/Rust/sib/benchmark_config.json @@ -0,0 +1,24 @@ +{ + "framework": "sib", + "tests": [ + { + "default": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "framework": "sib", + "language": "Rust", + "flavor": "None", + "platform": "None", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "sib", + "notes": "", + "versus": "None" + } + } + ] +} diff --git a/frameworks/Rust/sib/sib.dockerfile b/frameworks/Rust/sib/sib.dockerfile new file mode 100644 index 00000000000..98c76de2cdd --- /dev/null +++ b/frameworks/Rust/sib/sib.dockerfile @@ -0,0 +1,12 @@ +FROM rust:latest + +ADD ./ /sib +WORKDIR /sib + +RUN apt-get update && apt-get install -y cmake clang lld llvm libclang-dev +RUN cargo clean +RUN RUSTFLAGS="-C target-cpu=native" cargo build --release + +EXPOSE 8080 + +CMD ["./target/release/sib-techempower"] diff --git a/frameworks/Rust/sib/src/main.rs b/frameworks/Rust/sib/src/main.rs new file mode 100644 index 00000000000..0013400cf8a --- /dev/null +++ b/frameworks/Rust/sib/src/main.rs @@ -0,0 +1,107 @@ +use sib::network::http::{ + server::{H1Config, HFactory}, + session::{HService, Session}, +}; + +#[global_allocator] +static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; + +#[derive(serde::Serialize)] +struct JsonMessage<'a> { + message: &'a str, +} + +impl Default for JsonMessage<'_> { + fn default() -> Self { + JsonMessage { + message: "Hello, World!", + } + } +} + +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()) + } + } +} + +impl HFactory for Server { + type Service = Server; + + fn service(&self, _id: usize) -> Server { + Server + } +} + +fn main() { + let stack_size = 4 * 1024; // 4 KB stack + let cpus = num_cpus::get(); + + sib::init_global_poller(cpus, stack_size); + + // Pick a port and start the server + let addr = "0.0.0.0:8080"; + let mut threads = Vec::with_capacity(cpus); + + for _ in 0..cpus { + let handle = std::thread::spawn(move || { + let id = std::thread::current().id(); + println!("Listening {addr} on thread: {id:?}"); + Server + .start_h1( + addr, + H1Config { + io_timeout: std::time::Duration::from_secs(15), + stack_size, + }, + ) + .unwrap_or_else(|_| panic!("H1 server failed to start for thread {id:?}")) + .join() + .unwrap_or_else(|_| panic!("H1 server failed to join thread {id:?}")); + }); + threads.push(handle); + } + + // Wait for all threads to complete + for handle in threads { + handle.join().expect("Thread panicked"); + } +} diff --git a/frameworks/Rust/tachyon-concept/README.md b/frameworks/Rust/tachyon-concept/README.md new file mode 100644 index 00000000000..6ba0e93287a --- /dev/null +++ b/frameworks/Rust/tachyon-concept/README.md @@ -0,0 +1,43 @@ +# Tachyon + +[Tachyon Repo](https://github.com/TachyonConcepts/TachyonConcept) + +**Tachyon** is a web server written in 100% `unsafe` Rust. +Yes — **100%**. There isn’t a single `safe` block in the entire codebase. Safety is a suggestion, not a rule. + +This implementation is intentionally modest in scope and **supports only the `/plaintext` benchmark**. No JSON, no databases, no distractions. + +## Goals + +Tachyon is a server that makes no attempt to be fast, correct, or relevant. +It serves plaintext. Slowly. **VERY** slowly. +Nah... really... very slow. + +## Requirements + +- Linux kernel **6.0+** +- Rust **nightly** +- CPU with **AVX2** support + +> We require a modern Linux kernel to ensure our experimental use of io_uring does *not* work on older systems. +> Nightly Rust is used to maintain maximum instability across compiler versions. + +## Running Locally + +```bash +echo "2048 4096 8192" > /proc/sys/net/ipv4/tcp_wmem +echo "8192 16384 32768" > /proc/sys/net/ipv4/tcp_rmem +echo "4096 131072 262144" > /proc/sys/net/ipv4/tcp_mem + +sysctl -w net.core.somaxconn=65535 +sysctl -w net.ipv4.tcp_max_syn_backlog=65535 + +sysctl -w net.ipv4.tcp_fastopen=3 +sysctl -w net.ipv4.tcp_tw_reuse=1 +sysctl -w net.ipv4.tcp_fin_timeout=10 + +ulimit -n 65535 +ulimit -s unlimited + +git clone https://github.com/TachyonConcepts/TachyonConcept +cargo run --release diff --git a/frameworks/Rust/tachyon-concept/benchmark_config.json b/frameworks/Rust/tachyon-concept/benchmark_config.json new file mode 100644 index 00000000000..56db2f7293b --- /dev/null +++ b/frameworks/Rust/tachyon-concept/benchmark_config.json @@ -0,0 +1,45 @@ +{ + "framework": "tachyon-concept", + "tests": [ + { + "default": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Platform", + "database": "None", + "framework": "None", + "language": "Rust", + "flavor": "None", + "orm": "None", + "platform": "None", + "webserver": "Tachyon", + "os": "Linux", + "database_os": "Linux", + "display_name": "Tachyon-Concept", + "notes": "", + "versus": "None" + }, + "ub": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Platform", + "database": "None", + "framework": "None", + "language": "Rust", + "flavor": "None", + "orm": "None", + "platform": "None", + "webserver": "Tachyon", + "os": "Linux", + "database_os": "Linux", + "display_name": "Tachyon-Concept-UB", + "notes": "", + "versus": "None" + } + } + ] +} diff --git a/frameworks/Rust/tachyon-concept/tachyon-concept-ub.dockerfile b/frameworks/Rust/tachyon-concept/tachyon-concept-ub.dockerfile new file mode 100644 index 00000000000..4f7ea5501f0 --- /dev/null +++ b/frameworks/Rust/tachyon-concept/tachyon-concept-ub.dockerfile @@ -0,0 +1,10 @@ +FROM rust:latest +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 +RUN chmod +x /app/run_ub.sh +EXPOSE 8080 +CMD /app/run_ub.sh \ No newline at end of file diff --git a/frameworks/Rust/tachyon-concept/tachyon-concept.dockerfile b/frameworks/Rust/tachyon-concept/tachyon-concept.dockerfile new file mode 100644 index 00000000000..04aedcc6ac1 --- /dev/null +++ b/frameworks/Rust/tachyon-concept/tachyon-concept.dockerfile @@ -0,0 +1,10 @@ +FROM rust:latest +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 +RUN chmod +x /app/run.sh +EXPOSE 8080 +CMD /app/run.sh \ No newline at end of file diff --git a/frameworks/Rust/tide/Cargo.lock b/frameworks/Rust/tide/Cargo.lock index e9aa1d8598d..7ed70839854 100644 --- a/frameworks/Rust/tide/Cargo.lock +++ b/frameworks/Rust/tide/Cargo.lock @@ -93,7 +93,7 @@ checksum = "ca2925c4c290382f9d2fa3d1c1b6a63fa1427099721ecca4749b154cc9c25522" dependencies = [ "askama_shared", "proc-macro2", - "syn", + "syn 1.0.60", ] [[package]] @@ -116,7 +116,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn", + "syn 1.0.60", "toml", ] @@ -127,7 +127,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5" dependencies = [ "quote", - "syn", + "syn 1.0.60", ] [[package]] @@ -331,7 +331,7 @@ checksum = "8d3a45e77e34375a7923b1e8febb049bb011f064714a8e17a1a616fef01da13d" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.60", ] [[package]] @@ -380,6 +380,12 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + [[package]] name = "bitvec" version = "0.19.4" @@ -609,7 +615,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8f45d9ad417bcef4817d614a501ab55cdd96a6fdb24f49aab89a54acfd66b19" dependencies = [ "quote", - "syn", + "syn 1.0.60", ] [[package]] @@ -621,6 +627,41 @@ 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.75", +] + +[[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.75", +] + [[package]] name = "dashmap" version = "4.0.2" @@ -639,26 +680,38 @@ checksum = "3ee2393c4a91429dffb4bedf19f4d6abf27d8a732c8ce4980305d782e5426d57" [[package]] name = "diesel" -version = "1.4.6" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "047bfc4d5c3bd2ef6ca6f981941046113524b9a9f9a7cbdfdd7ff40f58e6f542" +checksum = "65e13bab2796f412722112327f3e575601a3e9cdcbe426f0d30dbf43f3f5dc71" dependencies = [ - "bitflags", + "bitflags 2.6.0", "byteorder", "diesel_derives", + "itoa 1.0.11", "pq-sys", "r2d2", ] [[package]] name = "diesel_derives" -version = "1.4.1" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45f5098f628d02a7a0f68ddba586fb61e80edec3bdc1be3b921f4ceec60858d3" +checksum = "e7f2c3de51e2ba6bf2a648285696137aaf0f5f487bcbea93972fe8a364e131a4" dependencies = [ + "diesel_table_macro_syntax", + "dsl_auto_type", "proc-macro2", "quote", - "syn", + "syn 2.0.75", +] + +[[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.75", ] [[package]] @@ -676,6 +729,26 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" +[[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", + "proc-macro2", + "quote", + "syn 2.0.75", +] + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + [[package]] name = "event-listener" version = "2.5.1" @@ -707,6 +780,12 @@ dependencies = [ "web-sys", ] +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + [[package]] name = "form_urlencoded" version = "1.0.1" @@ -768,7 +847,7 @@ dependencies = [ "proc-macro-hack", "proc-macro2", "quote", - "syn", + "syn 1.0.60", ] [[package]] @@ -837,6 +916,12 @@ dependencies = [ "web-sys", ] +[[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.1.18" @@ -923,6 +1008,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6cab2627acfc432780848602f3f558f7e9dd427352224b0d9324025796d2a5e" +[[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.2.2" @@ -955,6 +1046,12 @@ version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + [[package]] name = "js-sys" version = "0.3.48" @@ -986,7 +1083,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21f866863575d0e1d654fbeeabdc927292fdf862873dc3c96c6f753357e13374" dependencies = [ "arrayvec", - "bitflags", + "bitflags 1.2.1", "cfg-if 1.0.0", "ryu", "static_assertions", @@ -1153,7 +1250,7 @@ checksum = "758669ae3558c6f74bd2a18b41f7ac0b5a195aea6639d6a9b5e5d1ad5ba24c0b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.60", ] [[package]] @@ -1227,18 +1324,18 @@ checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" [[package]] name = "proc-macro2" -version = "1.0.24" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ - "unicode-xid", + "unicode-ident", ] [[package]] name = "quote" -version = "1.0.9" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -1317,7 +1414,7 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94341e4e44e24f6b591b59e47a8a027df12e008d73fd5672dbea9cc22f4507d9" dependencies = [ - "bitflags", + "bitflags 1.2.1", ] [[package]] @@ -1388,7 +1485,7 @@ checksum = "9391c295d64fc0abb2c556bad848f33cb8296276b1ad2677d1ae1ace4f258f31" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.60", ] [[package]] @@ -1397,7 +1494,7 @@ version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43535db9747a4ba938c0ce0a98cc631a46ebf943c9e1d604e091df6007620bf6" dependencies = [ - "itoa", + "itoa 0.4.7", "ryu", "serde", ] @@ -1421,7 +1518,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edfa57a7f8d9c1d260a549e7224100f6c43d43f9103e06dd8b4095a9b2b43ce9" dependencies = [ "form_urlencoded", - "itoa", + "itoa 0.4.7", "ryu", "serde", ] @@ -1541,7 +1638,7 @@ dependencies = [ "quote", "serde", "serde_derive", - "syn", + "syn 1.0.60", ] [[package]] @@ -1557,7 +1654,7 @@ dependencies = [ "serde_derive", "serde_json", "sha1", - "syn", + "syn 1.0.60", ] [[package]] @@ -1566,6 +1663,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "subtle" version = "2.4.0" @@ -1589,6 +1692,17 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "syn" +version = "2.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6af063034fc1935ede7be0122941bafa9bacb949334d090b77ca98b5817c7d9" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "tap" version = "1.0.1" @@ -1612,7 +1726,7 @@ checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.60", ] [[package]] @@ -1697,7 +1811,7 @@ dependencies = [ "proc-macro2", "quote", "standback", - "syn", + "syn 1.0.60", ] [[package]] @@ -1739,6 +1853,12 @@ dependencies = [ "matches", ] +[[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.17" @@ -1840,7 +1960,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn", + "syn 1.0.60", "wasm-bindgen-shared", ] @@ -1874,7 +1994,7 @@ checksum = "cc053ec74d454df287b9374ee8abb36ffd5acb95ba87da3ba5b7d3fe20eb401e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.60", "wasm-bindgen-backend", "wasm-bindgen-shared", ] diff --git a/frameworks/Rust/tide/Cargo.toml b/frameworks/Rust/tide/Cargo.toml index 80c05675a77..18b2aeea38c 100644 --- a/frameworks/Rust/tide/Cargo.toml +++ b/frameworks/Rust/tide/Cargo.toml @@ -8,7 +8,7 @@ edition = "2018" askama = "0.10.5" async-std = { version = "1.9.0", features = ["attributes"] } async-trait = "0.1.42" -diesel = { version = "1.4.6", features = ["postgres", "r2d2"] } +diesel = { version = "2.2.3", features = ["postgres", "r2d2"] } http-types = "2.10.0" rand = { version = "0.7", features = ["small_rng"] } serde = { version = "1.0.123", features = ["derive"] } diff --git a/frameworks/Rust/trillium/Cargo.lock b/frameworks/Rust/trillium/Cargo.lock index 080f122ca49..6875427cc51 100644 --- a/frameworks/Rust/trillium/Cargo.lock +++ b/frameworks/Rust/trillium/Cargo.lock @@ -3,20 +3,40 @@ version = 3 [[package]] -name = "Inflector" -version = "0.11.4" +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "ahash" -version = "0.7.6" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +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]] @@ -26,31 +46,86 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" [[package]] -name = "arrayvec" -version = "0.5.2" +name = "allocator-api2" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" + +[[package]] +name = "anstream" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" + +[[package]] +name = "anstyle-parse" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" +checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] [[package]] name = "askama" -version = "0.11.1" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb98f10f371286b177db5eeb9a6e5396609555686a35e1d4f7b9a9c6d8af0139" +checksum = "b79091df18a97caea757e28cd2d5fda49c6cd4bd01ddffd7ff01ace0c0ad2c28" dependencies = [ "askama_derive", "askama_escape", - "askama_shared", + "humansize", + "num-traits", + "percent-encoding", ] [[package]] name = "askama_derive" -version = "0.11.2" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87bf87e6e8b47264efa9bde63d6225c6276a52e05e91bf37eaa8afd0032d6b71" +checksum = "19fe8d6cb13c4714962c072ea496f3392015f0989b1a2847bb4b2d9effd71d83" dependencies = [ - "askama_shared", + "askama_parser", + "basic-toml", + "mime", + "mime_guess", "proc-macro2", - "syn", + "quote", + "serde", + "syn 2.0.58", ] [[package]] @@ -60,153 +135,169 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341" [[package]] -name = "askama_shared" -version = "0.12.2" +name = "askama_parser" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf722b94118a07fcbc6640190f247334027685d4e218b794dbfe17c32bf38ed0" +checksum = "acb1161c6b64d1c3d83108213c2a2533a342ac225aabd0bda218278c2ddb00c0" dependencies = [ - "askama_escape", - "humansize", - "mime", - "mime_guess", "nom", - "num-traits", - "percent-encoding", - "proc-macro2", - "quote", - "serde", - "syn", - "toml", ] [[package]] name = "async-channel" -version = "1.6.1" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" +dependencies = [ + "concurrent-queue", + "event-listener 2.5.3", + "futures-core", +] + +[[package]] +name = "async-channel" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2114d64672151c0c5eaa5e131ec84a74f06e1e559830dabba01ca30605d66319" +checksum = "f28243a43d821d11341ab73c80bed182dc015c514b951616cf79bd4af39af0c3" dependencies = [ "concurrent-queue", - "event-listener", + "event-listener 5.3.0", + "event-listener-strategy 0.5.1", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-compat" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f68a707c1feb095d8c07f8a65b9f506b117d30af431cab89374357de7c11461b" +dependencies = [ "futures-core", + "futures-io", + "once_cell", + "pin-project-lite", + "tokio", ] [[package]] name = "async-executor" -version = "1.4.1" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "871f9bb5e0a22eeb7e8cf16641feb87c9dc67032ccf8ff49e772eb9941d3a965" +checksum = "5f98c37cf288e302c16ef6c8472aad1e034c6c84ce5ea7b8101c98eb4a802fee" dependencies = [ + "async-lock 3.3.0", "async-task", "concurrent-queue", - "fastrand", - "futures-lite", - "once_cell", + "fastrand 2.0.2", + "futures-lite 2.3.0", "slab", ] [[package]] name = "async-global-executor" -version = "2.0.2" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9586ec52317f36de58453159d48351bc244bc24ced3effc1fce22f3d48664af6" +checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" dependencies = [ - "async-channel", + "async-channel 2.2.0", "async-executor", - "async-io", - "async-mutex", + "async-io 2.3.2", + "async-lock 3.3.0", "blocking", - "futures-lite", - "num_cpus", + "futures-lite 2.3.0", "once_cell", ] [[package]] name = "async-io" -version = "1.6.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a811e6a479f2439f0c04038796b5cfb3d2ad56c230e0f2d3f7b04d68cfee607b" +checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" dependencies = [ + "async-lock 2.8.0", + "autocfg", + "cfg-if", "concurrent-queue", - "futures-lite", - "libc", + "futures-lite 1.13.0", "log", - "once_cell", "parking", - "polling", + "polling 2.8.0", + "rustix 0.37.27", "slab", - "socket2", + "socket2 0.4.10", "waker-fn", - "winapi", ] [[package]] -name = "async-lock" -version = "2.4.0" +name = "async-io" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6a8ea61bf9947a1007c5cada31e647dbc77b103c679858150003ba697ea798b" +checksum = "dcccb0f599cfa2f8ace422d3555572f47424da5648a4382a9dd0310ff8210884" dependencies = [ - "event-listener", + "async-lock 3.3.0", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite 2.3.0", + "parking", + "polling 3.6.0", + "rustix 0.38.32", + "slab", + "tracing", + "windows-sys 0.52.0", ] [[package]] -name = "async-mutex" -version = "1.4.0" +name = "async-lock" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479db852db25d9dbf6204e6cb6253698f175c15726470f78af0d918e99d6156e" +checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" dependencies = [ - "event-listener", + "event-listener 2.5.3", ] [[package]] -name = "async-native-tls" -version = "0.3.3" +name = "async-lock" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e9e7a929bd34c68a82d58a4de7f86fffdaf97fb2af850162a7bb19dd7269b33" +checksum = "d034b430882f8381900d3fe6f0aaa3ad94f2cb4ac519b429692a1bc2dda4ae7b" dependencies = [ - "async-std", - "native-tls", - "thiserror", - "url", + "event-listener 4.0.3", + "event-listener-strategy 0.4.0", + "pin-project-lite", ] [[package]] -name = "async-process" -version = "1.3.0" +name = "async-net" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83137067e3a2a6a06d67168e49e68a0957d215410473a740cea95a2425c0b7c6" +checksum = "b948000fad4873c1c9339d60f2623323a0cfd3816e5181033c6a5cb68b2accf7" dependencies = [ - "async-io", + "async-io 2.3.2", "blocking", - "cfg-if", - "event-listener", - "futures-lite", - "libc", - "once_cell", - "signal-hook", - "winapi", + "futures-lite 2.3.0", ] [[package]] name = "async-std" -version = "1.10.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8056f1455169ab86dd47b47391e4ab0cbd25410a70e9fe675544f49bafaf952" +checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" dependencies = [ - "async-channel", + "async-channel 1.9.0", "async-global-executor", - "async-io", - "async-lock", - "async-process", + "async-io 1.13.0", + "async-lock 2.8.0", "crossbeam-utils", "futures-channel", "futures-core", "futures-io", - "futures-lite", + "futures-lite 1.13.0", "gloo-timers", "kv-log-macro", "log", "memchr", - "num_cpus", "once_cell", "pin-project-lite", "pin-utils", @@ -216,92 +307,105 @@ dependencies = [ [[package]] name = "async-stream" -version = "0.3.2" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "171374e7e3b2504e0e5236e3b59260560f9fe94bfe9ac39ba5e4e929c5590625" +checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" dependencies = [ "async-stream-impl", "futures-core", + "pin-project-lite", ] [[package]] name = "async-stream-impl" -version = "0.3.2" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "648ed8c8d2ce5409ccd57453d9d1b214b342a0d69376a6feda1fd6cae3299308" +checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.58", ] [[package]] name = "async-task" -version = "4.0.3" +version = "4.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91831deabf0d6d7ec49552e489aed63b7456a7a3c46cff62adad428110b0af0" +checksum = "fbb36e985947064623dbd357f727af08ffd077f93d696782f3c56365fa2e2799" [[package]] name = "async-trait" -version = "0.1.52" +version = "0.1.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "061a7acccaa286c011ddc30970520b98fa40e00c9d644633fb26b5fc63a265e3" +checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.58", ] +[[package]] +name = "async_cell" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "834eee9ce518130a3b4d5af09ecc43e9d6b57ee76613f227a1ddd6b77c7a62bc" + [[package]] name = "atoi" -version = "0.4.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616896e05fc0e2649463a93a15183c6a16bf03413a7af88ef1285ddedfa9cda5" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" dependencies = [ "num-traits", ] [[package]] name = "atomic-waker" -version = "1.0.0" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "065374052e7df7ee4047b1160cca5e1467a12351a40b3da123c870ba0b8eda2a" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] -name = "atty" -version = "0.2.14" +name = "autocfg" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" + +[[package]] +name = "backtrace" +version = "0.3.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" dependencies = [ - "hermit-abi", + "addr2line", + "cc", + "cfg-if", "libc", - "winapi", + "miniz_oxide", + "object", + "rustc-demangle", ] [[package]] -name = "autocfg" -version = "1.0.1" +name = "base64" +version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] -name = "bae" -version = "0.1.7" +name = "base64ct" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b8de67cc41132507eeece2584804efcb15f85ba516e34c944b7667f480397a" -dependencies = [ - "heck", - "proc-macro-error", - "proc-macro2", - "quote", - "syn", -] +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" [[package]] -name = "base64" -version = "0.13.0" +name = "basic-toml" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" +checksum = "823388e228f614e9558c6804262db37960ec8821856535f5c3f59913140558f8" +dependencies = [ + "serde", +] [[package]] name = "bitflags" @@ -309,58 +413,63 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +dependencies = [ + "serde", +] + [[package]] name = "block-buffer" -version = "0.9.0" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ "generic-array", ] [[package]] name = "blocking" -version = "1.1.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046e47d4b2d391b1f6f8b407b1deb8dee56c1852ccd868becf2710f601b5f427" +checksum = "6a37913e8dc4ddcc604f0c6d3bf2887c995153af3611de9e23c352b44c1b9118" dependencies = [ - "async-channel", + "async-channel 2.2.0", + "async-lock 3.3.0", "async-task", - "atomic-waker", - "fastrand", - "futures-lite", - "once_cell", + "fastrand 2.0.2", + "futures-io", + "futures-lite 2.3.0", + "piper", + "tracing", ] [[package]] name = "bumpalo" -version = "3.12.0" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "byteorder" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" - -[[package]] -name = "cache-padded" -version = "1.1.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "631ae5198c9be5e753e5cc215e1bd73c2b466a3565173db433f52bb9d3e66dba" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "cc" -version = "1.0.72" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee" +checksum = "2678b2e3449475e95b0aa6f9b506a28e61b3dc8996592b983695e8ebb58a8b41" [[package]] name = "cfg-if" @@ -369,234 +478,317 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] -name = "chrono" -version = "0.4.19" +name = "colorchoice" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" -dependencies = [ - "libc", - "num-integer", - "num-traits", - "serde", - "time", - "winapi", -] +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] name = "colored" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" +checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" dependencies = [ - "atty", "lazy_static", - "winapi", + "windows-sys 0.48.0", ] [[package]] name = "concurrent-queue" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ed07550be01594c6026cff2a1d7fe9c8f683caa798e12b68694ac9e88286a3" -dependencies = [ - "cache-padded", -] - -[[package]] -name = "core-foundation" -version = "0.9.2" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6888e10551bb93e424d8df1d07f1a8b4fceb0001a3a4b048bfc47554946f47b3" +checksum = "d16048cd947b08fa32c24458a22f5dc5e835264f689f4f5653210c69fd107363" dependencies = [ - "core-foundation-sys", - "libc", + "crossbeam-utils", ] [[package]] -name = "core-foundation-sys" -version = "0.8.3" +name = "const-oid" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "cpufeatures" -version = "0.2.1" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" dependencies = [ "libc", ] [[package]] name = "crc" -version = "2.1.0" +version = "3.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49fc9a695bca7f35f5f4c15cddc84415f66a74ea78eef08e90c5024f2b540e23" +checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" dependencies = [ "crc-catalog", ] [[package]] name = "crc-catalog" -version = "1.1.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccaeedb56da03b09f598226e25e80088cb4cd25f316e6e4df7d695f0feeb1403" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" [[package]] name = "crossbeam-channel" -version = "0.5.1" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4" +checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95" dependencies = [ - "cfg-if", "crossbeam-utils", ] [[package]] -name = "crossbeam-queue" -version = "0.3.2" +name = "crossbeam-epoch" +version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b10ddc024425c88c2ad148c1b0fd53f4c6d38db9697c9f1588381212fa657c9" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ - "cfg-if", "crossbeam-utils", ] [[package]] -name = "crossbeam-utils" -version = "0.8.8" +name = "crossbeam-queue" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" +checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" dependencies = [ - "cfg-if", - "lazy_static", + "crossbeam-utils", ] [[package]] -name = "crypto-mac" -version = "0.11.1" +name = "crossbeam-utils" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" + +[[package]] +name = "crypto-common" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", - "subtle", + "typenum", ] [[package]] -name = "ctor" -version = "0.1.21" +name = "der" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccc0a48a9b826acdf4028595adc9db92caea352f7af011a3034acd172a52a0aa" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" dependencies = [ - "quote", - "syn", + "const-oid", + "pem-rfc7468", + "zeroize", ] [[package]] -name = "digest" -version = "0.9.0" +name = "deranged" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" dependencies = [ - "generic-array", + "powerfmt", ] [[package]] -name = "dirs" -version = "3.0.2" +name = "derivative" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30baa043103c9d0c2a57cf537cc2f35623889dc0d405e6c3cccfadbc81c71309" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" dependencies = [ - "dirs-sys", + "proc-macro2", + "quote", + "syn 1.0.109", ] [[package]] -name = "dirs-sys" -version = "0.3.6" +name = "digest" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "libc", - "redox_users", - "winapi", + "block-buffer", + "const-oid", + "crypto-common", + "subtle", ] [[package]] -name = "dotenv" -version = "0.15.0" +name = "dotenvy" +version = "0.15.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" [[package]] name = "either" -version = "1.6.1" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" +checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" +dependencies = [ + "serde", +] [[package]] name = "encoding_rs" -version = "0.8.30" +version = "0.8.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dc8abb250ffdda33912550faa54c88ec8b998dec0b2c55ab224921ce11df" +checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" dependencies = [ "cfg-if", ] [[package]] -name = "event-listener" -version = "2.5.1" +name = "env_filter" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7531096570974c3a9dcf9e4b8e1cede1ec26cf5046219fb3b9d897503b9be59" +checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea" +dependencies = [ + "log", + "regex", +] [[package]] -name = "fastrand" -version = "1.7.0" +name = "env_logger" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" +checksum = "38b35839ba51819680ba087cd351788c9a3c476841207e0b8cee0b04722343b9" dependencies = [ - "instant", + "anstream", + "anstyle", + "env_filter", + "humantime", + "log", ] [[package]] -name = "fnv" -version = "1.0.7" +name = "equivalent" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] -name = "foreign-types" -version = "0.3.2" +name = "errno" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" dependencies = [ - "foreign-types-shared", + "libc", + "windows-sys 0.52.0", ] [[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.0.1" +name = "etcetera" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" +checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" dependencies = [ - "matches", - "percent-encoding", + "cfg-if", + "home", + "windows-sys 0.48.0", ] [[package]] -name = "futures" -version = "0.3.18" +name = "event-listener" +version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cd0210d8c325c245ff06fd95a3b13689a1a276ac8cfa8e8720cb840bfb84b9e" -dependencies = [ - "futures-channel", +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + +[[package]] +name = "event-listener" +version = "4.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b215c49b2b248c855fb73579eb1f4f26c38ffdc12973e20e07b91d78d5646e" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d9944b8ca13534cdfb2800775f8dd4902ff3fc75a50101466decadfdf322a24" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3" +dependencies = [ + "event-listener 4.0.3", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "332f51cb23d20b0de8458b86580878211da09bcd4503cb579c225b3d124cabb3" +dependencies = [ + "event-listener 5.3.0", + "pin-project-lite", +] + +[[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.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" + +[[package]] +name = "finl_unicode" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fcfdc7a0362c9f4444381a9e697c79d435fe65b52a37466fc2c1184cee9edc6" + +[[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 0.9.8", +] + +[[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" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +dependencies = [ + "futures-channel", "futures-core", - "futures-executor", "futures-io", "futures-sink", "futures-task", @@ -605,9 +797,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.21" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" dependencies = [ "futures-core", "futures-sink", @@ -615,15 +807,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.21" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" [[package]] name = "futures-executor" -version = "0.3.18" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b808bf53348a36cab739d7e04755909b9fcaaa69b7d7e588b37b6ec62704c97" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" dependencies = [ "futures-core", "futures-task", @@ -632,9 +824,9 @@ dependencies = [ [[package]] name = "futures-intrusive" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62007592ac46aa7c2b6416f7deb9a8a8f63a01e0f1d6e1787d5630170db2b63e" +checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" dependencies = [ "futures-core", "lock_api", @@ -643,17 +835,17 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.21" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" [[package]] name = "futures-lite" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7694489acd39452c77daa48516b894c153f192c3578d5a839b62c58099fcbf48" +checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" dependencies = [ - "fastrand", + "fastrand 1.9.0", "futures-core", "futures-io", "memchr", @@ -662,34 +854,47 @@ dependencies = [ "waker-fn", ] +[[package]] +name = "futures-lite" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" +dependencies = [ + "fastrand 2.0.2", + "futures-core", + "futures-io", + "parking", + "pin-project-lite", +] + [[package]] name = "futures-macro" -version = "0.3.21" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.58", ] [[package]] name = "futures-sink" -version = "0.3.21" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" [[package]] name = "futures-task" -version = "0.3.21" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" [[package]] name = "futures-util" -version = "0.3.21" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ "futures-channel", "futures-core", @@ -705,9 +910,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.4" +version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", @@ -715,82 +920,66 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.3" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" dependencies = [ "cfg-if", "libc", "wasi", ] +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + [[package]] name = "gloo-timers" -version = "0.2.2" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f16c88aa13d2656ef20d1c042086b8767bbe2bdb62526894275a1b062161b2e" +checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" dependencies = [ "futures-channel", "futures-core", "js-sys", "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "h2" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66b91535aa35fea1523ad1b86cb6b53c28e0ae566ba4a460f4457e936cad7c6f" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", ] [[package]] name = "hashbrown" -version = "0.11.2" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" dependencies = [ "ahash", + "allocator-api2", ] [[package]] name = "hashlink" -version = "0.7.0" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7249a3129cbc1ffccd74857f81464a323a152173cdb134e0fd81bc803b29facf" +checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" dependencies = [ "hashbrown", ] [[package]] name = "heck" -version = "0.3.3" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" dependencies = [ "unicode-segmentation", ] [[package]] name = "hermit-abi" -version = "0.1.19" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "hex" @@ -799,113 +988,90 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] -name = "hmac" -version = "0.11.0" +name = "hkdf" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" dependencies = [ - "crypto-mac", - "digest", + "hmac", ] [[package]] -name = "http" -version = "0.2.5" +name = "hmac" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1323096b05d41827dadeaee54c9981958c0f94e670bc94ed80037d1a7b8b186b" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "bytes", - "fnv", - "itoa 0.4.8", + "digest", ] [[package]] -name = "http-body" -version = "0.4.4" +name = "home" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ff4f84919677303da5f147645dbea6b1881f368d03ac84e1dc09031ebd7b2c6" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" dependencies = [ - "bytes", - "http", - "pin-project-lite", + "windows-sys 0.52.0", ] [[package]] name = "httparse" -version = "1.5.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acd94fdbe1d4ff688b67b04eee2e17bd50995534a61539e45adfefb45e5e5503" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" [[package]] name = "httpdate" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "humansize" -version = "1.1.1" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02296996cb8796d7c6e3bc2d9211b7802812d36999a51bb754123ead7d37d026" - -[[package]] -name = "hyper" -version = "0.14.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7ec3e62bdc98a2f0393a5048e4c30ef659440ea6e0e572965103e72bd836f55" +checksum = "6cb51c9a029ddc91b07a787f1d86b53ccfa49b0e86688c946ebe8d3555685dd7" dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "httparse", - "httpdate", - "itoa 0.4.8", - "pin-project-lite", - "socket2", - "tokio", - "tower-service", - "tracing", - "want", + "libm", ] [[package]] -name = "hyper-tls" -version = "0.5.0" +name = "humantime" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" -dependencies = [ - "bytes", - "hyper", - "native-tls", - "tokio", - "tokio-native-tls", -] +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "idna" -version = "0.2.3" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ - "matches", "unicode-bidi", "unicode-normalization", ] [[package]] name = "indexmap" -version = "1.7.0" +version = "2.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ - "autocfg", + "equivalent", "hashbrown", ] +[[package]] +name = "inherent" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0122b7114117e64a63ac49f752a5ca4624d534c7b1c7de796ac196381cd2d947" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.58", +] + [[package]] name = "instant" version = "0.1.12" @@ -916,37 +1082,56 @@ dependencies = [ ] [[package]] -name = "ipnet" -version = "2.3.1" +name = "io-lifetimes" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68f2d64f2edebec4ce84ad108148e67e1064789bee435edc5b60ad398714a3a9" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys 0.48.0", +] [[package]] name = "itertools" -version = "0.10.3" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" dependencies = [ "either", ] [[package]] name = "itoa" -version = "0.4.8" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] -name = "itoa" -version = "1.0.1" +name = "jemalloc-sys" +version = "0.5.4+5.3.0-patched" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac6c1946e1cea1788cbfde01c993b52a10e2da07f4bac608228d1bed20bfebf2" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "jemallocator" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" +checksum = "a0de374a9f8e63150e6f5e8a60cc14c668226d7a347d8aee1a45766e3c4dd3bc" +dependencies = [ + "jemalloc-sys", + "libc", +] [[package]] name = "js-sys" -version = "0.3.55" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" dependencies = [ "wasm-bindgen", ] @@ -965,77 +1150,85 @@ name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin 0.5.2", +] [[package]] name = "libc" -version = "0.2.112" +version = "0.2.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" + +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[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.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + +[[package]] +name = "linux-raw-sys" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" [[package]] name = "lock_api" -version = "0.4.5" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" dependencies = [ + "autocfg", "scopeguard", ] [[package]] name = "log" -version = "0.4.14" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" dependencies = [ - "cfg-if", "value-bag", ] -[[package]] -name = "matches" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" - [[package]] name = "md-5" -version = "0.9.1" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5a279bb9607f9f53c22d496eade00d138d1bdcccd07d74650387cf94942a15" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" dependencies = [ - "block-buffer", + "cfg-if", "digest", - "opaque-debug", ] [[package]] name = "memchr" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" - -[[package]] -name = "memmem" -version = "0.1.1" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a64a92489e2744ce060c349162be1c5f33c6969234104dbd99ddb5feb08b8c15" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" [[package]] name = "mime" -version = "0.3.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" - -[[package]] -name = "mime-db" -version = "1.6.0" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d7c816ec30c41f873e1eea969aa2261d78756629e468a427244ff8658b75e7d" -dependencies = [ - "reqwest", - "serde", - "tokio", -] +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "mime_guess" @@ -1054,247 +1247,234 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] -name = "mio" -version = "0.7.14" +name = "miniz_oxide" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc" +checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" dependencies = [ - "libc", - "log", - "miow", - "ntapi", - "winapi", + "adler", ] [[package]] -name = "miow" -version = "0.3.7" +name = "mio" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ - "winapi", + "libc", + "wasi", + "windows-sys 0.48.0", ] [[package]] -name = "native-tls" -version = "0.2.8" +name = "moka" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48ba9f7719b5a0f42f338907614285fb5fd70e53858141f69898a1fb7203b24d" +checksum = "87bfd249f570638bfb0b4f9d258e6b8cddd2a5a7d0ed47e8bb8b176bfc0e7a17" dependencies = [ - "lazy_static", - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", + "async-lock 3.3.0", + "async-trait", + "crossbeam-channel", + "crossbeam-epoch", + "crossbeam-utils", + "event-listener 5.3.0", + "futures-util", + "once_cell", + "parking_lot", + "quanta", + "rustc_version", + "smallvec", + "tagptr", + "thiserror", + "triomphe", + "uuid", ] [[package]] name = "nom" -version = "7.1.0" +version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1d11e1ef389c76fe5b81bcaf2ea32cf88b62bc494e19f493d0b30e7a930109" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" dependencies = [ "memchr", "minimal-lexical", - "version_check", -] - -[[package]] -name = "ntapi" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" -dependencies = [ - "winapi", ] [[package]] -name = "num-bigint" -version = "0.3.3" +name = "num-bigint-dig" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6f7833f2cbf2360a6cfd58cd41a53aa7a90bd4c202f5b1c7dd2ed73c57b2c3" +checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" dependencies = [ - "autocfg", + "byteorder", + "lazy_static", + "libm", "num-integer", + "num-iter", "num-traits", + "rand", + "smallvec", + "zeroize", ] [[package]] -name = "num-integer" +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.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +checksum = "d869c01cc0c455284163fd0092f1f93835385ccab5a98a0dcc497b2f8bf055a9" dependencies = [ "autocfg", + "num-integer", "num-traits", ] [[package]] name = "num-traits" -version = "0.2.14" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" dependencies = [ "autocfg", + "libm", ] [[package]] name = "num_cpus" -version = "1.13.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ "hermit-abi", "libc", ] [[package]] -name = "once_cell" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" - -[[package]] -name = "opaque-debug" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" - -[[package]] -name = "openssl" -version = "0.10.55" +name = "num_threads" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "345df152bc43501c5eb9e4654ff05f794effb78d4efe3d53abc158baddc0703d" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" dependencies = [ - "bitflags", - "cfg-if", - "foreign-types", "libc", - "once_cell", - "openssl-macros", - "openssl-sys", ] [[package]] -name = "openssl-macros" -version = "0.1.0" +name = "object" +version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" dependencies = [ - "proc-macro2", - "quote", - "syn", + "memchr", ] [[package]] -name = "openssl-probe" -version = "0.1.4" +name = "once_cell" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] -name = "openssl-sys" -version = "0.9.90" +name = "ordered-float" +version = "3.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374533b0e45f3a7ced10fcaeccca020e66656bc03dac384f852e4e5a7a8104a6" +checksum = "f1e1c390732d15f1d48471625cd92d154e66db2c56645e29a9cd26f4699f72dc" dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", + "num-traits", ] [[package]] name = "ouroboros" -version = "0.14.2" +version = "0.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71643f290d126e18ac2598876d01e1d57aed164afc78fdb6e2a0c6589a1f6662" +checksum = "e2ba07320d39dfea882faa70554b4bd342a5f273ed59ba7c1c6b4c840492c954" dependencies = [ "aliasable", "ouroboros_macro", - "stable_deref_trait", + "static_assertions", ] [[package]] name = "ouroboros_macro" -version = "0.14.2" +version = "0.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed9a247206016d424fe8497bc611e510887af5c261fbbf977877c4bb55ca4d82" +checksum = "ec4c6225c69b4ca778c0aea097321a64c421cf4577b331c61b229267edabb6f8" dependencies = [ - "Inflector", + "heck", "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 2.0.58", ] [[package]] name = "parking" -version = "2.0.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" +checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" [[package]] name = "parking_lot" -version = "0.11.2" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ - "instant", "lock_api", "parking_lot_core", ] [[package]] name = "parking_lot_core" -version = "0.8.5" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" dependencies = [ "cfg-if", - "instant", "libc", "redox_syscall", "smallvec", - "winapi", + "windows-targets 0.48.5", ] [[package]] -name = "percent-encoding" -version = "2.1.0" +name = "paste" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" [[package]] -name = "pin-project" -version = "1.0.8" +name = "pem-rfc7468" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "576bc800220cc65dac09e99e97b08b358cfab6e17078de8dc5fee223bd2d0c08" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" dependencies = [ - "pin-project-internal", + "base64ct", ] [[package]] -name = "pin-project-internal" -version = "1.0.8" +name = "percent-encoding" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e8fe8163d14ce7f0cdac2e040116f22eac817edabff0be91e8aff7e9accf389" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pin-project-lite" -version = "0.2.7" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pin-utils" @@ -1302,30 +1482,86 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "piper" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "668d31b1c4eba19242f2088b2bf3316b82ca31082a8335764db4e083db7485d4" +dependencies = [ + "atomic-waker", + "fastrand 2.0.2", + "futures-io", +] + +[[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.24" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "polling" -version = "2.2.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "685404d509889fade3e86fe3a5803bca2ec09b0c0778d5ada6ec8bf7a8de5259" +checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" dependencies = [ + "autocfg", + "bitflags 1.3.2", "cfg-if", + "concurrent-queue", "libc", "log", - "wepoll-ffi", - "winapi", + "pin-project-lite", + "windows-sys 0.48.0", ] +[[package]] +name = "polling" +version = "3.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0c976a60b2d7e99d6f229e414670a9b85d13ac305cc6d1e9c134de58c5aaaf6" +dependencies = [ + "cfg-if", + "concurrent-queue", + "hermit-abi", + "pin-project-lite", + "rustix 0.38.32", + "tracing", + "windows-sys 0.52.0", +] + +[[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.15" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro-error" @@ -1336,7 +1572,7 @@ dependencies = [ "proc-macro-error-attr", "proc-macro2", "quote", - "syn", + "syn 1.0.109", "version_check", ] @@ -1353,32 +1589,46 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.33" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quanta" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb37d2df5df740e582f28f8560cf425f52bb267d872fe58358eadb554909f07a" +checksum = "8e5167a477619228a0b284fac2674e3c388cba90631d7b7de620e6f1fcd08da5" dependencies = [ - "unicode-xid", + "crossbeam-utils", + "libc", + "once_cell", + "raw-cpuid", + "wasi", + "web-sys", + "winapi", ] [[package]] name = "quote" -version = "1.0.10" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] [[package]] name = "rand" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", "rand_core", - "rand_hc", ] [[package]] @@ -1393,327 +1643,300 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ "getrandom", ] [[package]] -name = "rand_hc" -version = "0.3.1" +name = "raw-cpuid" +version = "11.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" +checksum = "9d86a7c4638d42c44551f4791a20e687dbb4c3de1f33c43dd71e355cd429def1" dependencies = [ - "rand_core", + "bitflags 2.5.0", ] [[package]] name = "redox_syscall" -version = "0.2.10" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] -name = "redox_users" -version = "0.4.0" +name = "regex" +version = "1.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" +checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" dependencies = [ - "getrandom", - "redox_syscall", + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", ] [[package]] -name = "remove_dir_all" -version = "0.5.3" +name = "regex-automata" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" dependencies = [ - "winapi", + "aho-corasick", + "memchr", + "regex-syntax", ] [[package]] -name = "reqwest" -version = "0.11.7" +name = "regex-syntax" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bea77bc708afa10e59905c3d4af7c8fd43c9214251673095ff8b14345fcbc5" -dependencies = [ - "base64", - "bytes", - "encoding_rs", - "futures-core", - "futures-util", - "http", - "http-body", - "hyper", - "hyper-tls", - "ipnet", - "js-sys", - "lazy_static", - "log", - "mime", - "native-tls", - "percent-encoding", - "pin-project-lite", - "serde", - "serde_json", - "serde_urlencoded", - "tokio", - "tokio-native-tls", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "winreg", -] +checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" [[package]] name = "rlimit" -version = "0.6.2" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc0bf25554376fd362f54332b8410a625c71f15445bca32ffdfdf4ec9ac91726" +checksum = "3560f70f30a0f16d11d01ed078a07740fe6b489667abc7c7b029155d9f21c3d8" dependencies = [ "libc", ] [[package]] name = "routefinder" -version = "0.5.1" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "480a056df7cdee2fd55df6dc10ce137c70b00cc65f20a16f796d2250ef8e0cd8" +checksum = "0971d3c8943a6267d6bd0d782fdc4afa7593e7381a92a3df950ff58897e066b5" dependencies = [ + "memchr", "smartcow", "smartstring", ] [[package]] -name = "rust_decimal" -version = "1.18.0" +name = "rsa" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71b5a9625a7e6060b23db692facf49082cc78889a7e6ac94a735356ae49db4b0" +checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc" dependencies = [ - "arrayvec", + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", "num-traits", - "serde", + "pkcs1", + "pkcs8", + "rand_core", + "signature", + "spki", + "subtle", + "zeroize", ] [[package]] -name = "rustversion" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f" - -[[package]] -name = "ryu" -version = "1.0.9" +name = "rustc-demangle" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] -name = "schannel" -version = "0.1.19" +name = "rustc_version" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "lazy_static", - "winapi", + "semver", ] [[package]] -name = "scopeguard" -version = "1.1.0" +name = "rustix" +version = "0.37.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" +dependencies = [ + "bitflags 1.3.2", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys 0.3.8", + "windows-sys 0.48.0", +] [[package]] -name = "sea-orm" -version = "0.6.0" +name = "rustix" +version = "0.38.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd24380b48dacd3ed1c3d467c7b17ffa5818555a2c04066f4a0a9e17d830abc9" +checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89" dependencies = [ - "async-stream", - "async-trait", - "chrono", - "futures", - "futures-util", - "once_cell", - "ouroboros", - "rust_decimal", - "sea-orm-macros", - "sea-query", - "sea-strum", - "serde", - "serde_json", - "sqlx", - "tracing", - "url", - "uuid", + "bitflags 2.5.0", + "errno", + "libc", + "linux-raw-sys 0.4.13", + "windows-sys 0.52.0", ] [[package]] -name = "sea-orm-macros" -version = "0.6.0" +name = "ryu" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c199fa8630b1e195d7aef24ce8944af8f4ced67c4eccffd8926453b59f2565a1" -dependencies = [ - "bae", - "heck", - "proc-macro2", - "quote", - "syn", -] +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" [[package]] -name = "sea-query" -version = "0.21.0" +name = "scopeguard" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9088ff96158860a75d98a85a654fdd9d97b10515773af6d87339bfc48258c800" -dependencies = [ - "chrono", - "rust_decimal", - "sea-query-derive", - "serde_json", - "uuid", -] +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] -name = "sea-query-derive" +name = "sea-bae" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34cdc022b4f606353fe5dc85b09713a04e433323b70163e81513b141c6ae6eb5" +checksum = "3bd3534a9978d0aa7edd2808dc1f8f31c4d0ecd31ddf71d997b3c98e9f3c9114" dependencies = [ "heck", + "proc-macro-error", "proc-macro2", "quote", - "syn", - "thiserror", + "syn 2.0.58", ] [[package]] -name = "sea-strum" -version = "0.23.0" +name = "sea-orm" +version = "0.12.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "391d06a6007842cfe79ac6f7f53911b76dfd69fc9a6769f1cf6569d12ce20e1b" +checksum = "c8814e37dc25de54398ee62228323657520b7f29713b8e238649385dbe473ee0" dependencies = [ - "sea-strum_macros", + "async-stream", + "async-trait", + "futures", + "log", + "ouroboros", + "sea-orm-macros", + "sea-query", + "sea-query-binder", + "serde", + "sqlx", + "strum", + "thiserror", + "tracing", + "url", ] [[package]] -name = "sea-strum_macros" -version = "0.23.0" +name = "sea-orm-macros" +version = "0.12.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69b4397b825df6ccf1e98bcdabef3bbcfc47ff5853983467850eeab878384f21" +checksum = "5e115c6b078e013aa963cc2d38c196c2c40b05f03d0ac872fe06b6e0d5265603" dependencies = [ "heck", "proc-macro2", "quote", - "rustversion", - "syn", + "sea-bae", + "syn 2.0.58", + "unicode-ident", ] [[package]] -name = "security-framework" -version = "2.4.2" +name = "sea-query" +version = "0.30.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525bc1abfda2e1998d152c45cf13e696f76d0a4972310b22fac1658b05df7c87" +checksum = "4166a1e072292d46dc91f31617c2a1cdaf55a8be4b5c9f4bf2ba248e3ac4999b" dependencies = [ - "bitflags", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", + "derivative", + "inherent", + "ordered-float", ] [[package]] -name = "security-framework-sys" -version = "2.4.2" +name = "sea-query-binder" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9dd14d83160b528b7bfd66439110573efcfbe281b17fc2ca9f39f550d619c7e" +checksum = "36bbb68df92e820e4d5aeb17b4acd5cc8b5d18b2c36a4dd6f4626aabfa7ab1b9" dependencies = [ - "core-foundation-sys", - "libc", + "sea-query", + "sqlx", ] +[[package]] +name = "semver" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" + [[package]] name = "serde" -version = "1.0.136" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.136" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.58", ] [[package]] name = "serde_json" -version = "1.0.79" +version = "1.0.115" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95" +checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" dependencies = [ - "indexmap", - "itoa 1.0.1", + "itoa", "ryu", "serde", ] [[package]] name = "serde_urlencoded" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edfa57a7f8d9c1d260a549e7224100f6c43d43f9103e06dd8b4095a9b2b43ce9" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" dependencies = [ "form_urlencoded", - "itoa 0.4.8", + "itoa", "ryu", "serde", ] [[package]] -name = "sha-1" -version = "0.9.8" +name = "sha1" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ - "block-buffer", "cfg-if", "cpufeatures", "digest", - "opaque-debug", ] [[package]] name = "sha2" -version = "0.9.8" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b69f9a4c9740d74c5baa3fd2e547f9525fa8088a8a958e0ca2409a514e33f5fa" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ - "block-buffer", "cfg-if", "cpufeatures", "digest", - "opaque-debug", ] [[package]] name = "signal-hook" -version = "0.3.12" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c35dfd12afb7828318348b8c408383cf5071a086c1d4ab1c0f9840ec92dbb922" +checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" dependencies = [ "libc", "signal-hook-registry", @@ -1721,79 +1944,138 @@ dependencies = [ [[package]] name = "signal-hook-async-std" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90526e74631c69a79b38212e3d4fda4b00de9d6be56b3cead133bf67ad371af1" +checksum = "0c4aa94397e2023af5b7cff5b8d4785e935cfb77f0e4aab0cae3b26258ace556" dependencies = [ - "async-io", - "futures-lite", + "async-io 1.13.0", + "futures-lite 1.13.0", "libc", "signal-hook", ] [[package]] name = "signal-hook-registry" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" dependencies = [ "libc", ] [[package]] -name = "size" -version = "0.1.2" +name = "signal-hook-tokio" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e5021178e8e70579d009fb545932e274ec2dde4c917791c6063d1002bee2a56" +checksum = "213241f76fb1e37e27de3b6aa1b068a2c333233b59cca6634f634b80a27ecf1e" dependencies = [ - "num-traits", + "futures-core", + "libc", + "signal-hook", + "tokio", ] +[[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 = "size" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fed904c7fb2856d868b92464fc8fa597fce366edea1a9cbfaa8cb5fe080bd6d" + [[package]] name = "slab" -version = "0.4.5" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] [[package]] name = "smallvec" -version = "1.7.0" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "smartcow" -version = "0.1.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05e3ed3ccf93c7425507e5e2261a3fc90d14267d491f360b9b679ae0a4ce693e" +checksum = "656fcb1c1fca8c4655372134ce87d8afdf5ec5949ebabe8d314be0141d8b5da2" dependencies = [ "smartstring", ] [[package]] name = "smartstring" -version = "0.2.9" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31aa6a31c0c2b21327ce875f7e8952322acfcfd0c27569a6e18a647281352c9b" +checksum = "3fb72c633efbaa2dd666986505016c32c3044395ceaf881518399d2f4127ee29" dependencies = [ + "autocfg", "static_assertions", + "version_check", ] [[package]] name = "socket2" -version = "0.4.2" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dc90fe6c7be1a323296982db1836d1ea9e47b6839496dde9a541bc496df3516" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" dependencies = [ "libc", "winapi", ] +[[package]] +name = "socket2" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[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.1.8" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4b7922be017ee70900be125523f38bdd644f4f06a1b16e8fa5a8ee8c34bffd4" +checksum = "ce81b7bd7c4493975347ef60d8c7e8b742d4694f4c49f93e0a12ea263938176c" dependencies = [ "itertools", "nom", @@ -1802,102 +2084,200 @@ dependencies = [ [[package]] name = "sqlx" -version = "0.5.9" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7911b0031a0247af40095838002999c7a52fba29d9739e93326e71a5a1bc9d43" +checksum = "c9a2ccff1a000a5a59cd33da541d9f2fdcd9e6e8229cc200565942bff36d0aaa" dependencies = [ "sqlx-core", "sqlx-macros", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", ] [[package]] name = "sqlx-core" -version = "0.5.9" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aec89bfaca8f7737439bad16d52b07f1ccd0730520d3bf6ae9d069fe4b641fb1" +checksum = "24ba59a9342a3d9bab6c56c118be528b27c9b60e490080e9711a04dccac83ef6" dependencies = [ "ahash", + "async-io 1.13.0", + "async-std", "atoi", - "base64", - "bitflags", "byteorder", "bytes", - "chrono", "crc", - "crossbeam-channel", "crossbeam-queue", - "crossbeam-utils", - "dirs", "either", + "event-listener 2.5.3", "futures-channel", "futures-core", "futures-intrusive", + "futures-io", "futures-util", "hashlink", "hex", - "hmac", "indexmap", - "itoa 0.4.8", - "libc", "log", - "md-5", "memchr", - "num-bigint", "once_cell", - "parking_lot", + "paste", "percent-encoding", - "rand", - "rust_decimal", "serde", "serde_json", - "sha-1", "sha2", "smallvec", "sqlformat", - "sqlx-rt", - "stringprep", "thiserror", + "tokio", + "tokio-stream", + "tracing", "url", - "uuid", - "whoami", ] [[package]] name = "sqlx-macros" -version = "0.5.9" +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 = "584866c833511b1a152e87a7ee20dee2739746f60c858b3c5209150bc4b466f5" +checksum = "5833ef53aaa16d860e92123292f1f6a3d53c34ba8b1969f152ef1a7bb803f3c8" dependencies = [ - "dotenv", + "async-std", + "dotenvy", "either", "heck", + "hex", "once_cell", "proc-macro2", "quote", + "serde", "serde_json", "sha2", "sqlx-core", - "sqlx-rt", - "syn", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", + "syn 1.0.109", + "tempfile", + "tokio", "url", ] [[package]] -name = "sqlx-rt" -version = "0.5.9" +name = "sqlx-mysql" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d1bd069de53442e7a320f525a6d4deb8bb0621ac7a55f7eccbc2b58b57f43d0" +checksum = "1ed31390216d20e538e447a7a9b959e06ed9fc51c37b514b46eb758016ecd418" dependencies = [ - "async-native-tls", - "async-std", - "native-tls", + "atoi", + "base64", + "bitflags 2.5.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 = "stable_deref_trait" -version = "1.2.0" +name = "sqlx-postgres" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c824eb80b894f926f89a0b9da0c7f435d27cdd35b8c655b114e58223918577e" +dependencies = [ + "atoi", + "base64", + "bitflags 2.5.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 = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +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 = "static_assertions" @@ -1907,175 +2287,179 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "stopper" -version = "0.2.0" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4573bf2456e356934de15c7151d1c9fc8873e8866a7c2b5e0bb20f8244bd0073" +checksum = "66c82d03d16a1e591756e978782ce4bc4300f83048b57d44c5600dafa7337019" dependencies = [ - "futures-lite", - "pin-project", - "waker-set", + "event-listener 5.3.0", + "futures-lite 2.3.0", + "pin-project-lite", ] [[package]] name = "stringprep" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ee348cb74b87454fff4b551cbf727025810a004f88aeacae7f85b87f4e9a1c1" +checksum = "bb41d74e231a107a1b4ee36bd1214b11285b77768d2e3824aedafa988fd36ee6" dependencies = [ + "finl_unicode", "unicode-bidi", "unicode-normalization", ] +[[package]] +name = "strum" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" + [[package]] name = "subtle" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + +[[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 = "1.0.82" +version = "2.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59" +checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687" dependencies = [ "proc-macro2", "quote", - "unicode-xid", + "unicode-ident", ] +[[package]] +name = "tagptr" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" + [[package]] name = "tempfile" -version = "3.2.0" +version = "3.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ "cfg-if", - "libc", - "rand", - "redox_syscall", - "remove_dir_all", - "winapi", + "fastrand 2.0.2", + "rustix 0.38.32", + "windows-sys 0.52.0", ] [[package]] name = "thiserror" -version = "1.0.30" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" +checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.30" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" +checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.58", ] [[package]] name = "time" -version = "0.1.44" +version = "0.3.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" dependencies = [ + "deranged", + "itoa", "libc", - "wasi", - "winapi", -] - -[[package]] -name = "tinyvec" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2" -dependencies = [ - "tinyvec_macros", + "num-conv", + "num_threads", + "powerfmt", + "serde", + "time-core", + "time-macros", ] [[package]] -name = "tinyvec_macros" -version = "0.1.0" +name = "time-core" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] -name = "tokio" -version = "1.14.0" +name = "time-macros" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70e992e41e0d2fb9f755b37446f20900f64446ef54874f40a60c78f021ac6144" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" dependencies = [ - "autocfg", - "bytes", - "libc", - "memchr", - "mio", - "pin-project-lite", - "tokio-macros", - "winapi", + "num-conv", + "time-core", ] [[package]] -name = "tokio-macros" +name = "tinyvec" version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9efc1aba077437943f7515666aa2b882dfabfbfdf89c819ea75a8d6e9eaba5e" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" dependencies = [ - "proc-macro2", - "quote", - "syn", + "tinyvec_macros", ] [[package]] -name = "tokio-native-tls" -version = "0.3.0" +name = "tinyvec_macros" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" -dependencies = [ - "native-tls", - "tokio", -] +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] -name = "tokio-util" -version = "0.7.2" +name = "tokio" +version = "1.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f988a1a1adc2fb21f9c12aa96441da33a1728193ae0b95d2be22dbd17fcb4e5c" +checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" dependencies = [ + "backtrace", "bytes", - "futures-core", - "futures-sink", + "libc", + "mio", + "num_cpus", "pin-project-lite", - "tokio", - "tracing", + "socket2 0.5.6", + "windows-sys 0.48.0", ] [[package]] -name = "toml" -version = "0.5.8" +name = "tokio-stream" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" +checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" dependencies = [ - "serde", + "futures-core", + "pin-project-lite", + "tokio", ] -[[package]] -name = "tower-service" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" - [[package]] name = "tracing" -version = "0.1.29" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "cfg-if", "log", "pin-project-lite", "tracing-attributes", @@ -2084,32 +2468,31 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.19" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8276d9a4a3a558d7b7ad5303ad50b53d58264641b82914b7ada36bd762e7a716" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.58", ] [[package]] name = "tracing-core" -version = "0.1.21" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4ed65637b8390770814083d20756f87bfa2c21bf2f110babdc5438351746e4" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ - "lazy_static", + "once_cell", ] [[package]] name = "trillium" -version = "0.2.2" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a229016cb2f3be4209b40cfbd2f3a0cd11aa7d283be8f4612219227d3e4014e4" +checksum = "01c7180eac36666f14504c5a8606d027154a8e3a4704bd0acc69a13f56c202b6" dependencies = [ "async-trait", - "futures-lite", "log", "trillium-http", ] @@ -2129,20 +2512,20 @@ dependencies = [ [[package]] name = "trillium-askama" -version = "0.3.0" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace69c685aec173f963a8ab9cb44a0efb07519878c528d1863e78a153e31331c" +checksum = "f0a4eeb5246ff1baea3c81782ee46bc4601463d75d6a8502bcf44890456b4c1e" dependencies = [ "askama", - "mime-db", + "mime_guess", "trillium", ] [[package]] name = "trillium-async-std" -version = "0.2.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aaba69d82fa40cfb4ec00169ec29cad318dfbe6e4030d5a24916ef0b29131c16" +checksum = "1f753f918df0a52066abc1aeb1a7c09dca60c2edcc1d0fa285a0d4fde1617392" dependencies = [ "async-std", "log", @@ -2150,49 +2533,72 @@ dependencies = [ "signal-hook-async-std", "trillium", "trillium-http", + "trillium-macros 0.0.5", "trillium-server-common", ] [[package]] name = "trillium-http" -version = "0.2.6" +version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35699b044a43f0284c9726c78bbea94828edb7ffbd8d7ad552f04506da256747" +checksum = "a18d82a9418c6fc1a872bc163fffd49320229edf783cbbb1aa62ba49f517cfad" dependencies = [ "encoding_rs", - "futures-lite", + "futures-lite 2.3.0", "hashbrown", "httparse", "httpdate", "log", - "memmem", + "memchr", "mime", "smallvec", "smartcow", "smartstring", "stopper", "thiserror", + "trillium-macros 0.0.6", ] [[package]] name = "trillium-logger" -version = "0.4.0" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21a01e95a1a2021c465ed2773f9be589bc3b0138523389fd99366d1537c70fcd" +checksum = "da5e9b6c08a27d991b4a9c73dd7276c6f181fd4dee7218723b0fbd7fca3a1659" dependencies = [ - "atty", - "chrono", "colored", "log", "size", + "time", "trillium", ] +[[package]] +name = "trillium-macros" +version = "0.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "916054381183f0cfed7604bf7de2044a760624a50d26eef5492468fb73083bbb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.58", +] + +[[package]] +name = "trillium-macros" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "916e37646d33632b88ca02d4b8c4e2e6376f2a89d9888de71b7d82c150ed1f6c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.58", +] + [[package]] name = "trillium-router" -version = "0.3.2" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20eb6edfe01b2df89944e0371453dbc288d94cf8b779f9fbd89c24ed923217a9" +checksum = "6a7aed20d63101d7dcd165fd047141423009a7f4ccfc75db5b875312d8127dbe" dependencies = [ "log", "routefinder", @@ -2201,18 +2607,39 @@ dependencies = [ [[package]] name = "trillium-server-common" -version = "0.3.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02f8a8649680599d1142d454668be5f864f81809d77543ec5ac615b73241b8aa" +checksum = "a96faa60ceaf4b575886eb7d2ad3df4371acf67e0a4489585cccd4ff18966103" dependencies = [ - "atomic-waker", - "futures-lite", + "async-trait", + "async_cell", + "event-listener 4.0.3", + "futures-lite 2.3.0", "log", "pin-project-lite", "rlimit", "trillium", "trillium-http", - "trillium-tls-common", + "url", +] + +[[package]] +name = "trillium-smol" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a1c196273bd6e41705150834f5771699ad9c2e38ce317aecd3f6e0ec4c2b2e6" +dependencies = [ + "async-global-executor", + "async-io 2.3.2", + "async-net", + "futures-lite 2.3.0", + "log", + "signal-hook", + "signal-hook-async-std", + "trillium", + "trillium-http", + "trillium-macros 0.0.6", + "trillium-server-common", ] [[package]] @@ -2220,78 +2647,91 @@ name = "trillium-techempower" version = "0.1.0" dependencies = [ "askama", - "fastrand", - "futures-lite", - "futures-util", + "env_logger", + "fastrand 2.0.2", + "futures-lite 2.3.0", + "jemallocator", + "moka", "sea-orm", "serde", "serde_json", + "sqlx", "trillium", "trillium-api", "trillium-askama", "trillium-async-std", "trillium-logger", "trillium-router", + "trillium-smol", + "trillium-tokio", + "unicycle", ] [[package]] -name = "trillium-tls-common" -version = "0.1.0" +name = "trillium-tokio" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25c024962f8fdad586fb329e91b64ef0f4034652779ef5d3720102ca0f88d714" +checksum = "160f07d12cc798d7de6a65e2279bb445f0606ecc4a9c594315ffff556ab7968b" dependencies = [ - "async-trait", - "futures-lite", - "url", + "async-compat", + "log", + "signal-hook", + "signal-hook-tokio", + "tokio", + "tokio-stream", + "trillium", + "trillium-http", + "trillium-macros 0.0.5", + "trillium-server-common", ] [[package]] -name = "try-lock" -version = "0.2.3" +name = "triomphe" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" +checksum = "859eb650cfee7434994602c3a68b25d77ad9e68c8a6cd491616ef86661382eb3" [[package]] name = "typenum" -version = "1.14.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicase" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" dependencies = [ "version_check", ] [[package]] name = "unicode-bidi" -version = "0.3.7" +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 = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" -version = "0.1.19" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" dependencies = [ "tinyvec", ] [[package]] name = "unicode-segmentation" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" - -[[package]] -name = "unicode-xid" -version = "0.2.2" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" [[package]] name = "unicode_categories" @@ -2299,37 +2739,61 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" +[[package]] +name = "unicycle" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ca7c60c63c67acf573ef612b410c42b351c1028216085fd72fb43e2b1abd2fc" +dependencies = [ + "futures-core", + "lock_api", + "parking_lot", + "uniset", +] + +[[package]] +name = "uniset" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40789245bbff5f31eb773c9ac4ee5c4e15eab9640d975e124d6ce4c34a6410d7" + [[package]] name = "url" -version = "2.2.2" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" dependencies = [ "form_urlencoded", "idna", - "matches", "percent-encoding", ] +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + [[package]] name = "uuid" -version = "0.8.2" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" dependencies = [ "getrandom", - "serde", ] [[package]] name = "value-bag" -version = "1.0.0-alpha.8" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79923f7731dc61ebfba3633098bf3ac533bbd35ccd8c57e7088d9a5eebe0263f" -dependencies = [ - "ctor", - "version_check", -] +checksum = "74797339c3b98616c009c7c3eb53a0ce41e85c8ec66bd3db96ed132d20cfdee8" [[package]] name = "vcpkg" @@ -2339,47 +2803,33 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "version_check" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "waker-fn" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" - -[[package]] -name = "waker-set" -version = "0.2.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e958152c46345e1af5c61812030ac85200573a0b384c137e83ce2c01ac4bc07" -dependencies = [ - "crossbeam-utils", - "slab", -] +checksum = "f3c4517f54858c779bbcbf228f4fca63d121bf85fbecb2dc578cdf4a39395690" [[package]] -name = "want" -version = "0.3.0" +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" -dependencies = [ - "log", - "try-lock", -] +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] -name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" +name = "wasite" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" +checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.78" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -2387,24 +2837,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.78" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" dependencies = [ "bumpalo", - "lazy_static", "log", + "once_cell", "proc-macro2", "quote", - "syn", + "syn 2.0.58", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.28" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e8d7523cb1f2a4c96c1317ca690031b714a51cc14e05f712446691f413f5d39" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" dependencies = [ "cfg-if", "js-sys", @@ -2414,9 +2864,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.78" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2424,50 +2874,41 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.78" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.58", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.78" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "web-sys" -version = "0.3.55" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38eb105f1c59d9eaa6b5cdc92b859d85b926e82cb2e0945cd0c9259faa6fe9fb" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" dependencies = [ "js-sys", "wasm-bindgen", ] -[[package]] -name = "wepoll-ffi" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d743fdedc5c64377b5fc2bc036b01c7fd642205a0d96356034ae3404d49eb7fb" -dependencies = [ - "cc", -] - [[package]] name = "whoami" -version = "1.2.1" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524b58fa5a20a2fb3014dd6358b70e6579692a56ef6fce928834e488f42f65e8" +checksum = "a44ab49fad634e88f55bf8f9bb3abd2f27d7204172a112c7c9987e01c1c94ea9" dependencies = [ - "wasm-bindgen", - "web-sys", + "redox_syscall", + "wasite", ] [[package]] @@ -2493,10 +2934,166 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] -name = "winreg" -version = "0.7.0" +name = "windows-sys" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "winapi", + "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.5", +] + +[[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.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +dependencies = [ + "windows_aarch64_gnullvm 0.52.5", + "windows_aarch64_msvc 0.52.5", + "windows_i686_gnu 0.52.5", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.5", + "windows_x86_64_gnu 0.52.5", + "windows_x86_64_gnullvm 0.52.5", + "windows_x86_64_msvc 0.52.5", +] + +[[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.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" + +[[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.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" + +[[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.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" + +[[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.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" + +[[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.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" + +[[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.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" + +[[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.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" + +[[package]] +name = "zerocopy" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.58", ] + +[[package]] +name = "zeroize" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" diff --git a/frameworks/Rust/trillium/Cargo.toml b/frameworks/Rust/trillium/Cargo.toml index 9c1a1bcf338..25eb7edc467 100644 --- a/frameworks/Rust/trillium/Cargo.toml +++ b/frameworks/Rust/trillium/Cargo.toml @@ -3,25 +3,46 @@ name = "trillium-techempower" version = "0.1.0" edition = "2021" +[features] +jemallocator = ["dep:jemallocator"] +tokio = ["dep:trillium-tokio", "sea-orm/runtime-tokio", "sqlx/runtime-tokio"] +smol = [ + "dep:trillium-smol", + "sea-orm/runtime-async-std", + "sqlx/runtime-async-std", +] +async-std = [ + "dep:trillium-async-std", + "sea-orm/runtime-async-std", + "sqlx/runtime-async-std", +] + [dependencies] -askama = "0.11.1" -fastrand = "1.7.0" -futures-lite = "1.12.0" -futures-util = "0.3.21" -serde = { version = "1.0.136", features = ["derive"] } -serde_json = "1.0.79" -trillium = "0.2.2" +askama = "0.12.1" +env_logger = "0.11.3" +fastrand = "2.0.2" +futures-lite = "2.3.0" +jemallocator = { version = "0.5.4", optional = true } +moka = { version = "0.12.5", features = ["future"] } +serde = { version = "1.0.197", features = ["derive"] } +serde_json = "1.0.115" +sqlx = "0.7.4" +trillium = "0.2.19" trillium-api = "0.1.0" -trillium-askama = "0.3.0" -trillium-async-std = "0.2.0" -trillium-logger = "0.4.0" -trillium-router = "0.3.2" +trillium-askama = "0.3.2" +trillium-async-std = { version = "0.4.0", optional = true } +trillium-logger = "0.4.5" +trillium-router = "0.4.1" +trillium-smol = { version = "0.4.0", optional = true } +trillium-tokio = { version = "0.4.0", optional = true } +unicycle = "0.10.1" [dependencies.sea-orm] -version = "0.6.0" +version = "0.12.15" default-features = false -features = ["runtime-async-std-native-tls", "sqlx-postgres", "macros"] +features = ["sqlx-postgres", "macros"] [profile.release] panic = "abort" lto = "fat" +codegen-units = 1 diff --git a/frameworks/Rust/trillium/README.md b/frameworks/Rust/trillium/README.md index 586e669e5c1..007e4d454e2 100755 --- a/frameworks/Rust/trillium/README.md +++ b/frameworks/Rust/trillium/README.md @@ -53,3 +53,7 @@ PostgreSQL. ### Test 6: Plaintext http://localhost:8080/plaintext + +### Test 7: Caching + + http://localhost:8080/cached/20 diff --git a/frameworks/Rust/trillium/benchmark_config.json b/frameworks/Rust/trillium/benchmark_config.json index 19076a3598f..f12fc4ea218 100755 --- a/frameworks/Rust/trillium/benchmark_config.json +++ b/frameworks/Rust/trillium/benchmark_config.json @@ -1,5 +1,6 @@ { "framework": "trillium", + "maintainers": ["jbr"], "tests": [ { "default": { @@ -8,6 +9,8 @@ "query_url": "/queries/", "plaintext_url": "/plaintext", "fortune_url": "/fortunes", + "cached_query_url": "/cached-queries/", + "update_url": "/updates/", "port": 8080, "approach": "Realistic", "classification": "Micro", @@ -20,7 +23,57 @@ "webserver": "None", "os": "Linux", "database_os": "Linux", - "display_name": "Trillium", + "display_name": "Trillium [smol]", + "notes": "", + "versus": "None", + "tags": ["verified"] + }, + "async-std": { + "db_url": "/db", + "json_url": "/json", + "query_url": "/queries/", + "plaintext_url": "/plaintext", + "fortune_url": "/fortunes", + "cached_query_url": "/cached-queries/", + "update_url": "/updates/", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "postgres", + "framework": "Trillium", + "language": "Rust", + "flavor": "None", + "orm": "Full", + "platform": "None", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "Trillium [async-std]", + "notes": "", + "versus": "None", + "tags": ["verified"] + }, + "tokio": { + "db_url": "/db", + "json_url": "/json", + "query_url": "/queries/", + "plaintext_url": "/plaintext", + "fortune_url": "/fortunes", + "cached_query_url": "/cached-queries/", + "update_url": "/updates/", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "postgres", + "framework": "Trillium", + "language": "Rust", + "flavor": "None", + "orm": "Full", + "platform": "None", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "Trillium [tokio]", "notes": "", "versus": "None", "tags": ["verified"] diff --git a/frameworks/Rust/trillium/src/application.rs b/frameworks/Rust/trillium/src/application.rs index 83992f56eaa..d8ed8106628 100644 --- a/frameworks/Rust/trillium/src/application.rs +++ b/frameworks/Rust/trillium/src/application.rs @@ -1,14 +1,10 @@ use crate::db::Db; use crate::routes::router; -use trillium_logger::Logger; pub fn application() -> impl trillium::Handler { ( - if cfg!(debug_assertions) { - Some(Logger::new()) - } else { - None - }, + #[cfg(debug_assertions)] + trillium_logger::logger(), Db::default(), router(), ) diff --git a/frameworks/Rust/trillium/src/db.rs b/frameworks/Rust/trillium/src/db.rs index fb1d61e4ebe..3f9982a09bc 100644 --- a/frameworks/Rust/trillium/src/db.rs +++ b/frameworks/Rust/trillium/src/db.rs @@ -5,9 +5,23 @@ use trillium::{async_trait, Conn, Handler, Info}; #[derive(Debug, Default)] pub struct Db(Option); +pub mod cached_world; pub mod fortune; pub mod world; +impl Db { + pub(crate) async fn connection() -> DatabaseConnection { + let db_url = env::var("DATABASE_URL").expect("env var DATABASE_URL not found"); + + let connect_options = ConnectOptions::new(db_url.clone()); + + Database::connect(connect_options) + .await + .map_err(|e| format!("could not connect to {}: {}", &db_url, e)) + .unwrap() + } +} + #[async_trait] impl Handler for Db { async fn run(&self, conn: Conn) -> Conn { @@ -16,16 +30,7 @@ impl Handler for Db { async fn init(&mut self, _info: &mut Info) { if self.0.is_none() { - let db_url = env::var("DATABASE_URL").expect("env var DATABASE_URL not found"); - - let connect_options = ConnectOptions::new(db_url.clone()); - - let db = Database::connect(connect_options) - .await - .map_err(|e| format!("could not connect to {}: {}", &db_url, e)) - .unwrap(); - - self.0 = Some(db); + self.0 = Some(Self::connection().await); } } } diff --git a/frameworks/Rust/trillium/src/db/cached_world.rs b/frameworks/Rust/trillium/src/db/cached_world.rs new file mode 100644 index 00000000000..d8ea0b82223 --- /dev/null +++ b/frameworks/Rust/trillium/src/db/cached_world.rs @@ -0,0 +1,24 @@ +use sea_orm::entity::prelude::*; +use serde::Serialize; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize)] +#[sea_orm(table_name = "World")] +#[serde(rename_all = "camelCase")] +pub struct Model { + #[sea_orm(primary_key)] + pub id: i32, + + #[sea_orm(column_name = "randomnumber")] + pub random_number: i32, +} + +#[derive(Copy, Clone, Debug, EnumIter)] +pub enum Relation {} + +impl RelationTrait for Relation { + fn def(&self) -> RelationDef { + unimplemented!() + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/frameworks/Rust/trillium/src/db/fortune.rs b/frameworks/Rust/trillium/src/db/fortune.rs index b046f3ddfe4..b6d69229599 100644 --- a/frameworks/Rust/trillium/src/db/fortune.rs +++ b/frameworks/Rust/trillium/src/db/fortune.rs @@ -1,7 +1,8 @@ use sea_orm::entity::prelude::*; use serde::Serialize; +use std::cmp::Ordering; -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize)] +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Eq)] #[sea_orm(table_name = "Fortune")] pub struct Model { #[sea_orm(primary_key)] @@ -20,3 +21,15 @@ impl RelationTrait for Relation { } impl ActiveModelBehavior for ActiveModel {} + +impl PartialOrd for Model { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for Model { + fn cmp(&self, other: &Self) -> Ordering { + self.message.cmp(&other.message) + } +} diff --git a/frameworks/Rust/trillium/src/main.rs b/frameworks/Rust/trillium/src/main.rs index 65935b84a66..af8984ef208 100644 --- a/frameworks/Rust/trillium/src/main.rs +++ b/frameworks/Rust/trillium/src/main.rs @@ -1,9 +1,36 @@ +#[cfg(feature = "jemallocator")] +#[global_allocator] +static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; + mod application; mod db; mod routes; - use application::application; +use trillium::HttpConfig; + +#[cfg(all(feature = "smol", not(feature = "tokio"), not(feature = "async-std")))] +use trillium_smol::config; + +#[cfg(all(feature = "tokio", not(feature = "smol"), not(feature = "async-std")))] +use trillium_tokio::config; + +#[cfg(all(feature = "async-std", not(feature = "smol"), not(feature = "tokio")))] +use trillium_async_std::config; + +#[cfg(not(any(feature = "async-std", feature = "smol", feature = "tokio")))] +compile_error! {"please run with one of the following --features `async-std`, `smol`, `tokio`"} fn main() { - trillium_async_std::run(application()) + #[cfg(debug_assertions)] + env_logger::init(); + + let http_config = HttpConfig::default() + .with_response_buffer_len(256) + .with_request_buffer_initial_len(256) + .with_response_header_initial_capacity(5); + + config() + .with_nodelay() + .with_http_config(http_config) + .run(application()) } diff --git a/frameworks/Rust/trillium/src/routes.rs b/frameworks/Rust/trillium/src/routes.rs index b5cc8864564..4b807f5b0f7 100644 --- a/frameworks/Rust/trillium/src/routes.rs +++ b/frameworks/Rust/trillium/src/routes.rs @@ -1,11 +1,11 @@ use trillium_router::Router; +mod cached_queries; mod db; mod fortune; mod json; mod plaintext; mod queries; mod updates; - pub fn router() -> Router { Router::build(|mut router| { router.get("/fortunes", fortune::handler); @@ -16,5 +16,8 @@ pub fn router() -> Router { router.get("/plaintext", plaintext::handler); router.get("/updates/:updates", updates::handler); router.get("/updates", updates::handler); + let cached_queries = cached_queries::handler(); + router.get("/cached-queries/:count", cached_queries.clone()); + router.get("/cached-queries", cached_queries); }) } diff --git a/frameworks/Rust/trillium/src/routes/cached_queries.rs b/frameworks/Rust/trillium/src/routes/cached_queries.rs new file mode 100644 index 00000000000..25e007bf791 --- /dev/null +++ b/frameworks/Rust/trillium/src/routes/cached_queries.rs @@ -0,0 +1,80 @@ +use crate::db::{ + cached_world::{Entity as CachedWorlds, Model as CachedWorld}, + Db, DbConnExt, +}; +use futures_lite::StreamExt; +use moka::future::Cache; +use sea_orm::{DatabaseConnection, DbErr, EntityTrait}; +use std::{iter, sync::Arc}; +use trillium::{Conn, Handler, Info, Status}; +use trillium_api::ApiConnExt; +use trillium_router::RouterConnExt; +use unicycle::FuturesUnordered; + +pub fn handler() -> CachedWorldHandler { + CachedWorldHandler { + cache: Cache::new(10_000), + } +} + +#[derive(Debug, Clone)] +pub struct CachedWorldHandler { + cache: Cache, +} + +impl CachedWorldHandler { + #[inline(always)] + fn count_param(conn: &Conn) -> usize { + conn.param("count") + .and_then(|s| s.parse().ok()) + .unwrap_or(1) + .min(500) + .max(1) + } + + #[inline(always)] + async fn fetch_cached( + &self, + db: &DatabaseConnection, + id: i32, + ) -> Result> { + self.cache + .try_get_with(id, async { + CachedWorlds::find_by_id(id) + .one(db) + .await? + .ok_or_else(|| DbErr::RecordNotFound(String::from("not found"))) + }) + .await + } +} + +#[trillium::async_trait] +impl Handler for CachedWorldHandler { + async fn init(&mut self, _info: &mut Info) { + if self.cache.entry_count() == 0 { + let db = Db::connection().await; + let mut stream = CachedWorlds::find().stream(&db).await.unwrap(); + while let Some(Ok(world)) = stream.next().await { + self.cache.insert(world.id, world).await + } + self.cache.run_pending_tasks().await; + } + } + + async fn run(&self, conn: Conn) -> Conn { + let count = Self::count_param(&conn); + let db = conn.db(); + let worlds: Result, _> = + iter::repeat_with(|| self.fetch_cached(db, fastrand::i32(1..=10_000))) + .take(count) + .collect::>() + .try_collect() + .await; + + match worlds { + Ok(worlds) => conn.with_json(&worlds), + Err(_) => conn.with_status(Status::InternalServerError), + } + } +} diff --git a/frameworks/Rust/trillium/src/routes/db.rs b/frameworks/Rust/trillium/src/routes/db.rs index de1b8fc2fbd..8dbb00b499d 100644 --- a/frameworks/Rust/trillium/src/routes/db.rs +++ b/frameworks/Rust/trillium/src/routes/db.rs @@ -1,18 +1,13 @@ use crate::db::{world::Entity as World, DbConnExt}; use sea_orm::entity::prelude::*; -use trillium::{conn_unwrap, Conn}; +use trillium::{Conn, Status}; use trillium_api::ApiConnExt; pub async fn handler(conn: Conn) -> Conn { - let random = fastrand::i32(1..10000); - let world = conn_unwrap!( - World::find_by_id(random) - .one(conn.db()) - .await - .ok() - .flatten(), - conn - ); - - conn.with_json(&world) + let id = fastrand::i32(1..=10_000); + match World::find_by_id(id).one(conn.db()).await { + Ok(Some(world)) => conn.with_json(&world), + Err(_) => conn.with_status(Status::InternalServerError), + Ok(None) => conn.with_status(Status::NotFound), + } } diff --git a/frameworks/Rust/trillium/src/routes/fortune.rs b/frameworks/Rust/trillium/src/routes/fortune.rs index 66bcce25aef..c1658a64f69 100644 --- a/frameworks/Rust/trillium/src/routes/fortune.rs +++ b/frameworks/Rust/trillium/src/routes/fortune.rs @@ -2,29 +2,37 @@ use crate::db::{ fortune::{Entity as Fortunes, Model as Fortune}, DbConnExt, }; -use sea_orm::entity::prelude::*; -use trillium::{conn_try, Conn, KnownHeaderName::ContentType}; +use futures_lite::StreamExt; +use sea_orm::EntityTrait; +use std::collections::BTreeSet; +use trillium::{Conn, KnownHeaderName::ContentType, Status}; use trillium_askama::{AskamaConnExt, Template}; #[derive(Template)] #[template(path = "fortunes.html")] struct FortuneTemplate<'a> { - fortunes: &'a [Fortune], + fortunes: &'a BTreeSet, } pub async fn handler(conn: Conn) -> Conn { - let db = conn.db(); + let db = conn.db().clone(); - let mut fortunes = conn_try!(Fortunes::find().all(db).await, conn); - fortunes.push(Fortune { + let mut fortunes = BTreeSet::new(); + fortunes.insert(Fortune { id: 0, message: String::from("Additional fortune added at request time."), }); - fortunes.sort_by(|a, b| a.message.cmp(&b.message)); + let Ok(mut stream) = Fortunes::find().stream(&db).await else { + return conn.with_status(Status::InternalServerError); + }; + + while let Some(Ok(fortune)) = stream.next().await { + fortunes.insert(fortune); + } conn.render(FortuneTemplate { fortunes: &fortunes, }) - .with_header(ContentType, "text/html; charset=utf-8") + .with_response_header(ContentType, "text/html; charset=utf-8") } diff --git a/frameworks/Rust/trillium/src/routes/json.rs b/frameworks/Rust/trillium/src/routes/json.rs index e238b70a8b9..ce203fb921b 100644 --- a/frameworks/Rust/trillium/src/routes/json.rs +++ b/frameworks/Rust/trillium/src/routes/json.rs @@ -1,8 +1,7 @@ -use serde_json::{json, to_string}; -use trillium::{conn_try, Conn, KnownHeaderName}; +use serde_json::json; +use trillium::Conn; +use trillium_api::ApiConnExt; pub async fn handler(conn: Conn) -> Conn { - let body = conn_try!(to_string(&json!({"message": "Hello, World!"})), conn); - conn.ok(body) - .with_header(KnownHeaderName::ContentType, "application/json") + conn.with_json(&json!({"message": "Hello, World!"})) } diff --git a/frameworks/Rust/trillium/src/routes/plaintext.rs b/frameworks/Rust/trillium/src/routes/plaintext.rs index 3742526a1be..f423ead3780 100644 --- a/frameworks/Rust/trillium/src/routes/plaintext.rs +++ b/frameworks/Rust/trillium/src/routes/plaintext.rs @@ -1,6 +1,6 @@ use trillium::{Conn, KnownHeaderName}; pub async fn handler(conn: Conn) -> Conn { - conn.with_header(KnownHeaderName::ContentType, "text/plain") + conn.with_response_header(KnownHeaderName::ContentType, "text/plain") .ok("Hello, World!") } diff --git a/frameworks/Rust/trillium/src/routes/queries.rs b/frameworks/Rust/trillium/src/routes/queries.rs index a32d13d964c..dfd21e318d2 100644 --- a/frameworks/Rust/trillium/src/routes/queries.rs +++ b/frameworks/Rust/trillium/src/routes/queries.rs @@ -1,11 +1,11 @@ use crate::db::{world::Entity as Worlds, DbConnExt}; use futures_lite::StreamExt; -use futures_util::stream::futures_unordered::FuturesUnordered; -use sea_orm::entity::prelude::*; +use sea_orm::{entity::prelude::*, TransactionTrait}; use std::iter; -use trillium::{conn_try, Conn}; +use trillium::{Conn, Status}; use trillium_api::ApiConnExt; use trillium_router::RouterConnExt; +use unicycle::FuturesUnordered; pub async fn handler(conn: Conn) -> Conn { let queries = conn @@ -15,20 +15,23 @@ pub async fn handler(conn: Conn) -> Conn { .min(500) .max(1); - let db = conn.db(); + let Ok(tx) = conn.db().begin().await else { + return conn.with_status(Status::InternalServerError); + }; - let vec_of_worlds: Result, DbErr> = - iter::repeat_with(|| Worlds::find_by_id(fastrand::i32(1..10000)).one(db)) - .take(queries) - .collect::>() - .map(|x| match x { - Ok(None) => Err(DbErr::RecordNotFound(String::from("not found"))), - other => other, - }) - .try_collect() - .await; + let worlds = iter::repeat_with(|| async { + Worlds::find_by_id(fastrand::i32(1..=10_000)) + .one(&tx) + .await? + .ok_or_else(|| DbErr::RecordNotFound(String::from("not found"))) + }) + .take(queries) + .collect::>() + .try_collect::<_, _, Vec<_>>() + .await; - let vec_of_worlds = conn_try!(vec_of_worlds, conn); - - conn.with_json(&vec_of_worlds) + match worlds { + Ok(worlds) => conn.with_json(&worlds), + Err(_) => conn.with_status(Status::InternalServerError), + } } diff --git a/frameworks/Rust/trillium/src/routes/updates.rs b/frameworks/Rust/trillium/src/routes/updates.rs index c88e5595f67..46e7737d29b 100644 --- a/frameworks/Rust/trillium/src/routes/updates.rs +++ b/frameworks/Rust/trillium/src/routes/updates.rs @@ -1,14 +1,11 @@ -use crate::db::{ - world::{Entity as Worlds, Model as World}, - DbConnExt, -}; - -use futures_util::stream::{futures_unordered::FuturesUnordered, StreamExt}; +use crate::db::{world::Entity as Worlds, DbConnExt}; +use futures_lite::StreamExt; use sea_orm::{entity::prelude::*, IntoActiveModel, Set}; use std::iter; -use trillium::Conn; +use trillium::{Conn, Status}; use trillium_api::ApiConnExt; use trillium_router::RouterConnExt; +use unicycle::FuturesUnordered; pub async fn handler(conn: Conn) -> Conn { let queries = conn @@ -19,19 +16,22 @@ pub async fn handler(conn: Conn) -> Conn { .max(1); let db = conn.db(); + let worlds = iter::repeat_with(|| async { + let mut world = Worlds::find_by_id(fastrand::i32(1..=10_000)) + .one(db) + .await? + .ok_or_else(|| DbErr::RecordNotFound(String::from("not found")))? + .into_active_model(); + world.random_number = Set(fastrand::i32(1..=10_000)); + world.update(db).await + }) + .take(queries) + .collect::>() + .try_collect::<_, _, Vec<_>>() + .await; - let vec_of_worlds: Vec = - iter::repeat_with(|| Worlds::find_by_id(fastrand::i32(1..10000)).one(db)) - .take(queries) - .collect::>() - .filter_map(|x| async move { x.ok().flatten() }) - .filter_map(|w| async move { - let mut am = w.clone().into_active_model(); - am.random_number = Set(fastrand::i32(1..10000)); - am.update(db).await.ok() - }) - .collect() - .await; - - conn.with_json(&vec_of_worlds) + match worlds { + Ok(worlds) => conn.with_json(&worlds), + Err(_) => conn.with_status(Status::InternalServerError), + } } diff --git a/frameworks/Rust/trillium/templates/fortunes.html b/frameworks/Rust/trillium/templates/fortunes.html index 3619c728ea2..fb45d04e019 100644 --- a/frameworks/Rust/trillium/templates/fortunes.html +++ b/frameworks/Rust/trillium/templates/fortunes.html @@ -4,9 +4,9 @@ - {% for fortune in fortunes %} + {%- for fortune in fortunes -%} - {% endfor %} + {%- endfor -%}
idmessage
{{fortune.id}}{{fortune.message}}
diff --git a/frameworks/Rust/trillium/trillium-async-std.dockerfile b/frameworks/Rust/trillium/trillium-async-std.dockerfile new file mode 100644 index 00000000000..554bb671f5e --- /dev/null +++ b/frameworks/Rust/trillium/trillium-async-std.dockerfile @@ -0,0 +1,16 @@ +FROM rust:1.77 +WORKDIR /trillium +COPY src src +COPY templates templates +COPY Cargo.toml Cargo.toml +COPY Cargo.lock Cargo.lock + +EXPOSE 8080 + +ENV RUSTFLAGS="-C target-cpu=native" +ENV PORT=8080 +ENV HOST=0.0.0.0 +ENV DATABASE_URL=postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world + +RUN cargo build --release --features jemallocator,async-std +CMD ["./target/release/trillium-techempower"] diff --git a/frameworks/Rust/trillium/trillium-tokio.dockerfile b/frameworks/Rust/trillium/trillium-tokio.dockerfile new file mode 100644 index 00000000000..d3bf05bcb7f --- /dev/null +++ b/frameworks/Rust/trillium/trillium-tokio.dockerfile @@ -0,0 +1,16 @@ +FROM rust:1.77 +WORKDIR /trillium +COPY src src +COPY templates templates +COPY Cargo.toml Cargo.toml +COPY Cargo.lock Cargo.lock + +EXPOSE 8080 + +ENV RUSTFLAGS="-C target-cpu=native" +ENV PORT=8080 +ENV HOST=0.0.0.0 +ENV DATABASE_URL=postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world + +RUN cargo build --release --features jemallocator,tokio +CMD ["./target/release/trillium-techempower"] diff --git a/frameworks/Rust/trillium/trillium.dockerfile b/frameworks/Rust/trillium/trillium.dockerfile index eac19bbbd6a..667079dd84b 100644 --- a/frameworks/Rust/trillium/trillium.dockerfile +++ b/frameworks/Rust/trillium/trillium.dockerfile @@ -1,4 +1,4 @@ -FROM rust:1.57 +FROM rust:1.77 WORKDIR /trillium COPY src src COPY templates templates @@ -12,5 +12,5 @@ ENV PORT=8080 ENV HOST=0.0.0.0 ENV DATABASE_URL=postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world -RUN cargo build --release +RUN cargo build --release --features jemallocator,smol CMD ["./target/release/trillium-techempower"] diff --git a/frameworks/Rust/viz/Cargo.toml b/frameworks/Rust/viz/Cargo.toml index 462dbb7bc31..7047dbe3666 100644 --- a/frameworks/Rust/viz/Cargo.toml +++ b/frameworks/Rust/viz/Cargo.toml @@ -24,36 +24,49 @@ path = "src/main_diesel.rs" required-features = ["diesel", "diesel-async", "sailfish"] [dependencies] -viz = "0.4" -hyper = "0.14" +viz = "0.10" +hyper = "1.0" +hyper-util = "0.1" +http-body-util = "0.1" atoi = "2.0" serde = { version = "1.0", features = ["derive"] } -nanorand = "0.7" -rand = { version = "0.8", features = ["small_rng"] } -thiserror = "1.0" +serde_json = "1" +mime = "0.3" +rand = { version = "0.9", features = ["small_rng"] } +thiserror = "2.0" futures-util = "0.3" +socket2 = { version = "0.6.0", features = ["all"] } +num_cpus = "1.16.0" + +[target.'cfg(not(unix))'.dependencies] +nanorand = { version = "0.8" } + +[target.'cfg(unix)'.dependencies] +nanorand = { version = "0.8", features = ["getrandom"] } tokio = { version = "1", features = ["full"] } tokio-postgres = { version = "0.7", optional = true } -sqlx = { version = "0.7", features = [ +sqlx = { version = "0.8", features = [ "postgres", "macros", "runtime-tokio", - "tls-native-tls" + "tls-native-tls", ], optional = true } -diesel = { version = "2.0", default-features = false, features = [ +diesel = { version = "2.2", default-features = false, features = [ "i-implement-a-third-party-backend-and-opt-into-breaking-changes", ], optional = true } -diesel-async = { version = "0.4", default-features = false, features = [ +diesel-async = { version = "0.6", default-features = false, features = [ "postgres", "bb8", ], optional = true } yarte = { version = "0.15", features = ["bytes-buf", "json"], optional = true } -markup = { version = "0.13", optional = true } +markup = { version = "0.15", optional = true } v_htmlescape = { version = "0.15", optional = true } -sailfish = { version = "0.8", optional = true } +sailfish = { version = "0.10", optional = true } [profile.release] lto = true codegen-units = 1 +strip = true +opt-level = 3 diff --git a/frameworks/Rust/viz/src/db_diesel.rs b/frameworks/Rust/viz/src/db_diesel.rs index 9e93bb342ba..624000a7d1d 100644 --- a/frameworks/Rust/viz/src/db_diesel.rs +++ b/frameworks/Rust/viz/src/db_diesel.rs @@ -1,5 +1,3 @@ -use std::borrow::Cow; - use diesel::prelude::*; use diesel_async::{ pooled_connection::bb8::{Pool, RunError}, @@ -112,7 +110,7 @@ pub async fn tell_fortune(pool: Pool) -> Result Result { - let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); - let random_id = (rng.gen::() % 10_000 + 1) as i32; + let mut rng = SmallRng::from_rng(&mut rng()); + let random_id = (rng.random::() % 10_000 + 1) as i32; self.query_one_world(random_id).await } pub async fn get_worlds(&self, num: u16) -> Result, PgError> { - let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); + let mut rng = SmallRng::from_rng(&mut rng()); let worlds = FuturesUnordered::new(); for _ in 0..num { - let id = (rng.gen::() % 10_000 + 1) as i32; + let id = (rng.random::() % 10_000 + 1) as i32; worlds.push(self.query_one_world(id)); } @@ -125,13 +125,13 @@ impl PgConnection { } pub async fn update(&self, num: u16) -> Result, PgError> { - let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap(); + let mut rng = SmallRng::from_rng(&mut rng()); let worlds = FuturesUnordered::new(); for _ in 0..num { - let id = (rng.gen::() % 10_000 + 1) as i32; - let rid = (rng.gen::() % 10_000 + 1) as i32; + let id = (rng.random::() % 10_000 + 1) as i32; + let rid = (rng.random::() % 10_000 + 1) as i32; worlds.push(self.query_one_world(id).map_ok(move |mut world| { world.randomnumber = rid; @@ -162,7 +162,7 @@ impl PgConnection { pub async fn tell_fortune(&self) -> Result, PgError> { let mut items = vec![Fortune { id: 0, - message: Cow::Borrowed("Additional fortune added at request time."), + message: "Additional fortune added at request time.".to_string(), }]; let stream = self @@ -176,7 +176,7 @@ impl PgConnection { items.push(Fortune { id: row.get(0), - message: Cow::Owned(row.get(1)), + message: row.get(1), }); } diff --git a/frameworks/Rust/viz/src/db_sqlx.rs b/frameworks/Rust/viz/src/db_sqlx.rs index cf8c10c8799..40c39290265 100644 --- a/frameworks/Rust/viz/src/db_sqlx.rs +++ b/frameworks/Rust/viz/src/db_sqlx.rs @@ -1,5 +1,3 @@ -use std::borrow::Cow; - use nanorand::{Rng, WyRand}; pub use sqlx::{ @@ -8,10 +6,7 @@ pub use sqlx::{ Arguments, PgPool, Postgres, Row, }; -use viz::{ - async_trait, Error, FromRequest, IntoResponse, Request, RequestExt, Response, - StatusCode, -}; +use viz::{Error, FromRequest, IntoResponse, Request, RequestExt, Response, StatusCode}; use crate::models_sqlx::*; use crate::utils::get_query_param; @@ -19,7 +14,6 @@ use crate::RANGE; pub struct DatabaseConnection(pub PoolConnection); -#[async_trait] impl FromRequest for DatabaseConnection { type Error = PgError; @@ -53,7 +47,6 @@ impl IntoResponse for PgError { pub struct Counter(pub u16); -#[async_trait] impl FromRequest for Counter { type Error = Error; @@ -67,7 +60,7 @@ pub async fn get_world( id: i32, ) -> Result { let mut args = PgArguments::default(); - args.add(id); + let _ = args.add(id); let world = sqlx::query_as_with("SELECT id, randomnumber FROM World WHERE id = $1", args) @@ -93,8 +86,8 @@ pub async fn update_worlds( for w in &worlds { let mut args = PgArguments::default(); - args.add(w.randomnumber); - args.add(w.id); + let _ = args.add(w.randomnumber); + let _ = args.add(w.id); sqlx::query_with("UPDATE World SET randomNumber = $1 WHERE id = $2", args) .execute(&mut *conn) @@ -110,14 +103,14 @@ pub async fn get_fortunes( let mut items = sqlx::query("SELECT * FROM Fortune") .map(|row: PgRow| Fortune { id: row.get(0), - message: Cow::Owned(row.get(1)), + message: row.get(1), }) .fetch_all(&mut *conn) .await?; items.push(Fortune { id: 0, - message: Cow::Borrowed("Additional fortune added at request time."), + message: "Additional fortune added at request time.".to_string(), }); items.sort_by(|it, next| it.message.cmp(&next.message)); diff --git a/frameworks/Rust/viz/src/main.rs b/frameworks/Rust/viz/src/main.rs index 0550a8ffc4a..3552b23920c 100644 --- a/frameworks/Rust/viz/src/main.rs +++ b/frameworks/Rust/viz/src/main.rs @@ -2,8 +2,8 @@ use serde::Serialize; use viz::{ - header::{HeaderValue, SERVER}, - Error, Request, Response, ResponseExt, Result, Router, ServiceMaker, + header::{HeaderValue, CONTENT_TYPE, SERVER}, + Bytes, Request, Response, ResponseExt, Result, Router, }; mod server; @@ -14,6 +14,7 @@ struct Message { message: &'static str, } +#[inline(always)] async fn plaintext(_: Request) -> Result { let mut res = Response::text("Hello, World!"); res.headers_mut() @@ -21,24 +22,36 @@ async fn plaintext(_: Request) -> Result { Ok(res) } +#[inline(always)] async fn json(_: Request) -> Result { - let mut res = Response::json(Message { - message: "Hello, World!", - })?; - res.headers_mut() - .insert(SERVER, HeaderValue::from_static("Viz")); + let mut res = Response::builder() + .body( + http_body_util::Full::new(Bytes::from( + serde_json::to_vec(&Message { + message: "Hello, World!", + }) + .unwrap(), + )) + .into(), + ) + .unwrap(); + let headers = res.headers_mut(); + headers.insert(SERVER, HeaderValue::from_static("Viz")); + headers.insert( + CONTENT_TYPE, + HeaderValue::from_static(mime::APPLICATION_JSON.as_ref()), + ); Ok(res) } -#[tokio::main] -async fn main() -> Result<()> { +async fn app() { let app = Router::new() .get("/plaintext", plaintext) .get("/json", json); - server::builder() - .http1_pipeline_flush(true) - .serve(ServiceMaker::from(app)) - .await - .map_err(Error::normal) + server::serve(app).await.unwrap(); +} + +fn main() { + server::run(app) } diff --git a/frameworks/Rust/viz/src/main_diesel.rs b/frameworks/Rust/viz/src/main_diesel.rs index a8212b505fd..ec3a002c2a7 100644 --- a/frameworks/Rust/viz/src/main_diesel.rs +++ b/frameworks/Rust/viz/src/main_diesel.rs @@ -11,7 +11,7 @@ use nanorand::{Rng, WyRand}; use viz::{ header::{HeaderValue, SERVER}, types::State, - Request, RequestExt, Response, ResponseExt, Result, Router, ServiceMaker, + Request, RequestExt, Response, ResponseExt, Result, Router, }; mod db_diesel; @@ -77,8 +77,7 @@ async fn updates(req: Request) -> Result { Ok(res) } -#[tokio::main] -async fn main() { +async fn app() { let max = available_parallelism().map(|n| n.get()).unwrap_or(16) as u32; let pool = Pool::::builder() @@ -89,19 +88,17 @@ async fn main() { let rng = WyRand::new(); - let service = ServiceMaker::from( - Router::new() - .get("/db", db) - .get("/fortunes", fortunes) - .get("/queries", queries) - .get("/updates", updates) - .with(State::new(pool)) - .with(State::new(rng)), - ); - - serve(service).await; + let app = Router::new() + .get("/db", db) + .get("/fortunes", fortunes) + .get("/queries", queries) + .get("/updates", updates) + .with(State::new(pool)) + .with(State::new(rng)); + + server::serve(app).await.unwrap() } -async fn serve(service: ServiceMaker) { - server::builder().serve(service).await.unwrap() +fn main() { + server::run(app) } diff --git a/frameworks/Rust/viz/src/main_pg.rs b/frameworks/Rust/viz/src/main_pg.rs index abd3638b134..4898ca8f24a 100644 --- a/frameworks/Rust/viz/src/main_pg.rs +++ b/frameworks/Rust/viz/src/main_pg.rs @@ -1,12 +1,9 @@ -use std::{ - sync::Arc, - thread::{available_parallelism, spawn}, -}; +use std::sync::Arc; use viz::{ header::{HeaderValue, SERVER}, types::State, - Request, RequestExt, Response, ResponseExt, Result, Router, ServiceMaker, + Request, RequestExt, Response, ResponseExt, Result, Router, }; use yarte::Template; @@ -19,8 +16,8 @@ use db_pg::{get_conn, PgConnection}; #[derive(Template)] #[template(path = "fortune.hbs")] -pub struct FortunesTemplate<'a> { - pub fortunes: &'a Vec, +pub struct FortunesTemplate { + pub fortunes: Vec, } const DB_URL: &str = @@ -42,11 +39,9 @@ async fn fortunes(req: Request) -> Result { let fortunes = conn.tell_fortune().await?; - let buf = FortunesTemplate { - fortunes: &fortunes, - } - .call() - .expect("error rendering template"); + let buf = FortunesTemplate { fortunes } + .call() + .expect("error rendering template"); let mut res = Response::html(buf); res.headers_mut() @@ -78,26 +73,7 @@ async fn updates(req: Request) -> Result { Ok(res) } -fn main() { - let rt = tokio::runtime::Builder::new_current_thread() - .enable_all() - .build() - .unwrap(); - - for _ in 1..available_parallelism().map(|n| n.get()).unwrap_or(16) { - spawn(move || { - let rt = tokio::runtime::Builder::new_current_thread() - .enable_all() - .build() - .unwrap(); - rt.block_on(serve()); - }); - } - - rt.block_on(serve()); -} - -async fn serve() { +async fn app() { let conn = PgConnection::connect(DB_URL).await; let app = Router::new() @@ -107,8 +83,9 @@ async fn serve() { .get("/updates", updates) .with(State::new(conn)); - server::builder() - .serve(ServiceMaker::from(app)) - .await - .unwrap() + server::serve(app).await.unwrap() +} + +fn main() { + server::run(app) } diff --git a/frameworks/Rust/viz/src/main_sqlx.rs b/frameworks/Rust/viz/src/main_sqlx.rs index 9b150d13901..e2aff0ff98f 100644 --- a/frameworks/Rust/viz/src/main_sqlx.rs +++ b/frameworks/Rust/viz/src/main_sqlx.rs @@ -5,7 +5,6 @@ use viz::{ header::{HeaderValue, SERVER}, types::State, BytesMut, Error, Request, RequestExt, Response, ResponseExt, Result, Router, - ServiceMaker, }; mod db_sqlx; @@ -80,8 +79,7 @@ async fn updates(mut req: Request) -> Result { Ok(res) } -#[tokio::main] -async fn main() -> Result<()> { +async fn app() -> Result<()> { let max = available_parallelism().map(|n| n.get()).unwrap_or(16) as u32; let pool = PgPoolOptions::new() @@ -101,10 +99,11 @@ async fn main() -> Result<()> { .with(State::new(pool)) .with(State::new(rng)); - server::builder() - .serve(ServiceMaker::from(app)) - .await - .map_err(Error::normal) + server::serve(app).await.map_err(Error::Boxed) +} + +fn main() { + server::run(app) } markup::define! { diff --git a/frameworks/Rust/viz/src/models.rs b/frameworks/Rust/viz/src/models.rs index 016cb56bb63..b059bab4c23 100644 --- a/frameworks/Rust/viz/src/models.rs +++ b/frameworks/Rust/viz/src/models.rs @@ -1,5 +1,3 @@ -use std::borrow::Cow; - use serde::Serialize; #[derive(Serialize, Debug, yarte::Serialize)] @@ -11,5 +9,5 @@ pub struct World { #[derive(Serialize, Debug)] pub struct Fortune { pub id: i32, - pub message: Cow<'static, str>, + pub message: String, } diff --git a/frameworks/Rust/viz/src/models_diesel.rs b/frameworks/Rust/viz/src/models_diesel.rs index c0e3356b404..63711594223 100644 --- a/frameworks/Rust/viz/src/models_diesel.rs +++ b/frameworks/Rust/viz/src/models_diesel.rs @@ -1,5 +1,3 @@ -use std::borrow::Cow; - use diesel::Queryable; use sailfish::TemplateOnce; use serde::Serialize; @@ -13,7 +11,7 @@ pub struct World { #[derive(Serialize, Queryable, Debug)] pub struct Fortune { pub id: i32, - pub message: Cow<'static, str>, + pub message: String, } #[derive(TemplateOnce)] diff --git a/frameworks/Rust/viz/src/models_sqlx.rs b/frameworks/Rust/viz/src/models_sqlx.rs index 23ef27aa8c2..2f3657a9936 100644 --- a/frameworks/Rust/viz/src/models_sqlx.rs +++ b/frameworks/Rust/viz/src/models_sqlx.rs @@ -1,5 +1,3 @@ -use std::borrow::Cow; - use serde::{Deserialize, Serialize}; use sqlx::FromRow; @@ -12,5 +10,5 @@ pub struct World { #[derive(Debug, PartialEq, Deserialize, Serialize, FromRow)] pub struct Fortune { pub id: i32, - pub message: Cow<'static, str>, + pub message: String, } diff --git a/frameworks/Rust/viz/src/server.rs b/frameworks/Rust/viz/src/server.rs index 629ea202be8..047da0ba88a 100644 --- a/frameworks/Rust/viz/src/server.rs +++ b/frameworks/Rust/viz/src/server.rs @@ -1,35 +1,81 @@ +use std::error::Error; +use std::future::Future; use std::io; use std::net::{Ipv4Addr, SocketAddr}; +use std::sync::Arc; +use std::thread; -use hyper::server::conn::AddrIncoming; -use tokio::net::{TcpListener, TcpSocket}; +use hyper::server::conn::http1::Builder; +use hyper_util::rt::TokioIo; +use socket2::{Domain, SockAddr, Socket}; +use tokio::{net::TcpListener, runtime}; +use viz::{Responder, Router, Tree}; -pub fn builder() -> hyper::server::Builder { +pub async fn serve(router: Router) -> Result<(), Box> { let addr = SocketAddr::from((Ipv4Addr::UNSPECIFIED, 8080)); - let listener = reuse_listener(addr).expect("couldn't bind to addr"); - let incoming = AddrIncoming::from_listener(listener).unwrap(); + let socket = create_socket(addr).expect("couldn't bind to addr"); + let listener = TcpListener::from_std(socket.into())?; + + let tree = Arc::::new(router.into()); + + let mut http = Builder::new(); + http.pipeline_flush(true); println!("Started viz server at 8080"); - viz::Server::builder(incoming) - .http1_only(true) - .tcp_nodelay(true) + loop { + let (tcp, _) = listener.accept().await?; + tcp.set_nodelay(true).expect("couldn't set TCP_NODELAY!"); + + let http = http.clone(); + let tree = tree.clone(); + + tokio::spawn(async move { + http.serve_connection( + TokioIo::new(tcp), + Responder::>::new(tree, None), + ) + .await + }); + } } -fn reuse_listener(addr: SocketAddr) -> io::Result { - let socket = match addr { - SocketAddr::V4(_) => TcpSocket::new_v4()?, - SocketAddr::V6(_) => TcpSocket::new_v6()?, +fn create_socket(addr: SocketAddr) -> Result { + let domain = match addr { + SocketAddr::V4(_) => Domain::IPV4, + SocketAddr::V6(_) => Domain::IPV6, }; - + let addr = SockAddr::from(addr); + let socket = Socket::new(domain, socket2::Type::STREAM, None)?; + let backlog = 4096; #[cfg(unix)] - { - if let Err(e) = socket.set_reuseport(true) { - eprintln!("error setting SO_REUSEPORT: {e}"); - } + socket.set_reuse_port(true)?; + socket.set_reuse_address(true)?; + socket.set_tcp_nodelay(true)?; + socket.set_nonblocking(true)?; + socket.bind(&addr)?; + socket.listen(backlog)?; + + Ok(socket) +} + +pub fn run(f: fn() -> Fut) +where + Fut: Future + Send + 'static, +{ + for _ in 1..num_cpus::get() { + let runtime = runtime::Builder::new_current_thread() + .enable_all() + .build() + .unwrap(); + thread::spawn(move || { + runtime.block_on(f()); + }); } - socket.set_reuseaddr(true)?; - socket.bind(addr)?; - socket.listen(1024) + let runtime = runtime::Builder::new_current_thread() + .enable_all() + .build() + .unwrap(); + runtime.block_on(f()); } diff --git a/frameworks/Rust/viz/templates/fortune.stpl b/frameworks/Rust/viz/templates/fortune.stpl index eb1abe6a4fa..874b48cc6f5 100644 --- a/frameworks/Rust/viz/templates/fortune.stpl +++ b/frameworks/Rust/viz/templates/fortune.stpl @@ -4,7 +4,7 @@ - <% for item in items { %><% } %> + <% for item in self.items { %><% } %>
idmessage
<%= item.id %><%= &*item.message %>
<%= item.id %><%= &*item.message %>
- \ No newline at end of file + diff --git a/frameworks/Rust/viz/viz-diesel.dockerfile b/frameworks/Rust/viz/viz-diesel.dockerfile index 0a12925e22e..4d10b67baa1 100644 --- a/frameworks/Rust/viz/viz-diesel.dockerfile +++ b/frameworks/Rust/viz/viz-diesel.dockerfile @@ -1,6 +1,4 @@ -FROM rust:1.72 - -RUN apt-get update -yqq && apt-get install -yqq cmake g++ +FROM rust:1.89 ADD ./ /viz WORKDIR /viz diff --git a/frameworks/Rust/viz/viz-pg.dockerfile b/frameworks/Rust/viz/viz-pg.dockerfile index 94a47249193..23bc34e49c3 100644 --- a/frameworks/Rust/viz/viz-pg.dockerfile +++ b/frameworks/Rust/viz/viz-pg.dockerfile @@ -1,6 +1,4 @@ -FROM rust:1.72 - -RUN apt-get update -yqq && apt-get install -yqq cmake g++ +FROM rust:1.89 ADD ./ /viz WORKDIR /viz diff --git a/frameworks/Rust/viz/viz-sqlx.dockerfile b/frameworks/Rust/viz/viz-sqlx.dockerfile index d0045817729..c9a7685855f 100644 --- a/frameworks/Rust/viz/viz-sqlx.dockerfile +++ b/frameworks/Rust/viz/viz-sqlx.dockerfile @@ -1,6 +1,4 @@ -FROM rust:1.72 - -RUN apt-get update -yqq && apt-get install -yqq cmake g++ +FROM rust:1.89 ADD ./ /viz WORKDIR /viz diff --git a/frameworks/Rust/viz/viz.dockerfile b/frameworks/Rust/viz/viz.dockerfile index 4fce0bf378d..bf5102b2bec 100644 --- a/frameworks/Rust/viz/viz.dockerfile +++ b/frameworks/Rust/viz/viz.dockerfile @@ -1,6 +1,4 @@ -FROM rust:1.72 - -RUN apt-get update -yqq && apt-get install -yqq cmake g++ +FROM rust:1.89 ADD ./ /viz WORKDIR /viz diff --git a/frameworks/Rust/warp-rust/Cargo.lock b/frameworks/Rust/warp-rust/Cargo.lock index b9a3dc06488..abf2a98b4a9 100644 --- a/frameworks/Rust/warp-rust/Cargo.lock +++ b/frameworks/Rust/warp-rust/Cargo.lock @@ -969,9 +969,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.139" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "line-wrap" @@ -1069,14 +1069,14 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.5" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -1179,7 +1179,7 @@ dependencies = [ "cfg-if", "instant", "libc", - "redox_syscall", + "redox_syscall 0.2.10", "smallvec", "winapi", ] @@ -1345,6 +1345,15 @@ dependencies = [ "bitflags", ] +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags", +] + [[package]] name = "redox_users" version = "0.4.0" @@ -1352,7 +1361,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" dependencies = [ "getrandom", - "redox_syscall", + "redox_syscall 0.2.10", ] [[package]] @@ -1805,7 +1814,7 @@ dependencies = [ "cfg-if", "libc", "rand", - "redox_syscall", + "redox_syscall 0.2.10", "remove_dir_all", "winapi", ] @@ -1889,7 +1898,7 @@ dependencies = [ "pin-project-lite", "socket2", "tokio-macros", - "windows-sys", + "windows-sys 0.42.0", ] [[package]] @@ -2249,6 +2258,12 @@ 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.76" @@ -2334,11 +2349,12 @@ dependencies = [ [[package]] name = "whoami" -version = "1.1.3" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7741161a40200a867c96dfa5574544efa4178cf4c8f770b62dd1cc0362d7ae1" +checksum = "a44ab49fad634e88f55bf8f9bb3abd2f27d7204172a112c7c9987e01c1c94ea9" dependencies = [ - "wasm-bindgen", + "redox_syscall 0.4.1", + "wasite", "web-sys", ] @@ -2379,13 +2395,37 @@ version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.42.1", + "windows_aarch64_msvc 0.42.1", + "windows_i686_gnu 0.42.1", + "windows_i686_msvc 0.42.1", + "windows_x86_64_gnu 0.42.1", + "windows_x86_64_gnullvm 0.42.1", + "windows_x86_64_msvc 0.42.1", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets", +] + +[[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]] @@ -2394,42 +2434,84 @@ version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" +[[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_msvc" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + [[package]] name = "windows_i686_gnu" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" +[[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_msvc" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + [[package]] name = "windows_x86_64_gnu" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" +[[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_gnullvm" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" +[[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_msvc" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + [[package]] name = "xml-rs" version = "0.8.14" diff --git a/frameworks/Rust/warp-rust/benchmark_config.json b/frameworks/Rust/warp-rust/benchmark_config.json index 5d91146bef5..1f159f54957 100755 --- a/frameworks/Rust/warp-rust/benchmark_config.json +++ b/frameworks/Rust/warp-rust/benchmark_config.json @@ -22,6 +22,7 @@ "database_os": "Linux", "display_name": "warp-rust", "notes": "", + "tags": ["broken"], "versus": "None" } } diff --git a/frameworks/Rust/water-http/.gitignore b/frameworks/Rust/water-http/.gitignore new file mode 100644 index 00000000000..2da6cdebaac --- /dev/null +++ b/frameworks/Rust/water-http/.gitignore @@ -0,0 +1,3 @@ +target +Cargo.lock +.idea \ No newline at end of file diff --git a/frameworks/Rust/water-http/Cargo.toml b/frameworks/Rust/water-http/Cargo.toml new file mode 100644 index 00000000000..fe22c5a9a68 --- /dev/null +++ b/frameworks/Rust/water-http/Cargo.toml @@ -0,0 +1,45 @@ +[package] +name = "water-http" +version = "0.1.0" +edition = "2018" + +[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" } +smallvec = "1.15.1" +nanorand = "0.8.0" +tokio-postgres = "0.7.15" +sonic-rs = "0.5.5" +bytes = "1.10.1" +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} + + +[[bin]] +name = "plaintext" +path = "src/plaintext.rs" +required-features = ["json_plaintext"] + +[[bin]] +name = "json" +path = "src/json.rs" +required-features = ["json_plaintext"] + + +[[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"] diff --git a/frameworks/Rust/water-http/README b/frameworks/Rust/water-http/README new file mode 100644 index 00000000000..67e4ecc228a --- /dev/null +++ b/frameworks/Rust/water-http/README @@ -0,0 +1,39 @@ +🌊 Water HTTP — TechEmpower Benchmarks + +Water HTTP is a high-performance Rust web framework built and optimized for the TechEmpower Framework Benchmarks (TFB) +. It is designed to push the limits of speed, stability, and scalability using pure asynchronous Rust and Tokio’s runtime. Every part of the framework is hand-tuned to achieve predictable latency, minimal allocations, and efficient CPU utilization under extreme concurrency. + +This repository contains the official benchmark implementations for all test types, including Plaintext, JSON serialization, Single query, Multiple queries, Fortunes, Database updates, and Cached queries. + +⚡ Highlights + +🚀 One of the fastest and most stable frameworks in the TechEmpower Benchmarks + +🧵 Built entirely on Tokio’s asynchronous runtime — no io_uring or unsafe code + +💾 Zero-copy I/O, preallocated buffers, and predictable memory layout + +🔒 100% safe Rust with no hidden synchronization overhead + +🧱 Designed for consistent high performance at scale + + +🧠 Architecture + +Water HTTP is built around a fully asynchronous, event-driven architecture that leverages non-blocking I/O and efficient request processing. The system is designed to eliminate unnecessary locks and minimize latency even under heavy load. + +[ tokio::net::TcpListener ] + ↓ + [ connection handler ] + ↓ + [ water::http::parser ] + ↓ + [ application logic ] + ↓ + [ response encoder ] +This approach ensures optimal throughput and minimal per-request overhead while keeping code simple and safe. + + +🧭 Mission + +Water HTTP’s mission is to demonstrate how Rust’s async ecosystem can reach record-breaking performance without compromising simplicity, safety, or maintainability. It shows that carefully engineered async Rust can deliver unmatched speed and reliability in real-world workloads, setting a new standard for what modern web frameworks can achieve. diff --git a/frameworks/Rust/water-http/benchmark_config.json b/frameworks/Rust/water-http/benchmark_config.json new file mode 100644 index 00000000000..2b28f0476a3 --- /dev/null +++ b/frameworks/Rust/water-http/benchmark_config.json @@ -0,0 +1,90 @@ +{ + "framework": "water-http", + "tests": [ + { + "default": { + "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", + "database": "Postgres", + "framework": "water_http", + "language": "Rust", + "orm": "raw", + "platform": "Rust", + "webserver": "water_http", + "os": "Linux", + "database_os": "Linux", + "display_name": "water_http" + }, + + "db": { + "fortune_url": "/fortunes", + "db_url": "/db", + "query_url": "/queries?q=", + "update_url": "/updates?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" + }, + + "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": { + "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", + "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" + } + } + ] +} \ No newline at end of file diff --git a/frameworks/Rust/water-http/src/cached.rs b/frameworks/Rust/water-http/src/cached.rs new file mode 100644 index 00000000000..6e1cea1a77f --- /dev/null +++ b/frameworks/Rust/water-http/src/cached.rs @@ -0,0 +1,305 @@ +#![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/db.rs b/frameworks/Rust/water-http/src/db.rs new file mode 100644 index 00000000000..40640735f88 --- /dev/null +++ b/frameworks/Rust/water-http/src/db.rs @@ -0,0 +1,320 @@ +#![cfg(any(feature = "db",feature = "all"))] +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 nanorand::{Rng, WyRand}; +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 yarte::TemplateBytesTrait; + +/// Database connection pool with thread-local RNG +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)); + } + } + } +} + + +/// Reusable buffer pool per connection +struct BufferPool { + body: BytesMut, + worlds: Vec, + numbers: Vec, + fortunes: Vec, + fortune_output: Vec, +} + +impl BufferPool { + fn new() -> Self { + Self { + body: BytesMut::with_capacity(4096), + worlds: Vec::with_capacity(501), + numbers: Vec::with_capacity(501), + + fortunes: Vec::with_capacity(501), + fortune_output: Vec::with_capacity(4096), + } + } + +} + +/// PostgreSQL connection wrapper with pre-allocated buffers +pub struct PgConnection { + pub cl: Client, + pub fortune: Statement, + pub world: Statement, + pub updates: Vec, + rang:WyRand, + buffers: UnsafeCell, + _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, conn) = 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 _ = conn.await; + }); + + let fortune = cl.prepare("SELECT * FROM fortune").await.map_err(|_| ())?; + let world = cl.prepare("SELECT id,randomnumber FROM world WHERE id=$1 LIMIT 1").await.map_err(|_| ())?; + + // Pre-compile update statements for batch sizes 1-500 + let mut updates = vec![]; + for num in 1..=500 { + let sql = Self::generate_update_values_stmt(num); + updates.push(cl.prepare(&sql).await.unwrap()); + } + + Ok(PgConnection { + cl, + fortune, + world, + updates, + buffers: UnsafeCell::new(BufferPool::new()), + _connection_task: connection_task, + rang: WyRand::new() + }) + } /// Connect to the database + + #[inline(always)] + 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 { + let id_param = i * 2 + 1; + let val_param = id_param + 1; + sql.push_str(&format!("(${}::int, ${}::int),", id_param, val_param)); + } + + // Remove the trailing comma + sql.pop(); + + sql.push_str(") AS w(i, r) WHERE world.id = w.i"); + sql + } + + /// Get mutable access to buffers (safe because connection pool ensures single access) + #[inline(always)] + fn buffers(&self) -> &mut BufferPool { + unsafe { &mut *self.buffers.get() } + } + + /// Get a single random world - optimized with buffer reuse + #[inline] + pub async fn get_world(&self) -> &[u8] { + 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(); + + sonic_rs::to_writer( + BytesMuteWriter(&mut buffers.body), + &World { + id: row.get(0), + randomnumber: row.get(1), + }, + ).unwrap(); + + buffers.body.chunk() + } + + /// Get multiple random worlds - optimized with buffer reuse + pub async fn get_worlds(&self, num: usize) -> &[u8] { + let buffers = self.buffers(); + buffers.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 { + 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() + } + /// Update worlds in batch - optimized with buffer reuse + /// Update worlds in batch - optimized with buffer reuse + + /// Update worlds in batch - optimized with buffer reuse + + /// Update worlds in batch - optimized with buffer reuse + + /// 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(); + 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() + } + + + /// 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)), + }); + } + + 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) + } +} + +/// Zero-copy writer for BytesMut +pub struct BytesMuteWriter<'a>(pub &'a mut BytesMut); + +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(()) + } +} \ No newline at end of file diff --git a/frameworks/Rust/water-http/src/json.rs b/frameworks/Rust/water-http/src/json.rs new file mode 100644 index 00000000000..71f406b6051 --- /dev/null +++ b/frameworks/Rust/water-http/src/json.rs @@ -0,0 +1,55 @@ +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 new file mode 100644 index 00000000000..487409af1d6 --- /dev/null +++ b/frameworks/Rust/water-http/src/main.rs @@ -0,0 +1,7 @@ +mod server; +pub mod models; +mod db; + +fn main() { + server::run_server(); +} diff --git a/frameworks/Rust/water-http/src/models.rs b/frameworks/Rust/water-http/src/models.rs new file mode 100644 index 00000000000..1fee7283ba9 --- /dev/null +++ b/frameworks/Rust/water-http/src/models.rs @@ -0,0 +1,25 @@ +use std::borrow::Cow; +use sonic_rs::{Serialize}; +// use askama::Template; +#[derive(Serialize)] +pub struct World { + pub id: i32, + pub randomnumber: i32, +} +#[derive(Serialize,Debug)] +pub struct Fortune { + pub id: i32, + pub message: Cow<'static, str>, +} + +#[derive(yarte::TemplateBytes)] +#[template(path = "fortune.hbs")] +pub struct FortuneTemplate<'a>{ + pub items:&'a Vec +} + + + +// pub async fn to(model:FortuneTemplate<'_>){ +// model.r +// } \ No newline at end of file diff --git a/frameworks/Rust/water-http/src/plaintext.rs b/frameworks/Rust/water-http/src/plaintext.rs new file mode 100644 index 00000000000..197da216e9c --- /dev/null +++ b/frameworks/Rust/water-http/src/plaintext.rs @@ -0,0 +1,54 @@ +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 new file mode 100644 index 00000000000..be464a0e3d6 --- /dev/null +++ b/frameworks/Rust/water-http/src/server.rs @@ -0,0 +1,290 @@ + +use std::pin::Pin; +use std::rc::Rc; +use water_http::{InitControllersRoot, RunServer, WaterController}; +use water_http::server::ServerConfigurations; +use crate::db::{DbConnectionPool}; +InitControllersRoot! { + name:ROOT, + holder_type:MainType, + shared_type:SharedType, +} + +pub struct ThreadSharedStruct{ + pg_connection: DbConnectionPool +} + +pub type MainType = u8; +pub type SharedType = Rc; + + + + +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); + #[cfg(feature = "json_plaintext")] + { + conf.worker_threads_count = cpu_nums * 2 ; + } + #[cfg(not(feature = "json_plaintext"))] + { + 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"; + const URL:&'static str = "postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world"; + 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() + }; + pool.fill_pool(URL, 1).await; + Rc::new(ThreadSharedStruct{ + pg_connection:pool + }) + }) +} + +#[cfg(any(feature = "json_plaintext",feature = "all"))] +const JSON_RESPONSE:&'static [u8] = br#"{"message":"Hello, World!"}"#; +#[cfg(any(feature = "json_plaintext",feature = "all"))] +const P:&'static [u8] = br#"Hello, World!"#; + +#[cfg(feature = "all")] +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; + } + + + 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; + } + + } +} + + + +#[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/templates/fortune.hbs b/frameworks/Rust/water-http/templates/fortune.hbs new file mode 100644 index 00000000000..b219172a075 --- /dev/null +++ b/frameworks/Rust/water-http/templates/fortune.hbs @@ -0,0 +1,5 @@ +Fortunes +{{~# each items ~}} + +{{~/each ~}} +
idmessage
{{id}}{{message}}
diff --git a/frameworks/Rust/water-http/templates/fortune.html b/frameworks/Rust/water-http/templates/fortune.html new file mode 100644 index 00000000000..35923e04b21 --- /dev/null +++ b/frameworks/Rust/water-http/templates/fortune.html @@ -0,0 +1,12 @@ + + +Fortunes + + + + {% for item in items %} + + {% endfor %} +
idmessage
{{item.id}}{{item.message}}
+ + diff --git a/frameworks/Rust/water-http/water-http-cached.dockerfile b/frameworks/Rust/water-http/water-http-cached.dockerfile new file mode 100644 index 00000000000..3c873c71520 --- /dev/null +++ b/frameworks/Rust/water-http/water-http-cached.dockerfile @@ -0,0 +1,13 @@ +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 new file mode 100644 index 00000000000..01d9507b35f --- /dev/null +++ b/frameworks/Rust/water-http/water-http-db.dockerfile @@ -0,0 +1,13 @@ +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 new file mode 100644 index 00000000000..4c457496cec --- /dev/null +++ b/frameworks/Rust/water-http/water-http-json.dockerfile @@ -0,0 +1,13 @@ +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-plaintext.dockerfile b/frameworks/Rust/water-http/water-http-plaintext.dockerfile new file mode 100644 index 00000000000..ab53eb54496 --- /dev/null +++ b/frameworks/Rust/water-http/water-http-plaintext.dockerfile @@ -0,0 +1,13 @@ +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.dockerfile b/frameworks/Rust/water-http/water-http.dockerfile new file mode 100644 index 00000000000..5946c8b3821 --- /dev/null +++ b/frameworks/Rust/water-http/water-http.dockerfile @@ -0,0 +1,13 @@ +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 all + +EXPOSE 8080 + +CMD ./target/release/water-http \ No newline at end of file diff --git a/frameworks/Rust/xitca-web/.cargo/config.toml b/frameworks/Rust/xitca-web/.cargo/config.toml index bca4c6c1b26..df736010a76 100644 --- a/frameworks/Rust/xitca-web/.cargo/config.toml +++ b/frameworks/Rust/xitca-web/.cargo/config.toml @@ -1,6 +1,6 @@ [build] -rustflags = ["-C", "target-cpu=native"] +rustflags = ["-C", "target-cpu=native", "--cfg", "tokio_unstable"] incremental = false -[target.wasm32-wasi-preview1-threads] +[target.wasm32-wasip1-threads] rustflags = ["-C", "target-feature=+simd128", "--cfg", "tokio_unstable"] diff --git a/frameworks/Rust/xitca-web/Cargo.lock b/frameworks/Rust/xitca-web/Cargo.lock index 6a87ff4b1fb..4eb82962d66 100644 --- a/frameworks/Rust/xitca-web/Cargo.lock +++ b/frameworks/Rust/xitca-web/Cargo.lock @@ -1,27 +1,33 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "addr2line" -version = "0.21.0" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" dependencies = [ "gimli", ] [[package]] -name = "adler" -version = "1.0.2" +name = "adler2" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "async-trait" -version = "0.1.74" +version = "0.1.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", @@ -39,79 +45,41 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "axum" -version = "0.6.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" -dependencies = [ - "async-trait", - "axum-core", - "bitflags 1.3.2", - "bytes", - "futures-util", - "http", - "http-body", - "hyper", - "itoa", - "matchit", - "memchr", - "mime", - "percent-encoding", - "pin-project-lite", - "rustversion", - "serde", - "serde_json", - "serde_path_to_error", - "serde_urlencoded", - "sync_wrapper", - "tokio", - "tower", - "tower-layer", - "tower-service", -] - -[[package]] -name = "axum-core" -version = "0.3.4" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" -dependencies = [ - "async-trait", - "bytes", - "futures-util", - "http", - "http-body", - "mime", - "rustversion", - "tower-layer", - "tower-service", -] +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "backtrace" -version = "0.3.69" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", "miniz_oxide", "object", "rustc-demangle", + "windows-link", ] [[package]] name = "base64" -version = "0.21.5" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bb8" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" +checksum = "212d8b8e1a22743d9241575c6ba822cf9c8fef34771c86ab7e477a4fbfd254e5" +dependencies = [ + "futures-util", + "parking_lot", + "tokio", +] [[package]] name = "bitflags" @@ -121,9 +89,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.1" +version = "2.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" [[package]] name = "block-buffer" @@ -134,6 +102,12 @@ dependencies = [ "generic-array", ] +[[package]] +name = "bumpalo" +version = "3.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" + [[package]] name = "byteorder" version = "1.5.0" @@ -142,30 +116,42 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.5.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" [[package]] name = "cc" -version = "1.0.83" +version = "1.2.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +checksum = "e1d05d92f4b1fd76aad469d46cdd858ca761576082cd37df81416691e50199fb" dependencies = [ - "libc", + "find-msvc-tools", + "shlex", ] [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" + +[[package]] +name = "core_affinity" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a034b3a7b624016c6e13f5df875747cc25f884156aad2abd12b6c46797971342" +dependencies = [ + "libc", + "num_cpus", + "winapi", +] [[package]] name = "cpufeatures" -version = "0.2.11" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" dependencies = [ "libc", ] @@ -180,6 +166,93 @@ dependencies = [ "typenum", ] +[[package]] +name = "darling" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" +dependencies = [ + "darling_core", + "quote", + "syn", +] + +[[package]] +name = "diesel" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8496eeb328dce26ee9d9b73275d396d9bddb433fa30106cf6056dd8c3c2764c" +dependencies = [ + "bitflags 2.9.4", + "byteorder", + "diesel_derives", + "downcast-rs", + "itoa", + "pq-sys", + "r2d2", +] + +[[package]] +name = "diesel-async" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c69eded9cb72c7e112505caec23da00149d4dd49f4c96b3c83b2b63f0aa3da5f" +dependencies = [ + "bb8", + "diesel", + "futures-core", + "futures-util", + "scoped-futures", + "tokio", + "tokio-postgres", +] + +[[package]] +name = "diesel_derives" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09af0e983035368439f1383011cd87c46f41da81d0f21dc3727e2857d5a43c8e" +dependencies = [ + "diesel_table_macro_syntax", + "dsl_auto_type", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "diesel_table_macro_syntax" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe2444076b48641147115697648dc743c2c00b61adade0f01ce67133c7babe8c" +dependencies = [ + "syn", +] + [[package]] name = "digest" version = "0.10.7" @@ -191,6 +264,38 @@ dependencies = [ "subtle", ] +[[package]] +name = "downcast-rs" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "117240f60069e65410b3ae1bb213295bd828f707b5bec6596a1afc8793ce0cbc" + +[[package]] +name = "dsl_auto_type" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd122633e4bef06db27737f21d3738fb89c8f6d5360d6d9d7635dda142a7757e" +dependencies = [ + "darling", + "either", + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + [[package]] name = "fallible-iterator" version = "0.2.0" @@ -198,22 +303,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" [[package]] -name = "filetime" -version = "0.2.22" +name = "find-msvc-tools" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4029edd3e734da6fe05b6cd7bd2960760a616bd2ddd0d59a0124746d6272af0" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "windows-sys", -] +checksum = "0399f9d26e5191ce32c498bebd31e7a3ceabc2745f0ac54af3f335126c3f24b3" [[package]] -name = "finl_unicode" -version = "1.2.0" +name = "float-cmp" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fcfdc7a0362c9f4444381a9e697c79d435fe65b52a37466fc2c1184cee9edc6" +checksum = "b09cf3155332e944990140d967ff5eceb70df778b34f77d8075db46e4704e6d8" +dependencies = [ + "num-traits", +] [[package]] name = "fnv" @@ -221,46 +323,61 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + [[package]] name = "form_urlencoded" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" dependencies = [ "percent-encoding", ] [[package]] name = "futures-channel" -version = "0.3.29" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", + "futures-sink", ] [[package]] name = "futures-core" -version = "0.3.29" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-sink" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.29" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" -version = "0.3.29" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-core", + "futures-sink", "futures-task", "pin-project-lite", "pin-utils", + "slab", ] [[package]] @@ -275,78 +392,80 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.11" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ "cfg-if", "libc", - "wasi", + "r-efi", + "wasi 0.14.7+wasi-0.2.4", ] [[package]] name = "gimli" -version = "0.28.1" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" [[package]] -name = "hermit-abi" -version = "0.3.3" +name = "halfbrown" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" +checksum = "0c7ed2f2edad8a14c8186b847909a41fbb9c3eafa44f88bd891114ed5019da09" +dependencies = [ + "hashbrown", + "serde", +] [[package]] -name = "hmac" -version = "0.12.1" +name = "hashbrown" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" dependencies = [ - "digest", + "allocator-api2", + "equivalent", + "foldhash", ] [[package]] -name = "home" -version = "0.5.5" +name = "heck" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" -dependencies = [ - "windows-sys", -] +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] -name = "http" -version = "0.2.11" +name = "hermit-abi" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" -dependencies = [ - "bytes", - "fnv", - "itoa", -] +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" [[package]] -name = "http-body" -version = "0.4.5" +name = "hmac" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "bytes", - "http", - "pin-project-lite", + "digest", ] [[package]] -name = "http-range-header" -version = "0.3.1" +name = "http" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f" +checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +dependencies = [ + "bytes", + "fnv", + "itoa", +] [[package]] name = "httparse" -version = "1.8.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] name = "httpdate" @@ -355,43 +474,37 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] -name = "hyper" -version = "0.14.27" +name = "ident_case" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "io-uring" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "595a0399f411a508feb2ec1e970a4a30c249351e30208960d58298de8660b0e5" dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "http", - "http-body", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2 0.4.10", - "tokio", - "tower-service", - "tracing", - "want", + "bitflags 1.3.2", + "libc", ] [[package]] name = "io-uring" -version = "0.5.13" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd1e1a01cfb924fd8c5c43b6827965db394f5a3a16c599ce03452266e1cf984c" +checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.9.4", + "cfg-if", "libc", ] [[package]] name = "itoa" -version = "1.0.9" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "itoap" @@ -399,33 +512,57 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9028f49264629065d057f340a86acb84867925865f73bbf8d47b4d149a7e88b8" +[[package]] +name = "js-sys" +version = "0.3.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + [[package]] name = "libc" -version = "0.2.150" +version = "0.2.176" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" +checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" [[package]] name = "libmimalloc-sys" -version = "0.1.35" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3979b5c37ece694f1f5e51e7ecc871fdb0f517ed04ee45f88d15d6d553cb9664" +checksum = "667f4fec20f29dfc6bc7357c582d91796c169ad7e2fce709468aefeb2c099870" dependencies = [ "cc", "libc", ] [[package]] -name = "log" -version = "0.4.20" +name = "libredox" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" +dependencies = [ + "bitflags 2.9.4", + "libc", + "redox_syscall", +] [[package]] -name = "matchit" -version = "0.7.3" +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.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" [[package]] name = "md-5" @@ -439,64 +576,53 @@ dependencies = [ [[package]] name = "memchr" -version = "2.6.4" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "mimalloc" -version = "0.1.39" +version = "0.1.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa01922b5ea280a911e323e4d2fd24b7fe5cc4042e0d2cda3c40775cdc4bdc9c" +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 = "miniz_oxide" -version = "0.7.1" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ - "adler", + "adler2", ] [[package]] name = "mio" -version = "0.8.9" -source = "git+https://github.com/fakeshadow/mio.git?rev=52b72d372bfe5807755b7f5e3e1edf282954d6ba#52b72d372bfe5807755b7f5e3e1edf282954d6ba" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" dependencies = [ "libc", - "wasi", + "wasi 0.11.1+wasi-snapshot-preview1", "windows-sys", ] -[[package]] -name = "nanorand" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" - [[package]] name = "num-traits" -version = "0.2.17" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] [[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", @@ -504,50 +630,72 @@ dependencies = [ [[package]] name = "object" -version = "0.32.1" +version = "0.37.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.18.0" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "parking_lot" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +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.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.3" +name = "phf" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" +checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" dependencies = [ - "pin-project-internal", + "phf_shared", + "serde", ] [[package]] -name = "pin-project-internal" -version = "1.1.3" +name = "phf_shared" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" +checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" dependencies = [ - "proc-macro2", - "quote", - "syn", + "siphasher", ] [[package]] name = "pin-project-lite" -version = "0.2.13" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "pin-utils" @@ -555,11 +703,17 @@ 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 = "postgres-protocol" -version = "0.6.6" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49b6c5ef183cd3ab4ba005f1ca64c21e8bd97ce4699cfea9e8d9a2c4958ca520" +checksum = "fbef655056b916eb868048276cfd5d6a7dea4f81560dfd047f97c8c6fe3fcfd4" dependencies = [ "base64", "byteorder", @@ -575,9 +729,9 @@ dependencies = [ [[package]] name = "postgres-types" -version = "0.2.6" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d2234cdee9408b523530a9b6d2d6b373d1db34f6a8e51dc03ded1828d7fb67c" +checksum = "77a120daaabfcb0e324d5bf6e411e9222994cb3795c79943a0ef28ed27ea76e4" dependencies = [ "bytes", "fallible-iterator", @@ -586,141 +740,194 @@ dependencies = [ [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "pq-sys" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "412a4cb9e93795c0594dab7c1c4ec1c8b42b514e1baf6e9f63d14aa376e5bd04" +dependencies = [ + "libc", + "pkg-config", + "vcpkg", +] [[package]] name = "proc-macro2" -version = "1.0.70" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.33" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" 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 = "r2d2" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51de85fb3fb6524929c8a2eb85e6b6d363de4e8c48f9e2c2eac4944abc181c93" +dependencies = [ + "log", + "parking_lot", + "scheduled-thread-pool", +] + [[package]] name = "rand" -version = "0.8.5" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ - "libc", "rand_chacha", "rand_core", ] [[package]] -name = "rand_chacha" -version = "0.3.1" +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "ppv-lite86", - "rand_core", + "bitflags 2.9.4", ] [[package]] -name = "rand_core" -version = "0.6.4" +name = "ref-cast" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" dependencies = [ - "getrandom", + "ref-cast-impl", ] [[package]] -name = "redox_syscall" -version = "0.3.5" +name = "ref-cast-impl" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" dependencies = [ - "bitflags 1.3.2", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "rustc-demangle" -version = "0.1.23" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" [[package]] name = "rustversion" -version = "1.0.14" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" -version = "1.0.15" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "sailfish" -version = "0.8.3" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acd5f4680149b62b3478f6af08a8f1c37794bc1bc577e28874a4d0c70084d600" +checksum = "40efbac4e16ca6b1a5706348ada4d8b67d7b417ac2001aa6c4ae092511bb1763" dependencies = [ "itoap", "ryu", - "sailfish-macros", "version_check", ] [[package]] -name = "sailfish-compiler" -version = "0.8.3" +name = "scheduled-thread-pool" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67087aca4a3886686a88cee6835089c53e6143a0b8c5be01e63e4fe2f6dfe7cb" +checksum = "3cbc66816425a074528352f5789333ecff06ca41b36b0b0efdfbb29edc391a19" dependencies = [ - "filetime", - "home", - "memchr", - "proc-macro2", - "quote", - "syn", + "parking_lot", ] [[package]] -name = "sailfish-macros" -version = "0.8.3" +name = "scoped-futures" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e47e31910c5f9230e99992568d05a5968fe4f42a635c3f912c993e9f66a619a5" +checksum = "1b24aae2d0636530f359e9d5ef0c04669d11c5e756699b27a6a6d845d8329091" dependencies = [ - "proc-macro2", - "sailfish-compiler", + "pin-project-lite", ] [[package]] -name = "scoped-tls" -version = "1.0.1" +name = "scopeguard" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" -version = "1.0.193" +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 = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.193" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -729,23 +936,15 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.108" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" dependencies = [ "itoa", + "memchr", "ryu", "serde", -] - -[[package]] -name = "serde_path_to_error" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4beec8bce849d58d06238cb50db2e1c417cfeafa4c63f692b15c82b7c80f8335" -dependencies = [ - "itoa", - "serde", + "serde_core", ] [[package]] @@ -762,33 +961,95 @@ 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.1" +version = "1.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b" dependencies = [ "libc", ] [[package]] -name = "slab" -version = "0.4.9" +name = "simd-json" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +checksum = "4255126f310d2ba20048db6321c81ab376f6a6735608bf11f0785c41f01f64e3" dependencies = [ - "autocfg", + "halfbrown", + "ref-cast", + "serde", + "serde_json", + "simdutf8", + "value-trait", +] + +[[package]] +name = "simd-json-derive" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8582b571efbbb6d89a2d3807c283a42de7e2a5d92fa09c6498ac17abb3f58220" +dependencies = [ + "itoa", + "ryu", + "simd-json", + "simd-json-derive-int", + "thiserror", + "value-trait", +] + +[[package]] +name = "simd-json-derive-int" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e60b40db276e0d588874b1317a1603e0795ef38889e09111d841a9845623efd0" +dependencies = [ + "proc-macro2", + "quote", + "simd-json", + "syn", + "thiserror", ] +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + +[[package]] +name = "siphasher" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" + +[[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.4.10" @@ -801,9 +1062,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.5" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" dependencies = [ "libc", "windows-sys", @@ -811,26 +1072,32 @@ dependencies = [ [[package]] name = "stringprep" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb41d74e231a107a1b4ee36bd1214b11285b77768d2e3824aedafa988fd36ee6" +checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" dependencies = [ - "finl_unicode", "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.5.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.39" +version = "2.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" dependencies = [ "proc-macro2", "quote", @@ -838,16 +1105,30 @@ dependencies = [ ] [[package]] -name = "sync_wrapper" -version = "0.1.2" +name = "thiserror" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] name = "tinyvec" -version = "1.6.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" dependencies = [ "tinyvec_macros", ] @@ -860,154 +1141,259 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.34.0" +version = "1.47.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9" +checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" dependencies = [ "backtrace", + "bytes", + "io-uring 0.7.10", "libc", "mio", - "num_cpus", + "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.5.5", + "slab", + "socket2 0.6.0", "windows-sys", ] +[[package]] +name = "tokio-postgres" +version = "0.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156efe7fff213168257853e1dfde202eed5f487522cbbbf7d219941d753d853" +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 0.6.0", + "tokio", + "tokio-util", + "whoami", +] + [[package]] name = "tokio-uring" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d5e02bb137e030b3a547c65a3bd2f1836d66a97369fdcc69034002b10e155ef" +checksum = "748482e3e13584a34664a710168ad5068e8cb1d968aa4ffa887e83ca6dd27967" dependencies = [ "bytes", - "io-uring", + "futures-util", + "io-uring 0.6.4", "libc", - "scoped-tls", "slab", "socket2 0.4.10", "tokio", ] [[package]] -name = "tower" -version = "0.4.13" +name = "tokio-util" +version = "0.7.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5" dependencies = [ + "bytes", "futures-core", - "futures-util", - "pin-project", + "futures-sink", "pin-project-lite", "tokio", - "tower-layer", - "tower-service", - "tracing", ] [[package]] -name = "tower-http" -version = "0.4.4" +name = "tracing" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ - "bitflags 2.4.1", - "bytes", - "futures-core", - "futures-util", - "http", - "http-body", - "http-range-header", "pin-project-lite", - "tower-layer", - "tower-service", + "tracing-core", ] [[package]] -name = "tower-layer" -version = "0.3.2" +name = "tracing-core" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" [[package]] -name = "tower-service" -version = "0.3.2" +name = "typenum" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] -name = "tracing" -version = "0.1.40" +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.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" + +[[package]] +name = "unicode-normalization" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" dependencies = [ - "log", - "pin-project-lite", - "tracing-core", + "tinyvec", ] [[package]] -name = "tracing-core" -version = "0.1.32" +name = "unicode-properties" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" + +[[package]] +name = "value-trait" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +checksum = "f83d93718a3c9696765926b8acd98588727b285ae969901f76fcf1b6cad5d5d9" dependencies = [ - "once_cell", + "float-cmp", + "halfbrown", + "itoa", + "ryu", ] [[package]] -name = "try-lock" -version = "0.2.4" +name = "vcpkg" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] -name = "typenum" -version = "1.17.0" +name = "version_check" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] -name = "unicode-bidi" -version = "0.3.13" +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] -name = "unicode-ident" -version = "1.0.12" +name = "wasi" +version = "0.14.7+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" +dependencies = [ + "wasip2", +] [[package]] -name = "unicode-normalization" -version = "0.1.22" +name = "wasip2" +version = "1.0.1+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" dependencies = [ - "tinyvec", + "wit-bindgen", ] [[package]] -name = "version_check" -version = "0.9.4" +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.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] [[package]] -name = "want" -version = "0.3.1" +name = "wasm-bindgen-macro" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119" dependencies = [ - "try-lock", + "quote", + "wasm-bindgen-macro-support", ] [[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +name = "wasm-bindgen-macro-support" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-sys" +version = "0.3.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9367c417a924a74cae129e6a2ae3b47fabb1f8995595ab474029da749a8be120" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "whoami" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "5d4a4db5077702ca3015d3d02d74974948aba2ad9e12ab7df718ee64ccd7e97d" +dependencies = [ + "libredox", + "wasite", + "web-sys", +] [[package]] name = "winapi" @@ -1031,24 +1417,31 @@ 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.48.0" +version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ "windows-targets", ] [[package]] name = "windows-targets" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +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", @@ -1057,50 +1450,71 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +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" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" -version = "0.48.5" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "wit-bindgen" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" + +[[package]] +name = "xitca-codegen" +version = "0.4.0" +source = "git+http://github.com/HFQR/xitca-web?rev=7c22b4a#7c22b4a8a23500368be2c9e30e81bd8fb39ebc12" +dependencies = [ + "quote", + "syn", +] [[package]] name = "xitca-http" -version = "0.1.0" -source = "git+https://github.com/HFQR/xitca-web.git?rev=23ad63cbb3a853a548bd447cc59625a5d7c5833e#23ad63cbb3a853a548bd447cc59625a5d7c5833e" +version = "0.7.1" +source = "git+http://github.com/HFQR/xitca-web?rev=7c22b4a#7c22b4a8a23500368be2c9e30e81bd8fb39ebc12" dependencies = [ "futures-core", "http", @@ -1108,7 +1522,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2 0.5.5", + "socket2 0.6.0", "tokio", "tokio-uring", "tracing", @@ -1120,8 +1534,9 @@ dependencies = [ [[package]] name = "xitca-io" -version = "0.1.0" -source = "git+https://github.com/HFQR/xitca-web.git?rev=23ad63cbb3a853a548bd447cc59625a5d7c5833e#23ad63cbb3a853a548bd447cc59625a5d7c5833e" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b91b7a5ff9e3bed167b7e3bcc7b4462d2cb16d05e3ae913dbc384e463fdd7f" dependencies = [ "bytes", "tokio", @@ -1131,34 +1546,48 @@ dependencies = [ [[package]] name = "xitca-postgres" -version = "0.1.0" -source = "git+https://github.com/HFQR/xitca-web.git?rev=23ad63cbb3a853a548bd447cc59625a5d7c5833e#23ad63cbb3a853a548bd447cc59625a5d7c5833e" +version = "0.3.0" +source = "git+http://github.com/HFQR/xitca-web?rev=7c22b4a#7c22b4a8a23500368be2c9e30e81bd8fb39ebc12" dependencies = [ "fallible-iterator", + "futures-core", "percent-encoding", "postgres-protocol", "postgres-types", "tokio", "tracing", "xitca-io", - "xitca-service", "xitca-unsafe-collection", ] +[[package]] +name = "xitca-postgres-diesel" +version = "0.2.0" +source = "git+https://github.com/fakeshadow/xitca-postgres-diesel?rev=8ce4e5b#8ce4e5bb138765bc1780642adfefc4d3b8427bb7" +dependencies = [ + "diesel", + "diesel-async", + "futures-util", + "scoped-futures", + "tokio", + "xitca-postgres", +] + [[package]] name = "xitca-router" -version = "0.1.0" -source = "git+https://github.com/HFQR/xitca-web.git?rev=23ad63cbb3a853a548bd447cc59625a5d7c5833e#23ad63cbb3a853a548bd447cc59625a5d7c5833e" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35a771113f381c9a2f5ae1096b70d629ed241a1a473304ea902258c3d528f536" dependencies = [ "xitca-unsafe-collection", ] [[package]] name = "xitca-server" -version = "0.1.0" -source = "git+https://github.com/HFQR/xitca-web.git?rev=23ad63cbb3a853a548bd447cc59625a5d7c5833e#23ad63cbb3a853a548bd447cc59625a5d7c5833e" +version = "0.5.0" +source = "git+http://github.com/HFQR/xitca-web?rev=7c22b4a#7c22b4a8a23500368be2c9e30e81bd8fb39ebc12" dependencies = [ - "socket2 0.5.5", + "socket2 0.6.0", "tokio", "tokio-uring", "tracing", @@ -1169,13 +1598,14 @@ dependencies = [ [[package]] name = "xitca-service" -version = "0.1.0" -source = "git+https://github.com/HFQR/xitca-web.git?rev=23ad63cbb3a853a548bd447cc59625a5d7c5833e#23ad63cbb3a853a548bd447cc59625a5d7c5833e" +version = "0.3.0" +source = "git+http://github.com/HFQR/xitca-web?rev=7c22b4a#7c22b4a8a23500368be2c9e30e81bd8fb39ebc12" [[package]] name = "xitca-unsafe-collection" -version = "0.1.0" -source = "git+https://github.com/HFQR/xitca-web.git?rev=23ad63cbb3a853a548bd447cc59625a5d7c5833e#23ad63cbb3a853a548bd447cc59625a5d7c5833e" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "467b95b08735dcd7061be626d02aea062bc0b99918bc9de11b8fc15d901158ae" dependencies = [ "bytes", ] @@ -1185,39 +1615,65 @@ name = "xitca-web" version = "0.1.0" dependencies = [ "atoi", - "axum", + "core_affinity", + "diesel", + "diesel-async", "futures-core", - "http-body", + "futures-util", + "httparse", "mimalloc", - "nanorand", - "pin-project-lite", + "rand", "sailfish", "serde", "serde_json", + "simd-json", + "simd-json-derive", "tokio", - "tower", - "tower-http", + "tokio-uring", "xitca-http", "xitca-io", "xitca-postgres", + "xitca-postgres-diesel", "xitca-server", "xitca-service", "xitca-unsafe-collection", - "xitca-web 0.1.0 (git+https://github.com/HFQR/xitca-web.git?rev=23ad63cbb3a853a548bd447cc59625a5d7c5833e)", + "xitca-web 0.7.1", ] [[package]] name = "xitca-web" -version = "0.1.0" -source = "git+https://github.com/HFQR/xitca-web.git?rev=23ad63cbb3a853a548bd447cc59625a5d7c5833e#23ad63cbb3a853a548bd447cc59625a5d7c5833e" +version = "0.7.1" +source = "git+http://github.com/HFQR/xitca-web?rev=7c22b4a#7c22b4a8a23500368be2c9e30e81bd8fb39ebc12" dependencies = [ "futures-core", "pin-project-lite", "serde", "serde_json", + "serde_urlencoded", "tokio", + "xitca-codegen", "xitca-http", "xitca-server", "xitca-service", "xitca-unsafe-collection", ] + +[[package]] +name = "zerocopy" +version = "0.8.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/frameworks/Rust/xitca-web/Cargo.toml b/frameworks/Rust/xitca-web/Cargo.toml index 10af08ac491..dd95fc7b92a 100644 --- a/frameworks/Rust/xitca-web/Cargo.toml +++ b/frameworks/Rust/xitca-web/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "xitca-web" version = "0.1.0" -edition = "2021" +edition = "2024" [[bin]] name = "xitca-web" @@ -9,69 +9,81 @@ path = "./src/main.rs" required-features = ["io-uring", "pg", "router", "template"] [[bin]] -name = "xitca-web-iou" -path = "./src/main_iou.rs" -required-features = ["io-uring", "pg-iou", "template"] +name = "xitca-web-unrealistic" +path = "./src/main_unrealistic.rs" +required-features = ["perf", "pg", "template"] [[bin]] -name = "xitca-web-wasm" -path = "./src/main_wasm.rs" -required-features = ["web"] +name = "xitca-web-orm" +path = "./src/main_orm.rs" +required-features = ["pg-orm-async", "template", "web-codegen"] [[bin]] -name = "xitca-web-axum" -path = "./src/main_axum.rs" -required-features = ["axum", "io-uring"] +name = "xitca-web-sync" +path = "./src/main_sync.rs" +required-features = ["pg-orm", "template", "web-codegen"] [features] -# pg optional -pg = ["xitca-postgres"] -# pg io_uring optional -pg-iou = ["xitca-postgres/io-uring"] +# pg client optional +pg = ["dep:xitca-postgres"] +# diesel orm optional +pg-orm = ["diesel/r2d2"] +# diesel async orm optional +pg-orm-async = ["dep:diesel", "dep:diesel-async", "dep:xitca-postgres-diesel", "dep:futures-util"] # http router optional router = ["xitca-http/router"] # web optional -web = ["xitca-web"] +web = ["dep:xitca-web"] +# web with macros optional +web-codegen = ["xitca-web/codegen", "xitca-web/urlencoded"] # template optional -template = ["sailfish"] +template = ["dep:sailfish"] # io-uring optional -io-uring = ["xitca-http/io-uring", "xitca-server/io-uring"] -# axum optional -axum = ["dep:axum", "http-body", "pin-project-lite", "tower", "tower-http"] +io-uring = ["dep:tokio-uring", "xitca-http/io-uring", "xitca-server/io-uring"] +# unrealistic performance optimization +perf = ["dep:core_affinity", "dep:mimalloc", "tokio/parking_lot", "simd-json", "simd-json-derive"] [dependencies] -xitca-http = "0.1" -xitca-io = "0.1" -xitca-server = "0.1" -xitca-service = "0.1" -xitca-unsafe-collection = "0.1" +xitca-http = "0.7" +xitca-io = "0.4.1" +xitca-server = "0.5" +xitca-service = "0.3" +xitca-unsafe-collection = "0.2" atoi = "2" +httparse = "1" serde = { version = "1" } serde_json = { version = "1" } # web optional -xitca-web = { version = "0.1", features = ["json"], optional = true } +xitca-web = { version = "0.7", features = ["json"], optional = true } # raw-pg optional -xitca-postgres = { version = "0.1", features = ["single-thread"], optional = true } +xitca-postgres = { version = "0.3", optional = true } + +# orm optional +diesel = { version = "2", features = ["postgres"], optional = true } + +# orm async optional +diesel-async = { version = "0.7", features = ["bb8", "postgres"], optional = true } +xitca-postgres-diesel = { version = "0.2", optional = true } +futures-util = { version = "0.3", default-features = false, optional = true } # template optional -sailfish = { version = "0.8", default-features = false, features = ["derive", "perf-inline"], optional = true } +sailfish = { version = "0.10", default-features = false, features = ["perf-inline"], optional = true } -# axum optional -axum = { version = "0.6", optional = true } -http-body = { version = "0.4", optional = true } -pin-project-lite = { version = "0.2", optional = true } -tower = { version = "0.4", optional = true } -tower-http = { version = "0.4", features = ["set-header"], optional = true } +# 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 } +simd-json = { version = "0.17", optional = true } +simd-json-derive = { version = "0.18", default-features = false, optional = true } -# stuff can not be used or not needed in wasi target -[target.'cfg(not(target_family = "wasm"))'.dependencies] futures-core = { version = "0.3", default-features = false } -mimalloc = { version = "0.1", default-features = false } -nanorand = { version = "0.7", default-features = false, features = ["tls"] } -tokio = "1" +rand = { version = "0.9", features = ["os_rng", "small_rng"], default-features = false } +tokio = "1.41" [profile.release] lto = true @@ -80,13 +92,11 @@ codegen-units = 1 panic = "abort" [patch.crates-io] -xitca-http = { git = "https://github.com/HFQR/xitca-web.git", rev = "23ad63cbb3a853a548bd447cc59625a5d7c5833e" } -xitca-io = { git = "https://github.com/HFQR/xitca-web.git", rev = "23ad63cbb3a853a548bd447cc59625a5d7c5833e" } -xitca-postgres = { git = "https://github.com/HFQR/xitca-web.git", rev = "23ad63cbb3a853a548bd447cc59625a5d7c5833e" } -xitca-router = { git = "https://github.com/HFQR/xitca-web.git", rev = "23ad63cbb3a853a548bd447cc59625a5d7c5833e" } -xitca-server = { git = "https://github.com/HFQR/xitca-web.git", rev = "23ad63cbb3a853a548bd447cc59625a5d7c5833e" } -xitca-service = { git = "https://github.com/HFQR/xitca-web.git", rev = "23ad63cbb3a853a548bd447cc59625a5d7c5833e" } -xitca-unsafe-collection = { git = "https://github.com/HFQR/xitca-web.git", rev = "23ad63cbb3a853a548bd447cc59625a5d7c5833e" } -xitca-web = { git = "https://github.com/HFQR/xitca-web.git", rev = "23ad63cbb3a853a548bd447cc59625a5d7c5833e" } - -mio = { git = "https://github.com/fakeshadow/mio.git", rev = "52b72d372bfe5807755b7f5e3e1edf282954d6ba" } +xitca-postgres-diesel = { git = "https://github.com/fakeshadow/xitca-postgres-diesel", rev = "8ce4e5b" } + +xitca-codegen = { git = "http://github.com/HFQR/xitca-web", rev = "7c22b4a" } +xitca-http = { git = "http://github.com/HFQR/xitca-web", rev = "7c22b4a" } +xitca-postgres = { git = "http://github.com/HFQR/xitca-web", rev = "7c22b4a" } +xitca-server = { git = "http://github.com/HFQR/xitca-web", rev = "7c22b4a" } +xitca-service = { git = "http://github.com/HFQR/xitca-web", rev = "7c22b4a" } +xitca-web = { git = "http://github.com/HFQR/xitca-web", rev = "7c22b4a" } diff --git a/frameworks/Rust/xitca-web/benchmark_config.json b/frameworks/Rust/xitca-web/benchmark_config.json index 060cb47b354..c60cf0bc3b2 100755 --- a/frameworks/Rust/xitca-web/benchmark_config.json +++ b/frameworks/Rust/xitca-web/benchmark_config.json @@ -24,7 +24,7 @@ "notes": "", "versus": "" }, - "iou": { + "unrealistic": { "json_url": "/json", "plaintext_url": "/plaintext", "db_url": "/db", @@ -35,7 +35,7 @@ "approach": "Stripped", "classification": "Platform", "database": "Postgres", - "framework": "xitca-web [unrealistic]", + "framework": "xitca-web", "language": "Rust", "orm": "Raw", "platform": "None", @@ -46,39 +46,47 @@ "notes": "", "versus": "" }, - "wasm": { + "orm": { "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": "Micro", - "database": "none", - "framework": "xitca-web [wasm]", + "approach": "realistic", + "classification": "fullstack", + "database": "postgres", + "framework": "xitca-web", "language": "rust", - "orm": "raw", + "orm": "full", "platform": "none", "webserver": "xitca-server", "os": "linux", "database_os": "linux", - "display_name": "xitca-web [wasm]", + "display_name": "xitca-web [orm]", "notes": "", "versus": "" }, - "axum": { + "sync": { "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": "Micro", - "database": "none", - "framework": "axum [xitca]", + "approach": "realistic", + "classification": "micro", + "database": "postgres", + "framework": "xitca-web", "language": "rust", - "orm": "raw", + "orm": "full", "platform": "none", "webserver": "xitca-server", "os": "linux", "database_os": "linux", - "display_name": "axum [xitca]", + "display_name": "xitca-web [sync]", "notes": "", "versus": "" } diff --git a/frameworks/Rust/xitca-web/config.toml b/frameworks/Rust/xitca-web/config.toml index 7ffa19fbbce..8646eae05e0 100644 --- a/frameworks/Rust/xitca-web/config.toml +++ b/frameworks/Rust/xitca-web/config.toml @@ -47,13 +47,3 @@ orm = "Raw" platform = "None" webserver = "xitca-server" versus = "" - -[wasm] -urls.json = "/json" -urls.plaintext = "/plaintext" -approach = "Realistic" -classification = "Micro" -os = "wasi" -platform = "wasm" -webserver = "xitca-server" -versus = "" diff --git a/frameworks/Rust/xitca-web/rust-toolchain.toml b/frameworks/Rust/xitca-web/rust-toolchain.toml deleted file mode 100644 index 3191ef83ece..00000000000 --- a/frameworks/Rust/xitca-web/rust-toolchain.toml +++ /dev/null @@ -1,2 +0,0 @@ -[toolchain] -channel = "nightly-2023-11-24" diff --git a/frameworks/Rust/xitca-web/rustfmt.toml b/frameworks/Rust/xitca-web/rustfmt.toml new file mode 100644 index 00000000000..866c7561055 --- /dev/null +++ b/frameworks/Rust/xitca-web/rustfmt.toml @@ -0,0 +1 @@ +max_width = 120 \ No newline at end of file diff --git a/frameworks/Rust/xitca-web/src/db.rs b/frameworks/Rust/xitca-web/src/db.rs index 211931c1893..b35affdc61b 100644 --- a/frameworks/Rust/xitca-web/src/db.rs +++ b/frameworks/Rust/xitca-web/src/db.rs @@ -1,103 +1,61 @@ -use std::{cell::RefCell, collections::HashMap, fmt::Write, future::IntoFuture}; +#[path = "./db_util.rs"] +mod db_util; -use xitca_postgres::{statement::Statement, AsyncIterator, Postgres}; -use xitca_unsafe_collection::no_hash::NoHashBuilder; +use core::cell::RefCell; + +use xitca_postgres::{Execute, iter::AsyncLendingIterator, pipeline::Pipeline, pool::Pool, statement::Statement}; use super::{ ser::{Fortune, Fortunes, World}, - util::{HandleResult, Rand}, + util::{DB_URL, HandleResult}, }; -pub struct Client { - client: xitca_postgres::Client, - rng: RefCell, - fortune: Statement, - world: Statement, - updates: HashMap, -} +use db_util::{FORTUNE_STMT, Shared, WORLD_STMT, not_found, sort_update_params, update_query_from_num}; -impl Drop for Client { - fn drop(&mut self) { - drop(self.fortune.clone().into_guarded(&self.client)); - drop(self.world.clone().into_guarded(&self.client)); - for (_, stmt) in std::mem::take(&mut self.updates) { - drop(stmt.into_guarded(&self.client)) - } - } +pub struct Client { + pool: Pool, + shared: RefCell, + updates: Box<[Box]>, } -pub async fn create(config: &str) -> HandleResult { - let (client, driver) = Postgres::new(config.to_string()).connect().await?; - - tokio::task::spawn_local(tokio::task::unconstrained(driver.into_future())); - - let fortune = client.prepare("SELECT * FROM fortune", &[]).await?.leak(); - - let world = client - .prepare("SELECT * FROM world WHERE id=$1", &[]) - .await? - .leak(); - - let mut updates = HashMap::default(); - - for num in 1..=500u16 { - let mut pl = 1; - let mut q = String::new(); - q.push_str("UPDATE world SET randomnumber = CASE id "); - for _ in 1..=num { - let _ = write!(&mut q, "when ${} then ${} ", pl, pl + 1); - pl += 2; - } - q.push_str("ELSE randomnumber END WHERE id IN ("); - for _ in 1..=num { - let _ = write!(&mut q, "${},", pl); - pl += 1; - } - q.pop(); - q.push(')'); - - let st = client.prepare(&q, &[]).await?.leak(); - updates.insert(num, st); - } - +pub async fn create() -> HandleResult { Ok(Client { - client, - rng: RefCell::new(Rand::default()), - fortune, - world, - updates, + pool: Pool::builder(DB_URL).capacity(1).build()?, + shared: Default::default(), + updates: core::iter::once(Box::from("")) + .chain((1..=500).map(update_query_from_num)) + .collect(), }) } impl Client { pub async fn get_world(&self) -> HandleResult { - let id = self.rng.borrow_mut().gen_id(); - self.client - .query_raw(&self.world, [id]) - .await? - .next() - .await - .ok_or_else(|| format!("World {id} does not exist"))? - .map(|row| World::new(row.get_raw(0), row.get_raw(1))) - .map_err(Into::into) + let mut conn = self.pool.get().await?; + let stmt = WORLD_STMT.execute(&mut conn).await?; + let id = self.shared.borrow_mut().0.gen_id(); + let mut res = stmt.bind([id]).query(&conn.consume()).await?; + 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 pipe = self.client.pipeline(); + let len = num as usize; - { - let mut rng = self.rng.borrow_mut(); - (0..num).try_for_each(|_| pipe.query_raw(&self.world, [rng.gen_id()]))?; - } + let mut conn = self.pool.get().await?; + let stmt = WORLD_STMT.execute(&mut conn).await?; - let mut worlds = Vec::new(); - worlds.reserve(num as usize); + let mut res = { + let (ref mut rng, ref mut buf) = *self.shared.borrow_mut(); + let mut pipe = Pipeline::with_capacity_from_buf(len, buf); + (0..num).try_for_each(|_| stmt.bind([rng.gen_id()]).query(&mut pipe))?; + pipe.query(&conn.consume())? + }; - let mut res = pipe.run().await?; - while let Some(mut item) = res.next().await.transpose()? { - while let Some(row) = item.next().await.transpose()? { - worlds.push(World::new(row.get_raw(0), row.get_raw(1))) - } + let mut worlds = Vec::with_capacity(len); + + while let Some(mut item) = res.try_next().await? { + let row = item.try_next().await?.ok_or_else(not_found)?; + worlds.push(World::new(row.get(0), row.get(1))); } Ok(worlds) @@ -106,34 +64,34 @@ impl Client { pub async fn update(&self, num: u16) -> HandleResult> { let len = num as usize; - let mut params = Vec::new(); - params.reserve(len * 3); + let update = self.updates.get(len).ok_or("request num is out of range")?; + let mut conn = self.pool.get().await?; + let world_stmt = WORLD_STMT.execute(&mut conn).await?; + let update_stmt = Statement::named(update, &[]).execute(&mut conn).await?; - let mut pipe = self.client.pipeline(); + let mut params = Vec::with_capacity(len); - { - let mut rng = self.rng.borrow_mut(); + let mut res = { + let (ref mut rng, ref mut buf) = *self.shared.borrow_mut(); + let mut pipe = Pipeline::with_capacity_from_buf(len + 1, buf); (0..num).try_for_each(|_| { let w_id = rng.gen_id(); let r_id = rng.gen_id(); - params.extend([w_id, r_id]); - pipe.query_raw(&self.world, [w_id]) + params.push([w_id, r_id]); + world_stmt.bind([w_id]).query(&mut pipe) })?; - } + update_stmt.bind(sort_update_params(¶ms)).query(&mut pipe)?; + pipe.query(&conn.consume())? + }; - params.extend_from_within(..len); - let st = self.updates.get(&num).unwrap(); - pipe.query_raw(st, ¶ms)?; + let mut worlds = Vec::with_capacity(len); - let mut worlds = Vec::new(); - worlds.reserve(len); - let mut r_ids = params.into_iter().skip(1).step_by(2); + let mut r_ids = params.into_iter(); - let mut res = pipe.run().await?; - while let Some(mut item) = res.next().await.transpose()? { - while let Some(row) = item.next().await.transpose()? { - let r_id = r_ids.next().unwrap(); - worlds.push(World::new(row.get_raw(0), r_id)) + while let Some(mut item) = res.try_next().await? { + while let Some(row) = item.try_next().await? { + let r_id = r_ids.next().unwrap()[1]; + worlds.push(World::new(row.get(0), r_id)) } } @@ -144,10 +102,14 @@ impl Client { let mut items = Vec::with_capacity(32); items.push(Fortune::new(0, "Additional fortune added at request time.")); - let mut stream = self.client.query_raw::<[i32; 0]>(&self.fortune, []).await?; - while let Some(row) = stream.next().await.transpose()? { - items.push(Fortune::new(row.get_raw(0), row.get_raw::(1))); + let mut conn = self.pool.get().await?; + let stmt = FORTUNE_STMT.execute(&mut conn).await?; + let mut res = stmt.query(&conn.consume()).await?; + + while let Some(row) = res.try_next().await? { + items.push(Fortune::new(row.get(0), row.get::(1))); } + items.sort_by(|it, next| it.message.cmp(&next.message)); Ok(Fortunes::new(items)) diff --git a/frameworks/Rust/xitca-web/src/db_diesel.rs b/frameworks/Rust/xitca-web/src/db_diesel.rs new file mode 100644 index 00000000000..f187afc54e1 --- /dev/null +++ b/frameworks/Rust/xitca-web/src/db_diesel.rs @@ -0,0 +1,104 @@ +#[path = "./db_util.rs"] +mod db_util; + +use std::{ + io, + sync::{Arc, Mutex}, +}; + +use diesel::{prelude::*, r2d2}; + +use crate::{ + ser::{Fortune, Fortunes, World}, + util::{DB_URL, HandleResult, Rand}, +}; + +use db_util::{not_found, update_query_from_ids}; + +pub type Pool = Arc<_Pool>; + +pub struct _Pool { + pool: r2d2::Pool>, + rng: Mutex, +} + +pub fn create() -> io::Result> { + r2d2::Builder::new() + .max_size(100) + .min_idle(Some(100)) + .test_on_check_out(false) + .idle_timeout(None) + .max_lifetime(None) + .build(r2d2::ConnectionManager::new(DB_URL)) + .map_err(io::Error::other) + .map(|pool| { + Arc::new(_Pool { + pool, + rng: Mutex::new(Rand::default()), + }) + }) +} + +impl _Pool { + pub fn get_world(&self) -> HandleResult { + use crate::schema::world::dsl::*; + + let w_id = self.rng.lock().unwrap().gen_id(); + let mut conn = self.pool.get()?; + world.filter(id.eq(w_id)).load(&mut conn)?.pop().ok_or_else(not_found) + } + + pub fn get_worlds(&self, num: u16) -> HandleResult> { + use crate::schema::world::dsl::*; + + let mut conn = self.pool.get()?; + core::iter::repeat_with(|| { + let w_id = self.rng.lock().unwrap().gen_id(); + world.filter(id.eq(w_id)).load(&mut conn)?.pop().ok_or_else(not_found) + }) + .take(num as _) + .collect() + } + + pub fn update(&self, num: u16) -> HandleResult> { + use crate::schema::world::dsl::*; + + let mut rngs = { + let mut rng = self.rng.lock().unwrap(); + (0..num).map(|_| (rng.gen_id(), rng.gen_id())).collect::>() + }; + + rngs.sort_by(|(a, _), (b, _)| a.cmp(b)); + + let update_sql = update_query_from_ids(&rngs); + + let mut conn = self.pool.get()?; + + let worlds = rngs + .into_iter() + .map(|(w_id, num)| { + let mut w: World = world.filter(id.eq(w_id)).load(&mut conn)?.pop().ok_or_else(not_found)?; + w.randomnumber = num; + Ok(w) + }) + .collect::>>()?; + + diesel::sql_query(update_sql).execute(&mut conn)?; + + Ok(worlds) + } + + pub fn tell_fortune(&self) -> HandleResult { + use crate::schema::fortune::dsl::*; + + let mut items = { + let mut conn = self.pool.get()?; + fortune.load(&mut conn)? + }; + + items.push(Fortune::new(0, "Additional fortune added at request time.")); + items.sort_by(|it, next| it.message.cmp(&next.message)); + + Ok(Fortunes::new(items)) + } +} diff --git a/frameworks/Rust/xitca-web/src/db_diesel_async.rs b/frameworks/Rust/xitca-web/src/db_diesel_async.rs new file mode 100644 index 00000000000..edae0afec03 --- /dev/null +++ b/frameworks/Rust/xitca-web/src/db_diesel_async.rs @@ -0,0 +1,122 @@ +#[path = "./db_util.rs"] +mod db_util; + +use std::{io, sync::Mutex}; + +use diesel::prelude::*; +use diesel_async::{ + RunQueryDsl, + pooled_connection::{AsyncDieselConnectionManager, bb8}, +}; +use futures_util::{ + future::join, + stream::{FuturesUnordered, TryStreamExt}, +}; +use xitca_postgres_diesel::AsyncPgConnection; + +use crate::{ + ser::{Fortune, Fortunes, World}, + util::{DB_URL, HandleResult, Rand}, +}; + +use db_util::{not_found, update_query_from_ids}; + +pub struct Pool { + pool: bb8::Pool, + rng: Mutex, +} + +pub async fn create() -> io::Result { + bb8::Pool::builder() + .max_size(1) + .min_idle(Some(1)) + .test_on_check_out(false) + .build(AsyncDieselConnectionManager::new(DB_URL)) + .await + .map_err(io::Error::other) + .map(|pool| Pool { + pool, + rng: Mutex::new(Rand::default()), + }) +} + +impl Pool { + pub async fn get_world(&self) -> HandleResult { + use crate::schema::world::dsl::*; + { + let w_id = self.rng.lock().unwrap().gen_id(); + let mut conn = self.pool.get().await?; + world.filter(id.eq(w_id)).load(&mut conn) + } + .await? + .pop() + .ok_or_else(not_found) + } + + pub async fn get_worlds(&self, num: u16) -> HandleResult> { + use crate::schema::world::dsl::*; + { + let mut conn = self.pool.get().await?; + let mut rng = self.rng.lock().unwrap(); + core::iter::repeat_with(|| { + let w_id = rng.gen_id(); + let fut = world.filter(id.eq(w_id)).load(&mut conn); + async { fut.await?.pop().ok_or_else(not_found) } + }) + .take(num as _) + .collect::>() + } + .try_collect() + .await + } + + pub async fn update(&self, num: u16) -> HandleResult> { + use crate::schema::world::dsl::*; + + let (select_res, update_res) = { + let mut conn = self.pool.get().await?; + let mut rng = self.rng.lock().unwrap(); + + let (select, mut rngs) = core::iter::repeat_with(|| { + let w_id = rng.gen_id(); + let num = rng.gen_id(); + + let fut = world.filter(id.eq(w_id)).load::(&mut conn); + let select = async move { + let mut w = fut.await?.pop().ok_or_else(not_found)?; + w.randomnumber = num; + HandleResult::Ok(w) + }; + + (select, (w_id, num)) + }) + .take(num as _) + .collect::<(FuturesUnordered<_>, Vec<_>)>(); + + rngs.sort_by(|(a, _), (b, _)| a.cmp(b)); + + let update = diesel::sql_query(update_query_from_ids(&rngs)).execute(&mut conn); + + join(select.try_collect::>(), update) + } + .await; + + update_res?; + select_res + } + + pub async fn tell_fortune(&self) -> HandleResult { + use crate::schema::fortune::dsl::*; + + let mut items = { + let mut conn = self.pool.get().await?; + fortune.load(&mut conn) + } + .await?; + + items.push(Fortune::new(0, "Additional fortune added at request time.")); + items.sort_by(|it, next| it.message.cmp(&next.message)); + + Ok(Fortunes::new(items)) + } +} diff --git a/frameworks/Rust/xitca-web/src/db_unrealistic.rs b/frameworks/Rust/xitca-web/src/db_unrealistic.rs new file mode 100644 index 00000000000..cacd6367656 --- /dev/null +++ b/frameworks/Rust/xitca-web/src/db_unrealistic.rs @@ -0,0 +1,130 @@ +//! this module is unrealistic. related issue: +//! https://github.com/TechEmpower/FrameworkBenchmarks/issues/8790 + +#[path = "./db_util.rs"] +mod db_util; + +use std::cell::RefCell; + +use xitca_postgres::{Execute, iter::AsyncLendingIterator, pipeline::Pipeline, statement::Statement}; + +use super::{ + ser::{Fortune, Fortunes, World}, + util::{DB_URL, HandleResult}, +}; + +use db_util::{FORTUNE_STMT, Shared, WORLD_STMT, not_found, sort_update_params, update_query_from_num}; + +pub struct Client { + cli: xitca_postgres::Client, + shared: RefCell, + fortune: Statement, + world: Statement, + updates: Box<[Statement]>, +} + +pub async fn create() -> HandleResult { + let (cli, mut drv) = xitca_postgres::Postgres::new(DB_URL).connect().await?; + + tokio::task::spawn(tokio::task::unconstrained(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 mut updates = vec![Statement::default()]; + + for update in (1..=500).map(update_query_from_num) { + let stmt = Statement::named(&update, &[]).execute(&cli).await?.leak(); + updates.push(stmt); + } + + Ok(Client { + cli, + shared: Default::default(), + world, + fortune, + updates: updates.into_boxed_slice(), + }) +} + +impl Client { + pub async fn get_world(&self) -> HandleResult { + let id = self.shared.borrow_mut().0.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 get_worlds(&self, num: u16) -> HandleResult> { + let len = num as usize; + + let mut res = { + let (ref mut rng, ref mut buf) = *self.shared.borrow_mut(); + // unrealistic as all queries are sent with only one sync point. + let mut pipe = Pipeline::unsync_with_capacity_from_buf(len, buf); + (0..num).try_for_each(|_| self.world.bind([rng.gen_id()]).query(&mut pipe))?; + pipe.query(&self.cli)? + }; + + let mut worlds = Vec::with_capacity(len); + + while let Some(mut item) = res.try_next().await? { + while let Some(row) = item.try_next().await? { + worlds.push(World::new(row.get(0), row.get(1))); + } + } + + Ok(worlds) + } + + pub async fn update(&self, num: u16) -> HandleResult> { + let len = num as usize; + + let mut params = Vec::with_capacity(len); + + let mut res = { + let (ref mut rng, ref mut buf) = *self.shared.borrow_mut(); + // unrealistic as all queries are sent with only one sync point. + let mut pipe = Pipeline::unsync_with_capacity_from_buf(len + 1, buf); + (0..num).try_for_each(|_| { + let w_id = rng.gen_id(); + let r_id = rng.gen_id(); + params.push([w_id, r_id]); + self.world.bind([w_id]).query(&mut pipe) + })?; + self.updates[len].bind(sort_update_params(¶ms)).query(&mut pipe)?; + pipe.query(&self.cli)? + }; + + let mut worlds = Vec::with_capacity(len); + + let mut r_ids = params.into_iter(); + + while let Some(mut item) = res.try_next().await? { + while let Some(row) = item.try_next().await? { + let r_id = r_ids.next().unwrap()[1]; + worlds.push(World::new(row.get(0), r_id)) + } + } + + Ok(worlds) + } + + pub async fn tell_fortune(&self) -> HandleResult { + let mut items = Vec::with_capacity(32); + items.push(Fortune::new(0, "Additional fortune added at request time.")); + + 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))); + } + + items.sort_by(|it, next| it.message.cmp(&next.message)); + + Ok(Fortunes::new(items)) + } +} diff --git a/frameworks/Rust/xitca-web/src/db_util.rs b/frameworks/Rust/xitca-web/src/db_util.rs new file mode 100644 index 00000000000..74936ab14e4 --- /dev/null +++ b/frameworks/Rust/xitca-web/src/db_util.rs @@ -0,0 +1,97 @@ +use crate::util::Error; + +#[cfg(any(feature = "pg-orm", feature = "pg-orm-async"))] +// diesel does not support high level bulk update api. use raw sql to bypass the limitation. +// relate discussion: https://github.com/diesel-rs/diesel/discussions/2879 +pub fn update_query_from_ids(ids: &[(i32, i32)]) -> String { + update_query(|query| { + use core::fmt::Write; + ids.iter().for_each(|(w_id, num)| { + write!(query, "({}::int,{}::int),", w_id, num).unwrap(); + }); + }) +} + +fn update_query(func: impl FnOnce(&mut String)) -> String { + const PREFIX: &str = "UPDATE world SET randomNumber = w.r FROM (VALUES "; + const SUFFIX: &str = ") AS w (i,r) WHERE world.id = w.i"; + + let mut query = String::from(PREFIX); + + func(&mut query); + + if query.ends_with(',') { + query.pop(); + } + + query.push_str(SUFFIX); + + query +} + +#[cold] +#[inline(never)] +pub fn not_found() -> Error { + "request World does not exist".into() +} + +#[cfg(feature = "pg")] +pub use pg::*; + +#[cfg(feature = "pg")] +pub mod pg { + use xitca_io::bytes::BytesMut; + use xitca_postgres::{ + statement::{Statement, StatementNamed}, + types::Type, + }; + + use crate::util::Rand; + + pub type Shared = (Rand, BytesMut); + + pub const FORTUNE_STMT: StatementNamed = Statement::named("SELECT * FROM fortune", &[]); + pub const WORLD_STMT: StatementNamed = Statement::named("SELECT * FROM world WHERE id=$1", &[Type::INT4]); + + pub fn update_query_from_num(num: usize) -> Box { + super::update_query(|query| { + use core::fmt::Write; + (1..=num).fold(1, |idx, _| { + write!(query, "(${}::int,${}::int),", idx, idx + 1).unwrap(); + idx + 2 + }); + }) + .into_boxed_str() + } + + pub fn sort_update_params(params: &[[i32; 2]]) -> impl ExactSizeIterator + Clone { + let mut params = params.to_owned(); + params.sort_by(|a, b| a[0].cmp(&b[0])); + + #[derive(Clone)] + struct ParamIter(I); + + impl Iterator for ParamIter + where + I: Iterator, + { + type Item = I::Item; + + #[inline] + fn next(&mut self) -> Option { + self.0.next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.0.size_hint() + } + } + + // impl depends on compiler optimization to flat Vec<[T]> to Vec when inferring + // it's size hint. possible to cause runtime panic. + impl ExactSizeIterator for ParamIter where I: Iterator {} + + ParamIter(params.into_iter().flatten()) + } +} diff --git a/frameworks/Rust/xitca-web/src/main.rs b/frameworks/Rust/xitca-web/src/main.rs index 2bc0d5fc720..449651ed129 100755 --- a/frameworks/Rust/xitca-web/src/main.rs +++ b/frameworks/Rust/xitca-web/src/main.rs @@ -1,99 +1,94 @@ -#[global_allocator] -static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; - mod db; mod ser; mod util; use xitca_http::{ - body::Once, - bytes::Bytes, + HttpServiceBuilder, h1::RequestBody, - http::{ - self, - const_header_value::{TEXT, TEXT_HTML_UTF8}, - header::{CONTENT_TYPE, SERVER}, - IntoResponse, RequestExt, + http::{StatusCode, header::SERVER}, + util::{ + middleware::context::{Context, ContextBuilder}, + service::{ + route::get, + router::{Router, RouterError}, + }, }, - util::service::{route::get, router::Router}, - HttpServiceBuilder, }; -use xitca_service::{fn_service, Service, ServiceExt}; +use xitca_service::{Service, ServiceExt, fn_service}; -use self::{ - ser::{json_response, Message}, - util::{context_mw, HandleResult, QueryParse, SERVER_HEADER_VALUE}, -}; +use db::Client; +use ser::{IntoResponse, Message, Request, Response, error_response}; +use util::{QueryParse, SERVER_HEADER_VALUE, State}; -type Response = http::Response>; -type Request = http::Request>; -type Ctx<'a> = self::util::Ctx<'a, Request>; +type Ctx<'a> = Context<'a, Request, State>; fn main() -> std::io::Result<()> { let service = Router::new() - .insert("/plaintext", get(fn_service(plain_text))) - .insert("/json", get(fn_service(json))) - .insert("/db", get(fn_service(db))) - .insert("/fortunes", get(fn_service(fortunes))) - .insert("/queries", get(fn_service(queries))) - .insert("/updates", get(fn_service(updates))) - .enclosed_fn(middleware_fn) - .enclosed(context_mw()) + .insert( + "/plaintext", + get(fn_service(async |ctx: Ctx| ctx.into_parts().0.text_response())), + ) + .insert( + "/json", + get(fn_service(async |ctx: Ctx| { + let (req, state) = ctx.into_parts(); + req.json_response(state, &Message::new()) + })), + ) + .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) + })), + ) + .insert( + "/fortunes", + get(fn_service(async |ctx: Ctx| { + let (req, state) = ctx.into_parts(); + use sailfish::TemplateOnce; + let fortunes = state.client.tell_fortune().await?.render_once()?; + req.html_response(fortunes) + })), + ) + .insert( + "/queries", + get(fn_service(async |ctx: Ctx| { + let (req, state) = ctx.into_parts(); + let num = req.uri().query().parse_query(); + let worlds = state.client.get_worlds(num).await?; + req.json_response(state, &worlds) + })), + ) + .insert( + "/updates", + get(fn_service(async |ctx: Ctx| { + let (req, state) = ctx.into_parts(); + let num = req.uri().query().parse_query(); + let worlds = state.client.update(num).await?; + req.json_response(state, &worlds) + })), + ) + .enclosed(ContextBuilder::new(|| async { db::create().await.map(State::new) })) + .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); + Ok::<_, core::convert::Infallible>(res) + }) .enclosed(HttpServiceBuilder::h1().io_uring()); - xitca_server::Builder::new() .bind("xitca-web", "0.0.0.0:8080", service)? .build() .wait() } -async fn middleware_fn(service: &S, req: Ctx<'_>) -> Result -where - S: for<'c> Service, Response = Response, Error = E>, -{ - service.call(req).await.map(|mut res| { - res.headers_mut().insert(SERVER, SERVER_HEADER_VALUE); - res +#[cold] +#[inline(never)] +fn error_handler(e: RouterError) -> Response { + error_response(match e { + RouterError::Match(_) => StatusCode::NOT_FOUND, + RouterError::NotAllowed(_) => StatusCode::METHOD_NOT_ALLOWED, + RouterError::Service(_) => StatusCode::INTERNAL_SERVER_ERROR, }) } - -async fn plain_text(ctx: Ctx<'_>) -> HandleResult { - let (req, _) = ctx.into_parts(); - let mut res = req.into_response(Bytes::from_static(b"Hello, World!")); - res.headers_mut().insert(CONTENT_TYPE, TEXT); - Ok(res) -} - -async fn json(ctx: Ctx<'_>) -> HandleResult { - let (req, state) = ctx.into_parts(); - json_response(req, &mut state.write_buf.borrow_mut(), &Message::new()) -} - -async fn db(ctx: Ctx<'_>) -> HandleResult { - let (req, state) = ctx.into_parts(); - let world = state.client.get_world().await?; - json_response(req, &mut state.write_buf.borrow_mut(), &world) -} - -async fn fortunes(ctx: Ctx<'_>) -> HandleResult { - let (req, state) = ctx.into_parts(); - use sailfish::TemplateOnce; - let fortunes = state.client.tell_fortune().await?.render_once()?; - let mut res = req.into_response(Bytes::from(fortunes)); - res.headers_mut().insert(CONTENT_TYPE, TEXT_HTML_UTF8); - Ok(res) -} - -async fn queries(ctx: Ctx<'_>) -> HandleResult { - let (req, state) = ctx.into_parts(); - let num = req.uri().query().parse_query(); - let worlds = state.client.get_worlds(num).await?; - json_response(req, &mut state.write_buf.borrow_mut(), worlds.as_slice()) -} - -async fn updates(ctx: Ctx<'_>) -> HandleResult { - let (req, state) = ctx.into_parts(); - let num = req.uri().query().parse_query(); - let worlds = state.client.update(num).await?; - json_response(req, &mut state.write_buf.borrow_mut(), worlds.as_slice()) -} diff --git a/frameworks/Rust/xitca-web/src/main_axum.rs b/frameworks/Rust/xitca-web/src/main_axum.rs deleted file mode 100644 index 1345569126d..00000000000 --- a/frameworks/Rust/xitca-web/src/main_axum.rs +++ /dev/null @@ -1,189 +0,0 @@ -//! show case of axum running on proper thread per core server with io-uring enabled. - -#[global_allocator] -static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; - -mod ser; -mod util; - -use axum::{ - http::header::{HeaderValue, SERVER}, - response::IntoResponse, - routing::{get, Router}, - Json, -}; -use tower_http::set_header::SetResponseHeaderLayer; - -use crate::tower_compat::TowerHttp; - -fn main() -> std::io::Result<()> { - let service = TowerHttp::service(|| async { - Router::new() - .route("/plaintext", get(plain_text)) - .route("/json", get(json)) - .layer(SetResponseHeaderLayer::if_not_present( - SERVER, - HeaderValue::from_static("A"), - )) - }); - - xitca_server::Builder::new() - .bind("xitca-axum", "0.0.0.0:8080", service)? - .build() - .wait() -} - -async fn plain_text() -> &'static str { - "Hello, World!" -} - -async fn json() -> impl IntoResponse { - Json(ser::Message::new()) -} - -mod tower_compat { - use std::{ - cell::RefCell, - convert::Infallible, - error, fmt, - future::Future, - io, - marker::PhantomData, - net::SocketAddr, - pin::Pin, - task::{Context, Poll}, - }; - - use axum::extract::ConnectInfo; - use futures_core::stream::Stream; - use http_body::Body; - use pin_project_lite::pin_project; - use xitca_http::{ - body::none_body_hint, - bytes::Bytes, - h1::RequestBody, - http::{HeaderMap, Request, RequestExt, Response}, - BodyError, HttpServiceBuilder, - }; - use xitca_io::net::io_uring::TcpStream; - use xitca_service::{ - fn_build, middleware::UncheckedReady, ready::ReadyService, Service, ServiceExt, - }; - use xitca_unsafe_collection::fake_send_sync::FakeSend; - - pub struct TowerHttp { - service: RefCell, - _p: PhantomData, - } - - impl TowerHttp { - pub fn service( - service: F, - ) -> impl Service< - Response = impl ReadyService + Service<(TcpStream, SocketAddr)>, - Error = impl fmt::Debug, - > - where - F: Fn() -> Fut + Send + Sync + Clone, - Fut: Future, - S: tower::Service, Response = Response>, - S::Error: fmt::Debug, - B: Body + Send + 'static, - B::Error: error::Error + Send + Sync, - { - fn_build(move |_| { - let service = service.clone(); - async move { - let service = service().await; - Ok::<_, Infallible>(TowerHttp { - service: RefCell::new(service), - _p: PhantomData, - }) - } - }) - .enclosed(UncheckedReady) - .enclosed(HttpServiceBuilder::h1().io_uring()) - } - } - - impl Service>> for TowerHttp - where - S: tower::Service, Response = Response>, - B: Body + Send + 'static, - B::Error: error::Error + Send + Sync, - { - type Response = Response>; - type Error = S::Error; - - async fn call( - &self, - req: Request>, - ) -> Result { - let (parts, ext) = req.into_parts(); - let (ext, body) = ext.replace_body(()); - let body = _RequestBody { - body: FakeSend::new(body), - }; - let mut req = Request::from_parts(parts, body); - let _ = req.extensions_mut().insert(ConnectInfo(*ext.socket_addr())); - let fut = self.service.borrow_mut().call(req); - let (parts, body) = fut.await?.into_parts(); - let body = ResponseBody { body }; - let res = Response::from_parts(parts, body); - Ok(res) - } - } - - pub struct _RequestBody { - body: FakeSend, - } - - impl Body for _RequestBody { - type Data = Bytes; - type Error = io::Error; - - fn poll_data( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll>> { - Pin::new(&mut *self.get_mut().body).poll_next(cx) - } - - fn poll_trailers( - self: Pin<&mut Self>, - _: &mut Context<'_>, - ) -> Poll, Self::Error>> { - Poll::Ready(Ok(None)) - } - } - - pin_project! { - pub struct ResponseBody { - #[pin] - body: B - } - } - - impl Stream for ResponseBody - where - B: Body, - B::Error: error::Error + Send + Sync + 'static, - { - type Item = Result; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.project() - .body - .poll_data(cx) - .map_err(|e| BodyError::from(Box::new(e) as Box)) - } - - fn size_hint(&self) -> (usize, Option) { - if Body::is_end_stream(&self.body) { - return none_body_hint(); - } - let hint = Body::size_hint(&self.body); - (hint.lower() as _, hint.upper().map(|u| u as _)) - } - } -} diff --git a/frameworks/Rust/xitca-web/src/main_iou.rs b/frameworks/Rust/xitca-web/src/main_iou.rs deleted file mode 100644 index 7aaa784cef1..00000000000 --- a/frameworks/Rust/xitca-web/src/main_iou.rs +++ /dev/null @@ -1,158 +0,0 @@ -// used as reference of if/how moving from epoll to io-uring(or mixture of the two) make sense for -// network io. - -#[global_allocator] -static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; - -mod db; -mod ser; -mod util; - -use std::{convert::Infallible, fmt, future::poll_fn, io, pin::pin}; - -use futures_core::stream::Stream; -use xitca_http::{ - body::Once, - date::DateTimeService, - h1::proto::context::Context, - http::{ - self, - const_header_value::{TEXT, TEXT_HTML_UTF8}, - header::{CONTENT_TYPE, SERVER}, - IntoResponse, RequestExt, StatusCode, - }, -}; -use xitca_io::{ - bytes::{Bytes, BytesMut}, - io_uring::IoBuf, - net::{io_uring::TcpStream as IOUTcpStream, TcpStream}, -}; -use xitca_service::{fn_build, fn_service, middleware::UncheckedReady, Service, ServiceExt}; - -use self::{ - ser::{json_response, Message}, - util::{context_mw, Ctx, QueryParse, SERVER_HEADER_VALUE}, -}; - -type Request = http::Request>; -type Response = http::Response>; - -fn main() -> io::Result<()> { - let service = fn_service(handler) - .enclosed(context_mw()) - .enclosed(fn_build(|service| async { - Ok::<_, Infallible>(Http1IOU { - service, - date: DateTimeService::new(), - }) - })) - .enclosed(UncheckedReady); - xitca_server::Builder::new() - .bind("xitca-iou", "0.0.0.0:8080", service)? - .build() - .wait() -} - -async fn handler(ctx: Ctx<'_, Request>) -> Result { - let (req, state) = ctx.into_parts(); - let mut res = match req.uri().path() { - "/plaintext" => { - const HELLO: Bytes = Bytes::from_static(b"Hello, World!"); - let mut res = req.into_response(HELLO); - res.headers_mut().insert(CONTENT_TYPE, TEXT); - res - } - "/json" => json_response(req, &mut state.write_buf.borrow_mut(), &Message::new()).unwrap(), - "/db" => { - let world = state.client.get_world().await.unwrap(); - json_response(req, &mut state.write_buf.borrow_mut(), &world).unwrap() - } - "/queries" => { - let num = req.uri().query().parse_query(); - let worlds = state.client.get_worlds(num).await.unwrap(); - json_response(req, &mut state.write_buf.borrow_mut(), worlds.as_slice()).unwrap() - } - "/updates" => { - let num = req.uri().query().parse_query(); - let worlds = state.client.update(num).await.unwrap(); - json_response(req, &mut state.write_buf.borrow_mut(), worlds.as_slice()).unwrap() - } - "/fortunes" => { - use sailfish::TemplateOnce; - let fortunes = state - .client - .tell_fortune() - .await - .unwrap() - .render_once() - .unwrap(); - let mut res = req.into_response(Bytes::from(fortunes)); - res.headers_mut().append(CONTENT_TYPE, TEXT_HTML_UTF8); - res - } - _ => { - let mut res = req.into_response(Bytes::new()); - *res.status_mut() = StatusCode::NOT_FOUND; - res - } - }; - res.headers_mut().insert(SERVER, SERVER_HEADER_VALUE); - Ok(res) -} - -struct Http1IOU { - service: S, - date: DateTimeService, -} - -// runner for http service. -impl Service for Http1IOU -where - S: Service, - S::Error: fmt::Debug, -{ - type Response = (); - type Error = io::Error; - - async fn call(&self, stream: TcpStream) -> Result { - let std = stream.into_std()?; - let stream = IOUTcpStream::from_std(std); - - let mut ctx = Context::<_, 8>::new(self.date.get()); - let mut read_buf = BytesMut::new(); - let mut write_buf = BytesMut::with_capacity(4096); - - loop { - let len = read_buf.len(); - let rem = read_buf.capacity() - len; - if rem < 4096 { - read_buf.reserve(4096 - rem); - } - - let (res, buf) = stream.read(read_buf.slice(len..)).await; - read_buf = buf.into_inner(); - if res? == 0 { - break; - } - - while let Some((req, _)) = ctx.decode_head::<{ usize::MAX }>(&mut read_buf).unwrap() { - let (parts, body) = self.service.call(req).await.unwrap().into_parts(); - let mut encoder = ctx.encode_head(parts, &body, &mut write_buf).unwrap(); - let mut body = pin!(body); - let chunk = poll_fn(|cx| body.as_mut().poll_next(cx)) - .await - .unwrap() - .unwrap(); - encoder.encode(chunk, &mut write_buf); - encoder.encode_eof(&mut write_buf); - } - - let (res, b) = stream.write_all(write_buf).await; - write_buf = b; - write_buf.clear(); - res?; - } - - stream.shutdown(std::net::Shutdown::Both) - } -} diff --git a/frameworks/Rust/xitca-web/src/main_orm.rs b/frameworks/Rust/xitca-web/src/main_orm.rs new file mode 100644 index 00000000000..ed5a51069a7 --- /dev/null +++ b/frameworks/Rust/xitca-web/src/main_orm.rs @@ -0,0 +1,60 @@ +mod db_diesel_async; +mod schema; +mod ser; +mod util; + +use xitca_web::{ + App, + codegen::route, + handler::{html::Html, json::Json, query::Query, state::StateRef, text::Text}, + http::{WebResponse, header::SERVER}, + route::get, +}; + +use db_diesel_async::Pool; +use ser::{Num, World}; +use util::{HandleResult, SERVER_HEADER_VALUE}; + +fn main() -> std::io::Result<()> { + App::new() + .with_async_state(db_diesel_async::create) + .at("/plaintext", get(Text("Hello, World!"))) + .at("/json", get(Json(ser::Message::new()))) + .at_typed(db) + .at_typed(fortunes) + .at_typed(queries) + .at_typed(updates) + .map(header) + .serve() + .disable_vectored_write() + .bind("0.0.0.0:8080")? + .run() + .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) +} + +#[route("/fortunes", method = get)] +async fn fortunes(StateRef(pool): StateRef<'_, Pool>) -> HandleResult> { + use sailfish::TemplateOnce; + let html = pool.tell_fortune().await?.render_once()?; + Ok(Html(html)) +} + +#[route("/queries", method = get)] +async fn queries(Query(Num(num)): Query, StateRef(pool): StateRef<'_, Pool>) -> HandleResult>> { + pool.get_worlds(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) +} diff --git a/frameworks/Rust/xitca-web/src/main_sync.rs b/frameworks/Rust/xitca-web/src/main_sync.rs new file mode 100644 index 00000000000..48ac2520bd1 --- /dev/null +++ b/frameworks/Rust/xitca-web/src/main_sync.rs @@ -0,0 +1,61 @@ +mod db_diesel; +mod schema; +mod ser; +mod util; + +use serde::Serialize; +use xitca_web::{ + App, + codegen::route, + handler::{html::Html, json::Json, query::Query, state::StateOwn, text::Text}, + http::{WebResponse, header::SERVER}, + route::get, +}; + +use db_diesel::Pool; +use ser::Num; +use util::{HandleResult, SERVER_HEADER_VALUE}; + +fn main() -> std::io::Result<()> { + App::new() + .with_state(db_diesel::create()?) + .at("/plaintext", get(Text("Hello, World!"))) + .at("/json", get(Json(ser::Message::new()))) + .at_typed(db) + .at_typed(fortunes) + .at_typed(queries) + .at_typed(updates) + .map(header) + .serve() + .disable_vectored_write() + .bind("0.0.0.0:8080")? + .run() + .wait() +} + +fn header(mut res: WebResponse) -> WebResponse { + res.headers_mut().insert(SERVER, SERVER_HEADER_VALUE); + res +} + +#[route("/db", method = get)] +fn db(StateOwn(pool): StateOwn) -> HandleResult> { + pool.get_world().map(Json) +} + +#[route("/fortunes", method = get)] +fn fortunes(StateOwn(pool): StateOwn) -> HandleResult> { + use sailfish::TemplateOnce; + let html = pool.tell_fortune()?.render_once()?; + Ok(Html(html)) +} + +#[route("/queries", method = get)] +fn queries(Query(Num(num)): Query, StateOwn(pool): StateOwn) -> HandleResult> { + pool.get_worlds(num).map(Json) +} + +#[route("/updates", method = get)] +fn updates(Query(Num(num)): Query, StateOwn(pool): StateOwn) -> HandleResult> { + pool.update(num).map(Json) +} diff --git a/frameworks/Rust/xitca-web/src/main_unrealistic.rs b/frameworks/Rust/xitca-web/src/main_unrealistic.rs new file mode 100644 index 00000000000..2b45164fd8d --- /dev/null +++ b/frameworks/Rust/xitca-web/src/main_unrealistic.rs @@ -0,0 +1,156 @@ +// unrealistic bench showcase popular tricks for boosting bench score artificially + +// custom global memory allocator don't affect real world performance in noticeable amount. +// in real world they should be used for reason like security, debug/profiling capability etc. +#[global_allocator] +static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; + +#[path = "db_unrealistic.rs"] +mod db; +mod ser; +mod util; + +use std::io; + +use xitca_http::{ + bytes::BufMutWriter, + h1::dispatcher_unreal::{Dispatcher, Request, Response}, + http::StatusCode, +}; +use xitca_service::Service; +// simd-json 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 +use simd_json_derive::Serialize; + +use self::{ + ser::Message, + util::{QueryParse, State}, +}; + +fn main() -> io::Result<()> { + let addr = "0.0.0.0:8080".parse().unwrap(); + + let cores = std::thread::available_parallelism().map(|num| num.get()).unwrap_or(56); + + let mut ids = core_affinity::get_core_ids().unwrap(); + + let worker = move |id: Option| { + if let Some(id) = id { + let _ = core_affinity::set_for_current(id); + } + + tokio::runtime::Builder::new_current_thread() + .enable_all() + .build_local(Default::default()) + .unwrap() + .block_on(async { + let socket = tokio::net::TcpSocket::new_v4()?; + socket.set_reuseaddr(true)?; + // unrealistic due to following reason: + // 1. this only works good on unix system. + // 2. no resource distribution adjustment between sockets on different threads. causing uneven workload + // where some threads are idle while others busy. resulting in overall increased latency + socket.set_reuseport(true)?; + socket.bind(addr)?; + let listener = socket.listen(1024)?; + + let client = db::create().await.unwrap(); + + // unrealistic http dispatcher. no spec check. no security feature. + let service = Dispatcher::new(handler, State::new(client)); + + loop { + match listener.accept().await { + Ok((stream, _)) => { + let service = service.clone(); + tokio::task::spawn_local(async move { + let _ = service.call(stream.into()).await; + }); + } + 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 { + handle.join().unwrap()?; + } + + Ok(()) +} + +async fn handler<'h>(req: Request<'h, State>, 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) + .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!")) + } + "/json" => res + .status(StatusCode::OK) + .header("content-type", "application/json") + .header("server", "X") + // unrealistic content length header. + .header("content-length", "27") + .body_writer(|buf| Message::new().json_write(&mut BufMutWriter(buf)).unwrap()), + + // all database related categories are unrealistic. please reference db_unrealistic module for detail. + "/fortunes" => { + use sailfish::TemplateOnce; + let fortunes = req.ctx.client.tell_fortune().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) + } + 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) + } + 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) + } + _ => 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: Serialize, +{ + let buf = &mut *state.write_buf.borrow_mut(); + val.json_write(&mut BufMutWriter(buf)).unwrap(); + let res = res + .status(StatusCode::OK) + .header("content-type", "application/json") + .header("server", "X") + .body(buf.as_ref()); + buf.clear(); + res +} diff --git a/frameworks/Rust/xitca-web/src/main_wasm.rs b/frameworks/Rust/xitca-web/src/main_wasm.rs deleted file mode 100644 index f9961afb6ce..00000000000 --- a/frameworks/Rust/xitca-web/src/main_wasm.rs +++ /dev/null @@ -1,50 +0,0 @@ -mod ser; -mod util; - -use std::{env, io, net::TcpListener, os::wasi::io::FromRawFd}; - -use xitca_web::{ - dev::service::Service, - handler::{handler_service, json::Json}, - http::header::SERVER, - request::WebRequest, - response::WebResponse, - route::get, - App, -}; - -use self::util::SERVER_HEADER_VALUE; - -fn main() -> io::Result<()> { - let fd = env::var("FD_COUNT") - .ok() - .and_then(|var| var.parse().ok()) - .expect("failed to parse FD_COUNT env"); - - let listener = unsafe { TcpListener::from_raw_fd(fd) }; - - App::new() - .at( - "/json", - get(handler_service(|| async { Json(ser::Message::new()) })), - ) - .at( - "/plaintext", - get(handler_service(|| async { "Hello, World!" })), - ) - .enclosed_fn(middleware_fn) - .serve() - .listen(listener)? - .run() - .wait() -} - -async fn middleware_fn(service: &S, ctx: WebRequest<'_>) -> Result -where - S: for<'r> Service, Response = WebResponse, Error = E>, -{ - service.call(ctx).await.map(|mut res| { - res.headers_mut().append(SERVER, SERVER_HEADER_VALUE); - res - }) -} diff --git a/frameworks/Rust/roa/src/schema.rs b/frameworks/Rust/xitca-web/src/schema.rs similarity index 77% rename from frameworks/Rust/roa/src/schema.rs rename to frameworks/Rust/xitca-web/src/schema.rs index eb14aa98a75..758acfe9927 100644 --- a/frameworks/Rust/roa/src/schema.rs +++ b/frameworks/Rust/xitca-web/src/schema.rs @@ -1,13 +1,11 @@ -#![allow(non_snake_case)] - -table! { +diesel::table! { world (id) { id -> Integer, randomnumber -> Integer, } } -table! { +diesel::table! { fortune (id) { id -> Integer, message -> Text, diff --git a/frameworks/Rust/xitca-web/src/ser.rs b/frameworks/Rust/xitca-web/src/ser.rs index 3985d4c7888..8eadc873e2c 100644 --- a/frameworks/Rust/xitca-web/src/ser.rs +++ b/frameworks/Rust/xitca-web/src/ser.rs @@ -2,15 +2,24 @@ use std::borrow::Cow; -use serde::{ser::SerializeStruct, Serialize, Serializer}; +use serde::{Deserialize, Deserializer, Serialize, Serializer, ser::SerializeStruct}; use xitca_http::{ body::Once, - bytes::{BufMutWriter, Bytes, BytesMut}, - http::{const_header_value::JSON, header::CONTENT_TYPE, IntoResponse, Request, Response}, + bytes::{BufMutWriter, Bytes}, + http::{ + self, IntoResponse as _, RequestExt, StatusCode, + const_header_value::{JSON, TEXT_HTML_UTF8, TEXT_UTF8}, + header::CONTENT_TYPE, + }, }; -use crate::util::Error; +use crate::util::{Error, State}; +const HELLO: &str = "Hello, World!"; +const HELLO_BYTES: &[u8] = HELLO.as_bytes(); + +#[cfg_attr(feature = "perf", derive(simd_json_derive::Serialize))] +#[derive(Clone)] pub struct Message { message: &'static str, } @@ -18,12 +27,14 @@ pub struct Message { impl Message { #[inline] pub const fn new() -> Self { - Self { - message: "Hello, World!", - } + Self { message: HELLO } } } +pub struct Num(pub u16); + +#[cfg_attr(any(feature = "pg-orm", feature = "pg-orm-async"), derive(diesel::Queryable))] +#[cfg_attr(feature = "perf", derive(simd_json_derive::Serialize))] pub struct World { pub id: i32, pub randomnumber: i32, @@ -36,6 +47,7 @@ impl World { } } +#[cfg_attr(any(feature = "pg-orm", feature = "pg-orm-async"), derive(diesel::Queryable))] pub struct Fortune { pub id: i32, pub message: Cow<'static, str>, @@ -51,16 +63,41 @@ impl Fortune { } } -// TODO: use another template engine with faster compile time.(perferably with no proc macro) -#[cfg_attr( - feature = "template", - derive(sailfish::TemplateOnce), - template(path = "fortune.stpl", rm_whitespace = true) -)] 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 sailfish::TemplateOnce for Fortunes { + fn render_once(self) -> sailfish::RenderResult { + use sailfish::runtime::{Buffer, Render}; + + const PREFIX: &str = "\n\nFortunes\n\n\n\n"; + const SUFFIX: &str = "\n
idmessage
\n\n"; + + let mut buf = Buffer::with_capacity(1236); + + buf.push_str(PREFIX); + for item in self.items { + buf.push_str(""); + Render::render_escaped(&item.id, &mut buf)?; + buf.push_str(""); + Render::render_escaped(&item.message, &mut buf)?; + buf.push_str(""); + } + buf.push_str(SUFFIX); + + Ok(buf.into_string()) + } + + fn render_once_to(self, _: &mut sailfish::runtime::Buffer) -> Result<(), sailfish::runtime::RenderError> { + unimplemented!("") + } +} + impl Fortunes { #[inline] pub const fn new(items: Vec) -> Self { @@ -68,6 +105,70 @@ impl Fortunes { } } +impl<'de> Deserialize<'de> for Num { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + use core::fmt; + + use serde::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; + + 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))) + } + } + + deserializer.deserialize_struct("Num", FIELDS, NumVisitor) + } +} + impl Serialize for Message { fn serialize(&self, serializer: S) -> Result where @@ -91,16 +192,42 @@ impl Serialize for World { } } -pub fn json_response( - req: Request, - buf: &mut BytesMut, - value: &S, -) -> Result>, Error> -where - S: ?Sized + Serialize, -{ - serde_json::to_writer(BufMutWriter(buf), value)?; - let mut res = req.into_response(buf.split().freeze()); - res.headers_mut().append(CONTENT_TYPE, JSON); - Ok(res) +pub type Request = http::Request>; +pub type Response = http::Response>; + +pub trait IntoResponse: Sized { + fn json_response(self, state: &State, val: &impl Serialize) -> Result; + + fn text_response(self) -> Result; + + fn html_response(self, val: String) -> Result; +} + +impl IntoResponse for Request { + fn json_response(self, state: &State, val: &impl Serialize) -> Result { + let buf = &mut *state.write_buf.borrow_mut(); + serde_json::to_writer(BufMutWriter(buf), val)?; + let mut res = self.into_response(buf.split().freeze()); + res.headers_mut().insert(CONTENT_TYPE, JSON); + Ok(res) + } + + 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) + } + + 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) + } +} + +pub fn error_response(status: StatusCode) -> Response { + http::Response::builder() + .status(status) + .body(Once::new(Bytes::new())) + .unwrap() } diff --git a/frameworks/Rust/xitca-web/src/util.rs b/frameworks/Rust/xitca-web/src/util.rs index e9bc8695bd0..48e2c24cc68 100755 --- a/frameworks/Rust/xitca-web/src/util.rs +++ b/frameworks/Rust/xitca-web/src/util.rs @@ -1,8 +1,8 @@ #![allow(dead_code)] -use core::cmp; +use core::cell::RefCell; -use xitca_http::http::header::HeaderValue; +use xitca_http::{bytes::BytesMut, http::header::HeaderValue}; pub trait QueryParse { fn parse_query(self) -> u16; @@ -10,15 +10,15 @@ pub trait QueryParse { impl QueryParse for Option<&str> { fn parse_query(self) -> u16 { - let num = self - .and_then(|this| { - use atoi::FromRadix10; - this.find('q') - .map(|pos| u16::from_radix_10(this.split_at(pos + 2).1.as_ref()).0) - }) - .unwrap_or(1); + self.and_then(|q| q.find('q').map(|pos| q.split_at(pos + 2).1.parse_query())) + .unwrap_or(1) + } +} - cmp::min(500, cmp::max(1, num)) +impl QueryParse for &str { + fn parse_query(self) -> u16 { + use atoi::FromRadix10; + u16::from_radix_10(self.as_bytes()).0.clamp(1, 500) } } @@ -29,53 +29,35 @@ pub type Error = Box; pub type HandleResult = Result; -#[cfg(not(target_arch = "wasm32"))] -#[cfg(any(feature = "pg", feature = "pg-iou"))] -mod non_wasm { - use core::{cell::RefCell, future::Future, pin::Pin}; - - use xitca_http::{ - bytes::BytesMut, - util::middleware::context::{Context, ContextBuilder}, - }; - - use super::*; - - use crate::db::{self, Client}; +pub const DB_URL: &str = "postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world"; - pub const DB_URL: &str = "postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world"; - - #[derive(Default)] - pub struct Rand(nanorand::WyRand); +pub struct State { + pub client: DB, + pub write_buf: RefCell, +} - impl Rand { - #[inline] - pub fn gen_id(&mut self) -> i32 { - use nanorand::Rng; - (self.0.generate::() % 10_000 + 1) as _ +impl State { + pub fn new(client: DB) -> Self { + Self { + client, + write_buf: Default::default(), } } +} - pub type Ctx<'a, Req> = Context<'a, Req, State>; +use rand::{Rng, SeedableRng, rngs::SmallRng}; - pub struct State { - pub client: Client, - pub write_buf: RefCell, - } +pub struct Rand(SmallRng); - pub fn context_mw( - ) -> ContextBuilder Pin>>>> { - ContextBuilder::new(|| { - Box::pin(async { - db::create(DB_URL).await.map(|client| State { - client, - write_buf: RefCell::new(BytesMut::new()), - }) - }) as _ - }) +impl Default for Rand { + fn default() -> Self { + Self(SmallRng::from_os_rng()) } } -#[cfg(not(target_arch = "wasm32"))] -#[cfg(any(feature = "pg", feature = "pg-iou"))] -pub use non_wasm::*; +impl Rand { + #[inline] + pub fn gen_id(&mut self) -> i32 { + self.0.random_range(1..=10000) + } +} diff --git a/frameworks/Rust/xitca-web/templates/fortune.stpl b/frameworks/Rust/xitca-web/templates/fortune.stpl index eb1abe6a4fa..28227945b4c 100644 --- a/frameworks/Rust/xitca-web/templates/fortune.stpl +++ b/frameworks/Rust/xitca-web/templates/fortune.stpl @@ -4,7 +4,7 @@ - <% for item in items { %><% } %> + <% for item in self.items { %><% } %>
idmessage
<%= item.id %><%= &*item.message %>
<%= item.id %><%= &*item.message %>
\ No newline at end of file diff --git a/frameworks/Rust/xitca-web/xitca-web-axum.dockerfile b/frameworks/Rust/xitca-web/xitca-web-axum.dockerfile deleted file mode 100644 index 7c45bef27fb..00000000000 --- a/frameworks/Rust/xitca-web/xitca-web-axum.dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM rust:1.74 - -ADD ./ /xitca-web -WORKDIR /xitca-web - -RUN cargo build --release --bin xitca-web-axum --features axum,io-uring - -EXPOSE 8080 - -CMD ./target/release/xitca-web-axum diff --git a/frameworks/Rust/xitca-web/xitca-web-iou.dockerfile b/frameworks/Rust/xitca-web/xitca-web-iou.dockerfile deleted file mode 100644 index 4a79ed928bc..00000000000 --- a/frameworks/Rust/xitca-web/xitca-web-iou.dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM rust:latest - -ADD ./ /xitca-web -WORKDIR /xitca-web - -RUN cargo build --release --bin xitca-web-iou --features io-uring,pg-iou,template - -EXPOSE 8080 - -CMD ./target/release/xitca-web-iou diff --git a/frameworks/Rust/xitca-web/xitca-web-orm.dockerfile b/frameworks/Rust/xitca-web/xitca-web-orm.dockerfile new file mode 100644 index 00000000000..19a4adad80f --- /dev/null +++ b/frameworks/Rust/xitca-web/xitca-web-orm.dockerfile @@ -0,0 +1,10 @@ +FROM rust:1.90 + +ADD ./ /xitca-web +WORKDIR /xitca-web + +RUN cargo build --release --bin xitca-web-orm --features pg-orm-async,template,web-codegen + +EXPOSE 8080 + +CMD ./target/release/xitca-web-orm diff --git a/frameworks/Rust/xitca-web/xitca-web-sync.dockerfile b/frameworks/Rust/xitca-web/xitca-web-sync.dockerfile new file mode 100644 index 00000000000..b2f2b128395 --- /dev/null +++ b/frameworks/Rust/xitca-web/xitca-web-sync.dockerfile @@ -0,0 +1,10 @@ +FROM rust:1.90 + +ADD ./ /xitca-web +WORKDIR /xitca-web + +RUN cargo build --release --bin xitca-web-sync --features pg-orm,template,web-codegen + +EXPOSE 8080 + +CMD ./target/release/xitca-web-sync diff --git a/frameworks/Rust/xitca-web/xitca-web-unrealistic.dockerfile b/frameworks/Rust/xitca-web/xitca-web-unrealistic.dockerfile new file mode 100644 index 00000000000..6e6ed7828b6 --- /dev/null +++ b/frameworks/Rust/xitca-web/xitca-web-unrealistic.dockerfile @@ -0,0 +1,10 @@ +FROM rust:1.90 + +ADD ./ /xitca-web +WORKDIR /xitca-web + +RUN cargo build --release --bin xitca-web-unrealistic --features perf,pg,template + +EXPOSE 8080 + +CMD ./target/release/xitca-web-unrealistic diff --git a/frameworks/Rust/xitca-web/xitca-web-wasm.dockerfile b/frameworks/Rust/xitca-web/xitca-web-wasm.dockerfile deleted file mode 100644 index 08b43318c88..00000000000 --- a/frameworks/Rust/xitca-web/xitca-web-wasm.dockerfile +++ /dev/null @@ -1,34 +0,0 @@ -ARG WASMTIME_VERSION=15.0.0 -ARG WASM_TARGET=wasm32-wasi-preview1-threads - -FROM rust:1.74 AS compile - -ARG WASMTIME_VERSION -ARG WASM_TARGET - -WORKDIR /tmp -COPY / ./ -RUN curl -LSs "https://github.com/bytecodealliance/wasmtime/releases/download/v${WASMTIME_VERSION}/wasmtime-v${WASMTIME_VERSION}-$(uname -m)-linux.tar.xz" | \ -tar --strip-components=1 -Jx && \ -rustup target add ${WASM_TARGET} && \ -cargo build --bin xitca-web-wasm --features web --release --target ${WASM_TARGET} - - -FROM ubuntu:22.04 - -ARG WASM_TARGET -ARG BENCHMARK_ENV -ARG TFB_TEST_DATABASE -ARG TFB_TEST_NAME - -COPY --from=compile \ -/tmp/target/${WASM_TARGET}/release/xitca-web-wasm.wasm \ -/tmp/wasmtime \ -/opt/xitca-web-wasm/ -EXPOSE 8080 - -CMD /opt/xitca-web-wasm/wasmtime run \ ---wasm all-proposals=y \ ---wasi threads=y,tcplisten=0.0.0.0:8080 \ ---env FD_COUNT=3 \ -/opt/xitca-web-wasm/xitca-web-wasm.wasm diff --git a/frameworks/Rust/xitca-web/xitca-web.dockerfile b/frameworks/Rust/xitca-web/xitca-web.dockerfile index abbceb5e0ca..7558d46f428 100644 --- a/frameworks/Rust/xitca-web/xitca-web.dockerfile +++ b/frameworks/Rust/xitca-web/xitca-web.dockerfile @@ -1,4 +1,4 @@ -FROM rust:latest +FROM rust:1.90 ADD ./ /xitca-web WORKDIR /xitca-web diff --git a/frameworks/Scala/akka-http/akka-http-slick-postgres.dockerfile b/frameworks/Scala/akka-http/akka-http-slick-postgres.dockerfile index 992f0518f48..04cc70062f3 100644 --- a/frameworks/Scala/akka-http/akka-http-slick-postgres.dockerfile +++ b/frameworks/Scala/akka-http/akka-http-slick-postgres.dockerfile @@ -1,4 +1,4 @@ -FROM hseeberger/scala-sbt:8u265_1.3.13_2.13.3 +FROM sbtscala/scala-sbt:eclipse-temurin-21.0.6_7_1.10.11_2.13.16 WORKDIR /akka-http-slick-postgres diff --git a/frameworks/Scala/akka-http/akka-http-slick-postgres/build.sbt b/frameworks/Scala/akka-http/akka-http-slick-postgres/build.sbt index a9ecdaf4c5e..dd2c36af395 100644 --- a/frameworks/Scala/akka-http/akka-http-slick-postgres/build.sbt +++ b/frameworks/Scala/akka-http/akka-http-slick-postgres/build.sbt @@ -62,7 +62,7 @@ lazy val commonSettings = Seq( organization := "net.benchmark.akka.http", organizationName := "Akka", - scalaVersion := "2.13.3", + scalaVersion := "2.13.16", scalacOptions ++= Seq( "-deprecation", "-encoding", diff --git a/frameworks/Scala/akka-http/akka-http-slick-postgres/project/build.properties b/frameworks/Scala/akka-http/akka-http-slick-postgres/project/build.properties index cb6a5a8a90d..cc68b53f1a3 100644 --- a/frameworks/Scala/akka-http/akka-http-slick-postgres/project/build.properties +++ b/frameworks/Scala/akka-http/akka-http-slick-postgres/project/build.properties @@ -1 +1 @@ -sbt.version = 1.3.13 +sbt.version=1.10.11 diff --git a/frameworks/Scala/akka-http/akka-http-slick-postgres/project/plugins.sbt b/frameworks/Scala/akka-http/akka-http-slick-postgres/project/plugins.sbt index 112d7fab73a..4adc260be88 100644 --- a/frameworks/Scala/akka-http/akka-http-slick-postgres/project/plugins.sbt +++ b/frameworks/Scala/akka-http/akka-http-slick-postgres/project/plugins.sbt @@ -1,7 +1,7 @@ addSbtPlugin("com.typesafe.sbt" % "sbt-git" % "1.0.0") addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % "1.3.16") addSbtPlugin("com.lucidchart" % "sbt-scalafmt" % "1.15") -addSbtPlugin("org.wartremover" % "sbt-wartremover" % "2.4.10") +addSbtPlugin("org.wartremover" % "sbt-wartremover" % "3.3.2") addSbtPlugin("io.get-coursier" % "sbt-coursier" % "1.0.3") libraryDependencies += "org.slf4j" % "slf4j-nop" % "1.7.25" // Needed by sbt-git diff --git a/frameworks/Scala/akka-http/akka-http-slick-postgres/src/main/scala/net/benchmark/akka/http/fortune/FortuneRoute.scala b/frameworks/Scala/akka-http/akka-http-slick-postgres/src/main/scala/net/benchmark/akka/http/fortune/FortuneRoute.scala index 61e23375a52..553aa4735d9 100644 --- a/frameworks/Scala/akka-http/akka-http-slick-postgres/src/main/scala/net/benchmark/akka/http/fortune/FortuneRoute.scala +++ b/frameworks/Scala/akka-http/akka-http-slick-postgres/src/main/scala/net/benchmark/akka/http/fortune/FortuneRoute.scala @@ -35,7 +35,7 @@ object FortuneRoute { class FortuneRoute(fr: FortuneRepository, sd: ExecutionContextExecutor)(implicit val system: ActorSystem) { - private implicit val fmar = FortuneRoute.fm + private implicit val fmar: ToEntityMarshaller[Seq[Fortune]] = FortuneRoute.fm private def source(p: DatabasePublisher[Fortune]): Source[Fortune, NotUsed] = { Source diff --git a/frameworks/Scala/akka-http/akka-http.dockerfile b/frameworks/Scala/akka-http/akka-http.dockerfile index bcf2f9db95e..ee5351673cd 100644 --- a/frameworks/Scala/akka-http/akka-http.dockerfile +++ b/frameworks/Scala/akka-http/akka-http.dockerfile @@ -1,4 +1,4 @@ -FROM hseeberger/scala-sbt:8u265_1.3.13_2.13.3 +FROM sbtscala/scala-sbt:eclipse-temurin-21.0.6_7_1.10.11_2.13.16 WORKDIR /akka-http @@ -23,4 +23,4 @@ RUN sbt clean compile stage EXPOSE 9000 -CMD ["target/universal/stage/bin/akka-http-benchmark", "-Dakka.http.benchmark.mysql.dbhost=tfb-database", "-J-server", "-J-Xms2g", "-J-Xmx2g", "-J-XX:NewSize=1g", "-J-XX:MaxNewSize=1g", "-J-XX:InitialCodeCacheSize=256m", "-J-XX:ReservedCodeCacheSize=256m", "-J-XX:+UseParallelGC", "-J-XX:-UseBiasedLocking", "-J-XX:+AlwaysPreTouch", "-J-XX:+UseNUMA", "-J-XX:+AggressiveOpts"] +CMD ["target/universal/stage/bin/akka-http-benchmark", "-Dakka.http.benchmark.mysql.dbhost=tfb-database", "-J-server", "-J-Xms2g", "-J-Xmx2g", "-J-XX:NewSize=1g", "-J-XX:MaxNewSize=1g", "-J-XX:InitialCodeCacheSize=256m", "-J-XX:ReservedCodeCacheSize=256m", "-J-XX:+UseParallelGC", "-J-XX:+AlwaysPreTouch", "-J-XX:+UseNUMA"] diff --git a/frameworks/Scala/akka-http/akka-http/build.sbt b/frameworks/Scala/akka-http/akka-http/build.sbt index 9e22525b987..b4501a8ab06 100644 --- a/frameworks/Scala/akka-http/akka-http/build.sbt +++ b/frameworks/Scala/akka-http/akka-http/build.sbt @@ -6,7 +6,7 @@ name := "akka-http-benchmark" version := "0.1.0-SNAPSHOT" -scalaVersion := "2.13.8" +scalaVersion := "2.13.16" val akkaV = "2.6.19" val akkaHttpV = "10.2.9" diff --git a/frameworks/Scala/akka-http/akka-http/project/build.properties b/frameworks/Scala/akka-http/akka-http/project/build.properties index 9edb75b77c2..cc68b53f1a3 100644 --- a/frameworks/Scala/akka-http/akka-http/project/build.properties +++ b/frameworks/Scala/akka-http/akka-http/project/build.properties @@ -1 +1 @@ -sbt.version=1.5.4 +sbt.version=1.10.11 diff --git a/frameworks/Scala/blaze/blaze.dockerfile b/frameworks/Scala/blaze/blaze.dockerfile index 23a039acb7b..c7edcc70c4d 100644 --- a/frameworks/Scala/blaze/blaze.dockerfile +++ b/frameworks/Scala/blaze/blaze.dockerfile @@ -1,10 +1,10 @@ -FROM openjdk:15 +FROM sbtscala/scala-sbt:eclipse-temurin-21.0.6_7_1.10.11_2.13.16 + WORKDIR /blaze COPY project project COPY src src COPY build.sbt build.sbt -COPY sbt sbt -RUN ./sbt assembly -batch && \ +RUN sbt assembly -batch && \ mv target/blaze-assembly-1.0.jar . && \ rm -Rf target && \ rm -Rf project/target && \ @@ -14,4 +14,4 @@ RUN ./sbt assembly -batch && \ EXPOSE 8080 -CMD ["java", "-server", "-Xms2g", "-Xmx2g", "-XX:NewSize=1g", "-XX:MaxNewSize=1g", "-XX:InitialCodeCacheSize=256m", "-XX:ReservedCodeCacheSize=256m", "-XX:+UseParallelGC", "-XX:+UseNUMA", "-XX:-UseBiasedLocking", "-XX:+AlwaysPreTouch", "-jar", "blaze-assembly-1.0.jar", "tfb-database"] +CMD ["java", "-server", "-Xms2g", "-Xmx2g", "-XX:NewSize=1g", "-XX:MaxNewSize=1g", "-XX:InitialCodeCacheSize=256m", "-XX:ReservedCodeCacheSize=256m", "-XX:+UseParallelGC", "-XX:+UseNUMA", "-XX:+AlwaysPreTouch", "-jar", "blaze-assembly-1.0.jar", "tfb-database"] diff --git a/frameworks/Scala/blaze/build.sbt b/frameworks/Scala/blaze/build.sbt index 7b0cd7ed2cc..fa140d872e0 100644 --- a/frameworks/Scala/blaze/build.sbt +++ b/frameworks/Scala/blaze/build.sbt @@ -2,12 +2,19 @@ name := "blaze" version := "1.0" -scalaVersion := "2.13.5" +scalaVersion := "2.13.16" libraryDependencies ++= Seq( - "org.http4s" %% "blaze-http" % "0.14.16", - "com.github.plokhotnyuk.jsoniter-scala" %% "jsoniter-scala-macros" % "2.7.3", - "ch.qos.logback" % "logback-classic" % "1.2.3" + "org.http4s" %% "blaze-http" % "0.14.18", + "com.github.plokhotnyuk.jsoniter-scala" %% "jsoniter-scala-macros" % "2.34.0", + "ch.qos.logback" % "logback-classic" % "1.5.18" ) -crossPaths := false \ No newline at end of file +crossPaths := false + +assembly / assemblyMergeStrategy := { + case x if x.contains("module-info.class") => MergeStrategy.discard + case x => + val oldStrategy = (assembly / assemblyMergeStrategy).value + oldStrategy(x) +} \ No newline at end of file diff --git a/frameworks/Scala/blaze/project/build.properties b/frameworks/Scala/blaze/project/build.properties index f0be67b9f72..cc68b53f1a3 100644 --- a/frameworks/Scala/blaze/project/build.properties +++ b/frameworks/Scala/blaze/project/build.properties @@ -1 +1 @@ -sbt.version=1.5.1 +sbt.version=1.10.11 diff --git a/frameworks/Scala/blaze/sbt b/frameworks/Scala/blaze/sbt deleted file mode 100755 index 8cc9bada4e1..00000000000 --- a/frameworks/Scala/blaze/sbt +++ /dev/null @@ -1,579 +0,0 @@ -#!/usr/bin/env bash -# -# A more capable sbt runner, coincidentally also called sbt. -# Author: Paul Phillips -# https://github.com/paulp/sbt-extras - -set -o pipefail - -declare -r sbt_release_version="1.2.8" -declare -r sbt_unreleased_version="1.3.0-RC1" - -declare -r latest_213="2.13.0" -declare -r latest_212="2.12.8" -declare -r latest_211="2.11.12" -declare -r latest_210="2.10.7" -declare -r latest_29="2.9.3" -declare -r latest_28="2.8.2" - -declare -r buildProps="project/build.properties" - -declare -r sbt_launch_ivy_release_repo="https://repo.typesafe.com/typesafe/ivy-releases" -declare -r sbt_launch_ivy_snapshot_repo="https://repo.scala-sbt.org/scalasbt/ivy-snapshots" -declare -r sbt_launch_mvn_release_repo="https://repo.scala-sbt.org/scalasbt/maven-releases" -declare -r sbt_launch_mvn_snapshot_repo="https://repo.scala-sbt.org/scalasbt/maven-snapshots" - -declare -r default_jvm_opts_common="-Xms512m -Xss2m" -declare -r noshare_opts="-Dsbt.global.base=project/.sbtboot -Dsbt.boot.directory=project/.boot -Dsbt.ivy.home=project/.ivy" - -declare sbt_jar sbt_dir sbt_create sbt_version sbt_script sbt_new -declare sbt_explicit_version -declare verbose noshare batch trace_level -declare debugUs - -declare java_cmd="java" -declare sbt_launch_dir="$HOME/.sbt/launchers" -declare sbt_launch_repo - -# pull -J and -D options to give to java. -declare -a java_args scalac_args sbt_commands residual_args - -# args to jvm/sbt via files or environment variables -declare -a extra_jvm_opts extra_sbt_opts - -echoerr () { echo >&2 "$@"; } -vlog () { [[ -n "$verbose" ]] && echoerr "$@"; } -die () { echo "Aborting: $*" ; exit 1; } - -setTrapExit () { - # save stty and trap exit, to ensure echo is re-enabled if we are interrupted. - SBT_STTY="$(stty -g 2>/dev/null)" - export SBT_STTY - - # restore stty settings (echo in particular) - onSbtRunnerExit() { - [ -t 0 ] || return - vlog "" - vlog "restoring stty: $SBT_STTY" - stty "$SBT_STTY" - } - - vlog "saving stty: $SBT_STTY" - trap onSbtRunnerExit EXIT -} - -# this seems to cover the bases on OSX, and someone will -# have to tell me about the others. -get_script_path () { - local path="$1" - [[ -L "$path" ]] || { echo "$path" ; return; } - - local -r target="$(readlink "$path")" - if [[ "${target:0:1}" == "/" ]]; then - echo "$target" - else - echo "${path%/*}/$target" - fi -} - -script_path="$(get_script_path "${BASH_SOURCE[0]}")" -declare -r script_path -script_name="${script_path##*/}" -declare -r script_name - -init_default_option_file () { - local overriding_var="${!1}" - local default_file="$2" - if [[ ! -r "$default_file" && "$overriding_var" =~ ^@(.*)$ ]]; then - local envvar_file="${BASH_REMATCH[1]}" - if [[ -r "$envvar_file" ]]; then - default_file="$envvar_file" - fi - fi - echo "$default_file" -} - -sbt_opts_file="$(init_default_option_file SBT_OPTS .sbtopts)" -jvm_opts_file="$(init_default_option_file JVM_OPTS .jvmopts)" - -build_props_sbt () { - [[ -r "$buildProps" ]] && \ - grep '^sbt\.version' "$buildProps" | tr '=\r' ' ' | awk '{ print $2; }' -} - -set_sbt_version () { - sbt_version="${sbt_explicit_version:-$(build_props_sbt)}" - [[ -n "$sbt_version" ]] || sbt_version=$sbt_release_version - export sbt_version -} - -url_base () { - local version="$1" - - case "$version" in - 0.7.*) echo "http://simple-build-tool.googlecode.com" ;; - 0.10.* ) echo "$sbt_launch_ivy_release_repo" ;; - 0.11.[12]) echo "$sbt_launch_ivy_release_repo" ;; - 0.*-[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]-[0-9][0-9][0-9][0-9][0-9][0-9]) # ie "*-yyyymmdd-hhMMss" - echo "$sbt_launch_ivy_snapshot_repo" ;; - 0.*) echo "$sbt_launch_ivy_release_repo" ;; - *-[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]-[0-9][0-9][0-9][0-9][0-9][0-9]) # ie "*-yyyymmdd-hhMMss" - echo "$sbt_launch_mvn_snapshot_repo" ;; - *) echo "$sbt_launch_mvn_release_repo" ;; - esac -} - -make_url () { - local version="$1" - - local base="${sbt_launch_repo:-$(url_base "$version")}" - - case "$version" in - 0.7.*) echo "$base/files/sbt-launch-0.7.7.jar" ;; - 0.10.* ) echo "$base/org.scala-tools.sbt/sbt-launch/$version/sbt-launch.jar" ;; - 0.11.[12]) echo "$base/org.scala-tools.sbt/sbt-launch/$version/sbt-launch.jar" ;; - 0.*) echo "$base/org.scala-sbt/sbt-launch/$version/sbt-launch.jar" ;; - 1.5.*) echo "$base/org/scala-sbt/sbt-launch/$version/sbt-launch-$version.jar" ;; - *) echo "$base/org/scala-sbt/sbt-launch/$version/sbt-launch.jar" ;; - esac -} - -addJava () { vlog "[addJava] arg = '$1'" ; java_args+=("$1"); } -addSbt () { vlog "[addSbt] arg = '$1'" ; sbt_commands+=("$1"); } -addScalac () { vlog "[addScalac] arg = '$1'" ; scalac_args+=("$1"); } -addResidual () { vlog "[residual] arg = '$1'" ; residual_args+=("$1"); } - -addResolver () { addSbt "set resolvers += $1"; } -addDebugger () { addJava "-Xdebug" ; addJava "-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=$1"; } -setThisBuild () { - vlog "[addBuild] args = '$*'" - local key="$1" && shift - addSbt "set $key in ThisBuild := $*" -} -setScalaVersion () { - [[ "$1" == *"-SNAPSHOT" ]] && addResolver 'Resolver.sonatypeRepo("snapshots")' - addSbt "++ $1" -} -setJavaHome () { - java_cmd="$1/bin/java" - setThisBuild javaHome "_root_.scala.Some(file(\"$1\"))" - export JAVA_HOME="$1" - export JDK_HOME="$1" - export PATH="$JAVA_HOME/bin:$PATH" -} - -getJavaVersion() { - local -r str=$("$1" -version 2>&1 | grep -E -e '(java|openjdk) version' | awk '{ print $3 }' | tr -d '"') - - # java -version on java8 says 1.8.x - # but on 9 and 10 it's 9.x.y and 10.x.y. - if [[ "$str" =~ ^1\.([0-9]+)\..*$ ]]; then - echo "${BASH_REMATCH[1]}" - elif [[ "$str" =~ ^([0-9]+)\..*$ ]]; then - echo "${BASH_REMATCH[1]}" - elif [[ -n "$str" ]]; then - echoerr "Can't parse java version from: $str" - fi -} - -checkJava() { - # Warn if there is a Java version mismatch between PATH and JAVA_HOME/JDK_HOME - - [[ -n "$JAVA_HOME" && -e "$JAVA_HOME/bin/java" ]] && java="$JAVA_HOME/bin/java" - [[ -n "$JDK_HOME" && -e "$JDK_HOME/lib/tools.jar" ]] && java="$JDK_HOME/bin/java" - - if [[ -n "$java" ]]; then - pathJavaVersion=$(getJavaVersion java) - homeJavaVersion=$(getJavaVersion "$java") - if [[ "$pathJavaVersion" != "$homeJavaVersion" ]]; then - echoerr "Warning: Java version mismatch between PATH and JAVA_HOME/JDK_HOME, sbt will use the one in PATH" - echoerr " Either: fix your PATH, remove JAVA_HOME/JDK_HOME or use -java-home" - echoerr " java version from PATH: $pathJavaVersion" - echoerr " java version from JAVA_HOME/JDK_HOME: $homeJavaVersion" - fi - fi -} - -java_version () { - local -r version=$(getJavaVersion "$java_cmd") - vlog "Detected Java version: $version" - echo "$version" -} - -# MaxPermSize critical on pre-8 JVMs but incurs noisy warning on 8+ -default_jvm_opts () { - local -r v="$(java_version)" - if [[ $v -ge 8 ]]; then - echo "$default_jvm_opts_common" - else - echo "-XX:MaxPermSize=384m $default_jvm_opts_common" - fi -} - -build_props_scala () { - if [[ -r "$buildProps" ]]; then - versionLine="$(grep '^build.scala.versions' "$buildProps")" - versionString="${versionLine##build.scala.versions=}" - echo "${versionString%% .*}" - fi -} - -execRunner () { - # print the arguments one to a line, quoting any containing spaces - vlog "# Executing command line:" && { - for arg; do - if [[ -n "$arg" ]]; then - if printf "%s\n" "$arg" | grep -q ' '; then - printf >&2 "\"%s\"\n" "$arg" - else - printf >&2 "%s\n" "$arg" - fi - fi - done - vlog "" - } - - setTrapExit - - if [[ -n "$batch" ]]; then - "$@" < /dev/null - else - "$@" - fi -} - -jar_url () { make_url "$1"; } - -is_cygwin () { [[ "$(uname -a)" == "CYGWIN"* ]]; } - -jar_file () { - is_cygwin \ - && cygpath -w "$sbt_launch_dir/$1/sbt-launch.jar" \ - || echo "$sbt_launch_dir/$1/sbt-launch.jar" -} - -download_url () { - local url="$1" - local jar="$2" - - echoerr "Downloading sbt launcher for $sbt_version:" - echoerr " From $url" - echoerr " To $jar" - - mkdir -p "${jar%/*}" && { - if command -v curl > /dev/null 2>&1; then - curl --fail --silent --location "$url" --output "$jar" - elif command -v wget > /dev/null 2>&1; then - wget -q -O "$jar" "$url" - fi - } && [[ -r "$jar" ]] -} - -acquire_sbt_jar () { - { - sbt_jar="$(jar_file "$sbt_version")" - [[ -r "$sbt_jar" ]] - } || { - sbt_jar="$HOME/.ivy2/local/org.scala-sbt/sbt-launch/$sbt_version/jars/sbt-launch.jar" - [[ -r "$sbt_jar" ]] - } || { - sbt_jar="$(jar_file "$sbt_version")" - download_url "$(make_url "$sbt_version")" "$sbt_jar" - } -} - -usage () { - set_sbt_version - cat < display stack traces with a max of frames (default: -1, traces suppressed) - -debug-inc enable debugging log for the incremental compiler - -no-colors disable ANSI color codes - -sbt-create start sbt even if current directory contains no sbt project - -sbt-dir path to global settings/plugins directory (default: ~/.sbt/) - -sbt-boot path to shared boot directory (default: ~/.sbt/boot in 0.11+) - -ivy path to local Ivy repository (default: ~/.ivy2) - -no-share use all local caches; no sharing - -offline put sbt in offline mode - -jvm-debug Turn on JVM debugging, open at the given port. - -batch Disable interactive mode - -prompt Set the sbt prompt; in expr, 's' is the State and 'e' is Extracted - -script Run the specified file as a scala script - - # sbt version (default: sbt.version from $buildProps if present, otherwise $sbt_release_version) - -sbt-force-latest force the use of the latest release of sbt: $sbt_release_version - -sbt-version use the specified version of sbt (default: $sbt_release_version) - -sbt-dev use the latest pre-release version of sbt: $sbt_unreleased_version - -sbt-jar use the specified jar as the sbt launcher - -sbt-launch-dir directory to hold sbt launchers (default: $sbt_launch_dir) - -sbt-launch-repo repo url for downloading sbt launcher jar (default: $(url_base "$sbt_version")) - - # scala version (default: as chosen by sbt) - -28 use $latest_28 - -29 use $latest_29 - -210 use $latest_210 - -211 use $latest_211 - -212 use $latest_212 - -213 use $latest_213 - -scala-home use the scala build at the specified directory - -scala-version use the specified version of scala - -binary-version use the specified scala version when searching for dependencies - - # java version (default: java from PATH, currently $(java -version 2>&1 | grep version)) - -java-home alternate JAVA_HOME - - # passing options to the jvm - note it does NOT use JAVA_OPTS due to pollution - # The default set is used if JVM_OPTS is unset and no -jvm-opts file is found - $(default_jvm_opts) - JVM_OPTS environment variable holding either the jvm args directly, or - the reference to a file containing jvm args if given path is prepended by '@' (e.g. '@/etc/jvmopts') - Note: "@"-file is overridden by local '.jvmopts' or '-jvm-opts' argument. - -jvm-opts file containing jvm args (if not given, .jvmopts in project root is used if present) - -Dkey=val pass -Dkey=val directly to the jvm - -J-X pass option -X directly to the jvm (-J is stripped) - - # passing options to sbt, OR to this runner - SBT_OPTS environment variable holding either the sbt args directly, or - the reference to a file containing sbt args if given path is prepended by '@' (e.g. '@/etc/sbtopts') - Note: "@"-file is overridden by local '.sbtopts' or '-sbt-opts' argument. - -sbt-opts file containing sbt args (if not given, .sbtopts in project root is used if present) - -S-X add -X to sbt's scalacOptions (-S is stripped) -EOM -} - -process_args () { - require_arg () { - local type="$1" - local opt="$2" - local arg="$3" - - if [[ -z "$arg" ]] || [[ "${arg:0:1}" == "-" ]]; then - die "$opt requires <$type> argument" - fi - } - while [[ $# -gt 0 ]]; do - case "$1" in - -h|-help) usage; exit 0 ;; - -v) verbose=true && shift ;; - -d) addSbt "--debug" && shift ;; - -w) addSbt "--warn" && shift ;; - -q) addSbt "--error" && shift ;; - -x) debugUs=true && shift ;; - -trace) require_arg integer "$1" "$2" && trace_level="$2" && shift 2 ;; - -ivy) require_arg path "$1" "$2" && addJava "-Dsbt.ivy.home=$2" && shift 2 ;; - -no-colors) addJava "-Dsbt.log.noformat=true" && shift ;; - -no-share) noshare=true && shift ;; - -sbt-boot) require_arg path "$1" "$2" && addJava "-Dsbt.boot.directory=$2" && shift 2 ;; - -sbt-dir) require_arg path "$1" "$2" && sbt_dir="$2" && shift 2 ;; - -debug-inc) addJava "-Dxsbt.inc.debug=true" && shift ;; - -offline) addSbt "set offline in Global := true" && shift ;; - -jvm-debug) require_arg port "$1" "$2" && addDebugger "$2" && shift 2 ;; - -batch) batch=true && shift ;; - -prompt) require_arg "expr" "$1" "$2" && setThisBuild shellPrompt "(s => { val e = Project.extract(s) ; $2 })" && shift 2 ;; - -script) require_arg file "$1" "$2" && sbt_script="$2" && addJava "-Dsbt.main.class=sbt.ScriptMain" && shift 2 ;; - - -sbt-create) sbt_create=true && shift ;; - -sbt-jar) require_arg path "$1" "$2" && sbt_jar="$2" && shift 2 ;; - -sbt-version) require_arg version "$1" "$2" && sbt_explicit_version="$2" && shift 2 ;; - -sbt-force-latest) sbt_explicit_version="$sbt_release_version" && shift ;; - -sbt-dev) sbt_explicit_version="$sbt_unreleased_version" && shift ;; - -sbt-launch-dir) require_arg path "$1" "$2" && sbt_launch_dir="$2" && shift 2 ;; - -sbt-launch-repo) require_arg path "$1" "$2" && sbt_launch_repo="$2" && shift 2 ;; - -scala-version) require_arg version "$1" "$2" && setScalaVersion "$2" && shift 2 ;; - -binary-version) require_arg version "$1" "$2" && setThisBuild scalaBinaryVersion "\"$2\"" && shift 2 ;; - -scala-home) require_arg path "$1" "$2" && setThisBuild scalaHome "_root_.scala.Some(file(\"$2\"))" && shift 2 ;; - -java-home) require_arg path "$1" "$2" && setJavaHome "$2" && shift 2 ;; - -sbt-opts) require_arg path "$1" "$2" && sbt_opts_file="$2" && shift 2 ;; - -jvm-opts) require_arg path "$1" "$2" && jvm_opts_file="$2" && shift 2 ;; - - -D*) addJava "$1" && shift ;; - -J*) addJava "${1:2}" && shift ;; - -S*) addScalac "${1:2}" && shift ;; - -28) setScalaVersion "$latest_28" && shift ;; - -29) setScalaVersion "$latest_29" && shift ;; - -210) setScalaVersion "$latest_210" && shift ;; - -211) setScalaVersion "$latest_211" && shift ;; - -212) setScalaVersion "$latest_212" && shift ;; - -213) setScalaVersion "$latest_213" && shift ;; - new) sbt_new=true && : ${sbt_explicit_version:=$sbt_release_version} && addResidual "$1" && shift ;; - *) addResidual "$1" && shift ;; - esac - done -} - -# process the direct command line arguments -process_args "$@" - -# skip #-styled comments and blank lines -readConfigFile() { - local end=false - until $end; do - read -r || end=true - [[ $REPLY =~ ^# ]] || [[ -z $REPLY ]] || echo "$REPLY" - done < "$1" -} - -# if there are file/environment sbt_opts, process again so we -# can supply args to this runner -if [[ -r "$sbt_opts_file" ]]; then - vlog "Using sbt options defined in file $sbt_opts_file" - while read -r opt; do extra_sbt_opts+=("$opt"); done < <(readConfigFile "$sbt_opts_file") -elif [[ -n "$SBT_OPTS" && ! ("$SBT_OPTS" =~ ^@.*) ]]; then - vlog "Using sbt options defined in variable \$SBT_OPTS" - IFS=" " read -r -a extra_sbt_opts <<< "$SBT_OPTS" -else - vlog "No extra sbt options have been defined" -fi - -[[ -n "${extra_sbt_opts[*]}" ]] && process_args "${extra_sbt_opts[@]}" - -# reset "$@" to the residual args -set -- "${residual_args[@]}" -argumentCount=$# - -# set sbt version -set_sbt_version - -checkJava - -# only exists in 0.12+ -setTraceLevel() { - case "$sbt_version" in - "0.7."* | "0.10."* | "0.11."* ) echoerr "Cannot set trace level in sbt version $sbt_version" ;; - *) setThisBuild traceLevel "$trace_level" ;; - esac -} - -# set scalacOptions if we were given any -S opts -[[ ${#scalac_args[@]} -eq 0 ]] || addSbt "set scalacOptions in ThisBuild += \"${scalac_args[*]}\"" - -[[ -n "$sbt_explicit_version" && -z "$sbt_new" ]] && addJava "-Dsbt.version=$sbt_explicit_version" -vlog "Detected sbt version $sbt_version" - -if [[ -n "$sbt_script" ]]; then - residual_args=( "$sbt_script" "${residual_args[@]}" ) -else - # no args - alert them there's stuff in here - (( argumentCount > 0 )) || { - vlog "Starting $script_name: invoke with -help for other options" - residual_args=( shell ) - } -fi - -# verify this is an sbt dir, -create was given or user attempts to run a scala script -[[ -r ./build.sbt || -d ./project || -n "$sbt_create" || -n "$sbt_script" || -n "$sbt_new" ]] || { - cat < new Initializer(initContext) { - override def onConnect: RequestHandlerFactory = serverContext => new RequestHandler(serverContext, serviceConfig) { - override def handle: PartialHandler[Http] = { - case req if req.head.url == "/plaintext" => req.ok("Hello, World!") - case req if req.head.url == "/json" => req.ok(Message("Hello, World!")) - } - } - }) -} diff --git a/frameworks/Scala/finagle/build.sbt b/frameworks/Scala/finagle/build.sbt index 36aa3880420..280269a1ac6 100644 --- a/frameworks/Scala/finagle/build.sbt +++ b/frameworks/Scala/finagle/build.sbt @@ -1,7 +1,7 @@ lazy val finagleVersion = "22.7.0" name := "finagle-benchmark" -scalaVersion := "2.12.12" +scalaVersion := "2.12.20" version := finagleVersion libraryDependencies ++= Seq( diff --git a/frameworks/Scala/finagle/finagle.dockerfile b/frameworks/Scala/finagle/finagle.dockerfile index b8a84d6e75b..66445765167 100644 --- a/frameworks/Scala/finagle/finagle.dockerfile +++ b/frameworks/Scala/finagle/finagle.dockerfile @@ -1,4 +1,4 @@ -FROM hseeberger/scala-sbt:8u151-2.12.5-1.1.2 +FROM sbtscala/scala-sbt:eclipse-temurin-21.0.6_7_1.10.11_2.12.20 WORKDIR /finagle COPY project project COPY src src @@ -7,4 +7,4 @@ RUN sbt assembly -batch EXPOSE 8080 -CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AggressiveOpts", "-Dcom.twitter.finagle.tracing.enabled=false", "-Dio.netty.recycler.maxCapacityPerThread=0", "-Dio.netty.leakDetection.level=disabled", "-jar", "target/scala-2.12/finagle-benchmark.jar"] +CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-Dcom.twitter.finagle.tracing.enabled=false", "-Dio.netty.recycler.maxCapacityPerThread=0", "-Dio.netty.leakDetection.level=disabled", "-jar", "target/scala-2.12/finagle-benchmark.jar"] diff --git a/frameworks/Scala/finagle/project/build.properties b/frameworks/Scala/finagle/project/build.properties index 05313438a19..cc68b53f1a3 100644 --- a/frameworks/Scala/finagle/project/build.properties +++ b/frameworks/Scala/finagle/project/build.properties @@ -1 +1 @@ -sbt.version=1.1.2 +sbt.version=1.10.11 diff --git a/frameworks/Scala/finatra/build.sbt b/frameworks/Scala/finatra/build.sbt index b0c337a5843..15192c29609 100644 --- a/frameworks/Scala/finatra/build.sbt +++ b/frameworks/Scala/finatra/build.sbt @@ -4,7 +4,7 @@ name := "techempower-benchmarks-finatra" organization := "com.twitter" version := finatraVersion -scalaVersion := "2.12.12" +scalaVersion := "2.12.20" resolvers ++= Seq( Resolver.sonatypeRepo("releases") diff --git a/frameworks/Scala/finatra/finatra.dockerfile b/frameworks/Scala/finatra/finatra.dockerfile index 860ab876133..3f1b58e18d0 100644 --- a/frameworks/Scala/finatra/finatra.dockerfile +++ b/frameworks/Scala/finatra/finatra.dockerfile @@ -1,4 +1,4 @@ -FROM hseeberger/scala-sbt:8u151-2.12.5-1.1.2 +FROM sbtscala/scala-sbt:eclipse-temurin-21.0.6_7_1.10.11_2.12.20 WORKDIR /finatra COPY project project COPY src src @@ -7,4 +7,4 @@ RUN sbt clean assembly -batch EXPOSE 8888 -CMD ["java", "-Dio.netty.recycler.maxCapacityPerThread=0", "-Dio.netty.leakDetection.level=disabled", "-Dcom.twitter.finagle.tracing.enabled=false", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AggressiveOpts", "-jar", "target/scala-2.12/finatra-benchmark.jar", "-http.response.charset.enabled=false"] +CMD ["java", "-Dio.netty.recycler.maxCapacityPerThread=0", "-Dio.netty.leakDetection.level=disabled", "-Dcom.twitter.finagle.tracing.enabled=false", "--add-opens=java.base/java.lang=ALL-UNNAMED", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-jar", "target/scala-2.12/finatra-benchmark.jar", "-http.response.charset.enabled=false"] diff --git a/frameworks/Scala/finatra/project/build.properties b/frameworks/Scala/finatra/project/build.properties index 05313438a19..cc68b53f1a3 100644 --- a/frameworks/Scala/finatra/project/build.properties +++ b/frameworks/Scala/finatra/project/build.properties @@ -1 +1 @@ -sbt.version=1.1.2 +sbt.version=1.10.11 diff --git a/frameworks/Scala/finch/build.sbt b/frameworks/Scala/finch/build.sbt index 4bbae4fdc96..4497f5f3625 100644 --- a/frameworks/Scala/finch/build.sbt +++ b/frameworks/Scala/finch/build.sbt @@ -2,7 +2,7 @@ lazy val finchVersion = "0.27.0" name := """techempower-benchmarks-finch""" version := finchVersion -scalaVersion := "2.12.7" +scalaVersion := "2.12.20" libraryDependencies ++= Seq( "com.github.finagle" %% "finchx-core" % finchVersion, diff --git a/frameworks/Scala/finch/finch.dockerfile b/frameworks/Scala/finch/finch.dockerfile index 64dbac48266..48f5d92be33 100644 --- a/frameworks/Scala/finch/finch.dockerfile +++ b/frameworks/Scala/finch/finch.dockerfile @@ -1,4 +1,4 @@ -FROM hseeberger/scala-sbt:8u151-2.12.5-1.1.2 +FROM sbtscala/scala-sbt:eclipse-temurin-21.0.6_7_1.10.11_2.12.20 WORKDIR /finch COPY project project COPY src src @@ -7,4 +7,4 @@ RUN sbt assembly -batch EXPOSE 9000 -CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AggressiveOpts", "-Dio.netty.recycler.maxCapacityPerThread=0", "-Dcom.twitter.finagle.tracing.enabled=false", "-Dio.netty.leakDetection.level=disabled", "-jar", "target/scala-2.12/finch-benchmark.jar"] +CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-Dio.netty.recycler.maxCapacityPerThread=0", "-Dcom.twitter.finagle.tracing.enabled=false", "-Dio.netty.leakDetection.level=disabled", "-jar", "target/scala-2.12/finch-benchmark.jar"] diff --git a/frameworks/Scala/finch/project/build.properties b/frameworks/Scala/finch/project/build.properties index 05313438a19..cc68b53f1a3 100644 --- a/frameworks/Scala/finch/project/build.properties +++ b/frameworks/Scala/finch/project/build.properties @@ -1 +1 @@ -sbt.version=1.1.2 +sbt.version=1.10.11 diff --git a/frameworks/Scala/fintrospect/.gitignore b/frameworks/Scala/fintrospect/.gitignore deleted file mode 100644 index f6a61f70454..00000000000 --- a/frameworks/Scala/fintrospect/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -sbt -target/ - diff --git a/frameworks/Scala/fintrospect/README.md b/frameworks/Scala/fintrospect/README.md deleted file mode 100644 index 02810a411ce..00000000000 --- a/frameworks/Scala/fintrospect/README.md +++ /dev/null @@ -1,22 +0,0 @@ -#fintrospect Benchmarking Test - -## Infrastructure Software Versions -The tests were run with: - -* [Java Oracle 1.8.0_25](http://www.oracle.com/technetwork/java/javase) -* [fintrospect 14.15.0](https://github.com/daviddenton/fintrospect) - -## Test URLs - -- JSON Encoding: http://localhost:9000/json -- Plaintext: http://localhost:9000/plaintext -- Fortunes: http://localhost:9000/fortunes -- Single Query: http://localhost:9000/db -- Multi Query: http://localhost:9000/queries?queries=1 -- Update Query: http://localhost:9000/updates?queries=1 - -## How to run -sbt 'oneJar' - -`java -jar target/scala-2.12/*fintrospect*one-jar.jar` - diff --git a/frameworks/Scala/fintrospect/benchmark_config.json b/frameworks/Scala/fintrospect/benchmark_config.json deleted file mode 100644 index 9a5b941d7bf..00000000000 --- a/frameworks/Scala/fintrospect/benchmark_config.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "framework": "fintrospect", - "tests": [ - { - "default": { - "orm": "Raw", - "database_os": "Linux", - "db_url": "/db", - "fortune_url": "/fortunes", - "json_url": "/json", - "query_url": "/queries?queries=", - "plaintext_url": "/plaintext", - "update_url": "/updates?queries=", - "port": 9000, - "approach": "Realistic", - "classification": "Micro", - "database": "MySQL", - "framework": "fintrospect", - "language": "Scala", - "platform": "Netty", - "webserver": "None", - "os": "Linux", - "display_name": "fintrospect", - "notes": "", - "versus": "finagle" - } - } - ] -} \ No newline at end of file diff --git a/frameworks/Scala/fintrospect/build.sbt b/frameworks/Scala/fintrospect/build.sbt deleted file mode 100644 index a7c09556d6d..00000000000 --- a/frameworks/Scala/fintrospect/build.sbt +++ /dev/null @@ -1,25 +0,0 @@ -name := """techempower-benchmarks-fintrospect""" - -version := "1.0" - -scalaVersion := "2.13.3" - -scalacOptions += "-deprecation" - -scalacOptions += "-feature" - -resolvers += "JCenter" at "https://jcenter.bintray.com" - -resolvers += Resolver.sonatypeRepo("snapshots") - -libraryDependencies ++= Seq( - "io.fintrospect" %% "fintrospect-core" % "17.0.0", - "io.fintrospect" %% "fintrospect-jackson" % "17.0.0", - "io.fintrospect" %% "fintrospect-mustache" % "17.0.0", - "com.twitter" %% "finagle-mysql" % "20.8.0" -) - -assemblyMergeStrategy in assembly := { - case PathList("META-INF", xs @ _*) => MergeStrategy.discard - case x => MergeStrategy.first -} diff --git a/frameworks/Scala/fintrospect/config.toml b/frameworks/Scala/fintrospect/config.toml deleted file mode 100644 index 80a2f984dab..00000000000 --- a/frameworks/Scala/fintrospect/config.toml +++ /dev/null @@ -1,19 +0,0 @@ -[framework] -name = "fintrospect" - -[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 = "MySQL" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "Netty" -webserver = "None" -versus = "finagle" diff --git a/frameworks/Scala/fintrospect/fintrospect.dockerfile b/frameworks/Scala/fintrospect/fintrospect.dockerfile deleted file mode 100644 index 26d2f15fca0..00000000000 --- a/frameworks/Scala/fintrospect/fintrospect.dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM hseeberger/scala-sbt:8u222_1.3.5_2.13.1 -WORKDIR /fintrospect -COPY project project -COPY src src -COPY build.sbt build.sbt -RUN sbt assembly -batch - -EXPOSE 9000 - -CMD ["java", "-Dcom.twitter.finagle.toggle.flag.overrides=com.twitter.http.UseNetty4=1.0", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AggressiveOpts", "-XX:+AlwaysPreTouch", "-jar", "target/scala-2.13/techempower-benchmarks-fintrospect-assembly-1.0.jar"] diff --git a/frameworks/Scala/fintrospect/project/build.properties b/frameworks/Scala/fintrospect/project/build.properties deleted file mode 100644 index 0837f7a132d..00000000000 --- a/frameworks/Scala/fintrospect/project/build.properties +++ /dev/null @@ -1 +0,0 @@ -sbt.version=1.3.13 diff --git a/frameworks/Scala/fintrospect/project/plugins.sbt b/frameworks/Scala/fintrospect/project/plugins.sbt deleted file mode 100644 index 652a3b93be3..00000000000 --- a/frameworks/Scala/fintrospect/project/plugins.sbt +++ /dev/null @@ -1 +0,0 @@ -addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.6") diff --git a/frameworks/Scala/fintrospect/src/main/resources/FortunesList.mustache b/frameworks/Scala/fintrospect/src/main/resources/FortunesList.mustache deleted file mode 100644 index cce4d7b0393..00000000000 --- a/frameworks/Scala/fintrospect/src/main/resources/FortunesList.mustache +++ /dev/null @@ -1 +0,0 @@ -Fortunes{{#items}}{{/items}}
idmessage
{{id}}{{message}}
\ No newline at end of file diff --git a/frameworks/Scala/fintrospect/src/main/scala/Database.scala b/frameworks/Scala/fintrospect/src/main/scala/Database.scala deleted file mode 100644 index 8075fe44e31..00000000000 --- a/frameworks/Scala/fintrospect/src/main/scala/Database.scala +++ /dev/null @@ -1,22 +0,0 @@ -import com.twitter.finagle.Mysql -import com.twitter.finagle.client.DefaultPool.Param -import com.twitter.finagle.mysql.Client -import com.twitter.finagle.stats.NullStatsReceiver -import com.twitter.finagle.tracing.NullTracer -import com.twitter.util.Duration.fromSeconds -import com.twitter.util.NullMonitor -import io.fintrospect.configuration.Host - -object Database { - def apply(): Client = { - Mysql.client - .withCredentials("benchmarkdbuser", "benchmarkdbpass") - .withDatabase("hello_world") - .configured(Param(low = 256, high = 256, idleTime = fromSeconds(5 * 60), bufferSize = 0, maxWaiters = Int.MaxValue)) - .withStatsReceiver(NullStatsReceiver) - .withMonitor(NullMonitor) - .withTracer(NullTracer) - .withMaxConcurrentPrepareStatements(256) - .newRichClient("tfb-database:3306") - } -} diff --git a/frameworks/Scala/fintrospect/src/main/scala/DatabaseRoutes.scala b/frameworks/Scala/fintrospect/src/main/scala/DatabaseRoutes.scala deleted file mode 100644 index 1ba864a14ef..00000000000 --- a/frameworks/Scala/fintrospect/src/main/scala/DatabaseRoutes.scala +++ /dev/null @@ -1,77 +0,0 @@ -import com.fasterxml.jackson.databind.JsonNode -import com.twitter.finagle.Service -import com.twitter.finagle.http.Method.Get -import com.twitter.finagle.http.{Request, Response} -import com.twitter.finagle.mysql.Parameter.wrap -import com.twitter.finagle.mysql.{Client, IntValue, Result, ResultSet} -import com.twitter.util.Future.collect -import io.fintrospect.formats.Jackson.JsonFormat.{array, number, obj} -import io.fintrospect.formats.Jackson.ResponseBuilder._ -import io.fintrospect.parameters.{ParameterSpec, Query, StringValidations} -import io.fintrospect.{RouteSpec, ServerRoutes} - -import scala.language.reflectiveCalls -import scala.util.{Random, Try} - -object DatabaseRoutes { - - private val toJson: PartialFunction[Result, Option[JsonNode]] = { - case rs: ResultSet => rs.rows.headOption - .map(row => { - val IntValue(id) = row("id").get - val IntValue(random) = row("randomNumber").get - obj("id" -> number(id), "randomNumber" -> number(random)) - }) - case _ => None - } - - private def generateRandomNumber = Random.nextInt(9999) + 1 - - def apply(database: Client) = { - val getStatement = database.prepare("SELECT id, randomNumber FROM world WHERE id = ?") - val updateStatement = database.prepare("UPDATE world SET randomNumber = ? WHERE id = ?") - - val queryRoute = RouteSpec().at(Get) / "db" bindTo Service.mk { - _: Request => getStatement(generateRandomNumber) - .map(toJson) - .map(_.map(Ok(_)).getOrElse(NotFound("")).build()) - } - - val numberOfQueries = Query.optional(ParameterSpec.string(StringValidations.EmptyIsValid).map { - i => Try(i.toInt).getOrElse(1).max(1).min(500) - }, "queries") - - val multipleRoute = RouteSpec() - .taking(numberOfQueries) - .at(Get) / "queries" bindTo Service.mk { - r: Request => { - collect(1.to((numberOfQueries <-- r).getOrElse(1)) - .map(i => getStatement(generateRandomNumber).map(toJson))) - .map(f => f.flatMap(_.toSeq)) - .flatMap(c => Ok(array(c))) - } - } - - val updateRoute = RouteSpec() - .taking(numberOfQueries) - .at(Get) / "updates" bindTo Service.mk { - r: Request => { - collect(1.to((numberOfQueries <-- r).getOrElse(1)) - .map(i => { - val id = generateRandomNumber - updateStatement(generateRandomNumber, id) - .flatMap(_ => getStatement(id)) - .map(toJson) - })) - .map(f => f.flatMap(_.toSeq)) - .flatMap(c => Ok(array(c))) - } - } - - new ServerRoutes[Request, Response] { - add(queryRoute) - add(multipleRoute) - add(updateRoute) - } - } -} diff --git a/frameworks/Scala/fintrospect/src/main/scala/FintrospectBenchmarkServer.scala b/frameworks/Scala/fintrospect/src/main/scala/FintrospectBenchmarkServer.scala deleted file mode 100644 index bf08266724b..00000000000 --- a/frameworks/Scala/fintrospect/src/main/scala/FintrospectBenchmarkServer.scala +++ /dev/null @@ -1,36 +0,0 @@ -import java.util.TimeZone.getTimeZone - -import com.twitter.finagle.http.path.Root -import com.twitter.finagle.http.{Request, Response} -import com.twitter.finagle.{Filter, Http} -import com.twitter.util.Await -import io.fintrospect.RouteModule -import io.fintrospect.filters.ResponseFilters -import org.apache.commons.lang3.time.FastDateFormat.getInstance - -object FintrospectBenchmarkServer extends App { - - val dateFormat = getInstance("EEE, d MMM yyyy HH:mm:ss 'GMT'", getTimeZone("GMT")) - - val addServerAndDate = Filter.mk[Request, Response, Request, Response] { (req, svc) => - svc(req).map(resp => { - resp.headerMap("Server") = "Example" - resp.headerMap("Date") = dateFormat.format(System.currentTimeMillis()) - resp - }) - } - - val database = Database() - - val module = RouteModule(Root) - .withRoute(JsonRoute()) - .withRoute(PlainTextRoute()) - .withRoute(FortunesRoute(database)) - .withRoutes(DatabaseRoutes(database)) - - Await.ready( - Http.server - .withCompressionLevel(0) - .serve(":9000", ResponseFilters.CatchAll().andThen(addServerAndDate).andThen(module.toService)) - ) -} diff --git a/frameworks/Scala/fintrospect/src/main/scala/FortunesRoute.scala b/frameworks/Scala/fintrospect/src/main/scala/FortunesRoute.scala deleted file mode 100644 index e7d0b858dd6..00000000000 --- a/frameworks/Scala/fintrospect/src/main/scala/FortunesRoute.scala +++ /dev/null @@ -1,41 +0,0 @@ -import com.twitter.finagle.Service -import com.twitter.finagle.http.Method.Get -import com.twitter.finagle.http.Request -import com.twitter.finagle.mysql._ -import io.fintrospect.RouteSpec -import io.fintrospect.formats.Html -import io.fintrospect.templating.MustacheTemplates.CachingClasspath -import io.fintrospect.templating.{RenderView, View} - -case class Fortune(id: Int, message: String) - -case class FortunesList(items: Seq[Fortune]) extends View - -object FortunesRoute { - - private val toFortunes: PartialFunction[Result, Seq[Fortune]] = { - case rs: ResultSet => rs.rows - .map(row => { - val IntValue(id) = row("id").get - val StringValue(message) = row("message").get - Fortune(id, message) - }) - case _ => Seq.empty - } - - def apply(database: Client) = { - - val statement = database.prepare("SELECT * FROM fortune") - - val service = new RenderView(Html.ResponseBuilder, CachingClasspath()).andThen( - Service.mk { - _: Request => - statement().map(toFortunes).map(f => { - val sortedFortunes = (Fortune(0, "Additional fortune added at request time.") +: f).sortBy(_.message) - FortunesList(sortedFortunes) - }) - }) - - RouteSpec().at(Get) / "fortunes" bindTo service - } -} diff --git a/frameworks/Scala/fintrospect/src/main/scala/JsonRoute.scala b/frameworks/Scala/fintrospect/src/main/scala/JsonRoute.scala deleted file mode 100644 index e3bb2311891..00000000000 --- a/frameworks/Scala/fintrospect/src/main/scala/JsonRoute.scala +++ /dev/null @@ -1,13 +0,0 @@ -import com.twitter.finagle.Service -import com.twitter.finagle.http.Method.Get -import com.twitter.finagle.http.Request -import io.fintrospect.RouteSpec -import io.fintrospect.formats.Jackson.JsonFormat.{encodeToBuf, obj, string} -import io.fintrospect.formats.Jackson.ResponseBuilder._ - -object JsonRoute { - - private val service = Service.mk { _: Request => Ok(encodeToBuf(obj("message" -> string("Hello, World!")))) } - - def apply() = RouteSpec().at(Get) / "json" bindTo service -} diff --git a/frameworks/Scala/fintrospect/src/main/scala/PlainTextRoute.scala b/frameworks/Scala/fintrospect/src/main/scala/PlainTextRoute.scala deleted file mode 100644 index a2c5b6198d1..00000000000 --- a/frameworks/Scala/fintrospect/src/main/scala/PlainTextRoute.scala +++ /dev/null @@ -1,15 +0,0 @@ -import com.twitter.finagle.Service -import com.twitter.finagle.http.Method.Get -import com.twitter.finagle.http.Request -import com.twitter.io.Buf -import io.fintrospect.RouteSpec -import io.fintrospect.formats.PlainText.ResponseBuilder._ - -object PlainTextRoute { - - private val preallocatedMsgForPlainText = Buf.Utf8("Hello, World!") - - private val service = Service.mk { _: Request => Ok(preallocatedMsgForPlainText) } - - def apply() = RouteSpec().at(Get) / "plaintext" bindTo service -} diff --git a/frameworks/Scala/http4s/blaze/build.sbt b/frameworks/Scala/http4s/blaze/build.sbt index c7be0723a4b..71578bedef4 100644 --- a/frameworks/Scala/http4s/blaze/build.sbt +++ b/frameworks/Scala/http4s/blaze/build.sbt @@ -2,7 +2,7 @@ name := "http4s" version := "1.0" -scalaVersion := "2.13.11" +scalaVersion := "2.13.17" scalacOptions ++= Seq( "-deprecation", @@ -19,9 +19,9 @@ scalacOptions ++= Seq( enablePlugins(SbtTwirl) -val http4sVersion = "0.23.22" -val http4sBlazeVersion = "0.23.15" -val http4sTwirlVersion = "0.23.17" +val http4sVersion = "0.23.32" +val http4sBlazeVersion = "0.23.17" +val http4sTwirlVersion = "0.23.18" assembly / assemblyMergeStrategy := { case PathList(xs @ _*) if xs.last == "io.netty.versions.properties" => MergeStrategy.rename @@ -35,13 +35,13 @@ libraryDependencies ++= Seq( "org.http4s" %% "http4s-twirl" % http4sTwirlVersion, "org.http4s" %% "http4s-circe" % http4sVersion, // Optional for auto-derivation of JSON codecs - "io.circe" %% "circe-generic" % "0.14.5", - "org.typelevel" %% "cats-effect" % "3.5.1", - "co.fs2" %% "fs2-core" % "3.7.0", - "co.fs2" %% "fs2-io" % "3.7.0", - "io.getquill" %% "quill-jasync-postgres" % "3.19.0", - "io.getquill" %% "quill-jasync" % "3.19.0", - "ch.qos.logback" % "logback-classic" % "1.4.8" + "io.circe" %% "circe-generic" % "0.14.15", + "org.typelevel" %% "cats-effect" % "3.6.3", + "co.fs2" %% "fs2-core" % "3.12.2", + "co.fs2" %% "fs2-io" % "3.12.2", + "io.getquill" %% "quill-jasync-postgres" % "4.8.0", + "io.getquill" %% "quill-jasync" % "4.8.0", + "ch.qos.logback" % "logback-classic" % "1.5.19" ) addCompilerPlugin("com.olegpy" %% "better-monadic-for" % "0.3.1") diff --git a/frameworks/Scala/http4s/blaze/project/build.properties b/frameworks/Scala/http4s/blaze/project/build.properties index 22af2628c41..cc68b53f1a3 100644 --- a/frameworks/Scala/http4s/blaze/project/build.properties +++ b/frameworks/Scala/http4s/blaze/project/build.properties @@ -1 +1 @@ -sbt.version=1.7.1 +sbt.version=1.10.11 diff --git a/frameworks/Scala/http4s/blaze/project/plugins.sbt b/frameworks/Scala/http4s/blaze/project/plugins.sbt index c11f6507afd..e1af0437904 100644 --- a/frameworks/Scala/http4s/blaze/project/plugins.sbt +++ b/frameworks/Scala/http4s/blaze/project/plugins.sbt @@ -1,2 +1,4 @@ addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "1.2.0") addSbtPlugin("com.typesafe.sbt" % "sbt-twirl" % "1.5.1") + +libraryDependencySchemes += "org.scala-lang.modules" %% "scala-xml" % "always" \ No newline at end of file diff --git a/frameworks/Scala/http4s/http4s.dockerfile b/frameworks/Scala/http4s/http4s.dockerfile index f3cfdfcc73b..e059893aa79 100644 --- a/frameworks/Scala/http4s/http4s.dockerfile +++ b/frameworks/Scala/http4s/http4s.dockerfile @@ -1,18 +1,17 @@ -FROM openjdk:17 AS builder +FROM sbtscala/scala-sbt:eclipse-temurin-21.0.8_9_1.11.7_2.13.17 AS builder WORKDIR /http4s COPY blaze/project project COPY blaze/src src COPY blaze/build.sbt build.sbt -COPY sbt sbt -RUN ./sbt assembly -batch && \ +RUN sbt assembly -batch && \ mv target/scala-2.13/http4s-assembly-1.0.jar . && \ rm -Rf target && \ rm -Rf project/target && \ rm -Rf ~/.sbt && \ rm -Rf ~/.ivy2 && \ rm -Rf /var/cache - -FROM openjdk:17 + +FROM openjdk:21 WORKDIR /http4s COPY --from=builder /http4s/http4s-assembly-1.0.jar /http4s/http4s-assembly-1.0.jar diff --git a/frameworks/Scala/http4s/sbt b/frameworks/Scala/http4s/sbt deleted file mode 100755 index 20d08c9f260..00000000000 --- a/frameworks/Scala/http4s/sbt +++ /dev/null @@ -1,664 +0,0 @@ -#!/usr/bin/env bash -# -# A more capable sbt runner, coincidentally also called sbt. -# Author: Paul Phillips -# https://github.com/paulp/sbt-extras -# -# Generated from http://www.opensource.org/licenses/bsd-license.php -# Copyright (c) 2011, Paul Phillips. All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * 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. -# * Neither the name of the author 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. - -set -o pipefail - -declare -r sbt_release_version="1.7.1" -declare -r sbt_unreleased_version="1.7.1" - -declare -r latest_213="2.13.8" -declare -r latest_212="2.12.16" -declare -r latest_211="2.11.12" -declare -r latest_210="2.10.7" -declare -r latest_29="2.9.3" -declare -r latest_28="2.8.2" - -declare -r buildProps="project/build.properties" - -declare -r sbt_launch_ivy_release_repo="https://repo.typesafe.com/typesafe/ivy-releases" -declare -r sbt_launch_ivy_snapshot_repo="https://repo.scala-sbt.org/scalasbt/ivy-snapshots" -declare -r sbt_launch_mvn_release_repo="https://repo1.maven.org/maven2" -declare -r sbt_launch_mvn_snapshot_repo="https://repo.scala-sbt.org/scalasbt/maven-snapshots" - -declare -r default_jvm_opts_common="-Xms512m -Xss2m -XX:MaxInlineLevel=18" -declare -r noshare_opts="-Dsbt.global.base=project/.sbtboot -Dsbt.boot.directory=project/.boot -Dsbt.ivy.home=project/.ivy -Dsbt.coursier.home=project/.coursier" - -declare sbt_jar sbt_dir sbt_create sbt_version sbt_script sbt_new -declare sbt_explicit_version -declare verbose noshare batch trace_level - -declare java_cmd="java" -declare sbt_launch_dir="$HOME/.sbt/launchers" -declare sbt_launch_repo - -# pull -J and -D options to give to java. -declare -a java_args scalac_args sbt_commands residual_args - -# args to jvm/sbt via files or environment variables -declare -a extra_jvm_opts extra_sbt_opts - -echoerr() { echo >&2 "$@"; } -vlog() { [[ -n "$verbose" ]] && echoerr "$@"; } -die() { - echo "Aborting: $*" - exit 1 -} - -setTrapExit() { - # save stty and trap exit, to ensure echo is re-enabled if we are interrupted. - SBT_STTY="$(stty -g 2>/dev/null)" - export SBT_STTY - - # restore stty settings (echo in particular) - onSbtRunnerExit() { - [ -t 0 ] || return - vlog "" - vlog "restoring stty: $SBT_STTY" - stty "$SBT_STTY" - } - - vlog "saving stty: $SBT_STTY" - trap onSbtRunnerExit EXIT -} - -# this seems to cover the bases on OSX, and someone will -# have to tell me about the others. -get_script_path() { - local path="$1" - [[ -L "$path" ]] || { - echo "$path" - return - } - - local -r target="$(readlink "$path")" - if [[ "${target:0:1}" == "/" ]]; then - echo "$target" - else - echo "${path%/*}/$target" - fi -} - -script_path="$(get_script_path "${BASH_SOURCE[0]}")" -declare -r script_path -script_name="${script_path##*/}" -declare -r script_name - -init_default_option_file() { - local overriding_var="${!1}" - local default_file="$2" - if [[ ! -r "$default_file" && "$overriding_var" =~ ^@(.*)$ ]]; then - local envvar_file="${BASH_REMATCH[1]}" - if [[ -r "$envvar_file" ]]; then - default_file="$envvar_file" - fi - fi - echo "$default_file" -} - -sbt_opts_file="$(init_default_option_file SBT_OPTS .sbtopts)" -sbtx_opts_file="$(init_default_option_file SBTX_OPTS .sbtxopts)" -jvm_opts_file="$(init_default_option_file JVM_OPTS .jvmopts)" - -build_props_sbt() { - [[ -r "$buildProps" ]] && - grep '^sbt\.version' "$buildProps" | tr '=\r' ' ' | awk '{ print $2; }' -} - -set_sbt_version() { - sbt_version="${sbt_explicit_version:-$(build_props_sbt)}" - [[ -n "$sbt_version" ]] || sbt_version=$sbt_release_version - export sbt_version -} - -url_base() { - local version="$1" - - case "$version" in - 0.7.*) echo "https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/simple-build-tool" ;; - 0.10.*) echo "$sbt_launch_ivy_release_repo" ;; - 0.11.[12]) echo "$sbt_launch_ivy_release_repo" ;; - 0.*-[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]-[0-9][0-9][0-9][0-9][0-9][0-9]) # ie "*-yyyymmdd-hhMMss" - echo "$sbt_launch_ivy_snapshot_repo" ;; - 0.*) echo "$sbt_launch_ivy_release_repo" ;; - *-[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]T[0-9][0-9][0-9][0-9][0-9][0-9]) # ie "*-yyyymmddThhMMss" - echo "$sbt_launch_mvn_snapshot_repo" ;; - *) echo "$sbt_launch_mvn_release_repo" ;; - esac -} - -make_url() { - local version="$1" - - local base="${sbt_launch_repo:-$(url_base "$version")}" - - case "$version" in - 0.7.*) echo "$base/sbt-launch-0.7.7.jar" ;; - 0.10.*) echo "$base/org.scala-tools.sbt/sbt-launch/$version/sbt-launch.jar" ;; - 0.11.[12]) echo "$base/org.scala-tools.sbt/sbt-launch/$version/sbt-launch.jar" ;; - 0.*) echo "$base/org.scala-sbt/sbt-launch/$version/sbt-launch.jar" ;; - *) echo "$base/org/scala-sbt/sbt-launch/$version/sbt-launch-${version}.jar" ;; - esac -} - -addJava() { - vlog "[addJava] arg = '$1'" - java_args+=("$1") -} -addSbt() { - vlog "[addSbt] arg = '$1'" - sbt_commands+=("$1") -} -addScalac() { - vlog "[addScalac] arg = '$1'" - scalac_args+=("$1") -} -addResidual() { - vlog "[residual] arg = '$1'" - residual_args+=("$1") -} - -addResolver() { addSbt "set resolvers += $1"; } - -addDebugger() { addJava "-Xdebug" && addJava "-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=$1"; } - -setThisBuild() { - vlog "[addBuild] args = '$*'" - local key="$1" && shift - addSbt "set $key in ThisBuild := $*" -} -setScalaVersion() { - [[ "$1" == *"-SNAPSHOT" ]] && addResolver 'Resolver.sonatypeRepo("snapshots")' - addSbt "++ $1" -} -setJavaHome() { - java_cmd="$1/bin/java" - setThisBuild javaHome "_root_.scala.Some(file(\"$1\"))" - export JAVA_HOME="$1" - export JDK_HOME="$1" - export PATH="$JAVA_HOME/bin:$PATH" -} - -getJavaVersion() { - local -r str=$("$1" -version 2>&1 | grep -E -e '(java|openjdk) version' | awk '{ print $3 }' | tr -d '"') - - # java -version on java8 says 1.8.x - # but on 9 and 10 it's 9.x.y and 10.x.y. - if [[ "$str" =~ ^1\.([0-9]+)(\..*)?$ ]]; then - echo "${BASH_REMATCH[1]}" - # Fixes https://github.com/dwijnand/sbt-extras/issues/326 - elif [[ "$str" =~ ^([0-9]+)(\..*)?(-ea)?$ ]]; then - echo "${BASH_REMATCH[1]}" - elif [[ -n "$str" ]]; then - echoerr "Can't parse java version from: $str" - fi -} - -checkJava() { - # Warn if there is a Java version mismatch between PATH and JAVA_HOME/JDK_HOME - - [[ -n "$JAVA_HOME" && -e "$JAVA_HOME/bin/java" ]] && java="$JAVA_HOME/bin/java" - [[ -n "$JDK_HOME" && -e "$JDK_HOME/lib/tools.jar" ]] && java="$JDK_HOME/bin/java" - - if [[ -n "$java" ]]; then - pathJavaVersion=$(getJavaVersion java) - homeJavaVersion=$(getJavaVersion "$java") - if [[ "$pathJavaVersion" != "$homeJavaVersion" ]]; then - echoerr "Warning: Java version mismatch between PATH and JAVA_HOME/JDK_HOME, sbt will use the one in PATH" - echoerr " Either: fix your PATH, remove JAVA_HOME/JDK_HOME or use -java-home" - echoerr " java version from PATH: $pathJavaVersion" - echoerr " java version from JAVA_HOME/JDK_HOME: $homeJavaVersion" - fi - fi -} - -java_version() { - local -r version=$(getJavaVersion "$java_cmd") - vlog "Detected Java version: $version" - echo "$version" -} - -is_apple_silicon() { [[ "$(uname -s)" == "Darwin" && "$(uname -m)" == "arm64" ]]; } - -# MaxPermSize critical on pre-8 JVMs but incurs noisy warning on 8+ -default_jvm_opts() { - local -r v="$(java_version)" - if [[ $v -ge 17 ]]; then - echo "$default_jvm_opts_common" - elif [[ $v -ge 10 ]]; then - if is_apple_silicon; then - # As of Dec 2020, JVM for Apple Silicon (M1) doesn't support JVMCI - echo "$default_jvm_opts_common" - else - echo "$default_jvm_opts_common -XX:+UnlockExperimentalVMOptions -XX:+UseJVMCICompiler" - fi - elif [[ $v -ge 8 ]]; then - echo "$default_jvm_opts_common" - else - echo "-XX:MaxPermSize=384m $default_jvm_opts_common" - fi -} - -execRunner() { - # print the arguments one to a line, quoting any containing spaces - vlog "# Executing command line:" && { - for arg; do - if [[ -n "$arg" ]]; then - if printf "%s\n" "$arg" | grep -q ' '; then - printf >&2 "\"%s\"\n" "$arg" - else - printf >&2 "%s\n" "$arg" - fi - fi - done - vlog "" - } - - setTrapExit - - if [[ -n "$batch" ]]; then - "$@" /dev/null 2>&1; then - curl --fail --silent --location "$url" --output "$jar" - elif command -v wget >/dev/null 2>&1; then - wget -q -O "$jar" "$url" - fi - } && [[ -r "$jar" ]] -} - -acquire_sbt_jar() { - { - sbt_jar="$(jar_file "$sbt_version")" - [[ -r "$sbt_jar" ]] - } || { - sbt_jar="$HOME/.ivy2/local/org.scala-sbt/sbt-launch/$sbt_version/jars/sbt-launch.jar" - [[ -r "$sbt_jar" ]] - } || { - sbt_jar="$(jar_file "$sbt_version")" - jar_url="$(make_url "$sbt_version")" - - echoerr "Downloading sbt launcher for ${sbt_version}:" - echoerr " From ${jar_url}" - echoerr " To ${sbt_jar}" - - download_url "${jar_url}" "${sbt_jar}" - - case "${sbt_version}" in - 0.*) - vlog "SBT versions < 1.0 do not have published MD5 checksums, skipping check" - echo "" - ;; - *) verify_sbt_jar "${sbt_jar}" ;; - esac - } -} - -verify_sbt_jar() { - local jar="${1}" - local md5="${jar}.md5" - md5url="$(make_url "${sbt_version}").md5" - - echoerr "Downloading sbt launcher ${sbt_version} md5 hash:" - echoerr " From ${md5url}" - echoerr " To ${md5}" - - download_url "${md5url}" "${md5}" >/dev/null 2>&1 - - if command -v md5sum >/dev/null 2>&1; then - if echo "$(cat "${md5}") ${jar}" | md5sum -c -; then - rm -rf "${md5}" - return 0 - else - echoerr "Checksum does not match" - return 1 - fi - elif command -v md5 >/dev/null 2>&1; then - if [ "$(md5 -q "${jar}")" == "$(cat "${md5}")" ]; then - rm -rf "${md5}" - return 0 - else - echoerr "Checksum does not match" - return 1 - fi - elif command -v openssl >/dev/null 2>&1; then - if [ "$(openssl md5 -r "${jar}" | awk '{print $1}')" == "$(cat "${md5}")" ]; then - rm -rf "${md5}" - return 0 - else - echoerr "Checksum does not match" - return 1 - fi - else - echoerr "Could not find an MD5 command" - return 1 - fi -} - -usage() { - set_sbt_version - cat < display stack traces with a max of frames (default: -1, traces suppressed) - -debug-inc enable debugging log for the incremental compiler - -no-colors disable ANSI color codes - -sbt-create start sbt even if current directory contains no sbt project - -sbt-dir path to global settings/plugins directory (default: ~/.sbt/) - -sbt-boot path to shared boot directory (default: ~/.sbt/boot in 0.11+) - -ivy path to local Ivy repository (default: ~/.ivy2) - -no-share use all local caches; no sharing - -offline put sbt in offline mode - -jvm-debug Turn on JVM debugging, open at the given port. - -batch Disable interactive mode - -prompt Set the sbt prompt; in expr, 's' is the State and 'e' is Extracted - -script Run the specified file as a scala script - - # sbt version (default: sbt.version from $buildProps if present, otherwise $sbt_release_version) - -sbt-version use the specified version of sbt (default: $sbt_release_version) - -sbt-force-latest force the use of the latest release of sbt: $sbt_release_version - -sbt-dev use the latest pre-release version of sbt: $sbt_unreleased_version - -sbt-jar use the specified jar as the sbt launcher - -sbt-launch-dir directory to hold sbt launchers (default: $sbt_launch_dir) - -sbt-launch-repo repo url for downloading sbt launcher jar (default: $(url_base "$sbt_version")) - - # scala version (default: as chosen by sbt) - -28 use $latest_28 - -29 use $latest_29 - -210 use $latest_210 - -211 use $latest_211 - -212 use $latest_212 - -213 use $latest_213 - -scala-home use the scala build at the specified directory - -scala-version use the specified version of scala - -binary-version use the specified scala version when searching for dependencies - - # java version (default: java from PATH, currently $(java -version 2>&1 | grep version)) - -java-home alternate JAVA_HOME - - # passing options to the jvm - note it does NOT use JAVA_OPTS due to pollution - # The default set is used if JVM_OPTS is unset and no -jvm-opts file is found - $(default_jvm_opts) - JVM_OPTS environment variable holding either the jvm args directly, or - the reference to a file containing jvm args if given path is prepended by '@' (e.g. '@/etc/jvmopts') - Note: "@"-file is overridden by local '.jvmopts' or '-jvm-opts' argument. - -jvm-opts file containing jvm args (if not given, .jvmopts in project root is used if present) - -Dkey=val pass -Dkey=val directly to the jvm - -J-X pass option -X directly to the jvm (-J is stripped) - - # passing options to sbt, OR to this runner - SBT_OPTS environment variable holding either the sbt args directly, or - the reference to a file containing sbt args if given path is prepended by '@' (e.g. '@/etc/sbtopts') - Note: "@"-file is overridden by local '.sbtopts' or '-sbt-opts' argument. - -sbt-opts file containing sbt args (if not given, .sbtopts in project root is used if present) - -S-X add -X to sbt's scalacOptions (-S is stripped) - - # passing options exclusively to this runner - SBTX_OPTS environment variable holding either the sbt-extras args directly, or - the reference to a file containing sbt-extras args if given path is prepended by '@' (e.g. '@/etc/sbtxopts') - Note: "@"-file is overridden by local '.sbtxopts' or '-sbtx-opts' argument. - -sbtx-opts file containing sbt-extras args (if not given, .sbtxopts in project root is used if present) -EOM - exit 0 -} - -process_args() { - require_arg() { - local type="$1" - local opt="$2" - local arg="$3" - - if [[ -z "$arg" ]] || [[ "${arg:0:1}" == "-" ]]; then - die "$opt requires <$type> argument" - fi - } - while [[ $# -gt 0 ]]; do - case "$1" in - -h | -help) usage ;; - -v) verbose=true && shift ;; - -d) addSbt "--debug" && shift ;; - -w) addSbt "--warn" && shift ;; - -q) addSbt "--error" && shift ;; - -x) shift ;; # currently unused - -trace) require_arg integer "$1" "$2" && trace_level="$2" && shift 2 ;; - -debug-inc) addJava "-Dxsbt.inc.debug=true" && shift ;; - - -no-colors) addJava "-Dsbt.log.noformat=true" && addJava "-Dsbt.color=false" && shift ;; - -sbt-create) sbt_create=true && shift ;; - -sbt-dir) require_arg path "$1" "$2" && sbt_dir="$2" && shift 2 ;; - -sbt-boot) require_arg path "$1" "$2" && addJava "-Dsbt.boot.directory=$2" && shift 2 ;; - -ivy) require_arg path "$1" "$2" && addJava "-Dsbt.ivy.home=$2" && shift 2 ;; - -no-share) noshare=true && shift ;; - -offline) addSbt "set offline in Global := true" && shift ;; - -jvm-debug) require_arg port "$1" "$2" && addDebugger "$2" && shift 2 ;; - -batch) batch=true && shift ;; - -prompt) require_arg "expr" "$1" "$2" && setThisBuild shellPrompt "(s => { val e = Project.extract(s) ; $2 })" && shift 2 ;; - -script) require_arg file "$1" "$2" && sbt_script="$2" && addJava "-Dsbt.main.class=sbt.ScriptMain" && shift 2 ;; - - -sbt-version) require_arg version "$1" "$2" && sbt_explicit_version="$2" && shift 2 ;; - -sbt-force-latest) sbt_explicit_version="$sbt_release_version" && shift ;; - -sbt-dev) sbt_explicit_version="$sbt_unreleased_version" && shift ;; - -sbt-jar) require_arg path "$1" "$2" && sbt_jar="$2" && shift 2 ;; - -sbt-launch-dir) require_arg path "$1" "$2" && sbt_launch_dir="$2" && shift 2 ;; - -sbt-launch-repo) require_arg path "$1" "$2" && sbt_launch_repo="$2" && shift 2 ;; - - -28) setScalaVersion "$latest_28" && shift ;; - -29) setScalaVersion "$latest_29" && shift ;; - -210) setScalaVersion "$latest_210" && shift ;; - -211) setScalaVersion "$latest_211" && shift ;; - -212) setScalaVersion "$latest_212" && shift ;; - -213) setScalaVersion "$latest_213" && shift ;; - - -scala-version) require_arg version "$1" "$2" && setScalaVersion "$2" && shift 2 ;; - -binary-version) require_arg version "$1" "$2" && setThisBuild scalaBinaryVersion "\"$2\"" && shift 2 ;; - -scala-home) require_arg path "$1" "$2" && setThisBuild scalaHome "_root_.scala.Some(file(\"$2\"))" && shift 2 ;; - -java-home) require_arg path "$1" "$2" && setJavaHome "$2" && shift 2 ;; - -sbt-opts) require_arg path "$1" "$2" && sbt_opts_file="$2" && shift 2 ;; - -sbtx-opts) require_arg path "$1" "$2" && sbtx_opts_file="$2" && shift 2 ;; - -jvm-opts) require_arg path "$1" "$2" && jvm_opts_file="$2" && shift 2 ;; - - -D*) addJava "$1" && shift ;; - -J*) addJava "${1:2}" && shift ;; - -S*) addScalac "${1:2}" && shift ;; - - new) sbt_new=true && : ${sbt_explicit_version:=$sbt_release_version} && addResidual "$1" && shift ;; - - *) addResidual "$1" && shift ;; - esac - done -} - -# process the direct command line arguments -process_args "$@" - -# skip #-styled comments and blank lines -readConfigFile() { - local end=false - until $end; do - read -r || end=true - [[ $REPLY =~ ^# ]] || [[ -z $REPLY ]] || echo "$REPLY" - done <"$1" -} - -# if there are file/environment sbt_opts, process again so we -# can supply args to this runner -if [[ -r "$sbt_opts_file" ]]; then - vlog "Using sbt options defined in file $sbt_opts_file" - while read -r opt; do extra_sbt_opts+=("$opt"); done < <(readConfigFile "$sbt_opts_file") -elif [[ -n "$SBT_OPTS" && ! ("$SBT_OPTS" =~ ^@.*) ]]; then - vlog "Using sbt options defined in variable \$SBT_OPTS" - IFS=" " read -r -a extra_sbt_opts <<<"$SBT_OPTS" -else - vlog "No extra sbt options have been defined" -fi - -# if there are file/environment sbtx_opts, process again so we -# can supply args to this runner -if [[ -r "$sbtx_opts_file" ]]; then - vlog "Using sbt options defined in file $sbtx_opts_file" - while read -r opt; do extra_sbt_opts+=("$opt"); done < <(readConfigFile "$sbtx_opts_file") -elif [[ -n "$SBTX_OPTS" && ! ("$SBTX_OPTS" =~ ^@.*) ]]; then - vlog "Using sbt options defined in variable \$SBTX_OPTS" - IFS=" " read -r -a extra_sbt_opts <<<"$SBTX_OPTS" -else - vlog "No extra sbt options have been defined" -fi - -[[ -n "${extra_sbt_opts[*]}" ]] && process_args "${extra_sbt_opts[@]}" - -# reset "$@" to the residual args -set -- "${residual_args[@]}" -argumentCount=$# - -# set sbt version -set_sbt_version - -checkJava - -# only exists in 0.12+ -setTraceLevel() { - case "$sbt_version" in - "0.7."* | "0.10."* | "0.11."*) echoerr "Cannot set trace level in sbt version $sbt_version" ;; - *) setThisBuild traceLevel "$trace_level" ;; - esac -} - -# set scalacOptions if we were given any -S opts -[[ ${#scalac_args[@]} -eq 0 ]] || addSbt "set scalacOptions in ThisBuild += \"${scalac_args[*]}\"" - -[[ -n "$sbt_explicit_version" && -z "$sbt_new" ]] && addJava "-Dsbt.version=$sbt_explicit_version" -vlog "Detected sbt version $sbt_version" - -if [[ -n "$sbt_script" ]]; then - residual_args=("$sbt_script" "${residual_args[@]}") -else - # no args - alert them there's stuff in here - ((argumentCount > 0)) || { - vlog "Starting $script_name: invoke with -help for other options" - residual_args=(shell) - } -fi - -# verify this is an sbt dir, -create was given or user attempts to run a scala script -[[ -r ./build.sbt || -d ./project || -n "$sbt_create" || -n "$sbt_script" || -n "$sbt_new" ]] || { - cat < MergeStrategy.discard + case x if x.contains("module-info.class") => MergeStrategy.discard + case x => + val oldStrategy = (assembly / assemblyMergeStrategy).value + oldStrategy(x) +} + +// based on the framework/Scala/zio-http implementation +lazy val `zio-http` = (project in file("zio-http")) + .settings( + scalaVersion := "3.6.4", + name := "zio-http-kyo-scheduler-benchmark", + libraryDependencies ++= Seq( + "dev.zio" %% "zio-http" % "3.2.0", + "io.getkyo" %% "kyo-scheduler-zio" % kyoVersion, + ), + commonAssemblySettings + ) + +val http4sVersion = "0.23.22" +val http4sBlazeVersion = "0.23.15" +val http4sTwirlVersion = "0.23.17" + +// based on the framework/Scala/http4s implementation +lazy val http4s = (project in file("http4s")) + .settings( + scalaVersion := "2.13.16", + name := "http4s-kyo-scheduler-benchmark", + libraryDependencies ++= Seq( + "org.http4s" %% "http4s-blaze-server" % http4sBlazeVersion, + "org.http4s" %% "http4s-dsl" % http4sVersion, + "org.http4s" %% "http4s-twirl" % http4sTwirlVersion, + "org.http4s" %% "http4s-circe" % http4sVersion, + // Optional for auto-derivation of JSON codecs + "io.circe" %% "circe-generic" % "0.14.5", + "org.typelevel" %% "cats-effect" % "3.5.1", + "co.fs2" %% "fs2-core" % "3.7.0", + "co.fs2" %% "fs2-io" % "3.7.0", + "io.getquill" %% "quill-jasync-postgres" % "3.19.0", + "io.getquill" %% "quill-jasync" % "3.19.0", + "ch.qos.logback" % "logback-classic" % "1.4.8", + "io.getkyo" %% "kyo-scheduler-cats" % kyoVersion, + ), + commonAssemblySettings, + addCompilerPlugin("com.olegpy" %% "better-monadic-for" % "0.3.1") + ) + .enablePlugins(SbtTwirl) \ No newline at end of file diff --git a/frameworks/Scala/kyo-scheduler/config.toml b/frameworks/Scala/kyo-scheduler/config.toml new file mode 100644 index 00000000000..515c42b6557 --- /dev/null +++ b/frameworks/Scala/kyo-scheduler/config.toml @@ -0,0 +1,32 @@ +[framework] +name = "kyo-scheduler" + +[main] +urls.plaintext = "/plaintext" +urls.json = "/json" +approach = "Realistic" +classification = "Micro" +database = "None" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "Netty" +webserver = "None" +versus = "None" + +[http4s] +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 = "NIO2" +webserver = "blaze" +versus = "None" diff --git a/frameworks/Scala/kyo-scheduler/http4s/src/main/resources/application.properties b/frameworks/Scala/kyo-scheduler/http4s/src/main/resources/application.properties new file mode 100644 index 00000000000..614284866be --- /dev/null +++ b/frameworks/Scala/kyo-scheduler/http4s/src/main/resources/application.properties @@ -0,0 +1,4 @@ +ctx.port=5432 +ctx.username=benchmarkdbuser +ctx.password=benchmarkdbpass +ctx.database=hello_world diff --git a/frameworks/Scala/kyo-scheduler/http4s/src/main/resources/logback.xml b/frameworks/Scala/kyo-scheduler/http4s/src/main/resources/logback.xml new file mode 100644 index 00000000000..378a2fc929b --- /dev/null +++ b/frameworks/Scala/kyo-scheduler/http4s/src/main/resources/logback.xml @@ -0,0 +1,14 @@ + + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + diff --git a/frameworks/Scala/kyo-scheduler/http4s/src/main/scala/http4s/techempower/benchmark/DatabaseService.scala b/frameworks/Scala/kyo-scheduler/http4s/src/main/scala/http4s/techempower/benchmark/DatabaseService.scala new file mode 100644 index 00000000000..a08883458b9 --- /dev/null +++ b/frameworks/Scala/kyo-scheduler/http4s/src/main/scala/http4s/techempower/benchmark/DatabaseService.scala @@ -0,0 +1,71 @@ +package http4s.techempower.benchmark + +import java.util.concurrent.{Executor, ThreadLocalRandom} + +import scala.concurrent.{ExecutionContext, ExecutionContextExecutor} +import cats.effect.{IO => CatsIO} +import cats.syntax.all._ +import io.getquill._ + +class DatabaseService(ctx: PostgresJAsyncContext[LowerCase.type], executor: Executor) { + implicit val dbExecutionContext: ExecutionContextExecutor = ExecutionContext.fromExecutor(executor) + import ctx._ + + def close(): CatsIO[Unit] = { + CatsIO(ctx.close()) + } + + // Provide a random number between 1 and 10000 (inclusive) + private def randomWorldId() = + CatsIO(ThreadLocalRandom.current().nextInt(1, 10001)) + + // Update the randomNumber field with a random number + def updateRandomNumber(world: World): CatsIO[World] = + for { + randomId <- randomWorldId() + } yield world.copy(randomNumber = randomId) + + // Select a World object from the database by ID + def selectWorld(id: Int): CatsIO[World] = + CatsIO.fromFuture( + CatsIO.delay( + ctx + .run(quote { + query[World].filter(_.id == lift(id)) + }) + .map(rq => rq.head) + ) + ) + + // Select a random World object from the database + def selectRandomWorld(): CatsIO[World] = + for { + randomId <- randomWorldId() + world <- selectWorld(randomId) + } yield world + + // Select a specified number of random World objects from the database + def getWorlds(numQueries: Int): CatsIO[List[World]] = + (0 until numQueries).toList.traverse(_ => selectRandomWorld()) + + // Update the randomNumber field with a new random number, for a list of World objects + def getNewWorlds(worlds: List[World]): CatsIO[List[World]] = + worlds.map(updateRandomNumber).sequence + + // Update the randomNumber column in the database for a specified set of World objects, + // this uses a batch update SQL call. + def updateWorlds(newWorlds: List[World]): CatsIO[Int] = { + val u = quote { + liftQuery(newWorlds).foreach { world => + query[World] + .filter(_.id == world.id) + .update(_.randomNumber -> world.randomNumber) + } + } + CatsIO.fromFuture(CatsIO.delay(ctx.run(u).map(_.length))) + } + + // Retrieve all fortunes from the database + def getFortunes(): CatsIO[List[Fortune]] = + CatsIO.fromFuture(CatsIO.delay(ctx.run(query[Fortune]).map(_.toList))) +} diff --git a/frameworks/Scala/kyo-scheduler/http4s/src/main/scala/http4s/techempower/benchmark/WebServer.scala b/frameworks/Scala/kyo-scheduler/http4s/src/main/scala/http4s/techempower/benchmark/WebServer.scala new file mode 100644 index 00000000000..ffabe43f354 --- /dev/null +++ b/frameworks/Scala/kyo-scheduler/http4s/src/main/scala/http4s/techempower/benchmark/WebServer.scala @@ -0,0 +1,118 @@ +package http4s.techempower.benchmark + + +import java.util.concurrent.Executors +import cats.effect.{ExitCode, IO, Resource} +import com.typesafe.config.ConfigValueFactory +import io.circe.generic.auto._ +import io.circe.syntax._ +import io.getquill.util.LoadConfig +import io.getquill.LowerCase +import io.getquill.PostgresJAsyncContext +import org.http4s._ +import org.http4s.dsl._ +import org.http4s.circe._ +import org.http4s.implicits._ +import org.http4s.blaze.server.BlazeServerBuilder +import org.http4s.headers.Server +import org.http4s.twirl._ + +final case class Message(message: String) +final case class World(id: Int, randomNumber: Int) +final case class Fortune(id: Int, message: String) + +// Extract queries parameter (with default and min/maxed) +object Queries { + def unapply(params: Map[String, Seq[String]]): Option[Int] = + Some(params.getOrElse("queries", Nil).headOption match { + case None => 1 + case Some(x) => + Math.max(1, Math.min(500, scala.util.Try(x.toInt).getOrElse(1))) + }) +} + +// based on the framework/Scala/http4s implementation +object WebServer extends kyo.KyoSchedulerIOApp with Http4sDsl[IO] { + def makeDatabaseService( + host: String, + poolSize: Int + ): Resource[IO, DatabaseService] = { + for { + executor <- Resource(IO { + val pool = Executors.newFixedThreadPool(poolSize) + (pool, IO(pool.shutdown())) + }) + ctx <- Resource.fromAutoCloseable(IO(new PostgresJAsyncContext( + LowerCase, + LoadConfig("ctx") + .withValue("host", ConfigValueFactory.fromAnyRef(host)) + .withValue( + "maxActiveConnections", + ConfigValueFactory.fromAnyRef(poolSize) + ) + ))) + } yield new DatabaseService(ctx, executor) + } + + // Add a new fortune to an existing list, and sort by message. + def getSortedFortunes(old: List[Fortune]): List[Fortune] = { + val newFortune = Fortune(0, "Additional fortune added at request time.") + (newFortune :: old).sortBy(_.message) + } + + // Add Server header container server address + def addServerHeader(service: HttpRoutes[IO]): HttpRoutes[IO] = + cats.data.Kleisli { req: Request[IO] => + service.run(req).map(_.putHeaders(server)) + } + + val server = Server(ProductId("http4s", None)) + + // HTTP service definition + def service(db: DatabaseService) = + addServerHeader(HttpRoutes.of[IO] { + case GET -> Root / "plaintext" => + Ok("Hello, World!") + + case GET -> Root / "json" => + Ok(Message("Hello, World!").asJson) + + case GET -> Root / "db" => + Ok(db.selectRandomWorld().map(_.asJson)) + + case GET -> Root / "queries" :? Queries(numQueries) => + Ok(db.getWorlds(numQueries).map(_.asJson)) + + case GET -> Root / "fortunes" => + Ok(for { + oldFortunes <- db.getFortunes() + newFortunes = getSortedFortunes(oldFortunes) + } yield html.index(newFortunes)) + + case GET -> Root / "updates" :? Queries(numQueries) => + Ok(for { + worlds <- db.getWorlds(numQueries) + newWorlds <- db.getNewWorlds(worlds) + _ <- db.updateWorlds(newWorlds) + } yield newWorlds.asJson) + }) + + // Given a fully constructed HttpService, start the server and wait for completion + def startServer(service: HttpRoutes[IO]) = + BlazeServerBuilder[IO] + .bindHttp(8080, "0.0.0.0") + .withHttpApp(service.orNotFound) + .withSocketKeepAlive(true) + .resource + + // Entry point when starting service + override def run(args: List[String]): IO[ExitCode] = + (for { + db <- makeDatabaseService( + args.headOption.getOrElse("localhost"), + sys.env.get("DB_POOL_SIZE").map(_.toInt).getOrElse(64) + ) + server <- startServer(service(db)) + } yield server) + .use(_ => IO.never) +} diff --git a/frameworks/Scala/kyo-scheduler/http4s/src/main/twirl/index.scala.html b/frameworks/Scala/kyo-scheduler/http4s/src/main/twirl/index.scala.html new file mode 100644 index 00000000000..70dfcc42ca1 --- /dev/null +++ b/frameworks/Scala/kyo-scheduler/http4s/src/main/twirl/index.scala.html @@ -0,0 +1,14 @@ +@import http4s.techempower.benchmark.Fortune +@(fortunes: Seq[Fortune]) + + +Fortunes + + + + @for(fortune <- fortunes) { + + } +
idmessage
@fortune.id@fortune.message
+ + \ No newline at end of file diff --git a/frameworks/Scala/kyo-scheduler/kyo-scheduler-http4s.dockerfile b/frameworks/Scala/kyo-scheduler/kyo-scheduler-http4s.dockerfile new file mode 100644 index 00000000000..6ecf32cc149 --- /dev/null +++ b/frameworks/Scala/kyo-scheduler/kyo-scheduler-http4s.dockerfile @@ -0,0 +1,24 @@ +FROM sbtscala/scala-sbt:eclipse-temurin-21.0.6_7_1.10.11_2.13.16 + +WORKDIR /kyo-scheduler-benchmark +COPY http4s http4s +COPY project project +COPY build.sbt build.sbt +RUN sbt http4s/assembly + +EXPOSE 8080 + +CMD java \ + -server \ + -Xms2g \ + -Xmx2g \ + -XX:NewSize=1g \ + -XX:MaxNewSize=1g \ + -XX:InitialCodeCacheSize=256m \ + -XX:ReservedCodeCacheSize=256m \ + -XX:+UseParallelGC \ + -XX:+AlwaysPreTouch \ + -Dcats.effect.stackTracingMode=disabled \ + -jar \ + /kyo-scheduler-benchmark/http4s/target/scala-2.13/http4s-kyo-scheduler-benchmark-assembly-1.0.0.jar \ + tfb-database diff --git a/frameworks/Scala/kyo-scheduler/kyo-scheduler.dockerfile b/frameworks/Scala/kyo-scheduler/kyo-scheduler.dockerfile new file mode 100644 index 00000000000..3b7645aeda6 --- /dev/null +++ b/frameworks/Scala/kyo-scheduler/kyo-scheduler.dockerfile @@ -0,0 +1,10 @@ +FROM sbtscala/scala-sbt:eclipse-temurin-21.0.6_7_1.10.11_3.6.4 + +WORKDIR /kyo-scheduler-benchmark +COPY zio-http zio-http +COPY project project +COPY build.sbt build.sbt +RUN sbt zio-http/assembly + +EXPOSE 8080 +CMD ["java", "-Xms2G", "-Xmx2G", "-server", "-Dio.netty.leakDetection.level=disabled", "-Dio.netty.recycler.maxCapacityPerThread=0", "-jar", "/kyo-scheduler-benchmark/zio-http/target/scala-3.6.4/zio-http-kyo-scheduler-benchmark-assembly-1.0.0.jar"] \ No newline at end of file diff --git a/frameworks/Scala/kyo-scheduler/project/build.properties b/frameworks/Scala/kyo-scheduler/project/build.properties new file mode 100644 index 00000000000..0882e8a3906 --- /dev/null +++ b/frameworks/Scala/kyo-scheduler/project/build.properties @@ -0,0 +1 @@ +sbt.version = 1.10.7 \ No newline at end of file diff --git a/frameworks/Scala/kyo-scheduler/project/plugins.sbt b/frameworks/Scala/kyo-scheduler/project/plugins.sbt new file mode 100644 index 00000000000..5bd83c79d15 --- /dev/null +++ b/frameworks/Scala/kyo-scheduler/project/plugins.sbt @@ -0,0 +1,2 @@ +addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "2.3.1") +addSbtPlugin("com.typesafe.play" % "sbt-twirl" % "1.6.1") \ No newline at end of file diff --git a/frameworks/Scala/kyo-scheduler/zio-http/src/main/scala/Payload.scala b/frameworks/Scala/kyo-scheduler/zio-http/src/main/scala/Payload.scala new file mode 100644 index 00000000000..4806bf3380d --- /dev/null +++ b/frameworks/Scala/kyo-scheduler/zio-http/src/main/scala/Payload.scala @@ -0,0 +1,6 @@ +import zio.json.{DeriveJsonCodec, JsonCodec} + +case class Payload(message: String) +object Payload { + given JsonCodec[Payload] = DeriveJsonCodec.gen +} diff --git a/frameworks/Scala/kyo-scheduler/zio-http/src/main/scala/ZioHttp.scala b/frameworks/Scala/kyo-scheduler/zio-http/src/main/scala/ZioHttp.scala new file mode 100644 index 00000000000..448fd878f56 --- /dev/null +++ b/frameworks/Scala/kyo-scheduler/zio-http/src/main/scala/ZioHttp.scala @@ -0,0 +1,45 @@ +import zio._ +import zio.http._ +import zio.http.netty.NettyConfig +import zio.http.netty.NettyConfig.LeakDetectionLevel +import zio.json.* + +import java.lang.{Runtime => JRuntime} + +// based on the framework/Scala/zio-http implementation +object ZioHttp extends kyo.KyoSchedulerZIOAppDefault { + + private val plainTextMessage: String = "hello, world!" + + private val STATIC_SERVER_NAME = "zio-http" + private val NUM_PROCESSORS = JRuntime.getRuntime.availableProcessors() + + val app: Routes[Any, Response] = Routes( + Method.GET / "/plaintext" -> + Handler.fromResponse( + Response + .text(plainTextMessage) + .addHeader(Header.Server(STATIC_SERVER_NAME)), + ), + Method.GET / "/json" -> + Handler.fromResponse( + Response + .json(Payload(plainTextMessage).toJson) + .addHeader(Header.Server(STATIC_SERVER_NAME)), + ), + ) + + private val config = Server.Config.default + .port(8080) + .enableRequestStreaming + + private val nettyConfig = NettyConfig.default + .leakDetection(LeakDetectionLevel.DISABLED) + .maxThreads(NUM_PROCESSORS) + + private val configLayer = ZLayer.succeed(config) + private val nettyConfigLayer = ZLayer.succeed(nettyConfig) + + val run: UIO[ExitCode] = + Server.serve(app).provide(configLayer, nettyConfigLayer, Server.customized).exitCode +} \ No newline at end of file diff --git a/frameworks/Scala/otavia/.mill-version b/frameworks/Scala/otavia/.mill-version new file mode 100644 index 00000000000..f5f40dc335b --- /dev/null +++ b/frameworks/Scala/otavia/.mill-version @@ -0,0 +1 @@ +0.12.10 \ No newline at end of file diff --git a/frameworks/Scala/otavia/.scalafmt.conf b/frameworks/Scala/otavia/.scalafmt.conf new file mode 100644 index 00000000000..ff856188419 --- /dev/null +++ b/frameworks/Scala/otavia/.scalafmt.conf @@ -0,0 +1,16 @@ +version = "3.5.3" + +runner.dialect = scala3 +maxColumn = 120 +docstrings.blankFirstLine = no +docstrings.style = AsteriskSpace +docstrings.removeEmpty = true +docstrings.oneline = fold +docstrings.wrap = yes +docstrings.wrapMaxColumn = 120 +docstrings.forceBlankLineBefore = true +align.preset = more + +indent.main = 4 + +newlines.topLevelBodyIfMinStatements = [before,after] \ No newline at end of file diff --git a/frameworks/Scala/otavia/README.md b/frameworks/Scala/otavia/README.md new file mode 100644 index 00000000000..0ea11222811 --- /dev/null +++ b/frameworks/Scala/otavia/README.md @@ -0,0 +1,13 @@ +## Introduction + +[GitHub - otavia-projects/otavia : Your shiny new IO & Actor programming model!](https://github.com/otavia-projects/otavia) + +`otavia` is an IO and Actor programming model power by Scala 3, it provides a toolkit to make writing high-performance +concurrent programs more easily. + +You can get a quick overview of the basic usage and core design of `otavia` in the following documentation: + +- [Quick Start](https://github.com/otavia-projects/otavia/blob/main/docs/_docs/quick_start.md) +- [Core Concepts and Design](https://github.com/otavia-projects/otavia/blob/main/docs/_docs/core_concept.md) + +More document can be found at [website](https://otavia.cc/home.html) \ No newline at end of file diff --git a/frameworks/Scala/otavia/benchmark/src/app/controller/DBController.scala b/frameworks/Scala/otavia/benchmark/src/app/controller/DBController.scala new file mode 100644 index 00000000000..2e9e32abbe7 --- /dev/null +++ b/frameworks/Scala/otavia/benchmark/src/app/controller/DBController.scala @@ -0,0 +1,103 @@ +package app.controller + +import app.controller.DBController.* +import app.model.World +import cc.otavia.core.actor.{MessageOf, StateActor} +import cc.otavia.core.address.Address +import cc.otavia.core.message.{Ask, Reply} +import cc.otavia.core.stack.helper.{FutureState, FuturesState, StartState} +import cc.otavia.core.stack.{AskStack, StackState, StackYield} +import cc.otavia.http.server.{HttpRequest, HttpResponse} +import cc.otavia.sql.Connection +import cc.otavia.sql.statement.{ModifyRows, PrepareQuery} + +import java.util.SplittableRandom + +class DBController extends StateActor[REQ] { + + private var connection: Address[MessageOf[Connection]] = _ + + private val random = new SplittableRandom() + + override protected def afterMount(): Unit = connection = autowire[Connection]() + + override protected def resumeAsk(stack: AskStack[REQ & Ask[? <: Reply]]): StackYield = + stack.ask match + case _: SingleQueryRequest => handleSingleQuery(stack.asInstanceOf[AskStack[SingleQueryRequest]]) + case _: MultipleQueryRequest => handleMultipleQuery(stack.asInstanceOf[AskStack[MultipleQueryRequest]]) + case _: UpdateRequest => handleUpdateQuery(stack.asInstanceOf[AskStack[UpdateRequest]]) + + // Test 2: Single database query + private def handleSingleQuery(stack: AskStack[SingleQueryRequest]): StackYield = { + stack.state match + case _: StartState => + val state = FutureState[World]() + connection.ask(PrepareQuery.fetchOne[World](SELECT_WORLD, randomWorld()), state.future) + stack.suspend(state) + case state: FutureState[World] => + stack.`return`(state.future.getNow) + } + + // Test 3: Multiple database queries + private def handleMultipleQuery(stack: AskStack[MultipleQueryRequest]): StackYield = { + stack.state match + case _: StartState => + stack.suspend(selectWorlds(normalizeQueries(stack.ask.params))) + case state: FuturesState[World] => + val response = HttpResponse.builder.setContent(state.futures.map(_.getNow)).build() + stack.`return`(response) + } + + // Test 5: Database updates + private def handleUpdateQuery(stack: AskStack[UpdateRequest]): StackYield = { + stack.state match + case _: StartState => + stack.suspend(selectWorlds(normalizeQueries(stack.ask.params))) + case state: FuturesState[World] => + val worlds = state.futures.map(_.getNow) + stack.attach(worlds) + val newState = FutureState[ModifyRows]() + val newWorlds = worlds.sortBy(_.id).map(_.copy(randomNumber = randomWorld())) + connection.ask(PrepareQuery.updateBatch(UPDATE_WORLD, newWorlds), newState.future) + stack.suspend(newState) + case state: FutureState[ModifyRows] => + if (state.future.isFailed) state.future.causeUnsafe.printStackTrace() + val response = HttpResponse.builder.setContent(stack.attach[Seq[World]]).build() + stack.`return`(response) + } + + private def selectWorlds(queries: Int): StackState = { + val state = FuturesState[World](queries) + for (future <- state.futures) + connection.ask(PrepareQuery.fetchOne[World](SELECT_WORLD, randomWorld()), future) + state + } + + private def randomWorld(): Int = 1 + random.nextInt(10000) + + private def normalizeQueries(params: Map[String, String]): Int = { + params.get("queries") match + case Some(value) => + try { + val queries = value.toInt + if (queries < 1) 1 else if (queries > 500) 500 else queries + } catch { + case e: Throwable => 1 + } + case None => 1 + } + +} + +object DBController { + + type REQ = SingleQueryRequest | MultipleQueryRequest | UpdateRequest + + class SingleQueryRequest extends HttpRequest[Nothing, World] + class MultipleQueryRequest extends HttpRequest[Nothing, HttpResponse[Seq[World]]] + class UpdateRequest extends HttpRequest[Nothing, HttpResponse[Seq[World]]] + + private val SELECT_WORLD = "SELECT id, randomnumber from WORLD where id=$1" + private val UPDATE_WORLD = "update world set randomnumber=$2 where id=$1" + +} diff --git a/frameworks/Scala/otavia/benchmark/src/app/controller/FortuneController.scala b/frameworks/Scala/otavia/benchmark/src/app/controller/FortuneController.scala new file mode 100644 index 00000000000..4f7fe7bf800 --- /dev/null +++ b/frameworks/Scala/otavia/benchmark/src/app/controller/FortuneController.scala @@ -0,0 +1,51 @@ +package app.controller + +import app.controller.FortuneController.* +import app.model.Fortune +import cc.otavia.core.actor.{MessageOf, StateActor} +import cc.otavia.core.address.Address +import cc.otavia.core.stack.helper.{FutureState, StartState} +import cc.otavia.core.stack.{AskStack, StackState, StackYield} +import cc.otavia.http.server.{HttpRequest, HttpResponse} +import cc.otavia.sql.statement.PrepareQuery +import cc.otavia.sql.{Connection, RowSet} + +import java.util +import java.util.Comparator + +class FortuneController extends StateActor[FortuneRequest] { + + private var connection: Address[MessageOf[Connection]] = _ + private val tmpArray: Array[Fortune] = new Array[Fortune](13) + + private val comparator = new Comparator[Fortune] { + override def compare(o1: Fortune, o2: Fortune): Int = o1.message.compareTo(o2.message) + } + + override protected def afterMount(): Unit = connection = autowire[Connection]() + + // Test 4: Fortunes + override protected def resumeAsk(stack: AskStack[FortuneRequest]): StackYield = { + stack.state match + case _: StartState => + val state = FutureState[RowSet[Fortune]]() + connection.ask(PrepareQuery.fetchAll[Fortune](SELECT_FORTUNE), state.future) + stack.suspend(state) + case state: FutureState[RowSet[Fortune]] => + System.arraycopy(state.future.getNow.rows, 0, tmpArray, 0, 12) + tmpArray(12) = Fortune(0, "Additional fortune added at request time.") + util.Arrays.sort(tmpArray, comparator) + val fortunes = tmpArray.clone() + val response = HttpResponse.builder.setContent(fortunes).build() + stack.`return`(response) + } + +} + +object FortuneController { + + class FortuneRequest extends HttpRequest[Nothing, HttpResponse[Array[Fortune]]] + + private val SELECT_FORTUNE = "SELECT id, message from FORTUNE" + +} diff --git a/frameworks/Scala/otavia/benchmark/src/app/controller/JsonController.scala b/frameworks/Scala/otavia/benchmark/src/app/controller/JsonController.scala new file mode 100644 index 00000000000..4d7cf7c9dd9 --- /dev/null +++ b/frameworks/Scala/otavia/benchmark/src/app/controller/JsonController.scala @@ -0,0 +1,17 @@ +package app.controller + +import app.controller.JsonController.JsonRequest +import app.model.Message +import cc.otavia.core.actor.StateActor +import cc.otavia.http.server.{HttpRequest, HttpResponse} +import cc.otavia.core.stack.{AskStack, StackYield} + +class JsonController extends StateActor[JsonRequest] { + override protected def resumeAsk(stack: AskStack[JsonRequest]): StackYield = { + stack.`return`(HttpResponse.builder.setContent(Message("Hello, World!")).build()) + } +} +object JsonController { + object JsonRequest extends HttpRequest[Nothing, HttpResponse[Message]] + type JsonRequest = JsonRequest.type +} \ No newline at end of file diff --git a/frameworks/Scala/otavia/benchmark/src/app/model/Fortune.scala b/frameworks/Scala/otavia/benchmark/src/app/model/Fortune.scala new file mode 100644 index 00000000000..1df592954a4 --- /dev/null +++ b/frameworks/Scala/otavia/benchmark/src/app/model/Fortune.scala @@ -0,0 +1,7 @@ +package app.model + +import cc.otavia.json.JsonSerde +import cc.otavia.sql.{Row, RowCodec} + +/** The model for the "fortune" database table. */ +case class Fortune(id: Int, message: String) extends Row derives RowCodec, JsonSerde diff --git a/frameworks/Scala/otavia/benchmark/src/app/model/Message.scala b/frameworks/Scala/otavia/benchmark/src/app/model/Message.scala new file mode 100644 index 00000000000..a0d389090ae --- /dev/null +++ b/frameworks/Scala/otavia/benchmark/src/app/model/Message.scala @@ -0,0 +1,5 @@ +package app.model + +import cc.otavia.json.JsonSerde + +case class Message(message: String) derives JsonSerde diff --git a/frameworks/Scala/otavia/benchmark/src/app/model/World.scala b/frameworks/Scala/otavia/benchmark/src/app/model/World.scala new file mode 100644 index 00000000000..af6f8539d74 --- /dev/null +++ b/frameworks/Scala/otavia/benchmark/src/app/model/World.scala @@ -0,0 +1,8 @@ +package app.model + +import cc.otavia.json.JsonSerde +import cc.otavia.serde.annotation.rename +import cc.otavia.sql.{Row, RowCodec} + +/** The model for the "world" database table. */ +case class World(id: Int, randomNumber: Int) extends Row derives RowCodec, JsonSerde diff --git a/frameworks/Scala/otavia/benchmark/src/app/startup.scala b/frameworks/Scala/otavia/benchmark/src/app/startup.scala new file mode 100644 index 00000000000..8b81bbf8ad7 --- /dev/null +++ b/frameworks/Scala/otavia/benchmark/src/app/startup.scala @@ -0,0 +1,73 @@ +package app + +import app.controller.DBController.* +import app.controller.FortuneController.* +import app.controller.* +import app.model.* +import app.util.FortunesRender +import cc.otavia.core.actor.ChannelsActor.{Bind, ChannelEstablished} +import cc.otavia.core.actor.MainActor +import cc.otavia.core.slf4a.LoggerFactory +import cc.otavia.core.stack.helper.{FutureState, StartState} +import cc.otavia.core.stack.{NoticeStack, StackYield} +import cc.otavia.core.system.ActorSystem +import cc.otavia.http.HttpMethod.* +import cc.otavia.http.MediaType +import cc.otavia.http.MediaType.* +import cc.otavia.http.server.* +import cc.otavia.http.server.Router.* +import cc.otavia.json.JsonSerde +import cc.otavia.serde.helper.BytesSerde +import cc.otavia.sql.Connection + +import java.io.File +import java.nio.charset.StandardCharsets.UTF_8 +import java.nio.file.Path + +private class ServerMain(val port: Int = 8080) extends MainActor(Array.empty) { + + override def main0(stack: NoticeStack[MainActor.Args]): StackYield = stack.state match + case _: StartState => + val messageResponseSerde = HttpResponseSerde.json(summon[JsonSerde[Message]]) + val worldResponseSerde = HttpResponseSerde.json(summon[JsonSerde[World]]) + val worldsResponseSerde = HttpResponseSerde.json(JsonSerde.derived[Seq[World]]) + val fortunesResponseSerde = HttpResponseSerde(new FortunesRender(), MediaType.TEXT_HTML_UTF8) + + val dbController = autowire[DBController]() + val fortuneController = autowire[FortuneController]() + val jsonController = autowire[JsonController]() + + val routers = Seq( + // Test 6: plaintext + constant[Array[Byte]](GET, "/plaintext", "Hello, World!".getBytes(UTF_8), BytesSerde, TEXT_PLAIN_UTF8), + // Test 1: JSON serialization + get("/json", jsonController, () => JsonController.JsonRequest, messageResponseSerde), + // Test 2: Single database query. + get("/db", dbController, () => new SingleQueryRequest(), worldResponseSerde), + // Test 3: Multiple database queries + get("/queries", dbController, () => new MultipleQueryRequest(), worldsResponseSerde), + // Test 5: Database updates + get("/updates", dbController, () => new UpdateRequest(), worldsResponseSerde), + // Test 4: Fortunes + get("/fortunes", fortuneController, () => new FortuneRequest(), fortunesResponseSerde) + ) + val server = system.buildActor(() => new HttpServer(system.actorWorkerSize, routers)) + val state = FutureState[ChannelEstablished]() + server.ask(Bind(port), state.future) + stack.suspend(state) + case state: FutureState[ChannelEstablished] => + if (state.future.isFailed) state.future.causeUnsafe.printStackTrace() + logger.info(s"http server bind port $port success") + stack.`return`() + +} + +@main def startup(url: String, user: String, password: String, poolSize: Int): Unit = + val system = ActorSystem() + val logger = LoggerFactory.getLogger("startup", system) + logger.info("starting http server") + system.buildActor(() => new Connection(url, user, password), global = true, num = poolSize) + system.buildActor(() => new DBController(), global = true, num = system.actorWorkerSize) + system.buildActor(() => new FortuneController(), global = true, num = system.actorWorkerSize) + system.buildActor(() => new JsonController(), global = true, num = system.actorWorkerSize) + system.buildActor(() => new ServerMain()) diff --git a/frameworks/Scala/otavia/benchmark/src/app/util/FortunesRender.scala b/frameworks/Scala/otavia/benchmark/src/app/util/FortunesRender.scala new file mode 100644 index 00000000000..69401305550 --- /dev/null +++ b/frameworks/Scala/otavia/benchmark/src/app/util/FortunesRender.scala @@ -0,0 +1,64 @@ +package app.util + +import app.model.Fortune +import cc.otavia.buffer.{Buffer, BufferUtils} +import cc.otavia.serde.Serde + +import java.nio.charset.StandardCharsets +import scala.annotation.switch + +class FortunesRender extends Serde[Array[Fortune]] { + + private val text1 = + "Fortunes" + .getBytes(StandardCharsets.UTF_8) + + private val text2 = "".getBytes(StandardCharsets.UTF_8) + + private val text5 = "
idmessage
".getBytes(StandardCharsets.UTF_8) + + private val text3 = "".getBytes(StandardCharsets.UTF_8) + + private val text4 = "
".getBytes(StandardCharsets.UTF_8) + + private val lt = "<".getBytes() + private val gt = ">".getBytes() + private val quot = """.getBytes() + private val squot = "'".getBytes() + private val amp = "&".getBytes() + + override def serialize(fortunes: Array[Fortune], out: Buffer): Unit = { + out.writeBytes(text1) + for (fortune <- fortunes) { + out.writeBytes(text2) + BufferUtils.writeIntAsString(out, fortune.id) + out.writeBytes(text3) + writeEscapeMessage(out, fortune.message) + out.writeBytes(text4) + } + out.writeBytes(text5) + } + + override def deserialize(in: Buffer): Array[Fortune] = throw new UnsupportedOperationException() + + private def writeEscapeMessage(buffer: Buffer, message: String): Unit = { + var i = 0 + while (i < message.length) { + val ch = message.charAt(i) + writeChar(buffer, ch) + i += 1 + } + } + + private def writeChar(buffer: Buffer, ch: Char): Unit = (ch: @switch) match + case '<' => buffer.writeBytes(lt) + case '>' => buffer.writeBytes(gt) + case '"' => buffer.writeBytes(quot) + case '\'' => buffer.writeBytes(squot) + case '&' => buffer.writeBytes(amp) + case _ => + if (ch < 0x80) buffer.writeByte(ch.toByte) + else if (ch < 0x800) buffer.writeShortLE((ch >> 6 | (ch << 8 & 0x3f00) | 0x80c0).toShort) + else buffer.writeMediumLE(ch >> 12 | (ch << 2 & 0x3f00) | (ch << 16 & 0x3f0000) | 0x8080e0) + +} diff --git a/frameworks/Scala/otavia/benchmark_config.json b/frameworks/Scala/otavia/benchmark_config.json new file mode 100644 index 00000000000..53182b73c51 --- /dev/null +++ b/frameworks/Scala/otavia/benchmark_config.json @@ -0,0 +1,53 @@ +{ + "framework": "otavia", + "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": "Micro", + "database": "Postgres", + "framework": "otavia", + "language": "Scala", + "flavor": "None", + "orm": "Micro", + "platform": "Otavia", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "otavia (poolSize = 56)", + "notes": "", + "versus": "Otavia" + }, + "overshoot": { + "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": "Micro", + "database": "Postgres", + "framework": "otavia", + "language": "Scala", + "flavor": "None", + "orm": "Micro", + "platform": "Otavia", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "otavia (poolSize = 64)", + "notes": "", + "versus": "Otavia" + } + } + ] +} diff --git a/frameworks/Scala/otavia/build.sc b/frameworks/Scala/otavia/build.sc new file mode 100644 index 00000000000..c400dba3ec3 --- /dev/null +++ b/frameworks/Scala/otavia/build.sc @@ -0,0 +1,15 @@ +import mill._ +import mill.scalalib._ + +def otaviaVersion = "0.4.5" + +object benchmark extends ScalaModule { + + override def scalaVersion = "3.3.4" + + override def ivyDeps = Agg( + ivy"cc.otavia::otavia-codec-http:$otaviaVersion", + ivy"cc.otavia::otavia-postgres-driver:$otaviaVersion" + ) + +} diff --git a/frameworks/Scala/otavia/config.toml b/frameworks/Scala/otavia/config.toml new file mode 100644 index 00000000000..3a8b7f85e94 --- /dev/null +++ b/frameworks/Scala/otavia/config.toml @@ -0,0 +1,36 @@ +[framework] +name = "otavia" + +[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 = "Micro" +platform = "Otavia" +webserver = "None" +versus = "Otavia" + +[overshoot] +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 = "Micro" +platform = "Otavia" +webserver = "None" +versus = "Otavia" \ No newline at end of file diff --git a/frameworks/Scala/otavia/millw b/frameworks/Scala/otavia/millw new file mode 100644 index 00000000000..73bb4d0e4a0 --- /dev/null +++ b/frameworks/Scala/otavia/millw @@ -0,0 +1,194 @@ +#!/usr/bin/env sh + +# This is a wrapper script, that automatically download mill from GitHub release pages +# You can give the required mill version with --mill-version parameter +# If no version is given, it falls back to the value of DEFAULT_MILL_VERSION +# +# Project page: https://github.com/lefou/millw +# Script Version: 0.4.6 +# +# If you want to improve this script, please also contribute your changes back! +# +# Licensed under the Apache License, Version 2.0 + +set -e + +if [ -z "${DEFAULT_MILL_VERSION}" ] ; then + DEFAULT_MILL_VERSION="0.10.10" +fi + + +if [ -z "${GITHUB_RELEASE_CDN}" ] ; then + GITHUB_RELEASE_CDN="" +fi + + +MILL_REPO_URL="https://github.com/com-lihaoyi/mill" + +if [ -z "${CURL_CMD}" ] ; then + CURL_CMD=curl +fi + +# Explicit commandline argument takes precedence over all other methods +if [ "$1" = "--mill-version" ] ; then + shift + if [ "x$1" != "x" ] ; then + MILL_VERSION="$1" + shift + else + echo "You specified --mill-version without a version." 1>&2 + echo "Please provide a version that matches one provided on" 1>&2 + echo "${MILL_REPO_URL}/releases" 1>&2 + false + fi +fi + +# Please note, that if a MILL_VERSION is already set in the environment, +# We reuse it's value and skip searching for a value. + +# If not already set, read .mill-version file +if [ -z "${MILL_VERSION}" ] ; then + if [ -f ".mill-version" ] ; then + MILL_VERSION="$(head -n 1 .mill-version 2> /dev/null)" + elif [ -f ".config/mill-version" ] ; then + MILL_VERSION="$(head -n 1 .config/mill-version 2> /dev/null)" + fi +fi + +if [ -n "${XDG_CACHE_HOME}" ] ; then + MILL_DOWNLOAD_PATH="${XDG_CACHE_HOME}/mill/download" +else + MILL_DOWNLOAD_PATH="${HOME}/.cache/mill/download" +fi + +# If not already set, try to fetch newest from Github +if [ -z "${MILL_VERSION}" ] ; then + # TODO: try to load latest version from release page + echo "No mill version specified." 1>&2 + echo "You should provide a version via '.mill-version' file or --mill-version option." 1>&2 + + mkdir -p "${MILL_DOWNLOAD_PATH}" + LANG=C touch -d '1 hour ago' "${MILL_DOWNLOAD_PATH}/.expire_latest" 2>/dev/null || ( + # we might be on OSX or BSD which don't have -d option for touch + # but probably a -A [-][[hh]mm]SS + touch "${MILL_DOWNLOAD_PATH}/.expire_latest"; touch -A -010000 "${MILL_DOWNLOAD_PATH}/.expire_latest" + ) || ( + # in case we still failed, we retry the first touch command with the intention + # to show the (previously suppressed) error message + LANG=C touch -d '1 hour ago' "${MILL_DOWNLOAD_PATH}/.expire_latest" + ) + + # POSIX shell variant of bash's -nt operator, see https://unix.stackexchange.com/a/449744/6993 + # if [ "${MILL_DOWNLOAD_PATH}/.latest" -nt "${MILL_DOWNLOAD_PATH}/.expire_latest" ] ; then + if [ -n "$(find -L "${MILL_DOWNLOAD_PATH}/.latest" -prune -newer "${MILL_DOWNLOAD_PATH}/.expire_latest")" ]; then + # we know a current latest version + MILL_VERSION=$(head -n 1 "${MILL_DOWNLOAD_PATH}"/.latest 2> /dev/null) + fi + + if [ -z "${MILL_VERSION}" ] ; then + # we don't know a current latest version + echo "Retrieving latest mill version ..." 1>&2 + LANG=C ${CURL_CMD} -s -i -f -I ${MILL_REPO_URL}/releases/latest 2> /dev/null | grep --ignore-case Location: | sed s'/^.*tag\///' | tr -d '\r\n' > "${MILL_DOWNLOAD_PATH}/.latest" + MILL_VERSION=$(head -n 1 "${MILL_DOWNLOAD_PATH}"/.latest 2> /dev/null) + fi + + if [ -z "${MILL_VERSION}" ] ; then + # Last resort + MILL_VERSION="${DEFAULT_MILL_VERSION}" + echo "Falling back to hardcoded mill version ${MILL_VERSION}" 1>&2 + else + echo "Using mill version ${MILL_VERSION}" 1>&2 + fi +fi + +MILL="${MILL_DOWNLOAD_PATH}/${MILL_VERSION}" + +try_to_use_system_mill() { + MILL_IN_PATH="$(command -v mill || true)" + + if [ -z "${MILL_IN_PATH}" ]; then + return + fi + + UNIVERSAL_SCRIPT_MAGIC="@ 2>/dev/null # 2>nul & echo off & goto BOF" + + if ! head -c 128 "${MILL_IN_PATH}" | grep -qF "${UNIVERSAL_SCRIPT_MAGIC}"; then + if [ -n "${MILLW_VERBOSE}" ]; then + echo "Could not determine mill version of ${MILL_IN_PATH}, as it does not start with the universal script magic2" 1>&2 + fi + return + fi + + # Roughly the size of the universal script. + MILL_VERSION_SEARCH_RANGE="2403" + MILL_IN_PATH_VERSION=$(head -c "${MILL_VERSION_SEARCH_RANGE}" "${MILL_IN_PATH}" |\ + sed -n 's/^.*-DMILL_VERSION=\([^\s]*\) .*$/\1/p' |\ + head -n 1) + + if [ -z "${MILL_IN_PATH_VERSION}" ]; then + echo "Could not determine mill version, even though ${MILL_IN_PATH} has the universal script magic" 1>&2 + return + fi + + if [ "${MILL_IN_PATH_VERSION}" = "${MILL_VERSION}" ]; then + MILL="${MILL_IN_PATH}" + fi +} +try_to_use_system_mill + +# If not already downloaded, download it +if [ ! -s "${MILL}" ] ; then + + # support old non-XDG download dir + MILL_OLD_DOWNLOAD_PATH="${HOME}/.mill/download" + OLD_MILL="${MILL_OLD_DOWNLOAD_PATH}/${MILL_VERSION}" + if [ -x "${OLD_MILL}" ] ; then + MILL="${OLD_MILL}" + else + VERSION_PREFIX="$(echo $MILL_VERSION | cut -b -4)" + case $VERSION_PREFIX in + 0.0. | 0.1. | 0.2. | 0.3. | 0.4. ) + DOWNLOAD_SUFFIX="" + ;; + *) + DOWNLOAD_SUFFIX="-assembly" + ;; + esac + unset VERSION_PREFIX + + DOWNLOAD_FILE=$(mktemp mill.XXXXXX) + MILL_VERSION_TAG=$(echo $MILL_VERSION | sed -E 's/([^-]+)(-M[0-9]+)?(-.*)?/\1\2/') + DOWNLOAD_URL="${GITHUB_RELEASE_CDN}${MILL_REPO_URL}/releases/download/${MILL_VERSION_TAG}/${MILL_VERSION}${DOWNLOAD_SUFFIX}" + # TODO: handle command not found + echo "Downloading mill ${MILL_VERSION} from ${DOWNLOAD_URL} ..." 1>&2 + ${CURL_CMD} -f -L -o "${DOWNLOAD_FILE}" ${DOWNLOAD_URL} + chmod +x "${DOWNLOAD_FILE}" + mkdir -p "${MILL_DOWNLOAD_PATH}" + mv "${DOWNLOAD_FILE}" "${MILL}" + + unset DOWNLOAD_FILE + unset DOWNLOAD_SUFFIX + fi +fi + +if [ -z "$MILL_MAIN_CLI" ] ; then + MILL_MAIN_CLI="${0}" +fi + +MILL_FIRST_ARG="" +if [ "$1" = "--bsp" ] || [ "$1" = "-i" ] || [ "$1" = "--interactive" ] || [ "$1" = "--no-server" ] || [ "$1" = "--repl" ] || [ "$1" = "--help" ] ; then + # Need to preserve the first position of those listed options + MILL_FIRST_ARG=$1 + shift +fi + +unset MILL_DOWNLOAD_PATH +unset MILL_OLD_DOWNLOAD_PATH +unset OLD_MILL +unset MILL_VERSION +unset MILL_VERSION_TAG +unset MILL_REPO_URL + +# We don't quote MILL_FIRST_ARG on purpose, so we can expand the empty value without quotes +# shellcheck disable=SC2086 +exec "${MILL}" $MILL_FIRST_ARG -D "mill.main.cli=${MILL_MAIN_CLI}" "$@" diff --git a/frameworks/Scala/otavia/millw.bat b/frameworks/Scala/otavia/millw.bat new file mode 100644 index 00000000000..6359e35e500 --- /dev/null +++ b/frameworks/Scala/otavia/millw.bat @@ -0,0 +1,173 @@ +@echo off + +rem This is a wrapper script, that automatically download mill from GitHub release pages +rem You can give the required mill version with --mill-version parameter +rem If no version is given, it falls back to the value of DEFAULT_MILL_VERSION +rem +rem Project page: https://github.com/lefou/millw +rem Script Version: 0.4.6 +rem +rem If you want to improve this script, please also contribute your changes back! +rem +rem Licensed under the Apache License, Version 2.0 + +rem setlocal seems to be unavailable on Windows 95/98/ME +rem but I don't think we need to support them in 2019 +setlocal enabledelayedexpansion + +if [!DEFAULT_MILL_VERSION!]==[] ( + set "DEFAULT_MILL_VERSION=0.10.10" +) + +if [!GITHUB_RELEASE_CDN!]==[] ( + set "GITHUB_RELEASE_CDN=" +) + +set "MILL_REPO_URL=https://github.com/com-lihaoyi/mill" + +rem %~1% removes surrounding quotes +if [%~1%]==[--mill-version] ( + if not [%~2%]==[] ( + set MILL_VERSION=%~2% + rem shift command doesn't work within parentheses + set "STRIP_VERSION_PARAMS=true" + ) else ( + echo You specified --mill-version without a version. 1>&2 + echo Please provide a version that matches one provided on 1>&2 + echo %MILL_REPO_URL%/releases 1>&2 + exit /b 1 + ) +) + +if not defined STRIP_VERSION_PARAMS GOTO AfterStripVersionParams +rem strip the: --mill-version {version} +shift +shift +:AfterStripVersionParams + +if [!MILL_VERSION!]==[] ( + if exist .mill-version ( + set /p MILL_VERSION=<.mill-version + ) else ( + if exist .config\mill-version ( + set /p MILL_VERSION=<.config\mill-version + ) + ) +) + +if [!MILL_VERSION!]==[] ( + set MILL_VERSION=%DEFAULT_MILL_VERSION% +) + +set MILL_DOWNLOAD_PATH=%USERPROFILE%\.mill\download + +rem without bat file extension, cmd doesn't seem to be able to run it +set MILL=%MILL_DOWNLOAD_PATH%\!MILL_VERSION!.bat + +if not exist "%MILL%" ( + set VERSION_PREFIX=%MILL_VERSION:~0,4% + set DOWNLOAD_SUFFIX=-assembly + if [!VERSION_PREFIX!]==[0.0.] set DOWNLOAD_SUFFIX= + if [!VERSION_PREFIX!]==[0.1.] set DOWNLOAD_SUFFIX= + if [!VERSION_PREFIX!]==[0.2.] set DOWNLOAD_SUFFIX= + if [!VERSION_PREFIX!]==[0.3.] set DOWNLOAD_SUFFIX= + if [!VERSION_PREFIX!]==[0.4.] set DOWNLOAD_SUFFIX= + set VERSION_PREFIX= + + for /F "delims=- tokens=1" %%A in ("!MILL_VERSION!") do set MILL_VERSION_BASE=%%A + for /F "delims=- tokens=2" %%A in ("!MILL_VERSION!") do set MILL_VERSION_MILESTONE=%%A + set VERSION_MILESTONE_START=!MILL_VERSION_MILESTONE:~0,1! + if [!VERSION_MILESTONE_START!]==[M] ( + set MILL_VERSION_TAG="!MILL_VERSION_BASE!-!MILL_VERSION_MILESTONE!" + ) else ( + set MILL_VERSION_TAG=!MILL_VERSION_BASE! + ) + + rem there seems to be no way to generate a unique temporary file path (on native Windows) + set DOWNLOAD_FILE=%MILL%.tmp + + set DOWNLOAD_URL=!GITHUB_RELEASE_CDN!%MILL_REPO_URL%/releases/download/!MILL_VERSION_TAG!/!MILL_VERSION!!DOWNLOAD_SUFFIX! + + echo Downloading mill %MILL_VERSION% from !DOWNLOAD_URL! ... 1>&2 + + if not exist "%MILL_DOWNLOAD_PATH%" mkdir "%MILL_DOWNLOAD_PATH%" + rem curl is bundled with recent Windows 10 + rem but I don't think we can expect all the users to have it in 2019 + where /Q curl + if %ERRORLEVEL% EQU 0 ( + curl -f -L "!DOWNLOAD_URL!" -o "!DOWNLOAD_FILE!" + ) else ( + rem bitsadmin seems to be available on Windows 7 + rem without /dynamic, github returns 403 + rem bitsadmin is sometimes needlessly slow but it looks better with /priority foreground + bitsadmin /transfer millDownloadJob /dynamic /priority foreground "!DOWNLOAD_URL!" "!DOWNLOAD_FILE!" + ) + if not exist "!DOWNLOAD_FILE!" ( + echo Could not download mill %MILL_VERSION% 1>&2 + exit /b 1 + ) + + move /y "!DOWNLOAD_FILE!" "%MILL%" + + set DOWNLOAD_FILE= + set DOWNLOAD_SUFFIX= +) + +set MILL_DOWNLOAD_PATH= +set MILL_VERSION= +set MILL_REPO_URL= + +if [!MILL_MAIN_CLI!]==[] ( + set "MILL_MAIN_CLI=%0" +) + +rem Need to preserve the first position of those listed options +set MILL_FIRST_ARG= +if [%~1%]==[--bsp] ( + set MILL_FIRST_ARG=%1% +) else ( + if [%~1%]==[-i] ( + set MILL_FIRST_ARG=%1% + ) else ( + if [%~1%]==[--interactive] ( + set MILL_FIRST_ARG=%1% + ) else ( + if [%~1%]==[--no-server] ( + set MILL_FIRST_ARG=%1% + ) else ( + if [%~1%]==[--repl] ( + set MILL_FIRST_ARG=%1% + ) else ( + if [%~1%]==[--help] ( + set MILL_FIRST_ARG=%1% + ) + ) + ) + ) + ) +) + +set "MILL_PARAMS=%*%" + +if not [!MILL_FIRST_ARG!]==[] ( + if defined STRIP_VERSION_PARAMS ( + for /f "tokens=1-3*" %%a in ("%*") do ( + set "MILL_PARAMS=%%d" + ) + ) else ( + for /f "tokens=1*" %%a in ("%*") do ( + set "MILL_PARAMS=%%b" + ) + ) +) else ( + if defined STRIP_VERSION_PARAMS ( + for /f "tokens=1-2*" %%a in ("%*") do ( + rem strip %%a - It's the "--mill-version" option. + rem strip %%b - it's the version number that comes after the option. + rem keep %%c - It's the remaining options. + set "MILL_PARAMS=%%c" + ) + ) +) + +"%MILL%" %MILL_FIRST_ARG% -D "mill.main.cli=%MILL_MAIN_CLI%" %MILL_PARAMS% diff --git a/frameworks/Scala/otavia/otavia-overshoot.dockerfile b/frameworks/Scala/otavia/otavia-overshoot.dockerfile new file mode 100644 index 00000000000..41a86477eea --- /dev/null +++ b/frameworks/Scala/otavia/otavia-overshoot.dockerfile @@ -0,0 +1,18 @@ +FROM nightscape/scala-mill:eclipse-temurin-21.0.6_7-jdk-jammy_0.12.10 +WORKDIR /otavia +COPY benchmark benchmark +COPY build.sc build.sc +COPY .mill-version .mill-version +ENV COURSIER_REPOSITORIES=ivy2Local|central +RUN mill benchmark.assembly + +EXPOSE 8080 + +CMD java -server \ + -Dcc.otavia.actor.worker.size=64 \ + -Dcc.otavia.buffer.page.size=8 \ + -Dio.netty5.noKeySetOptimization=true \ + -jar \ + out/benchmark/assembly.dest/out.jar \ + jdbc:postgresql://tfb-database:5432/hello_world \ + benchmarkdbuser benchmarkdbpass 64 diff --git a/frameworks/Scala/otavia/otavia.dockerfile b/frameworks/Scala/otavia/otavia.dockerfile new file mode 100644 index 00000000000..7aaf65ea0fc --- /dev/null +++ b/frameworks/Scala/otavia/otavia.dockerfile @@ -0,0 +1,18 @@ +FROM nightscape/scala-mill:eclipse-temurin-21.0.6_7-jdk-jammy_0.12.10 +WORKDIR /otavia +COPY benchmark benchmark +COPY build.sc build.sc +COPY .mill-version .mill-version +ENV COURSIER_REPOSITORIES=ivy2Local|central +RUN mill benchmark.assembly + +EXPOSE 8080 + +CMD java -server \ + -Dcc.otavia.actor.worker.size=56 \ + -Dcc.otavia.buffer.page.size=8 \ + -Dio.netty5.noKeySetOptimization=true \ + -jar \ + out/benchmark/assembly.dest/out.jar \ + jdbc:postgresql://tfb-database:5432/hello_world \ + benchmarkdbuser benchmarkdbpass 56 diff --git a/frameworks/Scala/pekko-http/pekko-http.dockerfile b/frameworks/Scala/pekko-http/pekko-http.dockerfile index ffc651aee6a..ec5736799c4 100644 --- a/frameworks/Scala/pekko-http/pekko-http.dockerfile +++ b/frameworks/Scala/pekko-http/pekko-http.dockerfile @@ -1,4 +1,4 @@ -FROM sbtscala/scala-sbt:eclipse-temurin-jammy-17.0.5_8_1.9.3_2.13.11 as build +FROM sbtscala/scala-sbt:eclipse-temurin-21.0.6_7_1.10.11_2.13.16 as build WORKDIR /pekko-http COPY pekko-http ./ @@ -10,7 +10,7 @@ RUN \ sbt sbtVersion RUN sbt clean compile stage -FROM eclipse-temurin:17-jre-jammy +FROM eclipse-temurin:21-jre-noble COPY --from=build /pekko-http/target/universal/stage /pekko-http EXPOSE 9000 diff --git a/frameworks/Scala/pekko-http/pekko-http/build.sbt b/frameworks/Scala/pekko-http/pekko-http/build.sbt index de599af95cf..a61aa84ea90 100644 --- a/frameworks/Scala/pekko-http/pekko-http/build.sbt +++ b/frameworks/Scala/pekko-http/pekko-http/build.sbt @@ -6,7 +6,7 @@ name := "pekko-http-benchmark" version := "0.1.0-SNAPSHOT" -scalaVersion := "2.13.8" +scalaVersion := "2.13.16" val pekkoV = "1.0.1" val pekkoHttpV = "1.0.0" diff --git a/frameworks/Scala/pekko-http/pekko-http/project/build.properties b/frameworks/Scala/pekko-http/pekko-http/project/build.properties index 875b706a8ee..cc68b53f1a3 100644 --- a/frameworks/Scala/pekko-http/pekko-http/project/build.properties +++ b/frameworks/Scala/pekko-http/pekko-http/project/build.properties @@ -1 +1 @@ -sbt.version=1.9.2 +sbt.version=1.10.11 diff --git a/frameworks/Scala/play2-scala/benchmark_config.json b/frameworks/Scala/play2-scala/benchmark_config.json index bdb85c72917..94059dd7adb 100644 --- a/frameworks/Scala/play2-scala/benchmark_config.json +++ b/frameworks/Scala/play2-scala/benchmark_config.json @@ -103,7 +103,7 @@ "query_url": "/queries?queries=", "fortune_url": "/fortunes", "update_url": "/update?queries=", - "tags": ["broken"] + "tags": [] }, "reactivemongo-netty": { "display_name": "play2-scala-reactivemongo-netty", @@ -126,7 +126,7 @@ "query_url": "/queries?queries=", "fortune_url": "/fortunes", "update_url": "/update?queries=", - "tags": ["broken"] + "tags": [] }, "slick": { "display_name": "play2-scala-slick", diff --git a/frameworks/Scala/play2-scala/play2-scala-anorm-netty.dockerfile b/frameworks/Scala/play2-scala/play2-scala-anorm-netty.dockerfile index 8754255862a..e9fcf2cdb1b 100644 --- a/frameworks/Scala/play2-scala/play2-scala-anorm-netty.dockerfile +++ b/frameworks/Scala/play2-scala/play2-scala-anorm-netty.dockerfile @@ -1,4 +1,5 @@ -FROM hseeberger/scala-sbt:8u265_1.3.13_2.13.3 +FROM sbtscala/scala-sbt:eclipse-temurin-21.0.6_7_1.10.11_2.13.16 + WORKDIR /play2 COPY play2-scala-anorm . @@ -8,4 +9,4 @@ RUN sbt stage EXPOSE 9000 -CMD target/universal/stage/bin/play2-scala-anorm -Dplay.server.provider=play.core.server.NettyServerProvider -J-server -J-Xms1g -J-Xmx1g -J-XX:NewSize=512m -J-XX:+UseG1GC -J-XX:MaxGCPauseMillis=30 -J-XX:-UseBiasedLocking -J-XX:+AlwaysPreTouch -Dthread_count=$(nproc) -Dphysical_cpu_count=$(grep ^cpu\\scores /proc/cpuinfo | uniq | awk '{print $4}') -Ddb_pool_size=$(( $(( $(nproc) * 2 )) + 1 )) +CMD target/universal/stage/bin/play2-scala-anorm -Dplay.server.provider=play.core.server.NettyServerProvider -J-server -J-Xms1g -J-Xmx1g -J-XX:NewSize=512m -J-XX:+UseG1GC -J-XX:MaxGCPauseMillis=30 -J-XX:+AlwaysPreTouch -Dthread_count=$(nproc) -Dphysical_cpu_count=$(grep ^cpu\\scores /proc/cpuinfo | uniq | awk '{print $4}') -Ddb_pool_size=$(( $(( $(nproc) * 2 )) + 1 )) diff --git a/frameworks/Scala/play2-scala/play2-scala-anorm.dockerfile b/frameworks/Scala/play2-scala/play2-scala-anorm.dockerfile index f3b7a50007a..4e253519ef0 100644 --- a/frameworks/Scala/play2-scala/play2-scala-anorm.dockerfile +++ b/frameworks/Scala/play2-scala/play2-scala-anorm.dockerfile @@ -1,4 +1,5 @@ -FROM hseeberger/scala-sbt:8u265_1.3.13_2.13.3 +FROM sbtscala/scala-sbt:eclipse-temurin-21.0.6_7_1.10.11_2.13.16 + WORKDIR /play2 COPY play2-scala-anorm . @@ -8,4 +9,4 @@ RUN sbt stage EXPOSE 9000 -CMD target/universal/stage/bin/play2-scala-anorm -Dplay.server.provider=play.core.server.AkkaHttpServerProvider -J-server -J-Xms1g -J-Xmx1g -J-XX:NewSize=512m -J-XX:+UseG1GC -J-XX:MaxGCPauseMillis=30 -J-XX:-UseBiasedLocking -J-XX:+AlwaysPreTouch -Dthread_count=$(nproc) -Dphysical_cpu_count=$(grep ^cpu\\scores /proc/cpuinfo | uniq | awk '{print $4}') -Ddb_pool_size=$(( $(( $(nproc) * 2 )) + 1 )) +CMD target/universal/stage/bin/play2-scala-anorm -Dplay.server.provider=play.core.server.AkkaHttpServerProvider -J-server -J-Xms1g -J-Xmx1g -J-XX:NewSize=512m -J-XX:+UseG1GC -J-XX:MaxGCPauseMillis=30 -J-XX:+AlwaysPreTouch -Dthread_count=$(nproc) -Dphysical_cpu_count=$(grep ^cpu\\scores /proc/cpuinfo | uniq | awk '{print $4}') -Ddb_pool_size=$(( $(( $(nproc) * 2 )) + 1 )) diff --git a/frameworks/Scala/play2-scala/play2-scala-anorm/build.sbt b/frameworks/Scala/play2-scala/play2-scala-anorm/build.sbt index 3fc2bd3e088..47476130918 100644 --- a/frameworks/Scala/play2-scala/play2-scala-anorm/build.sbt +++ b/frameworks/Scala/play2-scala/play2-scala-anorm/build.sbt @@ -4,11 +4,11 @@ version := "1.0-SNAPSHOT" lazy val root = (project in file(".")).enablePlugins(PlayScala, PlayNettyServer).disablePlugins(PlayFilters) -scalaVersion := "2.13.3" +scalaVersion := "2.13.16" libraryDependencies ++= Seq( guice, jdbc, - "org.playframework.anorm" %% "anorm" % "2.6.7", - "mysql" % "mysql-connector-java" % "8.0.21" + "org.playframework.anorm" %% "anorm" % "2.8.1", + "mysql" % "mysql-connector-java" % "8.0.33" ) diff --git a/frameworks/Scala/play2-scala/play2-scala-anorm/conf/application.conf b/frameworks/Scala/play2-scala/play2-scala-anorm/conf/application.conf index 1f856e1aca3..00aed8e0964 100755 --- a/frameworks/Scala/play2-scala/play2-scala-anorm/conf/application.conf +++ b/frameworks/Scala/play2-scala/play2-scala-anorm/conf/application.conf @@ -29,8 +29,8 @@ play.server { option { SO_BACKLOG = 8192 SO_REUSEADDR = true - "io.netty.channel.epoll.EpollChannelOption#SO_REUSEPORT" = true - "io.netty.channel.epoll.EpollChannelOption#TCP_FASTOPEN" = 1 + "io.netty.channel.unix.UnixChannelOption#SO_REUSEPORT" = true + "io.netty.channel.ChannelOption#TCP_FASTOPEN" = 1 child { SO_KEEPALIVE = true @@ -40,7 +40,7 @@ play.server { # The default is 1 since Linux Kernel 3.13 # You can check via "cat /proc/sys/net/ipv4/tcp_fastopen" # However 3 would be better, but we can't change it to that value because we don't have root permission when running the benchmarks - "io.netty.channel.epoll.EpollChannelOption#TCP_FASTOPEN" = 1 + "io.netty.channel.ChannelOption#TCP_FASTOPEN" = 1 } } } diff --git a/frameworks/Scala/play2-scala/play2-scala-anorm/project/build.properties b/frameworks/Scala/play2-scala/play2-scala-anorm/project/build.properties index 0837f7a132d..cc68b53f1a3 100644 --- a/frameworks/Scala/play2-scala/play2-scala-anorm/project/build.properties +++ b/frameworks/Scala/play2-scala/play2-scala-anorm/project/build.properties @@ -1 +1 @@ -sbt.version=1.3.13 +sbt.version=1.10.11 diff --git a/frameworks/Scala/play2-scala/play2-scala-anorm/project/plugins.sbt b/frameworks/Scala/play2-scala/play2-scala-anorm/project/plugins.sbt index 33b55347b00..767dc8b1d7e 100644 --- a/frameworks/Scala/play2-scala/play2-scala-anorm/project/plugins.sbt +++ b/frameworks/Scala/play2-scala/play2-scala-anorm/project/plugins.sbt @@ -1 +1 @@ -addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.8.2") +addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.9.7") diff --git a/frameworks/Scala/play2-scala/play2-scala-netty.dockerfile b/frameworks/Scala/play2-scala/play2-scala-netty.dockerfile index 53a2a86d1f7..d440909019c 100644 --- a/frameworks/Scala/play2-scala/play2-scala-netty.dockerfile +++ b/frameworks/Scala/play2-scala/play2-scala-netty.dockerfile @@ -1,4 +1,4 @@ -FROM hseeberger/scala-sbt:8u242_1.3.8_2.13.1 +FROM sbtscala/scala-sbt:eclipse-temurin-21.0.6_7_1.10.11_2.13.16 WORKDIR /play2 COPY play2-scala . @@ -8,4 +8,4 @@ RUN sbt stage EXPOSE 9000 -CMD target/universal/stage/bin/play2-scala -Dplay.server.provider=play.core.server.NettyServerProvider -J-server -J-Xms1g -J-Xmx1g -J-XX:NewSize=512m -J-XX:+UseG1GC -J-XX:MaxGCPauseMillis=30 -J-XX:-UseBiasedLocking -J-XX:+AlwaysPreTouch -Dthread_count=$(nproc) -Dphysical_cpu_count=$(grep ^cpu\\scores /proc/cpuinfo | uniq | awk '{print $4}') +CMD target/universal/stage/bin/play2-scala -Dplay.server.provider=play.core.server.NettyServerProvider -J-server -J-Xms1g -J-Xmx1g -J-XX:NewSize=512m -J-XX:+UseG1GC -J-XX:MaxGCPauseMillis=30 -J-XX:+AlwaysPreTouch -Dthread_count=$(nproc) -Dphysical_cpu_count=$(grep ^cpu\\scores /proc/cpuinfo | uniq | awk '{print $4}') diff --git a/frameworks/Scala/play2-scala/play2-scala-reactivemongo-netty.dockerfile b/frameworks/Scala/play2-scala/play2-scala-reactivemongo-netty.dockerfile index 9c7ab35b634..011786d9558 100644 --- a/frameworks/Scala/play2-scala/play2-scala-reactivemongo-netty.dockerfile +++ b/frameworks/Scala/play2-scala/play2-scala-reactivemongo-netty.dockerfile @@ -1,4 +1,4 @@ -FROM hseeberger/scala-sbt:8u242_1.3.8_2.13.1 +FROM sbtscala/scala-sbt:eclipse-temurin-21.0.6_7_1.10.11_2.13.16 WORKDIR /play2 COPY play2-scala-reactivemongo . @@ -8,4 +8,4 @@ RUN sbt stage EXPOSE 9000 -CMD target/universal/stage/bin/play2-scala-reactivemongo -Dplay.server.provider=play.core.server.NettyServerProvider -J-server -J-Xms1g -J-Xmx1g -J-XX:NewSize=512m -J-XX:+UseG1GC -J-XX:MaxGCPauseMillis=30 -J-XX:-UseBiasedLocking -J-XX:+AlwaysPreTouch -Dthread_count=$(nproc) -Dphysical_cpu_count=$(grep ^cpu\\scores /proc/cpuinfo | uniq | awk '{print $4}') +CMD target/universal/stage/bin/play2-scala-reactivemongo -Dplay.server.provider=play.core.server.NettyServerProvider -J-server -J-Xms1g -J-Xmx1g -J-XX:NewSize=512m -J-XX:+UseG1GC -J-XX:MaxGCPauseMillis=30 -J-XX:+AlwaysPreTouch -Dthread_count=$(nproc) -Dphysical_cpu_count=$(grep ^cpu\\scores /proc/cpuinfo | uniq | awk '{print $4}') diff --git a/frameworks/Scala/play2-scala/play2-scala-reactivemongo.dockerfile b/frameworks/Scala/play2-scala/play2-scala-reactivemongo.dockerfile index 8d17c376886..1b726b0d1ec 100644 --- a/frameworks/Scala/play2-scala/play2-scala-reactivemongo.dockerfile +++ b/frameworks/Scala/play2-scala/play2-scala-reactivemongo.dockerfile @@ -1,4 +1,4 @@ -FROM hseeberger/scala-sbt:8u242_1.3.8_2.13.1 +FROM sbtscala/scala-sbt:eclipse-temurin-21.0.6_7_1.10.11_2.13.16 WORKDIR /play2 COPY play2-scala-reactivemongo . @@ -8,4 +8,4 @@ RUN sbt stage EXPOSE 9000 -CMD target/universal/stage/bin/play2-scala-reactivemongo -Dplay.server.provider=play.core.server.AkkaHttpServerProvider -J-server -J-Xms1g -J-Xmx1g -J-XX:NewSize=512m -J-XX:+UseG1GC -J-XX:MaxGCPauseMillis=30 -J-XX:-UseBiasedLocking -J-XX:+AlwaysPreTouch -Dthread_count=$(nproc) -Dphysical_cpu_count=$(grep ^cpu\\scores /proc/cpuinfo | uniq | awk '{print $4}') +CMD target/universal/stage/bin/play2-scala-reactivemongo -Dplay.server.provider=play.core.server.AkkaHttpServerProvider -J-server -J-Xms1g -J-Xmx1g -J-XX:NewSize=512m -J-XX:+UseG1GC -J-XX:MaxGCPauseMillis=30 -J-XX:+AlwaysPreTouch -Dthread_count=$(nproc) -Dphysical_cpu_count=$(grep ^cpu\\scores /proc/cpuinfo | uniq | awk '{print $4}') diff --git a/frameworks/Scala/play2-scala/play2-scala-reactivemongo/app/controllers/Application.scala b/frameworks/Scala/play2-scala/play2-scala-reactivemongo/app/controllers/Application.scala index b7151b62568..e76604eef9a 100644 --- a/frameworks/Scala/play2-scala/play2-scala-reactivemongo/app/controllers/Application.scala +++ b/frameworks/Scala/play2-scala/play2-scala-reactivemongo/app/controllers/Application.scala @@ -1,20 +1,21 @@ package controllers -import java.util.concurrent.ThreadLocalRandom - -import scala.concurrent.{ExecutionContext, Future} import play.api.libs.json.{JsObject, JsValue, Json} import play.api.mvc._ -import reactivemongo.api.{Cursor, ReadPreference} -import reactivemongo.play.json.collection.JSONCollection import play.modules.reactivemongo.ReactiveMongoApi -import reactivemongo.play.json._ +import reactivemongo.api.bson.collection.BSONCollection +import reactivemongo.api.{Cursor, ReadPreference} +import reactivemongo.play.json.compat.bson2json._ +import reactivemongo.play.json.compat.json2bson._ + +import java.util.concurrent.ThreadLocalRandom +import scala.concurrent.{ExecutionContext, Future} class Application (val controllerComponents: ControllerComponents, reactiveMongoApi: ReactiveMongoApi)(implicit ec: ExecutionContext) extends BaseController { - private def worldCollection: Future[JSONCollection] = reactiveMongoApi.database.map(_.collection[JSONCollection]("world")) - private def fortuneCollection: Future[JSONCollection] = reactiveMongoApi.database.map(_.collection[JSONCollection]("fortune")) + private def worldCollection: Future[BSONCollection] = reactiveMongoApi.database.map(_.collection[BSONCollection]("world")) + private def fortuneCollection: Future[BSONCollection] = reactiveMongoApi.database.map(_.collection[BSONCollection]("fortune")) private val projection = Json.obj("_id" -> 0) def getRandomWorlds(queries: Int): Future[Seq[Option[JsObject]]] = { @@ -35,7 +36,7 @@ class Application (val controllerComponents: ControllerComponents, reactiveMongo def getFortunes: Future[List[JsObject]] = { fortuneCollection.map(_.find(Json.obj(), Option.empty[JsObject]) - .cursor[JsObject](ReadPreference.primaryPreferred, false).collect[List](Int.MaxValue, (v, t) => Cursor.Fail(t))).flatten + .cursor[JsObject](ReadPreference.primaryPreferred).collect[List](Int.MaxValue, (v, t) => Cursor.Fail(t))).flatten } def updateWorlds(queries: Int): Future[Seq[JsObject]] = { @@ -43,7 +44,7 @@ class Application (val controllerComponents: ControllerComponents, reactiveMongo .map(_.flatten) .map(_.map(oldWorld => { val newWorld = oldWorld ++ Json.obj("randomNumber" -> getNextRandom) - worldCollection.map(_.update(oldWorld, newWorld).map(result => newWorld)).flatten + worldCollection.map(_.update.one(oldWorld, newWorld).map(result => newWorld)).flatten })) .map(Future.sequence(_)) .flatten diff --git a/frameworks/Scala/play2-scala/play2-scala-reactivemongo/build.sbt b/frameworks/Scala/play2-scala/play2-scala-reactivemongo/build.sbt index 484d2038b02..0ea31e4f2c5 100644 --- a/frameworks/Scala/play2-scala/play2-scala-reactivemongo/build.sbt +++ b/frameworks/Scala/play2-scala/play2-scala-reactivemongo/build.sbt @@ -4,11 +4,11 @@ version := "1.0-SNAPSHOT" lazy val root = (project in file(".")).enablePlugins(PlayScala, PlayNettyServer).disablePlugins(PlayFilters) -scalaVersion := "2.13.1" +scalaVersion := "2.13.16" libraryDependencies ++= Seq( - "org.reactivemongo" %% "play2-reactivemongo" % "0.20.3-play28", - "org.reactivemongo" %% "reactivemongo-play-json" % "0.20.3-play28", + "org.reactivemongo" %% "play2-reactivemongo" % "1.1.0-play29.RC15", + "org.reactivemongo" %% "reactivemongo-play-json-compat" % "1.1.0-play29.RC15", "com.softwaremill.macwire" %% "macros" % "2.3.3", "com.softwaremill.macwire" %% "util" % "2.3.3" ) diff --git a/frameworks/Scala/play2-scala/play2-scala-reactivemongo/conf/application.conf b/frameworks/Scala/play2-scala/play2-scala-reactivemongo/conf/application.conf index 56322983166..f2d6222c163 100755 --- a/frameworks/Scala/play2-scala/play2-scala-reactivemongo/conf/application.conf +++ b/frameworks/Scala/play2-scala/play2-scala-reactivemongo/conf/application.conf @@ -25,8 +25,8 @@ play.server { option { SO_BACKLOG = 8192 SO_REUSEADDR = true - "io.netty.channel.epoll.EpollChannelOption#SO_REUSEPORT" = true - "io.netty.channel.epoll.EpollChannelOption#TCP_FASTOPEN" = 1 + "io.netty.channel.unix.UnixChannelOption#SO_REUSEPORT" = true + "io.netty.channel.ChannelOption#TCP_FASTOPEN" = 1 child { SO_KEEPALIVE = true @@ -36,7 +36,7 @@ play.server { # The default is 1 since Linux Kernel 3.13 # You can check via "cat /proc/sys/net/ipv4/tcp_fastopen" # However 3 would be better, but we can't change it to that value because we don't have root permission when running the benchmarks - "io.netty.channel.epoll.EpollChannelOption#TCP_FASTOPEN" = 1 + "io.netty.channel.ChannelOption#TCP_FASTOPEN" = 1 } } } diff --git a/frameworks/Scala/play2-scala/play2-scala-reactivemongo/project/build.properties b/frameworks/Scala/play2-scala/play2-scala-reactivemongo/project/build.properties index a919a9b5f46..cc68b53f1a3 100644 --- a/frameworks/Scala/play2-scala/play2-scala-reactivemongo/project/build.properties +++ b/frameworks/Scala/play2-scala/play2-scala-reactivemongo/project/build.properties @@ -1 +1 @@ -sbt.version=1.3.8 +sbt.version=1.10.11 diff --git a/frameworks/Scala/play2-scala/play2-scala-reactivemongo/project/plugins.sbt b/frameworks/Scala/play2-scala/play2-scala-reactivemongo/project/plugins.sbt index 47b7a413447..767dc8b1d7e 100644 --- a/frameworks/Scala/play2-scala/play2-scala-reactivemongo/project/plugins.sbt +++ b/frameworks/Scala/play2-scala/play2-scala-reactivemongo/project/plugins.sbt @@ -1 +1 @@ -addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.8.1") +addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.9.7") diff --git a/frameworks/Scala/play2-scala/play2-scala-slick-netty.dockerfile b/frameworks/Scala/play2-scala/play2-scala-slick-netty.dockerfile index 6678a3bf7b4..bf4b513c63b 100644 --- a/frameworks/Scala/play2-scala/play2-scala-slick-netty.dockerfile +++ b/frameworks/Scala/play2-scala/play2-scala-slick-netty.dockerfile @@ -1,4 +1,4 @@ -FROM hseeberger/scala-sbt:8u242_1.3.8_2.13.1 +FROM sbtscala/scala-sbt:eclipse-temurin-21.0.6_7_1.10.11_2.13.16 WORKDIR /play2 COPY play2-scala-slick . @@ -8,4 +8,4 @@ RUN sbt stage EXPOSE 9000 -CMD target/universal/stage/bin/play2-scala-slick -Dplay.server.provider=play.core.server.NettyServerProvider -J-server -J-Xms1g -J-Xmx1g -J-XX:NewSize=512m -J-XX:+UseG1GC -J-XX:MaxGCPauseMillis=30 -J-XX:-UseBiasedLocking -J-XX:+AlwaysPreTouch -Dthread_count=$(nproc) -Dphysical_cpu_count=$(grep ^cpu\\scores /proc/cpuinfo | uniq | awk '{print $4}') -Ddb_pool_size=$(( $(( $(nproc) * 2 )) + 1 )) +CMD target/universal/stage/bin/play2-scala-slick -Dplay.server.provider=play.core.server.NettyServerProvider -J-server -J-Xms1g -J-Xmx1g -J-XX:NewSize=512m -J-XX:+UseG1GC -J-XX:MaxGCPauseMillis=30 -J-XX:+AlwaysPreTouch -Dthread_count=$(nproc) -Dphysical_cpu_count=$(grep ^cpu\\scores /proc/cpuinfo | uniq | awk '{print $4}') -Ddb_pool_size=$(( $(( $(nproc) * 2 )) + 1 )) diff --git a/frameworks/Scala/play2-scala/play2-scala-slick.dockerfile b/frameworks/Scala/play2-scala/play2-scala-slick.dockerfile index 50b4a87a59f..b2b45920454 100644 --- a/frameworks/Scala/play2-scala/play2-scala-slick.dockerfile +++ b/frameworks/Scala/play2-scala/play2-scala-slick.dockerfile @@ -1,4 +1,4 @@ -FROM hseeberger/scala-sbt:8u242_1.3.8_2.13.1 +FROM sbtscala/scala-sbt:eclipse-temurin-21.0.6_7_1.10.11_2.13.16 WORKDIR /play2 COPY play2-scala-slick . @@ -8,4 +8,4 @@ RUN sbt stage EXPOSE 9000 -CMD target/universal/stage/bin/play2-scala-slick -Dplay.server.provider=play.core.server.AkkaHttpServerProvider -J-server -J-Xms1g -J-Xmx1g -J-XX:NewSize=512m -J-XX:+UseG1GC -J-XX:MaxGCPauseMillis=30 -J-XX:-UseBiasedLocking -J-XX:+AlwaysPreTouch -Dthread_count=$(nproc) -Dphysical_cpu_count=$(grep ^cpu\\scores /proc/cpuinfo | uniq | awk '{print $4}') -Ddb_pool_size=$(( $(( $(nproc) * 2 )) + 1 )) +CMD target/universal/stage/bin/play2-scala-slick -Dplay.server.provider=play.core.server.AkkaHttpServerProvider -J-server -J-Xms1g -J-Xmx1g -J-XX:NewSize=512m -J-XX:+UseG1GC -J-XX:MaxGCPauseMillis=30 -J-XX:+AlwaysPreTouch -Dthread_count=$(nproc) -Dphysical_cpu_count=$(grep ^cpu\\scores /proc/cpuinfo | uniq | awk '{print $4}') -Ddb_pool_size=$(( $(( $(nproc) * 2 )) + 1 )) diff --git a/frameworks/Scala/play2-scala/play2-scala-slick/app/controllers/Application.scala b/frameworks/Scala/play2-scala/play2-scala-slick/app/controllers/Application.scala index f3f7178a03d..2c128a01228 100644 --- a/frameworks/Scala/play2-scala/play2-scala-slick/app/controllers/Application.scala +++ b/frameworks/Scala/play2-scala/play2-scala-slick/app/controllers/Application.scala @@ -23,15 +23,11 @@ class Application @Inject() (fortunesDAO: FortunesDAO, worldDAO: WorldDAO, val c fortunesDAO.getAll() } - def updateWorlds(n: Int): Future[Seq[World]] = { - val worlds: Seq[Future[World]] = for (_ <- 1 to n) yield { - val futureWorld: Future[World] = worldDAO.findById(getNextRandom) - val futureUpdatedWorld: Future[World] = futureWorld.map(_.copy(randomNumber = getNextRandom)) - futureUpdatedWorld.map(world => worldDAO.updateRandom(world)) - futureUpdatedWorld - } - Future.sequence(worlds) - } + def updateWorlds(n: Int): Future[Seq[World]] = for { + worlds <- getRandomWorlds(n) + updatedWorlds = worlds.map(_.copy(randomNumber = getNextRandom)) + _ <- worldDAO.updateRandom(updatedWorlds) + } yield updatedWorlds def getNextRandom: Int = { ThreadLocalRandom.current().nextInt(TestDatabaseRows) + 1 diff --git a/frameworks/Scala/play2-scala/play2-scala-slick/app/models/World.scala b/frameworks/Scala/play2-scala/play2-scala-slick/app/models/World.scala index 739175109ad..e66f347e468 100644 --- a/frameworks/Scala/play2-scala/play2-scala-slick/app/models/World.scala +++ b/frameworks/Scala/play2-scala/play2-scala-slick/app/models/World.scala @@ -34,8 +34,14 @@ class WorldDAO @Inject()(protected val dbConfigProvider: DatabaseConfigProvider) db.run(Worlds.filter(_.id === id).result.head) } - def updateRandom(world: World) = { - db.run(Worlds.filter(_.id === world.id).map(_.randomNumber).update(world.randomNumber)) + def updateRandom(updatedWorlds: Seq[World]): Future[Seq[Int]] = { + val updateActions = updatedWorlds.map { uw => + Worlds.filter(_.id === uw.id).map(_.randomNumber).update(uw.randomNumber) + } + + val combinedUpdateAction: DBIO[Seq[Int]] = DBIO.sequence(updateActions) + + db.run(combinedUpdateAction) } } diff --git a/frameworks/Scala/play2-scala/play2-scala-slick/build.sbt b/frameworks/Scala/play2-scala/play2-scala-slick/build.sbt index ed63d326af0..21629d238c8 100644 --- a/frameworks/Scala/play2-scala/play2-scala-slick/build.sbt +++ b/frameworks/Scala/play2-scala/play2-scala-slick/build.sbt @@ -4,11 +4,11 @@ version := "1.0-SNAPSHOT" lazy val root = (project in file(".")).enablePlugins(PlayScala, PlayNettyServer).disablePlugins(PlayFilters) -scalaVersion := "2.13.1" +scalaVersion := "2.13.16" libraryDependencies ++= Seq( guice, - "com.typesafe.play" %% "play-slick" % "5.0.0", - "mysql" % "mysql-connector-java" % "8.0.19", + "com.typesafe.play" %% "play-slick" % "5.3.0", + "mysql" % "mysql-connector-java" % "8.0.33", filters ) diff --git a/frameworks/Scala/play2-scala/play2-scala-slick/conf/application.conf b/frameworks/Scala/play2-scala/play2-scala-slick/conf/application.conf index b521fcfa503..c25f8b35fcb 100755 --- a/frameworks/Scala/play2-scala/play2-scala-slick/conf/application.conf +++ b/frameworks/Scala/play2-scala/play2-scala-slick/conf/application.conf @@ -29,8 +29,8 @@ play.server { option { SO_BACKLOG = 8192 SO_REUSEADDR = true - "io.netty.channel.epoll.EpollChannelOption#SO_REUSEPORT" = true - "io.netty.channel.epoll.EpollChannelOption#TCP_FASTOPEN" = 1 + "io.netty.channel.unix.UnixChannelOption#SO_REUSEPORT" = true + "io.netty.channel.ChannelOption#TCP_FASTOPEN" = 1 child { SO_KEEPALIVE = true @@ -40,7 +40,7 @@ play.server { # The default is 1 since Linux Kernel 3.13 # You can check via "cat /proc/sys/net/ipv4/tcp_fastopen" # However 3 would be better, but we can't change it to that value because we don't have root permission when running the benchmarks - "io.netty.channel.epoll.EpollChannelOption#TCP_FASTOPEN" = 1 + "io.netty.channel.ChannelOption#TCP_FASTOPEN" = 1 } } } @@ -78,7 +78,7 @@ slick.dbs.default { profile="slick.jdbc.MySQLProfile$" db { connectionPool=HikariCP - driver="com.mysql.jdbc.Driver" + driver="com.mysql.cj.jdbc.Driver" url="jdbc:mysql://tfb-database:3306/hello_world" user="benchmarkdbuser" password="benchmarkdbpass" @@ -90,7 +90,7 @@ slick.dbs.default { numThreads=17 numThreads=${?db_pool_size} - queueSize=2000 + queueSize=20000 properties { characterEncoding=UTF-8 diff --git a/frameworks/Scala/play2-scala/play2-scala-slick/project/build.properties b/frameworks/Scala/play2-scala/play2-scala-slick/project/build.properties index a919a9b5f46..cc68b53f1a3 100644 --- a/frameworks/Scala/play2-scala/play2-scala-slick/project/build.properties +++ b/frameworks/Scala/play2-scala/play2-scala-slick/project/build.properties @@ -1 +1 @@ -sbt.version=1.3.8 +sbt.version=1.10.11 diff --git a/frameworks/Scala/play2-scala/play2-scala-slick/project/plugins.sbt b/frameworks/Scala/play2-scala/play2-scala-slick/project/plugins.sbt index 47b7a413447..8ea96fc564c 100644 --- a/frameworks/Scala/play2-scala/play2-scala-slick/project/plugins.sbt +++ b/frameworks/Scala/play2-scala/play2-scala-slick/project/plugins.sbt @@ -1 +1 @@ -addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.8.1") +addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.9.7") \ No newline at end of file diff --git a/frameworks/Scala/play2-scala/play2-scala.dockerfile b/frameworks/Scala/play2-scala/play2-scala.dockerfile index 1f46df4a0bc..e555c2879a4 100644 --- a/frameworks/Scala/play2-scala/play2-scala.dockerfile +++ b/frameworks/Scala/play2-scala/play2-scala.dockerfile @@ -1,4 +1,4 @@ -FROM hseeberger/scala-sbt:8u242_1.3.8_2.13.1 +FROM sbtscala/scala-sbt:eclipse-temurin-21.0.6_7_1.10.11_2.13.16 WORKDIR /play2 COPY play2-scala . @@ -8,4 +8,4 @@ RUN sbt stage EXPOSE 9000 -CMD target/universal/stage/bin/play2-scala -Dplay.server.provider=play.core.server.AkkaHttpServerProvider -J-server -J-Xms1g -J-Xmx1g -J-XX:NewSize=512m -J-XX:+UseG1GC -J-XX:MaxGCPauseMillis=30 -J-XX:-UseBiasedLocking -J-XX:+AlwaysPreTouch -Dthread_count=$(nproc) -Dphysical_cpu_count=$(grep ^cpu\\scores /proc/cpuinfo | uniq | awk '{print $4}') +CMD target/universal/stage/bin/play2-scala -Dplay.server.provider=play.core.server.AkkaHttpServerProvider -J-server -J-Xms1g -J-Xmx1g -J-XX:NewSize=512m -J-XX:+UseG1GC -J-XX:MaxGCPauseMillis=30 -J-XX:+AlwaysPreTouch -Dthread_count=$(nproc) -Dphysical_cpu_count=$(grep ^cpu\\scores /proc/cpuinfo | uniq | awk '{print $4}') diff --git a/frameworks/Scala/play2-scala/play2-scala/build.sbt b/frameworks/Scala/play2-scala/play2-scala/build.sbt index 6a78172d066..3604ffba99c 100644 --- a/frameworks/Scala/play2-scala/play2-scala/build.sbt +++ b/frameworks/Scala/play2-scala/play2-scala/build.sbt @@ -4,6 +4,6 @@ version := "1.0-SNAPSHOT" lazy val root = (project in file(".")).enablePlugins(PlayScala, PlayNettyServer).disablePlugins(PlayFilters) -scalaVersion := "2.13.1" +scalaVersion := "2.13.16" libraryDependencies += guice \ No newline at end of file diff --git a/frameworks/Scala/play2-scala/play2-scala/conf/application.conf b/frameworks/Scala/play2-scala/play2-scala/conf/application.conf index 458e92dbff2..6b9a46aff98 100755 --- a/frameworks/Scala/play2-scala/play2-scala/conf/application.conf +++ b/frameworks/Scala/play2-scala/play2-scala/conf/application.conf @@ -29,8 +29,8 @@ play.server { option { SO_BACKLOG = 8192 SO_REUSEADDR = true - "io.netty.channel.epoll.EpollChannelOption#SO_REUSEPORT" = true - "io.netty.channel.epoll.EpollChannelOption#TCP_FASTOPEN" = 1 + "io.netty.channel.unix.UnixChannelOption#SO_REUSEPORT" = true + "io.netty.channel.ChannelOption#TCP_FASTOPEN" = 1 child { SO_KEEPALIVE = true @@ -40,7 +40,7 @@ play.server { # The default is 1 since Linux Kernel 3.13 # You can check via "cat /proc/sys/net/ipv4/tcp_fastopen" # However 3 would be better, but we can't change it to that value because we don't have root permission when running the benchmarks - "io.netty.channel.epoll.EpollChannelOption#TCP_FASTOPEN" = 1 + "io.netty.channel.ChannelOption#TCP_FASTOPEN" = 1 } } } diff --git a/frameworks/Scala/play2-scala/play2-scala/project/build.properties b/frameworks/Scala/play2-scala/play2-scala/project/build.properties index a919a9b5f46..cc68b53f1a3 100644 --- a/frameworks/Scala/play2-scala/play2-scala/project/build.properties +++ b/frameworks/Scala/play2-scala/play2-scala/project/build.properties @@ -1 +1 @@ -sbt.version=1.3.8 +sbt.version=1.10.11 diff --git a/frameworks/Scala/play2-scala/play2-scala/project/plugins.sbt b/frameworks/Scala/play2-scala/play2-scala/project/plugins.sbt index 47b7a413447..767dc8b1d7e 100644 --- a/frameworks/Scala/play2-scala/play2-scala/project/plugins.sbt +++ b/frameworks/Scala/play2-scala/play2-scala/project/plugins.sbt @@ -1 +1 @@ -addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.8.1") +addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.9.7") diff --git a/frameworks/Scala/scalene/scalene.dockerfile b/frameworks/Scala/scalene/scalene.dockerfile index 469e2c972ca..1741c321e7d 100644 --- a/frameworks/Scala/scalene/scalene.dockerfile +++ b/frameworks/Scala/scalene/scalene.dockerfile @@ -1,14 +1,4 @@ -FROM adoptopenjdk/openjdk13 - -RUN apt-get update -yqq -RUN apt-get install -yqq gnupg git - -# Install sbt -RUN echo "deb https://repo.scala-sbt.org/scalasbt/debian all main" | tee /etc/apt/sources.list.d/sbt.list -RUN echo "deb https://repo.scala-sbt.org/scalasbt/debian /" | tee /etc/apt/sources.list.d/sbt_old.list -RUN curl -sL "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x2EE0EA64E40A89B84B2DF73499E82A75642AC823" | apt-key add -RUN apt-get update -yqq -RUN apt-get install -yqq sbt +FROM sbtscala/scala-sbt:eclipse-temurin-17.0.14_7_1.10.11_2.13.16 WORKDIR /scalene COPY project project diff --git a/frameworks/Scala/sharaf/.mill-version b/frameworks/Scala/sharaf/.mill-version new file mode 100644 index 00000000000..f5f40dc335b --- /dev/null +++ b/frameworks/Scala/sharaf/.mill-version @@ -0,0 +1 @@ +0.12.10 \ No newline at end of file diff --git a/frameworks/Scala/sharaf/README.md b/frameworks/Scala/sharaf/README.md new file mode 100644 index 00000000000..82ec706d260 --- /dev/null +++ b/frameworks/Scala/sharaf/README.md @@ -0,0 +1,45 @@ + +# Sharaf Benchmarking Test + +[Sharaf](https://sake92.github.io/sharaf/) is a minimalistic Scala 3 web framework. + +### Test Type Implementation Source Code + +* [JSON](src/routes.scala) +* [PLAINTEXT](src/routes.scala) +* [DB](src/routes.scala) +* [QUERY](src/routes.scala) +* [UPDATE](src/routes.scala) +* [FORTUNES](src/routes.scala) + +## Important Libraries +The tests were run with: +* [squery](https://sake92.github.io/squery/) for SQL +* [tupson](https://sake92.github.io/tupson/) for JSON +* [scalatags](https://com-lihaoyi.github.io/scalatags/) for HTML + +## Test URLs +### JSON + +http://localhost:8080/json + +### PLAINTEXT + +http://localhost:8080/plaintext + +### 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/Scala/sharaf/benchmark_config.json b/frameworks/Scala/sharaf/benchmark_config.json new file mode 100644 index 00000000000..2864f92059a --- /dev/null +++ b/frameworks/Scala/sharaf/benchmark_config.json @@ -0,0 +1,30 @@ +{ + "framework": "sharaf", + "tests": [ + { + "default": { + "plaintext_url": "/plaintext", + "json_url": "/json", + "db_url": "/db", + "query_url": "/queries?queries=", + "fortune_url": "/fortunes", + "update_url": "/updates?queries=", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "database": "postgres", + "framework": "Sharaf", + "language": "Scala", + "flavor": "None", + "orm": "Micro", + "platform": "Undertow", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "Sharaf", + "notes": "", + "versus": "Undertow" + } + } + ] +} diff --git a/frameworks/Scala/sharaf/build.mill b/frameworks/Scala/sharaf/build.mill new file mode 100644 index 00000000000..c1723ad5f09 --- /dev/null +++ b/frameworks/Scala/sharaf/build.mill @@ -0,0 +1,15 @@ +package build + +import mill._ +import mill.scalalib._ + +object `package` extends RootModule with ScalaModule { + def scalaVersion = "3.6.2" + def ivyDeps = Agg( + ivy"ba.sake::sharaf:0.8.1", + ivy"ba.sake::squery:0.7.0", + ivy"org.postgresql:postgresql:42.6.0", + ivy"com.zaxxer:HikariCP:5.0.1", + ivy"org.slf4j:slf4j-nop:2.0.17" // disable logging + ) +} diff --git a/frameworks/Scala/sharaf/mill b/frameworks/Scala/sharaf/mill new file mode 100644 index 00000000000..5102f00fc92 --- /dev/null +++ b/frameworks/Scala/sharaf/mill @@ -0,0 +1,265 @@ +#!/usr/bin/env sh + +# This is a wrapper script, that automatically download mill from GitHub release pages +# You can give the required mill version with --mill-version parameter +# If no version is given, it falls back to the value of DEFAULT_MILL_VERSION +# +# Original Project page: https://github.com/lefou/millw +# Script Version: 0.4.12 +# +# If you want to improve this script, please also contribute your changes back! +# +# Licensed under the Apache License, Version 2.0 + +set -e + +if [ -z "${DEFAULT_MILL_VERSION}" ] ; then + DEFAULT_MILL_VERSION="0.11.4" +fi + + +if [ -z "${GITHUB_RELEASE_CDN}" ] ; then + GITHUB_RELEASE_CDN="" +fi + + +MILL_REPO_URL="https://github.com/com-lihaoyi/mill" + +if [ -z "${CURL_CMD}" ] ; then + CURL_CMD=curl +fi + +# Explicit commandline argument takes precedence over all other methods +if [ "$1" = "--mill-version" ] ; then + shift + if [ "x$1" != "x" ] ; then + MILL_VERSION="$1" + shift + else + echo "You specified --mill-version without a version." 1>&2 + echo "Please provide a version that matches one provided on" 1>&2 + echo "${MILL_REPO_URL}/releases" 1>&2 + false + fi +fi + +# Please note, that if a MILL_VERSION is already set in the environment, +# We reuse it's value and skip searching for a value. + +# If not already set, read .mill-version file +if [ -z "${MILL_VERSION}" ] ; then + if [ -f ".mill-version" ] ; then + MILL_VERSION="$(tr '\r' '\n' < .mill-version | head -n 1 2> /dev/null)" + elif [ -f ".config/mill-version" ] ; then + MILL_VERSION="$(tr '\r' '\n' < .config/mill-version | head -n 1 2> /dev/null)" + fi +fi + +MILL_USER_CACHE_DIR="${XDG_CACHE_HOME:-${HOME}/.cache}/mill" + +if [ -z "${MILL_DOWNLOAD_PATH}" ] ; then + MILL_DOWNLOAD_PATH="${MILL_USER_CACHE_DIR}/download" +fi + +# If not already set, try to fetch newest from Github +if [ -z "${MILL_VERSION}" ] ; then + # TODO: try to load latest version from release page + echo "No mill version specified." 1>&2 + echo "You should provide a version via '.mill-version' file or --mill-version option." 1>&2 + + mkdir -p "${MILL_DOWNLOAD_PATH}" + LANG=C touch -d '1 hour ago' "${MILL_DOWNLOAD_PATH}/.expire_latest" 2>/dev/null || ( + # we might be on OSX or BSD which don't have -d option for touch + # but probably a -A [-][[hh]mm]SS + touch "${MILL_DOWNLOAD_PATH}/.expire_latest"; touch -A -010000 "${MILL_DOWNLOAD_PATH}/.expire_latest" + ) || ( + # in case we still failed, we retry the first touch command with the intention + # to show the (previously suppressed) error message + LANG=C touch -d '1 hour ago' "${MILL_DOWNLOAD_PATH}/.expire_latest" + ) + + # POSIX shell variant of bash's -nt operator, see https://unix.stackexchange.com/a/449744/6993 + # if [ "${MILL_DOWNLOAD_PATH}/.latest" -nt "${MILL_DOWNLOAD_PATH}/.expire_latest" ] ; then + if [ -n "$(find -L "${MILL_DOWNLOAD_PATH}/.latest" -prune -newer "${MILL_DOWNLOAD_PATH}/.expire_latest")" ]; then + # we know a current latest version + MILL_VERSION=$(head -n 1 "${MILL_DOWNLOAD_PATH}"/.latest 2> /dev/null) + fi + + if [ -z "${MILL_VERSION}" ] ; then + # we don't know a current latest version + echo "Retrieving latest mill version ..." 1>&2 + LANG=C ${CURL_CMD} -s -i -f -I ${MILL_REPO_URL}/releases/latest 2> /dev/null | grep --ignore-case Location: | sed s'/^.*tag\///' | tr -d '\r\n' > "${MILL_DOWNLOAD_PATH}/.latest" + MILL_VERSION=$(head -n 1 "${MILL_DOWNLOAD_PATH}"/.latest 2> /dev/null) + fi + + if [ -z "${MILL_VERSION}" ] ; then + # Last resort + MILL_VERSION="${DEFAULT_MILL_VERSION}" + echo "Falling back to hardcoded mill version ${MILL_VERSION}" 1>&2 + else + echo "Using mill version ${MILL_VERSION}" 1>&2 + fi +fi + +MILL_NATIVE_SUFFIX="-native" +FULL_MILL_VERSION=$MILL_VERSION +ARTIFACT_SUFFIX="" +case "$MILL_VERSION" in + *"$MILL_NATIVE_SUFFIX") + MILL_VERSION=${MILL_VERSION%"$MILL_NATIVE_SUFFIX"} + if [ "$(expr substr $(uname -s) 1 5 2>/dev/null)" = "Linux" ]; then + if [ "$(uname -m)" = "aarch64" ]; then + ARTIFACT_SUFFIX="-native-linux-aarch64" + else + ARTIFACT_SUFFIX="-native-linux-amd64" + fi + elif [ "$(uname)" = "Darwin" ]; then + if [ "$(uname -m)" = "arm64" ]; then + ARTIFACT_SUFFIX="-native-mac-aarch64" + else + ARTIFACT_SUFFIX="-native-mac-amd64" + fi + else + echo "This native mill launcher supports only Linux and macOS." 1>&2 + exit 1 + fi +esac + +MILL="${MILL_DOWNLOAD_PATH}/${FULL_MILL_VERSION}" + +try_to_use_system_mill() { + if [ "$(uname)" != "Linux" ]; then + return 0 + fi + + MILL_IN_PATH="$(command -v mill || true)" + + if [ -z "${MILL_IN_PATH}" ]; then + return 0 + fi + + SYSTEM_MILL_FIRST_TWO_BYTES=$(head --bytes=2 "${MILL_IN_PATH}") + if [ "${SYSTEM_MILL_FIRST_TWO_BYTES}" = "#!" ]; then + # MILL_IN_PATH is (very likely) a shell script and not the mill + # executable, ignore it. + return 0 + fi + + SYSTEM_MILL_PATH=$(readlink -e "${MILL_IN_PATH}") + SYSTEM_MILL_SIZE=$(stat --format=%s "${SYSTEM_MILL_PATH}") + SYSTEM_MILL_MTIME=$(stat --format=%y "${SYSTEM_MILL_PATH}") + + if [ ! -d "${MILL_USER_CACHE_DIR}" ]; then + mkdir -p "${MILL_USER_CACHE_DIR}" + fi + + SYSTEM_MILL_INFO_FILE="${MILL_USER_CACHE_DIR}/system-mill-info" + if [ -f "${SYSTEM_MILL_INFO_FILE}" ]; then + parseSystemMillInfo() { + LINE_NUMBER="${1}" + # Select the line number of the SYSTEM_MILL_INFO_FILE, cut the + # variable definition in that line in two halves and return + # the value, and finally remove the quotes. + sed -n "${LINE_NUMBER}p" "${SYSTEM_MILL_INFO_FILE}" |\ + cut -d= -f2 |\ + sed 's/"\(.*\)"/\1/' + } + + CACHED_SYSTEM_MILL_PATH=$(parseSystemMillInfo 1) + CACHED_SYSTEM_MILL_VERSION=$(parseSystemMillInfo 2) + CACHED_SYSTEM_MILL_SIZE=$(parseSystemMillInfo 3) + CACHED_SYSTEM_MILL_MTIME=$(parseSystemMillInfo 4) + + if [ "${SYSTEM_MILL_PATH}" = "${CACHED_SYSTEM_MILL_PATH}" ] \ + && [ "${SYSTEM_MILL_SIZE}" = "${CACHED_SYSTEM_MILL_SIZE}" ] \ + && [ "${SYSTEM_MILL_MTIME}" = "${CACHED_SYSTEM_MILL_MTIME}" ]; then + if [ "${CACHED_SYSTEM_MILL_VERSION}" = "${MILL_VERSION}" ]; then + MILL="${SYSTEM_MILL_PATH}" + return 0 + else + return 0 + fi + fi + fi + + SYSTEM_MILL_VERSION=$(${SYSTEM_MILL_PATH} --version | head -n1 | sed -n 's/^Mill.*version \(.*\)/\1/p') + + cat < "${SYSTEM_MILL_INFO_FILE}" +CACHED_SYSTEM_MILL_PATH="${SYSTEM_MILL_PATH}" +CACHED_SYSTEM_MILL_VERSION="${SYSTEM_MILL_VERSION}" +CACHED_SYSTEM_MILL_SIZE="${SYSTEM_MILL_SIZE}" +CACHED_SYSTEM_MILL_MTIME="${SYSTEM_MILL_MTIME}" +EOF + + if [ "${SYSTEM_MILL_VERSION}" = "${MILL_VERSION}" ]; then + MILL="${SYSTEM_MILL_PATH}" + fi +} +try_to_use_system_mill + +# If not already downloaded, download it +if [ ! -s "${MILL}" ] ; then + + # support old non-XDG download dir + MILL_OLD_DOWNLOAD_PATH="${HOME}/.mill/download" + OLD_MILL="${MILL_OLD_DOWNLOAD_PATH}/${MILL_VERSION}" + if [ -x "${OLD_MILL}" ] ; then + MILL="${OLD_MILL}" + else + case $MILL_VERSION in + 0.0.* | 0.1.* | 0.2.* | 0.3.* | 0.4.* ) + DOWNLOAD_SUFFIX="" + DOWNLOAD_FROM_MAVEN=0 + ;; + 0.5.* | 0.6.* | 0.7.* | 0.8.* | 0.9.* | 0.10.* | 0.11.0-M* ) + DOWNLOAD_SUFFIX="-assembly" + DOWNLOAD_FROM_MAVEN=0 + ;; + *) + DOWNLOAD_SUFFIX="-assembly" + DOWNLOAD_FROM_MAVEN=1 + ;; + esac + + DOWNLOAD_FILE=$(mktemp mill.XXXXXX) + + if [ "$DOWNLOAD_FROM_MAVEN" = "1" ] ; then + DOWNLOAD_URL="https://repo1.maven.org/maven2/com/lihaoyi/mill-dist${ARTIFACT_SUFFIX}/${MILL_VERSION}/mill-dist${ARTIFACT_SUFFIX}-${MILL_VERSION}.jar" + else + MILL_VERSION_TAG=$(echo "$MILL_VERSION" | sed -E 's/([^-]+)(-M[0-9]+)?(-.*)?/\1\2/') + DOWNLOAD_URL="${GITHUB_RELEASE_CDN}${MILL_REPO_URL}/releases/download/${MILL_VERSION_TAG}/${MILL_VERSION}${DOWNLOAD_SUFFIX}" + unset MILL_VERSION_TAG + fi + + # TODO: handle command not found + echo "Downloading mill ${MILL_VERSION} from ${DOWNLOAD_URL} ..." 1>&2 + ${CURL_CMD} -f -L -o "${DOWNLOAD_FILE}" "${DOWNLOAD_URL}" + chmod +x "${DOWNLOAD_FILE}" + mkdir -p "${MILL_DOWNLOAD_PATH}" + mv "${DOWNLOAD_FILE}" "${MILL}" + + unset DOWNLOAD_FILE + unset DOWNLOAD_SUFFIX + fi +fi + +if [ -z "$MILL_MAIN_CLI" ] ; then + MILL_MAIN_CLI="${0}" +fi + +MILL_FIRST_ARG="" +if [ "$1" = "--bsp" ] || [ "$1" = "-i" ] || [ "$1" = "--interactive" ] || [ "$1" = "--no-server" ] || [ "$1" = "--repl" ] || [ "$1" = "--help" ] ; then + # Need to preserve the first position of those listed options + MILL_FIRST_ARG=$1 + shift +fi + +unset MILL_DOWNLOAD_PATH +unset MILL_OLD_DOWNLOAD_PATH +unset OLD_MILL +unset MILL_VERSION +unset MILL_REPO_URL + +# We don't quote MILL_FIRST_ARG on purpose, so we can expand the empty value without quotes +# shellcheck disable=SC2086 +exec "${MILL}" $MILL_FIRST_ARG -D "mill.main.cli=${MILL_MAIN_CLI}" "$@" \ No newline at end of file diff --git a/frameworks/Scala/sharaf/sharaf.dockerfile b/frameworks/Scala/sharaf/sharaf.dockerfile new file mode 100644 index 00000000000..44702c90b16 --- /dev/null +++ b/frameworks/Scala/sharaf/sharaf.dockerfile @@ -0,0 +1,14 @@ +FROM nightscape/scala-mill:eclipse-temurin-21.0.6_7-jdk-jammy_0.12.10 +WORKDIR /sharaf + +COPY src src +COPY build.mill build.mill +COPY mill mill +RUN chmod 777 mill +COPY .mill-version .mill-version + +RUN ./mill assembly + +EXPOSE 8080 + +CMD ["java", "-server", "-Xms2g", "-Xmx2g", "-jar", "out/assembly.dest/out.jar"] diff --git a/frameworks/Scala/sharaf/src/db.scala b/frameworks/Scala/sharaf/src/db.scala new file mode 100644 index 00000000000..795d4b02405 --- /dev/null +++ b/frameworks/Scala/sharaf/src/db.scala @@ -0,0 +1,52 @@ +package ba.sake.sharaf.benchmark + +import java.util.concurrent.ThreadLocalRandom +import scala.collection.mutable +import ba.sake.squery.{*, given} +import scala.collection.decorators.* + +class DAO { + private val ds = com.zaxxer.hikari.HikariDataSource() + ds.setJdbcUrl("jdbc:postgresql://tfb-database:5432/hello_world") + ds.setUsername("benchmarkdbuser") + ds.setPassword("benchmarkdbpass") + ds.setMaximumPoolSize(Runtime.getRuntime().availableProcessors() * 2 + 1) + private val squeryContext = SqueryContext(ds) + + def getRandomWorld(): WorldRow = squeryContext.run { + sql"SELECT id, randomnumber FROM world WHERE id = ${getRandomRowId()}" + .readRow() + } + + def getRandomWorlds(queriesCount: Int): Seq[WorldRow] = squeryContext.run { + val buffer = new mutable.ArrayBuffer[WorldRow](queriesCount) + for i <- 0 until queriesCount do + buffer += sql"SELECT id, randomnumber FROM world WHERE id = ${getRandomRowId()}" + .readRow() + buffer.toSeq + } + + def updateWorlds(rows: Seq[WorldRow]): Unit = squeryContext.run { + val values = rows + .map(row => sql"(${row.id}, ${row.randomnumber})") + .intersperse(sql",") + .reduce(_ ++ _) + sql""" + UPDATE world as w + SET randomnumber = c.randomnumber + FROM (VALUES ${values}) AS c(id, randomnumber) + WHERE w.id = c.id + """.update() + } + + def getFortunes(): Seq[FortuneRow] = squeryContext.run { + sql"SELECT id, message FROM fortune".readRows() + } + + def getRandomRowId(): Int = + return 1 + ThreadLocalRandom.current().nextInt(10000) + +} + +case class WorldRow(id: Int, randomnumber: Int) derives SqlReadRow +case class FortuneRow(id: Int, message: String) derives SqlReadRow diff --git a/frameworks/Scala/sharaf/src/main.scala b/frameworks/Scala/sharaf/src/main.scala new file mode 100644 index 00000000000..13207509600 --- /dev/null +++ b/frameworks/Scala/sharaf/src/main.scala @@ -0,0 +1,24 @@ +package ba.sake.sharaf.benchmark + +import io.undertow.Undertow +import io.undertow.UndertowOptions +import ba.sake.sharaf.* + +@main def run(): Unit = { + val dao = DAO() + val benchmarkRoutes = BenchmarkRoutes(dao) + // set to slf4j, thus disabling logging (slf4j-nop) + System.setProperty("org.jboss.logging.provider", "slf4j") + val server = Undertow + .builder() + .addHttpListener(8080, "0.0.0.0") + .setHandler(SharafHandler(benchmarkRoutes.routes)) + .setIoThreads(Runtime.getRuntime().availableProcessors() * 2) + // In HTTP/1.1, connections are persistent unless declared otherwise. + // Adding a "Connection: keep-alive" header to every response would only + // add useless bytes. + .setServerOption(UndertowOptions.ALWAYS_SET_KEEP_ALIVE, false) + .build() + server.start() + //println(s"Started HTTP server at localhost:8080") +} diff --git a/frameworks/Scala/sharaf/src/pages.scala b/frameworks/Scala/sharaf/src/pages.scala new file mode 100644 index 00000000000..659d7737b3b --- /dev/null +++ b/frameworks/Scala/sharaf/src/pages.scala @@ -0,0 +1,21 @@ +package ba.sake.sharaf.benchmark + +import scalatags.Text.all.* +import ba.sake.hepek.html.HtmlPage + +class FortunesPage(rows: Seq[FortuneRow]) extends HtmlPage { + override def pageSettings = super.pageSettings.withTitle("Fortunes") + + override def bodyContent = table( + tr( + th("id"), + th("message") + ), + rows.map { row => + tr( + td(row.id), + td(row.message) + ) + } + ) +} diff --git a/frameworks/Scala/sharaf/src/routes.scala b/frameworks/Scala/sharaf/src/routes.scala new file mode 100644 index 00000000000..01a456d7f39 --- /dev/null +++ b/frameworks/Scala/sharaf/src/routes.scala @@ -0,0 +1,59 @@ +package ba.sake.sharaf.benchmark + +import ba.sake.sharaf.*, routing.* +import ba.sake.querson.* +import ba.sake.tupson.* + +class BenchmarkRoutes(dao: DAO) { + + def routes: Routes = Routes { + case GET() -> Path("plaintext") => + Response.withBody("Hello, World!").settingHeader("Server", "sharaf") + + case GET() -> Path("json") => + Response + .withBody(MessageResponse("Hello, World!")) + .settingHeader("Server", "sharaf") + + case GET() -> Path("db") => + val row = dao.getRandomWorld() + val body = WorldResponse(row.id, row.randomnumber) + Response.withBody(body).settingHeader("Server", "sharaf") + + case GET() -> Path("queries") => + val queriesCountStr = Request.current.queryParams[QueriesQP].queries + var queriesCount = queriesCountStr.toIntOption.getOrElse(1) + if queriesCount < 1 then queriesCount = 1 + if queriesCount > 500 then queriesCount = 500 + val rows = dao.getRandomWorlds(queriesCount) + val body = rows.map(row => WorldResponse(row.id, row.randomnumber)) + Response.withBody(body).settingHeader("Server", "sharaf") + + case GET() -> Path("fortunes") => + val rows = dao + .getFortunes() + .appended(FortuneRow(0, "Additional fortune added at request time.")) + val rowsSorted = rows.sortBy(_.message) + val body = FortunesPage(rowsSorted) + Response.withBody(body).settingHeader("Server", "sharaf") + + case GET() -> Path("updates") => + val queriesCountStr = Request.current.queryParams[QueriesQP].queries + var queriesCount = queriesCountStr.toIntOption.getOrElse(1) + if queriesCount < 1 then queriesCount = 1 + if queriesCount > 500 then queriesCount = 500 + val rows = dao.getRandomWorlds(queriesCount) + val updatedRows = rows.map(_.copy(randomnumber = dao.getRandomRowId())) + dao.updateWorlds(updatedRows) + val body = updatedRows.map(row => WorldResponse(row.id, row.randomnumber)) + Response.withBody(body).settingHeader("Server", "sharaf") + + } +} + +// query params +case class QueriesQP(queries: String = "1") derives QueryStringRW + +// json responses +case class MessageResponse(message: String) derives JsonRW +case class WorldResponse(id: Int, randomNumber: Int) derives JsonRW diff --git a/frameworks/Scala/snunit/.dockerignore b/frameworks/Scala/snunit/.dockerignore index e4a162e5e02..2a371592c0f 100644 --- a/frameworks/Scala/snunit/.dockerignore +++ b/frameworks/Scala/snunit/.dockerignore @@ -3,7 +3,7 @@ # Allow files and directories !/build.sbt -!/config.sh +!/conf.json !/project/build.properties !/project/plugins.sbt !/src diff --git a/frameworks/Scala/snunit/benchmark_config.json b/frameworks/Scala/snunit/benchmark_config.json index 7711ab00316..f46cf29e0d8 100755 --- a/frameworks/Scala/snunit/benchmark_config.json +++ b/frameworks/Scala/snunit/benchmark_config.json @@ -19,8 +19,7 @@ "database_os": "Linux", "display_name": "SNUnit", "notes": "", - "versus": "", - "tags": ["broken"] + "versus": "" } } ] diff --git a/frameworks/Scala/snunit/build.sbt b/frameworks/Scala/snunit/build.sbt index 5573cd526ec..c44785e96c8 100644 --- a/frameworks/Scala/snunit/build.sbt +++ b/frameworks/Scala/snunit/build.sbt @@ -1,9 +1,9 @@ import scala.scalanative.build._ -scalaVersion := "2.13.10" +scalaVersion := "3.5.2" -val snunitVersion = "0.3.0" -val jsoniterScalaVersion = "2.20.6" +val snunitVersion = "0.10.3" +val jsoniterScalaVersion = "2.33.0" libraryDependencies ++= Seq( "com.github.lolgab" %%% "snunit" % snunitVersion, diff --git a/frameworks/Scala/snunit/conf.json b/frameworks/Scala/snunit/conf.json new file mode 100644 index 00000000000..0a6c3954949 --- /dev/null +++ b/frameworks/Scala/snunit/conf.json @@ -0,0 +1,20 @@ +{ + "listeners": { + "*:8080": { + "pass": "applications/example" + } + }, + "applications": { + "example": { + "type": "external", + "processes": { + "spare": 2, + "max": 20 + }, + "executable": "/app/example", + "environment": { + "SCALANATIVE_GC_THREADS": "2" + } + } + } +} diff --git a/frameworks/Scala/snunit/config.sh b/frameworks/Scala/snunit/config.sh deleted file mode 100755 index 12f0a511a10..00000000000 --- a/frameworks/Scala/snunit/config.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env bash - -processes=$(("$(nproc)" / 2)) - -config='{' -config+=' "listeners": {' -config+=' "*:8080": {' -config+=' "pass": "applications/example"' -config+=' }' -config+=' },' -config+=' "applications": {' -config+=' "example": {' -config+=' "type": "external",' -config+=' "processes": '"$processes"',' -config+=' "executable": "/app/example",' -config+=' "environment": {' -config+=' "SCALANATIVE_GC_THREADS": "2"' -config+=' }' -config+=' }' -config+=' }' -config+='}' - -curl -X PUT \ - --data-binary "$config" \ - --unix-socket /var/run/control.unit.sock \ - http://localhost/config diff --git a/frameworks/Scala/snunit/project/build.properties b/frameworks/Scala/snunit/project/build.properties index 8b9a0b0ab03..db1723b0862 100644 --- a/frameworks/Scala/snunit/project/build.properties +++ b/frameworks/Scala/snunit/project/build.properties @@ -1 +1 @@ -sbt.version=1.8.0 +sbt.version=1.10.5 diff --git a/frameworks/Scala/snunit/project/plugins.sbt b/frameworks/Scala/snunit/project/plugins.sbt index d1565a95c3a..2f7a1e7541a 100644 --- a/frameworks/Scala/snunit/project/plugins.sbt +++ b/frameworks/Scala/snunit/project/plugins.sbt @@ -1 +1 @@ -addSbtPlugin("org.scala-native" % "sbt-scala-native" % "0.4.9") +addSbtPlugin("org.scala-native" % "sbt-scala-native" % "0.5.6") diff --git a/frameworks/Scala/snunit/snunit.dockerfile b/frameworks/Scala/snunit/snunit.dockerfile index bbadb49027e..699c3c714f8 100644 --- a/frameworks/Scala/snunit/snunit.dockerfile +++ b/frameworks/Scala/snunit/snunit.dockerfile @@ -1,23 +1,30 @@ -FROM debian:bullseye-slim as builder +FROM debian:bookworm-slim as builder RUN apt-get update && apt-get install -y curl gnupg && \ - echo "deb https://repo.scala-sbt.org/scalasbt/debian /" > /etc/apt/sources.list.d/sbt.list && \ + echo "deb https://repo.scala-sbt.org/scalasbt/debian all main" | tee /etc/apt/sources.list.d/sbt.list && \ curl -sL "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x2EE0EA64E40A89B84B2DF73499E82A75642AC823" | apt-key add - && \ curl -sL https://nginx.org/keys/nginx_signing.key | apt-key add - && \ - echo "deb https://packages.nginx.org/unit/debian/ bullseye unit" > /etc/apt/sources.list.d/unit.list && \ - echo "deb-src https://packages.nginx.org/unit/debian/ bullseye unit" >> /etc/apt/sources.list.d/unit.list && \ - apt-get update && apt-get install -y clang unit-dev=1.29* openjdk-11-jdk sbt && \ + echo "deb https://packages.nginx.org/unit/debian/ bookworm unit" > /etc/apt/sources.list.d/unit.list && \ + echo "deb-src https://packages.nginx.org/unit/debian/ bookworm unit" >> /etc/apt/sources.list.d/unit.list && \ + apt-get update && apt-get install -y clang unit-dev=1.34* openjdk-17-jdk sbt=1.10.5 && \ apt-get purge -y gnupg WORKDIR /workdir +RUN sbt version + COPY . . RUN sbt nativeLink -FROM nginx/unit:1.29.1-minimal +FROM unit:1.34.0-minimal + +WORKDIR /workdir -COPY /config.sh /docker-entrypoint.d/ -COPY --from=builder /workdir/target/scala-2.13/workdir-out /app/example +COPY conf.json statedir/ +COPY --from=builder /usr/sbin/unitd /usr/sbin/unitd +COPY --from=builder /workdir/target/scala-3.5.2/workdir /app/example EXPOSE 8080 + +ENTRYPOINT [ "unitd", "--no-daemon", "--statedir", "/workdir/statedir", "--log", "/dev/stdout" ] diff --git a/frameworks/Scala/snunit/src/main/scala/Main.scala b/frameworks/Scala/snunit/src/main/scala/Main.scala index a6a6c54ae00..4fe53ab5d3c 100644 --- a/frameworks/Scala/snunit/src/main/scala/Main.scala +++ b/frameworks/Scala/snunit/src/main/scala/Main.scala @@ -1,43 +1,37 @@ -import com.github.plokhotnyuk.jsoniter_scala.core._ -import com.github.plokhotnyuk.jsoniter_scala.macros._ -import snunit._ +import com.github.plokhotnyuk.jsoniter_scala.core.* +import com.github.plokhotnyuk.jsoniter_scala.macros.* +import snunit.* -final case class Message(message: String) +final case class Message(message: String) derives ConfiguredJsonValueCodec -object Message { - implicit final val codec: JsonValueCodec[Message] = JsonCodecMaker.make -} +final val applicationJson = Headers("Content-Type" -> "application/json") +final val textPlain = Headers("Content-Type" -> "text/plain") -object Main { - val applicationJson = Seq("Content-Type" -> "application/json") - val textPlain = Seq("Content-Type" -> "text/plain") +inline def notFound(req: Request) = req.send( + statusCode = StatusCode.NotFound, + content = "Not found", + headers = textPlain +) - @inline - private def notFound(req: Request) = req.send( - statusCode = StatusCode.NotFound, - content = "Not found", - headers = textPlain - ) - - def main(args: Array[String]): Unit = { - SyncServerBuilder - .build(req => - if (req.method == Method.GET) { - if(req.target == "/plaintext") - req.send( - statusCode = StatusCode.OK, - content = "Hello, World!", - headers = textPlain - ) - else if(req.target == "/json") - req.send( - statusCode = StatusCode.OK, - content = writeToArray(Message("Hello, World!")), - headers = applicationJson - ) - else notFound(req) - } else notFound(req) - ) - .listen() - } -} +@main +def main = + SyncServerBuilder + .setRequestHandler(req => + if (req.method == Method.GET) { + if(req.target == "/plaintext") + req.send( + statusCode = StatusCode.OK, + content = "Hello, World!", + headers = textPlain + ) + else if(req.target == "/json") + req.send( + statusCode = StatusCode.OK, + content = writeToArray(Message("Hello, World!")), + headers = applicationJson + ) + else notFound(req) + } else notFound(req) + ) + .build() + .listen() diff --git a/frameworks/Scala/tapir/README.md b/frameworks/Scala/tapir/README.md new file mode 100644 index 00000000000..8375201828c --- /dev/null +++ b/frameworks/Scala/tapir/README.md @@ -0,0 +1,28 @@ +# Tapir Benchmarking Test + +This is a simple test to benchmark the performance of the Tapir libraries along with different backends in Scala. + +### Test Type Implementation Source Code + +* JSON +* PLAINTEXT + +## Software Versions + +* [Java OpenJDK 21](https://adoptium.net/temurin/releases/) +* [Scala 3.6.4](https://www.scala-lang.org/) +* [Tapir 1.11.24](https://tapir.softwaremill.com) + +### Backend Implementations +* [Tapir running as zio-http server](https://tapir.softwaremill.com/en/latest/server/ziohttp.html) +* [Tapir running as http4s server](https://tapir.softwaremill.com/en/latest/server/http4s.html) +* [as an http4s server using ZIO](https://tapir.softwaremill.com/en/latest/server/zio-http4s.html) +* [Tapir running as Netty-based server(Cats)](https://tapir.softwaremill.com/en/latest/server/netty.html) +* [Tapir running as Netty-based server(Kyo)](https://getkyo.io/#/?id=routes-http-server-via-tapir) +* [Tapir running as Netty-based server(ZIO)](https://tapir.softwaremill.com/en/latest/server/netty.html) +* [Tapir running as pekko-http server](https://tapir.softwaremill.com/en/latest/server/pekkohttp.html) + +## Test URLs + +* JSON - http://localhost:8080/json +* PLAINTEXT - http://localhost:8080/plaintext diff --git a/frameworks/Scala/tapir/benchmark_config.json b/frameworks/Scala/tapir/benchmark_config.json new file mode 100644 index 00000000000..96c27368335 --- /dev/null +++ b/frameworks/Scala/tapir/benchmark_config.json @@ -0,0 +1,140 @@ +{ + "framework": "tapir", + "tests": [ + { + "default": { + "plaintext_url": "/plaintext", + "json_url": "/json", + "port": 8080, + "database": "None", + "approach": "Realistic", + "classification": "Micro", + "framework": "tapir", + "language": "Scala", + "flavor": "None", + "orm": "Raw", + "platform": "Netty", + "webserver": "None", + "database_os": "Linux", + "os": "Linux", + "display_name": "tapir as zio-http server", + "notes": "https://tapir.softwaremill.com/en/latest/server/ziohttp.html", + "versus": "None" + }, + "http4s": { + "plaintext_url": "/plaintext", + "json_url": "/json", + "port": 8080, + "database": "None", + "approach": "Realistic", + "classification": "Micro", + "framework": "tapir", + "language": "Scala", + "flavor": "None", + "orm": "Raw", + "platform": "Netty", + "webserver": "None", + "database_os": "Linux", + "os": "Linux", + "display_name": "tapir as http4s server", + "notes": "https://tapir.softwaremill.com/en/latest/server/http4s.html", + "versus": "None" + }, + "http4s-zio": { + "plaintext_url": "/plaintext", + "json_url": "/json", + "port": 8080, + "database": "None", + "approach": "Realistic", + "classification": "Micro", + "framework": "tapir", + "language": "Scala", + "flavor": "None", + "orm": "Raw", + "platform": "Netty", + "webserver": "None", + "database_os": "Linux", + "os": "Linux", + "display_name": "tapir as http4s server using ZIO", + "notes": "https://tapir.softwaremill.com/en/latest/server/zio-http4s.html", + "versus": "None" + }, + "netty-cats": { + "plaintext_url": "/plaintext", + "json_url": "/json", + "port": 8080, + "database": "None", + "approach": "Realistic", + "classification": "Micro", + "framework": "tapir", + "language": "Scala", + "flavor": "None", + "orm": "Raw", + "platform": "Netty", + "webserver": "None", + "database_os": "Linux", + "os": "Linux", + "display_name": "tapir as netty(cats) server", + "notes": "https://tapir.softwaremill.com/en/latest/server/netty.html", + "versus": "None" + }, + "netty-kyo": { + "plaintext_url": "/plaintext", + "json_url": "/json", + "port": 8080, + "database": "None", + "approach": "Realistic", + "classification": "Micro", + "framework": "tapir", + "language": "Scala", + "flavor": "None", + "orm": "Raw", + "platform": "Netty", + "webserver": "None", + "database_os": "Linux", + "os": "Linux", + "display_name": "tapir as netty(kyo) server", + "notes": "https://getkyo.io/#/?id=routes-http-server-via-tapir", + "versus": "None" + }, + "netty-zio": { + "plaintext_url": "/plaintext", + "json_url": "/json", + "port": 8080, + "database": "None", + "approach": "Realistic", + "classification": "Micro", + "framework": "tapir", + "language": "Scala", + "flavor": "None", + "orm": "Raw", + "platform": "Netty", + "webserver": "None", + "database_os": "Linux", + "os": "Linux", + "display_name": "tapir as netty(zio) server", + "notes": "https://tapir.softwaremill.com/en/latest/server/netty.html", + "versus": "None" + }, + "pekko-http": { + "plaintext_url": "/plaintext", + "json_url": "/json", + "port": 8080, + "database": "None", + "approach": "Realistic", + "classification": "Micro", + "framework": "tapir", + "language": "Scala", + "flavor": "None", + "orm": "Raw", + "platform": "Netty", + "webserver": "None", + "database_os": "Linux", + "os": "Linux", + "display_name": "tapir as pekko-http server", + "notes": "https://tapir.softwaremill.com/en/latest/server/pekkohttp.html", + "versus": "None" + } + } + ] +} \ No newline at end of file diff --git a/frameworks/Scala/tapir/build.sbt b/frameworks/Scala/tapir/build.sbt new file mode 100644 index 00000000000..99947e9a16c --- /dev/null +++ b/frameworks/Scala/tapir/build.sbt @@ -0,0 +1,100 @@ +name := "tapir-benchmark" + +ThisBuild / version := "1.0.0" +ThisBuild / scalaVersion := "3.6.4" + +val tapirVersion = "1.11.24" + +val commonAssemblySettings = assembly / assemblyMergeStrategy := { + case x if x.contains("io.netty.versions.properties") => MergeStrategy.discard + case x if x.contains("module-info.class") => MergeStrategy.discard + case x => + val oldStrategy = (assembly / assemblyMergeStrategy).value + oldStrategy(x) +} + +lazy val common = (project in file("common")) + .settings( + name := "tapir-benchmark-common" + ) + +lazy val `zio-http-server` = (project in file("zio-http-server")) + .dependsOn(common) + .settings( + name := "tapir-zio-http-server", + libraryDependencies ++= Seq( + "com.softwaremill.sttp.tapir" %% "tapir-zio-http-server" % tapirVersion, + "com.softwaremill.sttp.tapir" %% "tapir-json-zio" % tapirVersion + ), + commonAssemblySettings + ) + +lazy val `http4s-server` = (project in file("http4s-server")) + .dependsOn(common) + .settings( + name := "tapir-http4s-server", + libraryDependencies ++= Seq( + "com.softwaremill.sttp.tapir" %% "tapir-http4s-server" % tapirVersion, + "com.softwaremill.sttp.tapir" %% "tapir-json-circe" % tapirVersion, + "org.http4s" %% "http4s-blaze-server" % "0.23.17", + ), + commonAssemblySettings + ) + +lazy val `http4s-server-zio` = (project in file("http4s-server-zio")) + .dependsOn(common) + .settings( + name := "tapir-http4s-server-zio", + libraryDependencies ++= Seq( + "com.softwaremill.sttp.tapir" %% "tapir-http4s-server-zio" % tapirVersion, + "com.softwaremill.sttp.tapir" %% "tapir-json-circe" % tapirVersion, + "org.http4s" %% "http4s-blaze-server" % "0.23.17", + "dev.zio" %% "zio-interop-cats" % "23.1.0.5" + ), + commonAssemblySettings + ) + +lazy val `netty-kyo-server` = (project in file("netty-kyo-server")) + .dependsOn(common) + .settings( + name := "tapir-netty-kyo-server", + libraryDependencies ++= Seq( + "io.getkyo" %% "kyo-tapir" % "0.18.0", + "com.softwaremill.sttp.tapir" %% "tapir-json-zio" % tapirVersion + ), + commonAssemblySettings + ) + +lazy val `netty-zio-server` = (project in file("netty-zio-server")) + .dependsOn(common) + .settings( + name := "tapir-netty-zio-server", + libraryDependencies ++= Seq( + "com.softwaremill.sttp.tapir" %% "tapir-netty-server-zio" % tapirVersion, + "com.softwaremill.sttp.tapir" %% "tapir-json-zio" % tapirVersion, + ), + commonAssemblySettings + ) + +lazy val `netty-cats-server` = (project in file("netty-cats-server")) + .dependsOn(common) + .settings( + name := "tapir-netty-cats-server", + libraryDependencies ++= Seq( + "com.softwaremill.sttp.tapir" %% "tapir-netty-server-cats" % tapirVersion, + "com.softwaremill.sttp.tapir" %% "tapir-json-circe" % tapirVersion, + "org.http4s" %% "http4s-blaze-server" % "0.23.17", + ), + commonAssemblySettings + ) + +lazy val `pekko-http-server` = (project in file("pekko-http-server")) + .dependsOn(common) + .settings( + name := "tapir-pekko-http-server", + libraryDependencies ++= Seq( + "com.softwaremill.sttp.tapir" %% "tapir-pekko-http-server" % tapirVersion, + "com.softwaremill.sttp.tapir" %% "tapir-json-circe" % tapirVersion, + ), + commonAssemblySettings + ) diff --git a/frameworks/Scala/tapir/common/src/main/scala/Payload.scala b/frameworks/Scala/tapir/common/src/main/scala/Payload.scala new file mode 100644 index 00000000000..2b886ef91b8 --- /dev/null +++ b/frameworks/Scala/tapir/common/src/main/scala/Payload.scala @@ -0,0 +1 @@ +case class Payload(message: String) diff --git a/frameworks/Scala/tapir/config.toml b/frameworks/Scala/tapir/config.toml new file mode 100644 index 00000000000..895f262659b --- /dev/null +++ b/frameworks/Scala/tapir/config.toml @@ -0,0 +1,93 @@ +[framework] +name = "tapir" + +[main] +urls.plaintext = "/plaintext" +urls.json = "/json" +approach = "Realistic" +classification = "Micro" +database = "None" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "Netty" +webserver = "None" +versus = "None" + +[http4s] +urls.plaintext = "/plaintext" +urls.json = "/json" +approach = "Realistic" +classification = "Micro" +database = "None" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "Netty" +webserver = "None" +versus = "None" + +[http4s-zio] +urls.plaintext = "/plaintext" +urls.json = "/json" +approach = "Realistic" +classification = "Micro" +database = "None" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "Netty" +webserver = "None" +versus = "None" + +[netty-cats] +urls.plaintext = "/plaintext" +urls.json = "/json" +approach = "Realistic" +classification = "Micro" +database = "None" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "Netty" +webserver = "None" +versus = "None" + +[netty-kyo] +urls.plaintext = "/plaintext" +urls.json = "/json" +approach = "Realistic" +classification = "Micro" +database = "None" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "Netty" +webserver = "None" +versus = "None" + +[netty-zio] +urls.plaintext = "/plaintext" +urls.json = "/json" +approach = "Realistic" +classification = "Micro" +database = "None" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "Netty" +webserver = "None" +versus = "None" + +[pekko-http] +urls.plaintext = "/plaintext" +urls.json = "/json" +approach = "Realistic" +classification = "Micro" +database = "None" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "Netty" +webserver = "None" +versus = "None" \ No newline at end of file diff --git a/frameworks/Scala/tapir/http4s-server-zio/src/main/scala/TapirHttp4sServerZioBenchmark.scala b/frameworks/Scala/tapir/http4s-server-zio/src/main/scala/TapirHttp4sServerZioBenchmark.scala new file mode 100644 index 00000000000..8e93bd7445c --- /dev/null +++ b/frameworks/Scala/tapir/http4s-server-zio/src/main/scala/TapirHttp4sServerZioBenchmark.scala @@ -0,0 +1,55 @@ +import io.circe.generic.auto.* +import org.http4s.HttpRoutes +import org.http4s.blaze.server.BlazeServerBuilder +import org.http4s.server.Router +import sttp.model.{Header, HeaderNames, StatusCode} +import sttp.tapir.generic.auto.* +import sttp.tapir.json.circe.* +import sttp.tapir.server.http4s.ztapir.ZHttp4sServerInterpreter +import sttp.tapir.ztapir.* +import zio.* + +import java.time.format.DateTimeFormatter +import java.time.{Clock, LocalDateTime, ZoneOffset, ZonedDateTime} +import java.util.Date +import java.util.concurrent.locks.LockSupport +import scala.concurrent.ExecutionContext +import zio.interop.catz.* + +object TapirHttp4sServerZioBenchmark extends ZIOAppDefault: + private val STATIC_SERVER_NAME = "tapir-http4s-server-zio" + + private val plainTextMessage: String = "Hello, World!" + + private val plaintextEndpoint: ZServerEndpoint[Any, Any] = + endpoint.get.in("plaintext") + .out(header(HeaderNames.Server, STATIC_SERVER_NAME)) + .out(stringBody) + .zServerLogic(_ => ZIO.succeed(plainTextMessage)) + + private val jsonEndpoint: ZServerEndpoint[Any, Any] = + endpoint.get.in("json") + .out(header(HeaderNames.Server, STATIC_SERVER_NAME)) + .out(jsonBody[Payload]) + .zServerLogic(_ => ZIO.succeed(Payload(plainTextMessage))) + + + private val declaredPort = 8080 + private val declaredHost = "0.0.0.0" + + private val routes: HttpRoutes[Task] = ZHttp4sServerInterpreter() + .from(List(plaintextEndpoint, jsonEndpoint)) + .toRoutes + + implicit val ec: ExecutionContext = scala.concurrent.ExecutionContext.Implicits.global + + override def run: URIO[Any, ExitCode] = + ZIO.executor.flatMap(executor => + BlazeServerBuilder[Task] + .withExecutionContext(executor.asExecutionContext) + .bindHttp(8080, declaredHost) + .withHttpApp(Router("/" -> routes).orNotFound) + .serve + .compile + .drain + ).exitCode diff --git a/frameworks/Scala/tapir/http4s-server/src/main/scala/TapirHttp4sServerBenchmark.scala b/frameworks/Scala/tapir/http4s-server/src/main/scala/TapirHttp4sServerBenchmark.scala new file mode 100644 index 00000000000..f8dadd8d446 --- /dev/null +++ b/frameworks/Scala/tapir/http4s-server/src/main/scala/TapirHttp4sServerBenchmark.scala @@ -0,0 +1,50 @@ +import cats.effect.{ExitCode, IO, IOApp} +import io.circe.generic.auto.* +import org.http4s.HttpRoutes +import org.http4s.blaze.server.BlazeServerBuilder +import org.http4s.server.Router +import sttp.model.{Header, HeaderNames, StatusCode} +import sttp.tapir.* +import sttp.tapir.generic.auto.* +import sttp.tapir.json.circe.* +import sttp.tapir.server.http4s.Http4sServerInterpreter + +import java.time.format.DateTimeFormatter +import java.time.{Clock, LocalDateTime, ZoneOffset, ZonedDateTime} +import java.util.Date +import java.util.concurrent.locks.LockSupport +import scala.concurrent.ExecutionContext + +object TapirHttp4sServerBenchmark extends IOApp: + private val STATIC_SERVER_NAME = "tapir-http4s-server" + + private val plainTextMessage: String = "Hello, World!" + + val plaintextEndpoint = + endpoint.get.in("plaintext") + .out(header(HeaderNames.Server, STATIC_SERVER_NAME)) + .out(stringBody) + .serverLogic(_ => IO.pure[Either[Unit, String]](Right(plainTextMessage))) + + val jsonEndpoint = + endpoint.get.in("json") + .out(header(HeaderNames.Server, STATIC_SERVER_NAME)) + .out(jsonBody[Payload]) + .serverLogic(_ => IO.pure[Either[Unit, Payload]](Right(Payload(plainTextMessage)))) + + + private val declaredPort = 8080 + private val declaredHost = "0.0.0.0" + + val routes = Http4sServerInterpreter[IO]().toRoutes(List(plaintextEndpoint, jsonEndpoint)) + + implicit val ec: ExecutionContext = scala.concurrent.ExecutionContext.Implicits.global + + override def run(args: List[String]): IO[ExitCode] = + BlazeServerBuilder[IO] + .withExecutionContext(ec) + .bindHttp(declaredPort, declaredHost) + .withHttpApp(Router("/" -> routes).orNotFound) + .resource + .useForever + .as(ExitCode.Success) diff --git a/frameworks/Scala/tapir/netty-cats-server/src/main/scala/TapirNettyCatsServerBenchmark.scala b/frameworks/Scala/tapir/netty-cats-server/src/main/scala/TapirNettyCatsServerBenchmark.scala new file mode 100644 index 00000000000..824b538a079 --- /dev/null +++ b/frameworks/Scala/tapir/netty-cats-server/src/main/scala/TapirNettyCatsServerBenchmark.scala @@ -0,0 +1,54 @@ +import cats.effect.{IO, IOApp} +import io.circe.generic.auto.* +import sttp.model.{Header, HeaderNames} +import sttp.tapir.* +import sttp.tapir.generic.auto.* +import sttp.tapir.json.circe.* +import sttp.tapir.server.netty.cats.NettyCatsServer + +import java.time.Instant + +object TapirNettyCatsServerBenchmark extends IOApp.Simple: + private val STATIC_SERVER_NAME = "tapir-netty-cats-server" + + private val plainTextMessage: String = "Hello, World!" + + val plaintextEndpoint = + endpoint.get.in("plaintext") + .out(header(HeaderNames.Server, STATIC_SERVER_NAME)) + .out(header[String](HeaderNames.Date)) + .out(stringBody) + .serverLogic(_ => + for { + now <- IO.realTime.map(time => Instant.ofEpochMilli(time.toMillis)) + } yield Right(Header.toHttpDateString(now) -> plainTextMessage) + ) + + val jsonEndpoint = + endpoint.get.in("json") + .out(header(HeaderNames.Server, STATIC_SERVER_NAME)) + .out(header[String](HeaderNames.Date)) + .out(jsonBody[Payload]) + .serverLogic(_ => + for { + now <- IO.realTime.map(time => Instant.ofEpochMilli(time.toMillis)) + } yield Right(Header.toHttpDateString(now) -> Payload(plainTextMessage)) + ) + + + private val declaredPort = 8080 + private val declaredHost = "0.0.0.0" + + override def run = NettyCatsServer + .io() + .use { server => + for { + _ <- server + .port(declaredPort) + .host(declaredHost) + .addEndpoint(plaintextEndpoint) + .addEndpoint(jsonEndpoint) + .start() + _ <- IO.never + } yield () + } diff --git a/frameworks/Scala/tapir/netty-kyo-server/src/main/scala/TapirNettyKyoServerBenchmark.scala b/frameworks/Scala/tapir/netty-kyo-server/src/main/scala/TapirNettyKyoServerBenchmark.scala new file mode 100644 index 00000000000..f8cbdb4618c --- /dev/null +++ b/frameworks/Scala/tapir/netty-kyo-server/src/main/scala/TapirNettyKyoServerBenchmark.scala @@ -0,0 +1,52 @@ +import kyo.* +import sttp.model.{Header, HeaderNames} +import sttp.tapir.* +import sttp.tapir.json.zio.* +import sttp.tapir.server.netty.* +import zio.json.* + +object TapirNettyKyoServerBenchmark extends KyoApp { + private val STATIC_SERVER_NAME = "kyo-tapir" + + private val plainTextMessage: String = "Hello, World!" + + private given JsonCodec[Payload] = DeriveJsonCodec.gen + private given Schema[Payload] = Schema.derived + + run { + val plaintextRoute: Unit < Routes = + Routes.add( + _.get.in("plaintext") + .out(header(HeaderNames.Server, STATIC_SERVER_NAME)) + .out(header[String](HeaderNames.Date)) + .out(stringBody) + ) { _ => + for { + now <- Clock.now + } yield Header.toHttpDateString(now.toJava) -> plainTextMessage + } + + val jsonRoute: Unit < Routes = + Routes.add( + _.get.in("json") + .out(header(HeaderNames.Server, STATIC_SERVER_NAME)) + .out(header[String](HeaderNames.Date)) + .out(jsonBody[Payload]) + ) { _ => + for { + now <- Clock.now + } yield Header.toHttpDateString(now.toJava) -> Payload(plainTextMessage) + } + + val config = NettyConfig.default + .withSocketKeepAlive + .copy(lingerTimeout = None) + + val server = NettyKyoServer(config).host("0.0.0.0").port(8080) + + val binding: NettyKyoServerBinding < Async = + Routes.run(server)(plaintextRoute.andThen(jsonRoute)) + + binding + } +} \ No newline at end of file diff --git a/frameworks/Scala/tapir/netty-zio-server/src/main/scala/TapirNettyZioServerBenchmark.scala b/frameworks/Scala/tapir/netty-zio-server/src/main/scala/TapirNettyZioServerBenchmark.scala new file mode 100644 index 00000000000..fbd2fa34477 --- /dev/null +++ b/frameworks/Scala/tapir/netty-zio-server/src/main/scala/TapirNettyZioServerBenchmark.scala @@ -0,0 +1,57 @@ +import sttp.model.{Header, HeaderNames} +import sttp.tapir.Schema +import sttp.tapir.json.zio.* +import sttp.tapir.server.netty.zio.NettyZioServer +import sttp.tapir.ztapir.* +import zio.* +import zio.json.* +import sttp.tapir.server.netty.* + +object TapirNettyZioServerBenchmark extends ZIOAppDefault { + private val STATIC_SERVER_NAME = "tapir-netty-zio-server" + + private val plainTextMessage: String = "Hello, World!" + + given JsonCodec[Payload] = DeriveJsonCodec.gen + given Schema[Payload] = Schema.derived + + override def run = { + val plaintextRoute: ZServerEndpoint[Any, Any] = + endpoint.get.in("plaintext") + .out(header(HeaderNames.Server, STATIC_SERVER_NAME)) + .out(header[String](HeaderNames.Date)) + .out(stringBody) + .zServerLogic { _ => + for { + now <- Clock.currentDateTime + } yield Header.toHttpDateString(now.toInstant) -> plainTextMessage + } + + val jsonRoute: ZServerEndpoint[Any, Any] = + endpoint.get.in("json") + .out(header(HeaderNames.Server, STATIC_SERVER_NAME)) + .out(header[String](HeaderNames.Date)) + .out(jsonBody[Payload]) + .zServerLogic { _ => + for { + now <- Clock.currentDateTime + } yield Header.toHttpDateString(now.toInstant) -> Payload(plainTextMessage) + } + + val config = NettyConfig.default + .withSocketKeepAlive + .copy(lingerTimeout = None) + + + + val server = NettyZioServer[Any](config) + .addEndpoint(plaintextRoute) + .addEndpoint(jsonRoute) + .host("0.0.0.0") + .port(8080) + + server.start().flatMap { _ => + ZIO.never + } + } +} \ No newline at end of file diff --git a/frameworks/Scala/tapir/pekko-http-server/src/main/scala/Main.scala b/frameworks/Scala/tapir/pekko-http-server/src/main/scala/Main.scala new file mode 100644 index 00000000000..ebcdd901368 --- /dev/null +++ b/frameworks/Scala/tapir/pekko-http-server/src/main/scala/Main.scala @@ -0,0 +1,42 @@ +import io.circe.generic.auto.* +import org.apache.pekko.actor.ActorSystem +import org.apache.pekko.http.scaladsl.Http +import sttp.model.HeaderNames +import sttp.tapir.* +import sttp.tapir.json.circe.* +import sttp.tapir.server.pekkohttp.PekkoHttpServerInterpreter + +import scala.concurrent.Future + +@main def tapirPekkoServerBenchmark(): Unit = { + implicit val actorSystem: ActorSystem = ActorSystem() + import actorSystem.dispatcher + + val STATIC_SERVER_NAME = "tapir-pekko-http-server" + + val plainTextMessage: String = "Hello, World!" + + given Schema[Payload] = Schema.derived + + val plaintextRoute = + endpoint.get + .in("plaintext") + .out(header(HeaderNames.Server, STATIC_SERVER_NAME)) + .out(stringBody) + .serverLogic[Future] { _ => + Future.successful(Right(plainTextMessage)) + } + + val jsonRoute = + endpoint.get + .in("json") + .out(header(HeaderNames.Server, STATIC_SERVER_NAME)) + .out(jsonBody[Payload]) + .serverLogic[Future] { _ => + Future.successful(Right(Payload(plainTextMessage))) + } + + val route = PekkoHttpServerInterpreter().toRoute(List(plaintextRoute, jsonRoute)) + + Http().newServerAt("0.0.0.0", 8080).bindFlow(route) +} \ No newline at end of file diff --git a/frameworks/Scala/tapir/project/build.properties b/frameworks/Scala/tapir/project/build.properties new file mode 100644 index 00000000000..00a19d65b65 --- /dev/null +++ b/frameworks/Scala/tapir/project/build.properties @@ -0,0 +1 @@ +sbt.version = 1.10.11 \ No newline at end of file diff --git a/frameworks/Scala/tapir/project/plugins.sbt b/frameworks/Scala/tapir/project/plugins.sbt new file mode 100644 index 00000000000..f8ea5d0fbb0 --- /dev/null +++ b/frameworks/Scala/tapir/project/plugins.sbt @@ -0,0 +1 @@ +addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "2.3.1") diff --git a/frameworks/Scala/tapir/tapir-http4s-zio.dockerfile b/frameworks/Scala/tapir/tapir-http4s-zio.dockerfile new file mode 100644 index 00000000000..7ef30135459 --- /dev/null +++ b/frameworks/Scala/tapir/tapir-http4s-zio.dockerfile @@ -0,0 +1,11 @@ +FROM sbtscala/scala-sbt:eclipse-temurin-21.0.6_7_1.10.11_3.6.4 + +WORKDIR /tapir-benchmark +COPY http4s-server-zio http4s-server-zio +COPY common common +COPY project project +COPY build.sbt build.sbt +RUN sbt http4s-server-zio/assembly + +EXPOSE 8080 +CMD ["java", "-Xms2G", "-Xmx2G", "-server", "-jar", "/tapir-benchmark/http4s-server-zio/target/scala-3.6.4/tapir-http4s-server-zio-assembly-1.0.0.jar"] \ No newline at end of file diff --git a/frameworks/Scala/tapir/tapir-http4s.dockerfile b/frameworks/Scala/tapir/tapir-http4s.dockerfile new file mode 100644 index 00000000000..892210bc692 --- /dev/null +++ b/frameworks/Scala/tapir/tapir-http4s.dockerfile @@ -0,0 +1,11 @@ +FROM sbtscala/scala-sbt:eclipse-temurin-21.0.6_7_1.10.11_3.6.4 + +WORKDIR /tapir-benchmark +COPY http4s-server http4s-server +COPY common common +COPY project project +COPY build.sbt build.sbt +RUN sbt http4s-server/assembly + +EXPOSE 8080 +CMD ["java", "-Xms2G", "-Xmx2G", "-server", "-jar", "/tapir-benchmark/http4s-server/target/scala-3.6.4/tapir-http4s-server-assembly-1.0.0.jar"] \ No newline at end of file diff --git a/frameworks/Scala/tapir/tapir-netty-cats.dockerfile b/frameworks/Scala/tapir/tapir-netty-cats.dockerfile new file mode 100644 index 00000000000..5dec450e3d5 --- /dev/null +++ b/frameworks/Scala/tapir/tapir-netty-cats.dockerfile @@ -0,0 +1,11 @@ +FROM sbtscala/scala-sbt:eclipse-temurin-21.0.6_7_1.10.11_3.6.4 + +WORKDIR /tapir-benchmark +COPY netty-cats-server netty-cats-server +COPY common common +COPY project project +COPY build.sbt build.sbt +RUN sbt netty-cats-server/assembly + +EXPOSE 8080 +CMD ["java", "-Xms2G", "-Xmx2G", "-server", "-Dio.netty.leakDetection.level=disabled", "-Dio.netty.recycler.maxCapacityPerThread=0", "-jar", "/tapir-benchmark/netty-cats-server/target/scala-3.6.4/tapir-netty-cats-server-assembly-1.0.0.jar"] \ No newline at end of file diff --git a/frameworks/Scala/tapir/tapir-netty-kyo.dockerfile b/frameworks/Scala/tapir/tapir-netty-kyo.dockerfile new file mode 100644 index 00000000000..ed7a5991624 --- /dev/null +++ b/frameworks/Scala/tapir/tapir-netty-kyo.dockerfile @@ -0,0 +1,11 @@ +FROM sbtscala/scala-sbt:eclipse-temurin-21.0.6_7_1.10.11_3.6.4 + +WORKDIR /tapir-benchmark +COPY netty-kyo-server netty-kyo-server +COPY common common +COPY project project +COPY build.sbt build.sbt +RUN sbt netty-kyo-server/assembly + +EXPOSE 8080 +CMD ["java", "-Xms2G", "-Xmx2G", "-server", "-Dio.netty.leakDetection.level=disabled", "-Dio.netty.recycler.maxCapacityPerThread=0", "-jar", "/tapir-benchmark/netty-kyo-server/target/scala-3.6.4/tapir-netty-kyo-server-assembly-1.0.0.jar"] \ No newline at end of file diff --git a/frameworks/Scala/tapir/tapir-netty-zio.dockerfile b/frameworks/Scala/tapir/tapir-netty-zio.dockerfile new file mode 100644 index 00000000000..aa9c3607080 --- /dev/null +++ b/frameworks/Scala/tapir/tapir-netty-zio.dockerfile @@ -0,0 +1,11 @@ +FROM sbtscala/scala-sbt:eclipse-temurin-21.0.6_7_1.10.11_3.6.4 + +WORKDIR /tapir-benchmark +COPY netty-zio-server netty-zio-server +COPY common common +COPY project project +COPY build.sbt build.sbt +RUN sbt netty-zio-server/assembly + +EXPOSE 8080 +CMD ["java", "-Xms2G", "-Xmx2G", "-server", "-Dio.netty.leakDetection.level=disabled", "-Dio.netty.recycler.maxCapacityPerThread=0", "-jar", "/tapir-benchmark/netty-zio-server/target/scala-3.6.4/tapir-netty-zio-server-assembly-1.0.0.jar"] \ No newline at end of file diff --git a/frameworks/Scala/tapir/tapir-pekko-http.dockerfile b/frameworks/Scala/tapir/tapir-pekko-http.dockerfile new file mode 100644 index 00000000000..f21480ae5be --- /dev/null +++ b/frameworks/Scala/tapir/tapir-pekko-http.dockerfile @@ -0,0 +1,11 @@ +FROM sbtscala/scala-sbt:eclipse-temurin-21.0.6_7_1.10.11_3.6.4 + +WORKDIR /tapir-benchmark +COPY pekko-http-server pekko-http-server +COPY common common +COPY project project +COPY build.sbt build.sbt +RUN sbt pekko-http-server/assembly + +EXPOSE 8080 +CMD ["java", "-Xms2G", "-Xmx2G", "-server", "-jar", "/tapir-benchmark/pekko-http-server/target/scala-3.6.4/tapir-pekko-http-server-assembly-1.0.0.jar"] \ No newline at end of file diff --git a/frameworks/Scala/tapir/tapir.dockerfile b/frameworks/Scala/tapir/tapir.dockerfile new file mode 100644 index 00000000000..33e2438eea7 --- /dev/null +++ b/frameworks/Scala/tapir/tapir.dockerfile @@ -0,0 +1,11 @@ +FROM sbtscala/scala-sbt:eclipse-temurin-21.0.6_7_1.10.11_3.6.4 + +WORKDIR /tapir-benchmark +COPY zio-http-server zio-http-server +COPY common common +COPY project project +COPY build.sbt build.sbt +RUN sbt zio-http-server/assembly + +EXPOSE 8080 +CMD ["java", "-Xms2G", "-Xmx2G", "-server", "-Dio.netty.leakDetection.level=disabled", "-Dio.netty.recycler.maxCapacityPerThread=0", "-jar", "/tapir-benchmark/zio-http-server/target/scala-3.6.4/tapir-zio-http-server-assembly-1.0.0.jar"] \ No newline at end of file diff --git a/frameworks/Scala/tapir/zio-http-server/src/main/scala/TapirZioHttpServerBenchmark.scala b/frameworks/Scala/tapir/zio-http-server/src/main/scala/TapirZioHttpServerBenchmark.scala new file mode 100644 index 00000000000..59e189b01bd --- /dev/null +++ b/frameworks/Scala/tapir/zio-http-server/src/main/scala/TapirZioHttpServerBenchmark.scala @@ -0,0 +1,56 @@ +import sttp.model.{Header, HeaderNames} +import sttp.tapir.Schema +import sttp.tapir.json.zio.* +import sttp.tapir.server.ziohttp.ZioHttpInterpreter +import sttp.tapir.ztapir.* +import zio.* +import zio.http.netty.NettyConfig +import zio.http.netty.NettyConfig.LeakDetectionLevel +import zio.http.{Request, Response, Routes, Server} +import zio.json.* + +import java.lang.Runtime as JRuntime + +object TapirZioHttpServerBenchmark extends ZIOAppDefault { + private val STATIC_SERVER_NAME = "zio-http-tapir" + + private val plainTextMessage: String = "Hello, World!" + private val NUM_PROCESSORS = JRuntime.getRuntime.availableProcessors() + + given JsonCodec[Payload] = DeriveJsonCodec.gen + given Schema[Payload] = Schema.derived + + override def run = { + val plaintextRoute: ZServerEndpoint[Any, Any] = + endpoint.get.in("plaintext") + .out(header(HeaderNames.Server, STATIC_SERVER_NAME)) + .out(stringBody) + .zServerLogic { _ => + ZIO.succeed(plainTextMessage) + } + + val jsonRoute: ZServerEndpoint[Any, Any] = + endpoint.get.in("json") + .out(header(HeaderNames.Server, STATIC_SERVER_NAME)) + .out(jsonBody[Payload]) + .zServerLogic { _ => + ZIO.succeed(Payload(plainTextMessage)) + } + + val app = ZioHttpInterpreter().toHttp(List(plaintextRoute, jsonRoute)) + + + val config = Server.Config.default + .port(8080) + .enableRequestStreaming + + val nettyConfig = NettyConfig.default + .leakDetection(LeakDetectionLevel.DISABLED) + .maxThreads(NUM_PROCESSORS) + + val configLayer = ZLayer.succeed(config) + val nettyConfigLayer = ZLayer.succeed(nettyConfig) + + Server.serve(app).provide(configLayer, nettyConfigLayer, Server.customized).exitCode + } +} \ No newline at end of file diff --git a/frameworks/Scala/vertx-web-scala/benchmark_config.json b/frameworks/Scala/vertx-web-scala/benchmark_config.json index d5f73751a49..4a8c4242d34 100755 --- a/frameworks/Scala/vertx-web-scala/benchmark_config.json +++ b/frameworks/Scala/vertx-web-scala/benchmark_config.json @@ -8,6 +8,7 @@ "fortune_url": "/fortunes", "update_url": "/updates?queries=", "plaintext_url": "/plaintext", + "json_url": "/json", "port": 8080, "approach": "Realistic", "classification": "Micro", diff --git a/frameworks/Scala/vertx-web-scala/build.sbt b/frameworks/Scala/vertx-web-scala/build.sbt index 668c7c86e16..5a75b7a6502 100644 --- a/frameworks/Scala/vertx-web-scala/build.sbt +++ b/frameworks/Scala/vertx-web-scala/build.sbt @@ -2,7 +2,7 @@ name := "vertx-web-scala" version := "1" -scalaVersion := "2.12.17" +scalaVersion := "2.12.20" lazy val root = (project in file(".")).enablePlugins(SbtTwirl) diff --git a/frameworks/Scala/vertx-web-scala/project/build.properties b/frameworks/Scala/vertx-web-scala/project/build.properties index 46e43a97ed8..cc68b53f1a3 100644 --- a/frameworks/Scala/vertx-web-scala/project/build.properties +++ b/frameworks/Scala/vertx-web-scala/project/build.properties @@ -1 +1 @@ -sbt.version=1.8.2 +sbt.version=1.10.11 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 469ba0512d6..0f2991c3b47 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 @@ -26,7 +26,7 @@ import scala.util.{Failure, Sorting, Success, Try} case class Header(name: CharSequence, value: String) class App extends ScalaVerticle { - + import App._ private val HELLO_WORLD = "Hello, world!" private val HELLO_WORLD_BUFFER = Buffer.buffer(HELLO_WORLD, "UTF-8") private val SERVER = "vert.x" @@ -116,8 +116,7 @@ class App extends ScalaVerticle { .end(World(row.getInteger(0), row.getInteger(1)).encode()) } } else { - App.logger.error("Failed to handle request", ar.cause()) - request.response.setStatusCode(500).end(ar.cause.getMessage) + sendError(request, ar.cause, "Failed to handle Db request") } } ) @@ -136,7 +135,7 @@ class App extends ScalaVerticle { if (!failed) { if (ar.failed) { failed = true - request.response.setStatusCode(500).end(ar.cause.getMessage) + sendError(request, ar.cause, "Failed to handle Queries request") return } // we need a final reference @@ -155,11 +154,6 @@ class App extends ScalaVerticle { } private def handleUpdates(request: HttpServerRequest): Unit = { - def sendError(err: Throwable): Unit = { - App.logger.error("", err) - request.response.setStatusCode(500).end(err.getMessage) - } - def handleUpdates(conn: SqlConnection, worlds: Array[World]): Unit = { Sorting.quickSort(worlds) @@ -170,7 +164,7 @@ class App extends ScalaVerticle { batch, (ar: AsyncResult[RowSet[Row]]) => { if (ar.failed) { - sendError(ar.cause) + sendError(request, ar.cause, "handleUpdates: failed to update DB") return } @@ -197,7 +191,7 @@ class App extends ScalaVerticle { if (!failed) { if (ar2.failed) { failed = true - sendError(ar2.cause) + sendError(request, ar2.cause, "handleUpdates: failed to read DB") return } worlds(index) = World(ar2.result.iterator.next.getInteger(0), App.randomWorld()) @@ -206,7 +200,6 @@ class App extends ScalaVerticle { } } ) - i += 1 } } @@ -230,9 +223,7 @@ class App extends ScalaVerticle { responseWithHeaders(request.response, contentTypeHtml) .end(html.fortune(fortunes).body) } else { - val err = ar.cause - App.logger.error("", err) - response.setStatusCode(500).end(err.getMessage) + sendError(request, ar.cause, "handleFortunes failed to update DB") } } ) @@ -241,9 +232,9 @@ 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(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) @@ -299,4 +290,9 @@ object App { logger.info("Event Loop Size: {}", JVertxOptions.DEFAULT_EVENT_LOOP_POOL_SIZE) logger.info("Native transport: {}", vertx.isNativeTransportEnabled) } + + def sendError(request: HttpServerRequest, err: Throwable, msg: String = ""): Unit = { + App.logger.error(msg, err) + request.response.setStatusCode(500).end(err.getMessage) + } } diff --git a/frameworks/Scala/vertx-web-scala/vertx-web-scala.dockerfile b/frameworks/Scala/vertx-web-scala/vertx-web-scala.dockerfile index 536e92fe8fe..047d042d2dc 100644 --- a/frameworks/Scala/vertx-web-scala/vertx-web-scala.dockerfile +++ b/frameworks/Scala/vertx-web-scala/vertx-web-scala.dockerfile @@ -1,4 +1,4 @@ -FROM sbtscala/scala-sbt:eclipse-temurin-17.0.5_8_1.8.2_2.12.17 +FROM sbtscala/scala-sbt:eclipse-temurin-21.0.6_7_1.10.11_2.12.20 ARG SBT_VERSION=1.8.2 diff --git a/frameworks/Scala/youi/build.sbt b/frameworks/Scala/youi/build.sbt index f9bf305fbbd..9a91d56bdfb 100644 --- a/frameworks/Scala/youi/build.sbt +++ b/frameworks/Scala/youi/build.sbt @@ -1,6 +1,6 @@ name := "youi-server" version := "1.0" -scalaVersion := "2.13.3" +scalaVersion := "2.13.16" libraryDependencies ++= Seq( "io.youi" %% "youi-server" % "0.13.17", diff --git a/frameworks/Scala/youi/project/build.properties b/frameworks/Scala/youi/project/build.properties index b80399a6ad9..af06c851bbb 100644 --- a/frameworks/Scala/youi/project/build.properties +++ b/frameworks/Scala/youi/project/build.properties @@ -1 +1 @@ -sbt.version=1.4.2 \ No newline at end of file +sbt.version=1.10.11 \ No newline at end of file diff --git a/frameworks/Scala/youi/project/plugins.sbt b/frameworks/Scala/youi/project/plugins.sbt index 53ea63437dd..0750d5f24e1 100644 --- a/frameworks/Scala/youi/project/plugins.sbt +++ b/frameworks/Scala/youi/project/plugins.sbt @@ -1 +1,3 @@ -addSbtPlugin("org.xerial.sbt" % "sbt-pack" % "0.13") \ No newline at end of file +addSbtPlugin("org.xerial.sbt" % "sbt-pack" % "0.13") + +libraryDependencySchemes += "org.scala-lang.modules" %% "scala-xml" % "always" diff --git a/frameworks/Scala/youi/youi.dockerfile b/frameworks/Scala/youi/youi.dockerfile index 8b69d3a395f..7ff252d0a5e 100644 --- a/frameworks/Scala/youi/youi.dockerfile +++ b/frameworks/Scala/youi/youi.dockerfile @@ -1,4 +1,4 @@ -FROM hseeberger/scala-sbt:8u151-2.12.5-1.1.2 +FROM sbtscala/scala-sbt:eclipse-temurin-21.0.6_7_1.10.11_2.13.16 WORKDIR /youi COPY project project COPY src src diff --git a/frameworks/Scala/zio-http/README.md b/frameworks/Scala/zio-http/README.md index b5ea957391f..e9eb2759004 100644 --- a/frameworks/Scala/zio-http/README.md +++ b/frameworks/Scala/zio-http/README.md @@ -9,7 +9,7 @@ This is the ZIO Http portion of a [benchmarking test suite](../) comparing a var ## Versions -* [Java OpenJDK 11](https://openjdk.java.net/) +* [Java OpenJDK 21](https://openjdk.java.net/) ## Test URLs diff --git a/frameworks/Scala/zio-http/build.sbt b/frameworks/Scala/zio-http/build.sbt index 987ee8cbbd2..4c0157b1354 100644 --- a/frameworks/Scala/zio-http/build.sbt +++ b/frameworks/Scala/zio-http/build.sbt @@ -1,13 +1,14 @@ name := "zio-http" version := "1.0.0" -scalaVersion := "2.13.6" +scalaVersion := "2.13.16" lazy val root = (project in file(".")) .settings( - libraryDependencies ++= - Seq( - "com.github.plokhotnyuk.jsoniter-scala" %% "jsoniter-scala-core" % "2.9.1", - "com.github.plokhotnyuk.jsoniter-scala" %% "jsoniter-scala-macros" % "2.9.1" % "compile-internal", - "io.d11" % "zhttp" % "1.0.0-RC5", - ), + libraryDependencies += "dev.zio" %% "zio-http" % "3.2.0", testFrameworks += new TestFramework("zio.test.sbt.ZTestFramework"), + assembly / assemblyMergeStrategy := { + case x if x.contains("io.netty.versions.properties") => MergeStrategy.discard + case x => + val oldStrategy = (assembly / assemblyMergeStrategy).value + oldStrategy(x) + } ) diff --git a/frameworks/Scala/zio-http/project/build.properties b/frameworks/Scala/zio-http/project/build.properties index 215ddd2b39d..ee06c398644 100644 --- a/frameworks/Scala/zio-http/project/build.properties +++ b/frameworks/Scala/zio-http/project/build.properties @@ -1 +1 @@ -sbt.version = 1.5.5 \ No newline at end of file +sbt.version = 1.10.0 \ No newline at end of file diff --git a/frameworks/Scala/zio-http/project/plugins.sbt b/frameworks/Scala/zio-http/project/plugins.sbt index 585d1930dc6..ec25e7aa776 100644 --- a/frameworks/Scala/zio-http/project/plugins.sbt +++ b/frameworks/Scala/zio-http/project/plugins.sbt @@ -1 +1 @@ -addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "1.0.0") +addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "2.1.0") diff --git a/frameworks/Scala/zio-http/src/main/scala/Main.scala b/frameworks/Scala/zio-http/src/main/scala/Main.scala index b72da4e089c..652a4a43357 100644 --- a/frameworks/Scala/zio-http/src/main/scala/Main.scala +++ b/frameworks/Scala/zio-http/src/main/scala/Main.scala @@ -1,42 +1,44 @@ -import zhttp.http._ -import zhttp.service.Server -import zio.{App, ExitCode, URIO} -import com.github.plokhotnyuk.jsoniter_scala.macros._ -import com.github.plokhotnyuk.jsoniter_scala.core._ -import zhttp.http.Response - -import java.time.format.DateTimeFormatter -import java.time.{Instant, ZoneOffset} - -case class Message(message: String) - -object Main extends App { - val message: String = "Hello, World!" - implicit val codec: JsonValueCodec[Message] = JsonCodecMaker.make - - val app: Http[Any, HttpError, Request, Response] = Http.collect[Request] { - case Method.GET -> Root / "plaintext" => - Response.http( - content = HttpContent.Complete(message), - headers = Header.contentTypeTextPlain :: headers(), - ) - case Method.GET -> Root / "json" => - Response.http( - content = HttpContent.Complete(writeToString(Message(message))), - headers = Header.contentTypeJson :: headers(), - ) - } - - override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] = Server.start(8080, app).exitCode - - val formatter: DateTimeFormatter = DateTimeFormatter.RFC_1123_DATE_TIME.withZone(ZoneOffset.UTC) - val constantHeaders: List[Header] = Header("server", "zio-http") :: Nil - @volatile var lastHeaders: (Long, List[Header]) = (0, Nil) - - def headers(): List[Header] = { - val t = System.currentTimeMillis() - if (t - lastHeaders._1 >= 1000) - lastHeaders = (t, Header("date", formatter.format(Instant.ofEpochMilli(t))) :: constantHeaders) - lastHeaders._2 - } -} +import zio._ +import zio.http._ +import zio.http.netty.NettyConfig +import zio.http.netty.NettyConfig.LeakDetectionLevel +import zio.json.EncoderOps + +import java.lang.{Runtime => JRuntime} + +object Main extends ZIOAppDefault { + + private val plainTextMessage: String = "hello, world!" + + private val STATIC_SERVER_NAME = "zio-http" + private val NUM_PROCESSORS = JRuntime.getRuntime.availableProcessors() + + val app: Routes[Any, Response] = Routes( + Method.GET / "/plaintext" -> + Handler.fromResponse( + Response + .text(plainTextMessage) + .addHeader(Header.Server(STATIC_SERVER_NAME)), + ), + Method.GET / "/json" -> + Handler.fromResponse( + Response + .json(Payload(plainTextMessage).toJson) + .addHeader(Header.Server(STATIC_SERVER_NAME)), + ), + ) + + private val config = Server.Config.default + .port(8080) + .enableRequestStreaming + + private val nettyConfig = NettyConfig.default + .leakDetection(LeakDetectionLevel.DISABLED) + .maxThreads(NUM_PROCESSORS) + + private val configLayer = ZLayer.succeed(config) + private val nettyConfigLayer = ZLayer.succeed(nettyConfig) + + val run: UIO[ExitCode] = + Server.serve(app).provide(configLayer, nettyConfigLayer, Server.customized).exitCode +} \ No newline at end of file diff --git a/frameworks/Scala/zio-http/src/main/scala/Payload.scala b/frameworks/Scala/zio-http/src/main/scala/Payload.scala new file mode 100644 index 00000000000..86b4fc705d7 --- /dev/null +++ b/frameworks/Scala/zio-http/src/main/scala/Payload.scala @@ -0,0 +1,6 @@ +import zio.json.{DeriveJsonCodec, JsonCodec} + +case class Payload(message: String) +object Payload { + implicit val codec: JsonCodec[Payload] = DeriveJsonCodec.gen +} \ No newline at end of file diff --git a/frameworks/Scala/zio-http/zio-http.dockerfile b/frameworks/Scala/zio-http/zio-http.dockerfile index f05ead620fe..5c814e5887a 100644 --- a/frameworks/Scala/zio-http/zio-http.dockerfile +++ b/frameworks/Scala/zio-http/zio-http.dockerfile @@ -1,4 +1,4 @@ -FROM hseeberger/scala-sbt:11.0.12_1.5.5_2.13.6 +FROM sbtscala/scala-sbt:eclipse-temurin-21.0.6_7_1.10.11_2.13.16 WORKDIR /zhttp COPY src src diff --git a/frameworks/Swift/.gitignore b/frameworks/Swift/.gitignore new file mode 100644 index 00000000000..e638150e387 --- /dev/null +++ b/frameworks/Swift/.gitignore @@ -0,0 +1,8 @@ +.DS_Store +.build/ +/*.xcodeproj +xcuserdata/ +.swiftpm/ +DerivedData/ +Package.resolved +.vscode/ diff --git a/frameworks/Swift/README.md b/frameworks/Swift/README.md index 367e5b6b0c0..878251045c8 100644 --- a/frameworks/Swift/README.md +++ b/frameworks/Swift/README.md @@ -8,4 +8,5 @@ For further guidance, review the [documentation](https://frameworkbenchmarks.rea ### Swift Experts -[tanner0101](https://github.com/tanner0101) +[Adam Fowler](https://github.com/adam-fowler) +[Tim Condon](https://github.com/0xTim) diff --git a/frameworks/Swift/hummingbird-core/.gitignore b/frameworks/Swift/hummingbird-core/.gitignore deleted file mode 100644 index 1d982c0de86..00000000000 --- a/frameworks/Swift/hummingbird-core/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -.DS_Store -.build/ -/*.xcodeproj -xcuserdata/ -.swiftpm/ -DerivedData/ -Package.resolved diff --git a/frameworks/Swift/hummingbird-core/README.md b/frameworks/Swift/hummingbird-core/README.md index c8885474760..9f738a83389 100755 --- a/frameworks/Swift/hummingbird-core/README.md +++ b/frameworks/Swift/hummingbird-core/README.md @@ -9,7 +9,7 @@ Hummingbird Core is the HTTP server for the Hummingbird framework. ## Important Libraries This version of Hummingbird requires -* [Swift 5.7](https://swift.org) +* [Swift 5.10](https://swift.org) * [SwiftNIO 2.x](https://github.com/apple/swift-nio/) ## Test URLs diff --git a/frameworks/Swift/hummingbird-core/benchmark_config.json b/frameworks/Swift/hummingbird-core/benchmark_config.json index 8a78cb1a141..8b811b8656c 100755 --- a/frameworks/Swift/hummingbird-core/benchmark_config.json +++ b/frameworks/Swift/hummingbird-core/benchmark_config.json @@ -18,7 +18,7 @@ "database_os": "Linux", "display_name": "HummingbirdCore", "notes": "", - "versus": "None" + "versus": "swift-nio" } }] } diff --git a/frameworks/Swift/hummingbird-core/hummingbird-core.dockerfile b/frameworks/Swift/hummingbird-core/hummingbird-core.dockerfile index c384cc96fd0..2c474797381 100644 --- a/frameworks/Swift/hummingbird-core/hummingbird-core.dockerfile +++ b/frameworks/Swift/hummingbird-core/hummingbird-core.dockerfile @@ -1,7 +1,7 @@ # ================================ # Build image # ================================ -FROM swift:5.9 as build +FROM swift:6.1 AS build WORKDIR /build # Copy entire repo into container @@ -15,7 +15,7 @@ RUN swift build \ # ================================ # Run image # ================================ -FROM swift:5.9-slim +FROM swift:6.1-slim WORKDIR /run # Copy build artifacts diff --git a/frameworks/Swift/hummingbird/.gitignore b/frameworks/Swift/hummingbird/.gitignore deleted file mode 100644 index 1d982c0de86..00000000000 --- a/frameworks/Swift/hummingbird/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -.DS_Store -.build/ -/*.xcodeproj -xcuserdata/ -.swiftpm/ -DerivedData/ -Package.resolved diff --git a/frameworks/Swift/hummingbird/README.md b/frameworks/Swift/hummingbird/README.md index 3482a31f993..dc7d8af7b9c 100755 --- a/frameworks/Swift/hummingbird/README.md +++ b/frameworks/Swift/hummingbird/README.md @@ -13,7 +13,7 @@ Hummingbird is a lightweight, flexible HTTP server framework written in Swift. ## Important Libraries This version of Hummingbird requires -* [Swift 5.7](https://swift.org) +* [Swift 5.10](https://swift.org) * [SwiftNIO 2.x](https://github.com/apple/swift-nio/) In these tests for database access it uses * [PostgresKit 2.0](https://github.com/vapor/postgres-kit/) diff --git a/frameworks/Swift/hummingbird/benchmark_config.json b/frameworks/Swift/hummingbird/benchmark_config.json index 7b60aa6ec1b..91bff409efe 100755 --- a/frameworks/Swift/hummingbird/benchmark_config.json +++ b/frameworks/Swift/hummingbird/benchmark_config.json @@ -18,7 +18,7 @@ "database_os": "Linux", "display_name": "Hummingbird", "notes": "", - "versus": "None" + "versus": "swift-nio" }, "postgres": { "db_url": "/db", diff --git a/frameworks/Swift/hummingbird/hummingbird-postgres.dockerfile b/frameworks/Swift/hummingbird/hummingbird-postgres.dockerfile index 27e0d6aad07..544e4d8752e 100644 --- a/frameworks/Swift/hummingbird/hummingbird-postgres.dockerfile +++ b/frameworks/Swift/hummingbird/hummingbird-postgres.dockerfile @@ -1,7 +1,7 @@ # ================================ # Build image # ================================ -FROM swift:5.9 as build +FROM swift:6.1 AS build WORKDIR /build # Copy entire repo into container @@ -15,7 +15,7 @@ RUN swift build \ # ================================ # Run image # ================================ -FROM swift:5.9-slim +FROM swift:6.1-slim WORKDIR /run # Copy build artifacts diff --git a/frameworks/Swift/hummingbird/hummingbird.dockerfile b/frameworks/Swift/hummingbird/hummingbird.dockerfile index c384cc96fd0..2c474797381 100644 --- a/frameworks/Swift/hummingbird/hummingbird.dockerfile +++ b/frameworks/Swift/hummingbird/hummingbird.dockerfile @@ -1,7 +1,7 @@ # ================================ # Build image # ================================ -FROM swift:5.9 as build +FROM swift:6.1 AS build WORKDIR /build # Copy entire repo into container @@ -15,7 +15,7 @@ RUN swift build \ # ================================ # Run image # ================================ -FROM swift:5.9-slim +FROM swift:6.1-slim WORKDIR /run # Copy build artifacts diff --git a/frameworks/Swift/hummingbird2/README.md b/frameworks/Swift/hummingbird2/README.md new file mode 100755 index 00000000000..2a46d18fd45 --- /dev/null +++ b/frameworks/Swift/hummingbird2/README.md @@ -0,0 +1,44 @@ +# Hummingbird 2 Benchmarking Test + +Hummingbird 2 is a lightweight, flexible HTTP server framework written in Swift. HUmmingbird 2 is a complete rewrite using Swift concurrency. + +### Test Type Implementation Source Code + +* [JSON](src/Sources/server/main.swift) +* [PLAINTEXT](src/Sources/server/main.swift) +* [DB](src-postgres/Sources/server/Controllers/WorldController.swift) +* [Query](src-postgres/Sources/server/Controllers/WorldController.swift) +* [Updates](src-postgres/Sources/server/Controllers/WorldController.swift) +* [Fortunes](src-postgres/Sources/server/Controllers/FortunesController.swift) + +## Important Libraries +This version of Hummingbird requires +* [Swift 6.0](https://swift.org) +* [SwiftNIO 2.x](https://github.com/apple/swift-nio/) +In these tests for database access it uses +* [PostgresKit 2.21](https://github.com/vapor/postgres-nio/) + +## Test URLs +### JSON + +http://localhost:8080/json + +### PLAINTEXT + +http://localhost:8080/plaintext + +### DB + +http://localhost:8080/db + +### Query + +http://localhost:8080/queries?queries= + +### Updates + +http://localhost:8080/updates?queries= + +### Fortunes + +http://localhost:8080/fortunes diff --git a/frameworks/Swift/hummingbird2/benchmark_config.json b/frameworks/Swift/hummingbird2/benchmark_config.json new file mode 100755 index 00000000000..c6001e41811 --- /dev/null +++ b/frameworks/Swift/hummingbird2/benchmark_config.json @@ -0,0 +1,47 @@ +{ + "framework": "hummingbird2", + "tests": [ + { + "default": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "None", + "framework": "Hummingbird2", + "language": "Swift", + "flavor": "None", + "orm": "Raw", + "platform": "None", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "Hummingbird 2", + "notes": "", + "versus": "swift-nio" + }, + "postgres": { + "db_url": "/db", + "query_url": "/queries?queries=", + "update_url": "/updates?queries=", + "fortune_url": "/fortunes", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "postgres", + "framework": "Hummingbird2", + "language": "Swift", + "flavor": "None", + "orm": "Raw", + "platform": "None", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "Hummingbird 2", + "notes": "", + "versus": "None" + } + } + ] +} diff --git a/frameworks/Swift/hummingbird2/hummingbird2-postgres.dockerfile b/frameworks/Swift/hummingbird2/hummingbird2-postgres.dockerfile new file mode 100644 index 00000000000..dea0a3ddc22 --- /dev/null +++ b/frameworks/Swift/hummingbird2/hummingbird2-postgres.dockerfile @@ -0,0 +1,29 @@ +# ================================ +# Build image +# ================================ +FROM swift:6.2 AS build +WORKDIR /build + +# Copy entire repo into container +COPY ./src-postgres . + +# Compile with optimizations +RUN swift build \ + -c release \ + -Xswiftc -enforce-exclusivity=unchecked + +# ================================ +# Run image +# ================================ +FROM swift:6.2-slim +WORKDIR /run + +# Copy build artifacts +COPY --from=build /build/.build/release /run + +ENV SERVER_PORT=8080 +ENV SERVER_HOSTNAME=0.0.0.0 + +EXPOSE 8080 + +CMD ["./server"] diff --git a/frameworks/Swift/hummingbird2/hummingbird2.dockerfile b/frameworks/Swift/hummingbird2/hummingbird2.dockerfile new file mode 100644 index 00000000000..79f0d72c891 --- /dev/null +++ b/frameworks/Swift/hummingbird2/hummingbird2.dockerfile @@ -0,0 +1,29 @@ +# ================================ +# Build image +# ================================ +FROM swift:6.2 AS build +WORKDIR /build + +# Copy entire repo into container +COPY ./src . + +# Compile with optimizations +RUN swift build \ + -c release \ + -Xswiftc -enforce-exclusivity=unchecked + +# ================================ +# Run image +# ================================ +FROM swift:6.2-slim +WORKDIR /run + +# Copy build artifacts +COPY --from=build /build/.build/release /run + +ENV SERVER_PORT=8080 +ENV SERVER_HOSTNAME=0.0.0.0 + +EXPOSE 8080 + +CMD ["./server"] diff --git a/frameworks/Swift/hummingbird2/src-postgres/Package.swift b/frameworks/Swift/hummingbird2/src-postgres/Package.swift new file mode 100644 index 00000000000..840869e7289 --- /dev/null +++ b/frameworks/Swift/hummingbird2/src-postgres/Package.swift @@ -0,0 +1,30 @@ +// swift-tools-version:6.1 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription + +let package = Package( + name: "server", + platforms: [.macOS(.v14)], + dependencies: [ + .package(url: "https://github.com/hummingbird-project/hummingbird.git", from: "2.16.0"), + .package(url: "https://github.com/hummingbird-project/swift-mustache.git", from: "2.0.0"), + .package(url: "https://github.com/vapor/postgres-nio.git", from: "1.21.0"), + ], + targets: [ + .executableTarget( + name: "server", + dependencies: [ + .product(name: "Hummingbird", package: "hummingbird"), + .product(name: "Mustache", package: "swift-mustache"), + .product(name: "PostgresNIO", package: "postgres-nio"), + ], + swiftSettings: [ + // Enable better optimizations when building in Release configuration. Despite the use of + // the `.unsafeFlags` construct required by SwiftPM, this flag is recommended for Release + // builds. See for details. + .unsafeFlags(["-cross-module-optimization"], .when(configuration: .release)) + ] + ) + ] +) diff --git a/frameworks/Swift/hummingbird2/src-postgres/Sources/server/Controllers/FortunesController.swift b/frameworks/Swift/hummingbird2/src-postgres/Sources/server/Controllers/FortunesController.swift new file mode 100644 index 00000000000..135e5d12b14 --- /dev/null +++ b/frameworks/Swift/hummingbird2/src-postgres/Sources/server/Controllers/FortunesController.swift @@ -0,0 +1,63 @@ +import Hummingbird +import Mustache +import PostgresNIO + +struct HTML: ResponseGenerator, Sendable { + let html: String + public func response(from request: Request, context: some RequestContext) -> Response { + return Response( + status: .ok, headers: [.contentType: "text/html; charset=utf-8"], + body: .init(byteBuffer: .init(string: html))) + } +} + +final class FortunesController: Sendable { + typealias Context = TechFrameworkRequestContext + let template: MustacheTemplate + let postgresClient: PostgresClient + + init(postgresClient: PostgresClient) { + self.postgresClient = postgresClient + self.template = try! MustacheTemplate( + string: """ + Fortunes{{#.}}{{/.}}
idmessage
{{id}}{{message}}
+ """) + } + + var routes: RouteCollection { + RouteCollection(context: Context.self) + .get("fortunes", use: fortunes) + } + + /// In this test, the framework's ORM is used to fetch all rows from a database + /// table containing an unknown number of Unix fortune cookie messages (the + /// table has 12 rows, but the code cannot have foreknowledge of the table's + /// size). An additional fortune cookie message is inserted into the list at + /// runtime and then the list is sorted by the message text. Finally, the list + /// is delivered to the client using a server-side HTML template. The message + /// text must be considered untrusted and properly escaped and the UTF-8 fortune messages must be rendered properly. + @Sendable func fortunes(request: Request, context: Context) async throws -> HTML { + let rows = try await self.postgresClient.execute(SelectFortuneStatement()) + var fortunes: [Fortune] = [] + for try await fortune in rows { + fortunes.append(.init(id: fortune.0, message: fortune.1)) + } + + fortunes.append(.init(id: 0, message: "Additional fortune added at request time.")) + let sortedFortunes = fortunes.sorted { $0.message < $1.message } + return HTML(html: self.template.render(sortedFortunes)) + + } + + struct SelectFortuneStatement: PostgresPreparedStatement { + typealias Row = (Int32, String) + + static let sql = "SELECT id, message FROM Fortune" + + func makeBindings() throws -> PostgresNIO.PostgresBindings { + return .init() + } + + func decodeRow(_ row: PostgresNIO.PostgresRow) throws -> Row { try row.decode(Row.self) } + } +} diff --git a/frameworks/Swift/hummingbird2/src-postgres/Sources/server/Controllers/WorldController.swift b/frameworks/Swift/hummingbird2/src-postgres/Sources/server/Controllers/WorldController.swift new file mode 100644 index 00000000000..0764a5e186b --- /dev/null +++ b/frameworks/Swift/hummingbird2/src-postgres/Sources/server/Controllers/WorldController.swift @@ -0,0 +1,111 @@ +import Hummingbird +import PostgresNIO + +struct WorldController { + typealias Context = TechFrameworkRequestContext + let postgresClient: PostgresClient + + var routes: RouteCollection { + RouteCollection(context: Context.self) + .get("db", use: single) + .get("queries", use: multiple) + .get("updates", use: updates) + } + + /// In this test, each request is processed by fetching a single row from a + /// simple database table. That row is then serialized as a JSON response. + @Sendable func single(request: Request, context: Context) async throws -> World { + let id = Int32.random(in: 1...10_000) + let rows = try await self.postgresClient.execute(SelectWorldStatement(id: id)) + guard let row = try await rows.first(where: { _ in true }) else { + throw HTTPError(.notFound) + } + return World(id: row.0, randomNumber: row.1) + } + + /// In this test, each request is processed by fetching multiple rows from a + /// simple database table and serializing these rows as a JSON response. The + /// test is run multiple times: testing 1, 5, 10, 15, and 20 queries per request. + /// All tests are run at 512 concurrency. + @Sendable func multiple(request: Request, context: Context) async throws -> [World] { + let queries = (request.uri.queryParameters.get("queries", as: Int.self) ?? 1).bound(1, 500) + return try await self.postgresClient.withConnection { conn in + var result: [World] = .init() + result.reserveCapacity(queries) + for _ in 0.. [World] { + let queries = (request.uri.queryParameters.get("queries", as: Int.self) ?? 1).bound(1, 500) + return try await self.postgresClient.withConnection { conn in + var result: [World] = .init() + result.reserveCapacity(queries) + for _ in 0.. PostgresNIO.PostgresBindings { + var bindings = PostgresNIO.PostgresBindings(capacity: 1) + bindings.append(.init(int32: self.id)) + return bindings + } + + func decodeRow(_ row: PostgresNIO.PostgresRow) throws -> Row { try row.decode(Row.self) } + } + + struct UpdateWorldStatement: PostgresPreparedStatement { + typealias Row = Int32 + + let id: Int32 + let randomNumber: Int32 + + static let sql = "UPDATE World SET randomnumber = $2 WHERE id = $1" + + func makeBindings() throws -> PostgresNIO.PostgresBindings { + var bindings = PostgresNIO.PostgresBindings(capacity: 2) + bindings.append(.init(int32: self.id)) + bindings.append(.init(int32: self.randomNumber)) + return bindings + } + + func decodeRow(_ row: PostgresNIO.PostgresRow) throws -> Row { try row.decode(Row.self) } + } +} diff --git a/frameworks/Swift/hummingbird2/src-postgres/Sources/server/Models/Fortune.swift b/frameworks/Swift/hummingbird2/src-postgres/Sources/server/Models/Fortune.swift new file mode 100644 index 00000000000..cb8ff2ee1ae --- /dev/null +++ b/frameworks/Swift/hummingbird2/src-postgres/Sources/server/Models/Fortune.swift @@ -0,0 +1,21 @@ +import Hummingbird +import Mustache + +struct Fortune: ResponseEncodable, Sendable { + var id: Int32 + var message: String +} + +// avoid using Mirror as it is expensive +extension Fortune: MustacheParent { + func child(named: String) -> Any? { + switch named { + case "id": + return id + case "message": + return message + default: + return nil + } + } +} diff --git a/frameworks/Swift/hummingbird2/src-postgres/Sources/server/Models/World.swift b/frameworks/Swift/hummingbird2/src-postgres/Sources/server/Models/World.swift new file mode 100644 index 00000000000..03077e0aadf --- /dev/null +++ b/frameworks/Swift/hummingbird2/src-postgres/Sources/server/Models/World.swift @@ -0,0 +1,7 @@ +import Hummingbird + +struct World: ResponseEncodable { + var id: Int32 + var randomNumber: Int32 +} + diff --git a/frameworks/Swift/hummingbird2/src-postgres/Sources/server/main.swift b/frameworks/Swift/hummingbird2/src-postgres/Sources/server/main.swift new file mode 100644 index 00000000000..a062237d6f9 --- /dev/null +++ b/frameworks/Swift/hummingbird2/src-postgres/Sources/server/main.swift @@ -0,0 +1,55 @@ +import Foundation +import Hummingbird +import PostgresNIO + +// postgresql.conf specifies max_connections = 2000 +// https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Environment#citrine-self-hosted +// https://github.com/TechEmpower/FrameworkBenchmarks/blob/master/toolset/databases/postgres/postgresql.conf#L64 + +extension Int { + func bound(_ minValue: Int, _ maxValue: Int) -> Int { + return Swift.min(maxValue, Swift.max(minValue, self)) + } +} + +struct TechFrameworkRequestContext: RequestContext { + var coreContext: CoreRequestContextStorage + + init(source: ApplicationRequestContextSource) { + self.coreContext = CoreRequestContextStorage(source: source) + } +} + +func runApp() async throws { + let env = Environment() + let serverHostName = env.get("SERVER_HOSTNAME") ?? "127.0.0.1" + let serverPort = env.get("SERVER_PORT", as: Int.self) ?? 8080 + + var postgresConfiguration = PostgresClient.Configuration( + host: "tfb-database", + username: "benchmarkdbuser", + password: "benchmarkdbpass", + database: "hello_world", + tls: .disable + ) + postgresConfiguration.options.maximumConnections = 200 + let postgresClient = PostgresClient( + configuration: postgresConfiguration, + eventLoopGroup: MultiThreadedEventLoopGroup.singleton + ) + let router = Router(context: TechFrameworkRequestContext.self) + router.addRoutes(WorldController(postgresClient: postgresClient).routes) + router.addRoutes(FortunesController(postgresClient: postgresClient).routes) + var app = Application( + router: router, + configuration: .init( + address: .hostname(serverHostName, port: serverPort), + serverName: "HB2", + backlog: 8192 + ) + ) + app.addServices(postgresClient) + try await app.runService() +} + +try await runApp() diff --git a/frameworks/Swift/hummingbird2/src/Package.swift b/frameworks/Swift/hummingbird2/src/Package.swift new file mode 100644 index 00000000000..dfa3529b4a2 --- /dev/null +++ b/frameworks/Swift/hummingbird2/src/Package.swift @@ -0,0 +1,26 @@ +// swift-tools-version:6.1 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription + +let package = Package( + name: "server", + platforms: [.macOS(.v14)], + dependencies: [ + .package(url: "https://github.com/hummingbird-project/hummingbird.git", from: "2.16.0") + ], + targets: [ + .executableTarget( + name: "server", + dependencies: [ + .product(name: "Hummingbird", package: "hummingbird") + ], + swiftSettings: [ + // Enable better optimizations when building in Release configuration. Despite the use of + // the `.unsafeFlags` construct required by SwiftPM, this flag is recommended for Release + // builds. See for details. + .unsafeFlags(["-cross-module-optimization"], .when(configuration: .release)) + ] + ) + ] +) diff --git a/frameworks/Swift/hummingbird2/src/Sources/server/main.swift b/frameworks/Swift/hummingbird2/src/Sources/server/main.swift new file mode 100644 index 00000000000..29ece6eadf1 --- /dev/null +++ b/frameworks/Swift/hummingbird2/src/Sources/server/main.swift @@ -0,0 +1,42 @@ +import Foundation +import Hummingbird +import HummingbirdCore +import Logging +import NIOCore + +struct Object: ResponseEncodable { + let message: String +} + +struct TechFrameworkRequestContext: RequestContext { + var coreContext: CoreRequestContextStorage + + init(source: ApplicationRequestContextSource) { + self.coreContext = CoreRequestContextStorage(source: source) + } +} + +func runApp() async throws { + let env = Environment() + let serverHostName = env.get("SERVER_HOSTNAME") ?? "127.0.0.1" + let serverPort = env.get("SERVER_PORT", as: Int.self) ?? 8080 + + let router = Router(context: TechFrameworkRequestContext.self) + router.get("plaintext") { _, _ in + "Hello, world!" + } + router.get("json") { _, _ in + Object(message: "Hello, world!") + } + let app = Application( + router: router, + configuration: .init( + address: .hostname(serverHostName, port: serverPort), + serverName: "HB", + backlog: 8192 + ) + ) + try await app.runService() +} + +try await runApp() diff --git a/frameworks/Swift/kitura/.gitignore b/frameworks/Swift/kitura/.gitignore deleted file mode 100644 index 94822102415..00000000000 --- a/frameworks/Swift/kitura/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -.DS_Store -.build -build_gcd -.swiftenv -Packages -*.xcodeproj diff --git a/frameworks/Swift/kitura/.swift-version b/frameworks/Swift/kitura/.swift-version deleted file mode 100644 index 4d0dcda01c4..00000000000 --- a/frameworks/Swift/kitura/.swift-version +++ /dev/null @@ -1 +0,0 @@ -4.1.2 diff --git a/frameworks/Swift/kitura/Package.swift b/frameworks/Swift/kitura/Package.swift deleted file mode 100644 index 89164e6e02d..00000000000 --- a/frameworks/Swift/kitura/Package.swift +++ /dev/null @@ -1,51 +0,0 @@ -// swift-tools-version:4.0 -// The swift-tools-version declares the minimum version of Swift required to build this package. - -import PackageDescription - -let package = Package( - name: "Kitura-TechEmpower", - dependencies: [ - .package(url: "https://github.com/IBM-Swift/Kitura.git", .upToNextMinor(from: "2.6.0")), - .package(url: "https://github.com/IBM-Swift/LoggerAPI.git", from: "1.8.0"), - .package(url: "https://github.com/IBM-Swift/HeliumLogger.git", from: "1.8.0"), - .package(url: "https://github.com/IBM-Swift/Configuration.git", from: "3.0.0"), - .package(url: "https://github.com/IBM-Swift/Swift-Kuery-PostgreSQL.git", from: "2.0.0"), - .package(url: "https://github.com/IBM-Swift/Swift-Kuery-ORM.git", from: "0.4.0"), - .package(url: "https://github.com/IBM-Swift/Kitura-StencilTemplateEngine.git", from: "1.9.0"), - .package(url: "https://github.com/IBM-Swift/Kitura-MustacheTemplateEngine.git", from: "1.7.2"), - .package(url: "https://github.com/OpenKitten/MongoKitten.git", from: "4.1.3"), - ], - targets: [ - .target( - name: "TechEmpowerCommon", - dependencies: []), - .target( - name: "KueryPostgres", - dependencies: [.target(name: "TechEmpowerCommon"), "Configuration", "SwiftKueryPostgreSQL"]), - .target( - name: "KueryPostgresRaw", - dependencies: [.target(name: "KueryPostgres"), "LoggerAPI"]), - .target( - name: "KueryPostgresORM", - dependencies: [.target(name: "KueryPostgres"), "LoggerAPI", "SwiftKueryORM"]), - .target( - name: "TechEmpower", - dependencies: ["Kitura"]), - .target( - name: "TechEmpowerPostgres", - dependencies: [.target(name: "KueryPostgresRaw"), "Kitura", "HeliumLogger", "KituraStencil"]), - .target( - name: "TechEmpowerPostgresORM", - dependencies: [.target(name: "KueryPostgresORM"), "Kitura", "HeliumLogger", "KituraStencil"]), - .target( - name: "TechEmpowerPostgresORMCodable", - dependencies: [.target(name: "KueryPostgresORM"), "Kitura", "HeliumLogger", "KituraStencil"]), - .target( - name: "TechEmpowerPostgresMustache", - dependencies: [.target(name: "KueryPostgresRaw"), "Kitura", "HeliumLogger", "KituraMustache"]), - .target( - name: "TechEmpowerMongoKitten", - dependencies: [.target(name: "TechEmpowerCommon"), "Kitura", "HeliumLogger", "Configuration", "MongoKitten", "KituraStencil"]), - ] -) diff --git a/frameworks/Swift/kitura/README.md b/frameworks/Swift/kitura/README.md deleted file mode 100644 index aacadafd94b..00000000000 --- a/frameworks/Swift/kitura/README.md +++ /dev/null @@ -1,56 +0,0 @@ -# [Kitura](https://kitura.io) Benchmark Test - -This is the [Kitura](https://kitura.io) portion of a [benchmarking test suite](https://www.techempower.com/benchmarks/) comparing a variety of web development platforms. - -## Variants - -The benchmark is split up into multiple executable targets, demonstrating different database backends and uses of the Kitura routing APIs: -- `kitura`: Implementations of Plaintext and JSON using 'raw' (Express-style) routing -- `kitura-postgres`: Implementation of database tests, using Postgres with Swift-Kuery (no ORM) -- `kitura-postgres-orm`: Equivalent implementation with Postgres and Swift-Kuery-ORM -- `kitura-postgres-orm-codable`: Equivalent implementation with Postgres, using [Codable Routing together with Swift-Kuery-ORM](https://developer.ibm.com/swift/2018/03/01/introducing-swift-kuery-orm/) -- `kitura-mongodb`: Implementation of database tests, using MongoDB with MongoKitten (no ORM) -- `kitura-nio`: `kitura` implementations of Plaintext and JSON run on [Kitura-NIO](https://github.com/IBM-Swift/Kitura-NIO) -- `kitura-nio-postgres`: Testing `kitura` implementations of database tests using Postgres on [Kitura-NIO](https://github.com/IBM-Swift/Kitura-NIO) - -There are additional variants for each of the above implementations, with the '-gcd' suffix: These are compiled from the same source, but use the Grand Central Dispatch threading model (used by default on macOS) instead of a direct epoll implementation (the default on Linux). - -Each listens on port 8080, and uses the common URLs described below. - -## Versions and Dependencies - -This version of the benchmark requires Swift 4.0.3 or higher, and uses the following versions of Kitura and dependencies: - -- [Kitura 2.5](https://github.com/IBM-Swift/Kitura) -- [HeliumLogger 1.x](https://github.com/IBM-Swift/HeliumLogger) -- [Configuration 3.x](https://github.com/IBM-Swift/Configuration) -- [SwiftKueryPostgreSQL 1.x](https://github.com/IBM-Swift/Swift-Kuery-PostgreSQL) -- [SwiftKueryORM 0.x](https://github.com/IBM-Swift/Swift-Kuery-ORM) -- [KituraStencil 1.x](https://github.com/IBM-Swift/Kitura-StencilTemplateEngine) -- [KituraMustache 1.x](https://github.com/IBM-Swift/Kitura-MustacheTemplateEngine) -- [MongoKitten 4.x](https://github.com/OpenKitten/MongoKitten) - -## Test URLs -### JSON serialization - -http://localhost:8080/json - -### Single database query - -http://localhost:8080/db - -### Multiple database queries - -http://localhost:8080/queries?queries=n - -### Fortunes - -http://localhost:8080/fortunes - -### Database updates - -http://localhost:8080/updates?queries=n - -### Plaintext - -http://localhost:8080/plaintext diff --git a/frameworks/Swift/kitura/Sources/KueryPostgres/Postgres.swift b/frameworks/Swift/kitura/Sources/KueryPostgres/Postgres.swift deleted file mode 100644 index a1c35e631df..00000000000 --- a/frameworks/Swift/kitura/Sources/KueryPostgres/Postgres.swift +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright IBM Corporation 2018 - * - * 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. - */ - -import Foundation -import SwiftKuery -import SwiftKueryPostgreSQL -import Configuration - -#if os(Linux) - import Glibc -#else - import Darwin -#endif - -// We will load our database configuration from config.json, but this can be -// overridden with the TFB_DB_CONFIG environment variable. -let configurationFilename: String = ProcessInfo.processInfo.environment["TFB_DB_CONFIG"] ?? "config.json" -let manager = ConfigurationManager().load(file: configurationFilename, relativeFrom: .pwd).load(.environmentVariables) - -let dbHost = manager["DB_HOST"] as? String ?? manager["db:host"] as? String ?? "localhost" -let dbPort = Int32(manager["DB_PORT"] as? String != nil ? Int(manager["DB_PORT"] as! String) ?? 5432 : manager["db:port"] as? Int ?? 5432) -let dbName = manager["db:name"] as? String ?? "hello_world" -let dbUser = manager["db:user"] as? String ?? "benchmarkdbuser" -let dbPass = manager["db:password"] as? String ?? "benchmarkdbpass" - -let dbConnPoolOpts = ConnectionPoolOptions(initialCapacity: 20, maxCapacity: 50) - -public let dbConnPool = PostgreSQLConnection.createPool(host: dbHost, port: dbPort, options: [.databaseName(dbName), .userName(dbUser), .password(dbPass)], poolOptions: dbConnPoolOpts) - diff --git a/frameworks/Swift/kitura/Sources/KueryPostgresORM/PostgresORM.swift b/frameworks/Swift/kitura/Sources/KueryPostgresORM/PostgresORM.swift deleted file mode 100644 index a267e9d4121..00000000000 --- a/frameworks/Swift/kitura/Sources/KueryPostgresORM/PostgresORM.swift +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Copyright IBM Corporation 2018 - * - * 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. - */ - -import Foundation -import Dispatch -import LoggerAPI -import SwiftKuery -import SwiftKueryORM -import KueryPostgres -import TechEmpowerCommon - -// ORM conformance -extension RandomRow: Model { - public static var tableName: String { return "world" } -} - -// ORM conformance -extension Fortune: Model { - public static var tableName: String { return "fortune" } -} - -// Configure our ORM Database connection pool as dbConnPool created by KueryPostgres -public func setupORM() { - Database.default = Database(dbConnPool) -} - -/// Get a list of Fortunes from the database. -/// -/// - Parameter callback: The callback that will be invoked once the DB query -/// has completed and results are available, passing an -/// optional [Fortune] (on success) or RequestError on -/// failure. -/// -public func getFortunes(callback: @escaping ([Fortune]?, RequestError?) -> Void) -> Void { - Fortune.findAll { (fortunes, err) in - if let err = err { - return callback(nil, err) - } else { - callback(fortunes, nil) - } - } -} - -/// Get a random row (range 1 to 10,000) from the database. -/// -/// - Parameter callback: The callback that will be invoked once the DB query -/// has completed and results are available, passing an -/// optional RandomRow (on success) or RequestError on -/// failure. -/// -public func getRandomRow(callback: @escaping (RandomRow?, RequestError?) -> Void) -> Void { - // Select random row from database range - let rnd = RandomRow.randomId - RandomRow.find(id: rnd, callback) -} - -/// Updates a row of World to a new value. -/// -/// - Parameter callback: The callback that will be invoked once the DB update -/// has completed, passing an optional RequestError if the -/// update failed. -/// -public func updateRow(id: Int, callback: @escaping (RequestError?) -> Void) -> Void { - // Generate a random number for this row - let row = RandomRow(id: id, randomNumber: RandomRow.randomValue) - row.update(id: id) { (resultRow, err) in - if let err = err { - return callback(err) - } else { - callback(nil) - } - } -} - -/// Get `count` random rows from the database, and pass the resulting array -/// to a completion handler (or a RequestError, in the event that a row could -/// not be retrieved). -/// -/// - Parameter count: The number of rows to retrieve -/// - Parameter result: The intermediate result array being built -/// - Parameter completion: The closure to invoke with the result array, or error -/// -public func getRandomRows(count: Int, result: [RandomRow] = [], completion: @escaping ([RandomRow]?, RequestError?) -> Void) { - if count > 0 { - // Select random row from database range - RandomRow.find(id: RandomRow.randomId) { (resultRow, err) in - if let resultRow = resultRow { - var result = result - result.append(resultRow) - getRandomRows(count: count-1, result: result, completion: completion) - } else { - if let err = err { - completion(nil, err) - } else { - fatalError("Unexpected: result and error both nil") - } - } - } - } else { - completion(result, nil) - } -} - -/// A parallel version of `getRandomRows` that invokes each get in parallel, builds an -/// array of results and waits for each get to complete before returning. -/// -/// - Parameter count: The number of rows to retrieve -/// - Parameter completion: The closure to invoke with the result array, or error -/// -public func getRandomRowsParallel(count: Int, completion: @escaping ([RandomRow]?, RequestError?) -> Void) { - var results: [RandomRow] = [] - guard count > 0 else { - return completion(results, nil) - } - // Used to protect result array from concurrent modification - let updateLock = DispatchSemaphore(value: 1) - // Execute each query. Each callback will append its result to `results` - for _ in 1...count { - RandomRow.find(id: RandomRow.randomId) { (resultRow, err) in - guard let resultRow = resultRow else { - Log.error("\(err ?? .internalServerError)") - completion(nil, err ?? .internalServerError) - return - } - updateLock.wait() - results.append(resultRow) - if results.count == count { - completion(results, nil) - } - updateLock.signal() - } - } -} - -/// Update and retrieve `count` random rows from the database, and pass the -/// resulting array to a completion handler (or a RequestError, in the event -/// that a row could not be retrieved or updated). -/// -/// - Parameter count: The number of rows to retrieve -/// - Parameter result: The intermediate result array being built -/// - Parameter completion: The closure to invoke with the result array, or error -/// -public func updateRandomRows(count: Int, result: [RandomRow] = [], completion: @escaping ([RandomRow]?, RequestError?) -> Void) { - if count > 0 { - // Select random row from database range - RandomRow.find(id: RandomRow.randomId) { (resultRow, err) in - if let resultRow = resultRow { - var result = result - let row = RandomRow(id: resultRow.id, randomNumber: RandomRow.randomValue) - row.update(id: row.id) { (resultRow, err) in - if let resultRow = resultRow { - result.append(resultRow) - updateRandomRows(count: count-1, result: result, completion: completion) - } else { - completion(nil, err) - } - } - } else { - if let err = err { - completion(nil, err) - } else { - fatalError("Unexpected: result and error both nil") - } - } - } - } else { - completion(result, nil) - } -} - -/// A parallel version of `updateRandomRows` that invokes each get/update operation -/// in parallel, builds an array of results and waits for each get to complete before -/// returning. -/// -/// - Parameter count: The number of rows to retrieve -/// - Parameter completion: The closure to invoke with the result array, or error -/// -public func updateRandomRowsParallel(count: Int, completion: @escaping ([RandomRow]?, RequestError?) -> Void) { - var results: [RandomRow] = [] - guard count > 0 else { - return completion(results, nil) - } - // Used to protect result array from concurrent modification - let updateLock = DispatchSemaphore(value: 1) - // Execute each query. Each callback will append its result to `results` - for _ in 1...count { - RandomRow.find(id: RandomRow.randomId) { (resultRow, err) in - guard let resultRow = resultRow else { - Log.error("\(err ?? .internalServerError)") - completion(nil, err ?? .internalServerError) - return - } - let row = RandomRow(id: resultRow.id, randomNumber: RandomRow.randomValue) - row.update(id: row.id) { (resultRow, err) in - if let resultRow = resultRow { - updateLock.wait() - results.append(resultRow) - if results.count == count { - completion(results, nil) - } - updateLock.signal() - } else { - Log.error("\(err ?? .internalServerError)") - completion(nil, err ?? .internalServerError) - return - } - } - } - } -} diff --git a/frameworks/Swift/kitura/Sources/KueryPostgresRaw/PostgresRaw.swift b/frameworks/Swift/kitura/Sources/KueryPostgresRaw/PostgresRaw.swift deleted file mode 100644 index c32d6784933..00000000000 --- a/frameworks/Swift/kitura/Sources/KueryPostgresRaw/PostgresRaw.swift +++ /dev/null @@ -1,285 +0,0 @@ -/* - * Copyright IBM Corporation 2018 - * - * 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. - */ - -import Foundation -import LoggerAPI -import SwiftKuery -import KueryPostgres -import TechEmpowerCommon - -let dbRows = 10000 -let maxValue = 10000 - -// Kuery table definition for World -class World: Table { - let tableName = "world" - - let id = Column("id") - let randomNumber = Column("randomnumber") -} - -// Kuery table definition for Fortune -class Fortunes: Table { - let tableName = "fortune" - - let id = Column("id") - let message = Column("message") -} - -let world = World() -let fortunes = Fortunes() - -// Kuery update statement for Updates -var update = Update(world, set: [(world.randomNumber, RandomRow.randomValue)]) - .where(world.id == RandomRow.randomId) - -/// Get a list of Fortunes from the database. -/// -/// - Parameter callback: The callback that will be invoked once the DB query -/// has completed and results are available, passing an -/// optional [Fortune] (on success) or AppError on -/// failure. -/// -public func getFortunes(callback: @escaping ([Fortune]?, AppError?) -> Void) -> Void { - // Get a dedicated connection object for this transaction from the pool - dbConnPool.getConnection { (dbConn, dbConnErr) in - guard let dbConn = dbConn else { - guard let err = dbConnErr else { - return callback(nil, AppError.OtherError("Unknown error getting connection from pool")) - } - return callback(nil, AppError.OtherError("Error getting connection from pool: \(err)")) - } - // Initiate database query - let query = Select(from: fortunes) - dbConn.execute(query: query) { result in - var resultFortunes: [Fortune] = [] - // Retrieve all rows from the query result - result.asRows { - results, err in - guard let results = results else { - guard let err = err else { - return callback(nil, AppError.DBKueryError("Query failed, and no error was returned")) - } - return callback(nil, AppError.DBKueryError("Query failed: \(err)")) - } - do { - // Transform the result rows into an array of Fortune objects - resultFortunes = try results.map { try Fortune.init(row: $0) } - } catch { - return callback(nil, AppError.DataFormatError("\(error)")) - } - // Invoke callback with results - callback(resultFortunes, nil) - } - } - } -} - -/// Alternate implementation of getFortunes that uses ResultSet.forEach to fetch each -/// database row sequentially, rather than QueryResult.asRows (which produces an array -/// of rows). The benefit of forEach is that we do not need to hold two copies of the -/// entire result set in memory. -/// -/// - Parameter callback: The callback that will be invoked once the DB query -/// has completed and results are available, passing an -/// optional [Fortune] (on success) or AppError on -/// failure. -/// -public func getFortunes_forEach(callback: @escaping ([Fortune]?, AppError?) -> Void) -> Void { - // Get a dedicated connection object for this transaction from the pool - dbConnPool.getConnection { (dbConn, dbConnErr) in - guard let dbConn = dbConn else { - guard let err = dbConnErr else { - return callback(nil, AppError.OtherError("Unknown error getting connection from pool")) - } - return callback(nil, AppError.OtherError("Error getting connection from pool: \(err)")) - } - // Initiate database query - let query = Select(from: fortunes) - dbConn.execute(query: query) { result in - var resultFortunes: [Fortune] = [] - guard let results = result.asResultSet else { - guard let queryErr = result.asError else { - return callback(nil, AppError.DBKueryError("Expected a result set, but result was \(result)")) - } - return callback(nil, AppError.DBKueryError("Query failed: \(queryErr)")) - } - // Build an array of Fortune objects - results.forEach { (values, rowErr, next) in - guard let values = values else { - // Reached the final row - call back with the results - return callback(resultFortunes, nil) - } - // Append this Fortune to the list - do { - resultFortunes.append(try Fortune(values: values)) - // Process the next column - next() - } catch { - return callback(nil, AppError.DataFormatError("\(error)")) - } - } - } - } -} - -/// Get a random row (range 1 to 10,000) from the database. -/// -/// - Parameter callback: The callback that will be invoked once the DB query -/// has completed and results are available, passing an -/// optional RandomRow (on success) or AppError on -/// failure. -/// -public func getRandomRow_Raw(callback: @escaping (RandomRow?, AppError?) -> Void) -> Void { - // Get a dedicated connection object for this transaction from the pool - dbConnPool.getConnection { (dbConn, dbConnErr) in - guard let dbConn = dbConn else { - guard let dbConnErr = dbConnErr else { - return callback(nil, AppError.OtherError("Unknown error getting connection from pool")) - } - return callback(nil, AppError.OtherError("Error getting connection from pool: \(dbConnErr)")) - } - // Select random row from database range - let rnd = RandomRow.randomId - let query = Select(world.randomNumber, from: world) - .where(world.id == rnd) - // Initiate database query - dbConn.execute(query: query) { result in - guard let resultSet = result.asResultSet else { - guard let queryErr = result.asError else { - return callback(nil, AppError.DBKueryError("Expected a result set, but result was \(result)")) - } - return callback(nil, AppError.DBKueryError("Query failed: \(queryErr)")) - } - resultSet.nextRow { - values, nextErr in - guard let values = values else { - guard let nextErr = nextErr else { - return callback(nil, AppError.DBKueryError("Query failed, and no error was returned")) - } - return callback(nil, AppError.DBKueryError("Query failed: \(nextErr)")) - } - // There should be exactly one value - guard values.count == 1 else { - return callback(nil, AppError.DBKueryError("\(values.count) values returned, expected 1, for query '\(query)'")) - } - // The value should be an Int32 - guard let randomNumber = values[0] as? Int32 else { - return callback(nil, AppError.DBKueryError("Could not convert \(String(describing: values[0])) to Int32")) - } - let resultRow = RandomRow(id: rnd, randomNumber: Int(randomNumber)) - // Invoke callback with results - callback(resultRow, nil) - } - } - } -} - -/// Updates a row of World to a new value. -/// -/// - Parameter callback: The callback that will be invoked once the DB update -/// has completed, passing an optional AppError if the -/// update failed. -/// -public func updateRow_Raw(id: Int, callback: @escaping (AppError?) -> Void) -> Void { - // Get a dedicated connection object for this transaction from the pool - dbConnPool.getConnection { (dbConn, err) in - guard let dbConn = dbConn else { - guard let err = err else { - return callback(AppError.OtherError("Unknown error getting connection from pool")) - } - return callback(AppError.OtherError("Error getting connection from pool: \(err)")) - } - // Generate a random number for this row - let rndValue = RandomRow.randomValue - let query = Update(world, set: [(world.randomNumber, rndValue)]) - .where(world.id == id) - // Initiate database query - dbConn.execute(query: query) { result in - guard result.success else { - return callback(AppError.DBKueryError("Update failed: \(String(describing: result.asError))")) - } - // Invoke callback once done - callback(nil) - } - } -} - -/// Get `count` random rows from the database, and pass the resulting array -/// to a completion handler (or an AppError, in the event that a row could -/// not be retrieved). -/// -/// - Parameter count: The number of rows to retrieve -/// - Parameter result: The intermediate result array being built -/// - Parameter completion: The closure to invoke with the result array, or error -/// -public func getRandomRows_Raw(count: Int, result: [RandomRow] = [], completion: @escaping ([RandomRow]?, AppError?) -> Void) { - if count > 0 { - // Select random row from database range - getRandomRow_Raw { (resultRow, err) in - if let resultRow = resultRow { - var result = result - result.append(resultRow) - // Call recursively to get remaining rows - getRandomRows_Raw(count: count-1, result: result, completion: completion) - } else { - if let err = err { - completion(nil, err) - } else { - fatalError("Unexpected: result and error both nil") - } - } - } - } else { - completion(result, nil) - } -} - -/// Update and retrieve `count` random rows from the database, and pass the -/// resulting array to a completion handler (or an AppError, in the event -/// that a row could not be retrieved or updated). -/// -/// - Parameter count: The number of rows to retrieve -/// - Parameter result: The intermediate result array being built -/// - Parameter completion: The closure to invoke with the result array, or error -/// -public func updateRandomRows_Raw(count: Int, result: [RandomRow] = [], completion: @escaping ([RandomRow]?, AppError?) -> Void) { - if count > 0 { - // Select random row from database range - getRandomRow_Raw { (resultRow, err) in - if let resultRow = resultRow { - var result = result - // Execute inner callback for updating the row - updateRow_Raw(id: resultRow.id) { (err) in - if let err = err { - return completion(nil, err) - } - result.append(resultRow) - // Call recursively to update remaining rows - updateRandomRows_Raw(count: count-1, result: result, completion: completion) - } - } else { - if let err = err { - completion(nil, err) - } else { - fatalError("Unexpected: result and error both nil") - } - } - } - } else { - completion(result, nil) - } -} diff --git a/frameworks/Swift/kitura/Sources/TechEmpower/main.swift b/frameworks/Swift/kitura/Sources/TechEmpower/main.swift deleted file mode 100644 index 83a9f083fc5..00000000000 --- a/frameworks/Swift/kitura/Sources/TechEmpower/main.swift +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright IBM Corporation 2018 - * - * 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. - */ - -import Foundation -import Kitura -import TechEmpowerCommon - -let router = Router() - -// -// TechEmpower test 6: plaintext -// -router.get("/plaintext") { - request, response, next in - response.headers["Server"] = "Kitura" - response.headers["Content-Type"] = "text/plain" - try response.status(.OK).send("Hello, world!").end() -} - -// -// TechEmpower test 1: JSON serialization -// -router.get("/json") { - request, response, next in - response.headers["Server"] = "Kitura" - let result = ["message":"Hello, World!"] - try response.status(.OK).send(json: result).end() -} - -Kitura.addHTTPServer(onPort: 8080, with: router) -Kitura.run() diff --git a/frameworks/Swift/kitura/Sources/TechEmpowerCommon/Error.swift b/frameworks/Swift/kitura/Sources/TechEmpowerCommon/Error.swift deleted file mode 100644 index d8b1b78614f..00000000000 --- a/frameworks/Swift/kitura/Sources/TechEmpowerCommon/Error.swift +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright IBM Corporation 2018 - * - * 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. - */ - -/// Represents various errors that can occur with the Kitura TechEmpower benchmark. -public enum AppError: Error { - - /// An error occurring when executing a raw SQL query against a database. - case DBError(String, query: String) - - /// An error occurring when executing a Kuery operation against a database. - case DBKueryError(String) - - /// An error occurring when the format of the data retrieved by a database - /// operation was not as expected. - case DataFormatError(String) - - /// An error occurring when a connection to the database cannot be established. - case ConnectionError(String) - - /// Any other type of error - case OtherError(String) -} diff --git a/frameworks/Swift/kitura/Sources/TechEmpowerCommon/Fortune.swift b/frameworks/Swift/kitura/Sources/TechEmpowerCommon/Fortune.swift deleted file mode 100644 index 182c3a95d61..00000000000 --- a/frameworks/Swift/kitura/Sources/TechEmpowerCommon/Fortune.swift +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright IBM Corporation 2018 - * - * 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. - */ - -import Foundation - -public struct Fortune: Codable { - - /// The id of this Fortune - public let id: Int - - /// The message contained within this Fortune - public let message: String - - public init(id: Int, message: String) { - self.id = id - self.message = message - } - - /// Create a Fortune instance from a [String: Any?] dictionary, - /// such as that retrieved by Kuery using `QueryResult.asRows()`. - /// - /// - Parameter row: A dictionary representing the fields of a - /// Fortune database row. - /// - throws: if the fields and types contained in the dictionary - /// do not match those expected. - public init(row: [String:Any?]) throws { - guard let idField = row["id"] else { - throw AppError.DataFormatError("Missing 'id' field") - } - guard let msgField = row["message"] else { - throw AppError.DataFormatError("Missing 'message' field") - } - guard let message = msgField as? String else { - throw AppError.DataFormatError("'message' field not a String") - } - guard let id = idField as? Int32 else { - throw AppError.DataFormatError("'id' field not an Int32") - } - self.init(id: Int(id), message: message) - } - - /// Create a Fortune instance from an [Any?] array, such as that retrieved - /// by Kuery using `ResultSet.forEach()`. - /// - /// - Parameter row: An array representing the fields of a Fortune - /// database row. - /// - throws: if the fields and types contained in the array do not match - /// those expected. - public init(values: [Any?]) throws { - // There should be two columns - guard values.count == 2 else { - throw AppError.DBKueryError("Expected 2 values but found \(values.count)") - } - // First should be an Int32 - guard let id = values[0] as? Int32 else { - throw AppError.DataFormatError("Fortune id '\(String(describing: values[0]))' is not an Int") - } - // Second should be a String - guard let msg = values[1] as? String else { - throw AppError.DataFormatError("Fortune message '\(String(describing: values[1]))' is not a String") - } - self.init(id: Int(id), message: msg) - } - -} - -extension Fortune: Comparable { - - public static func == (lhs: Fortune, rhs: Fortune) -> Bool { - return lhs.id == rhs.id && lhs.message == rhs.message - } - - public static func < (lhs: Fortune, rhs: Fortune) -> Bool { - return lhs.message < rhs.message || (lhs.message == rhs.message && lhs.id < rhs.id) - } - -} diff --git a/frameworks/Swift/kitura/Sources/TechEmpowerCommon/RandomRow.swift b/frameworks/Swift/kitura/Sources/TechEmpowerCommon/RandomRow.swift deleted file mode 100644 index 053dc6cba11..00000000000 --- a/frameworks/Swift/kitura/Sources/TechEmpowerCommon/RandomRow.swift +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright IBM Corporation 2018 - * - * 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. - */ - -import Foundation - -// Return a random number within the range of rows in the database -private func randomNumberGenerator(_ maxVal: Int) -> Int { - #if os(Linux) - return Int(random() % maxVal) + 1 - #else - return Int(arc4random_uniform(UInt32(maxVal))) + 1 - #endif -} - -public struct RandomRow: Codable { - - /// The number of rows in the World table - public static let dbRows = 10000 - - /// The maximum value for randomNumber - public static let maxValue = 10000 - - /// A generated random row id suitable for retrieving - /// or creating a RandomRow instance. - public static var randomId: Int { - return randomNumberGenerator(dbRows) - } - - /// A generated random value suitable for assigning as the - /// `randomNumber` for a RandomRow instance. - public static var randomValue: Int { - return randomNumberGenerator(maxValue) - } - - /// The id for this RandomRow, ranging from 1 to dbRows - public let id: Int - - /// A random number ranging from 1 to maxValue - public let randomNumber: Int - - public init(id: Int, randomNumber: Int) { - self.id = id - self.randomNumber = randomNumber - } - - /// Map the properties of this type to their corresponding database - /// column names (required by the ORM). - enum CodingKeys: String, CodingKey { - case id - case randomNumber = "randomnumber" - } - - /// Returns a JSON-convertible dictionary representation of this RandomRow. - public func asDictionary() -> [String: Int] { - return ["id": self.id, "randomNumber": self.randomNumber] - } -} diff --git a/frameworks/Swift/kitura/Sources/TechEmpowerMongoKitten/Mongo.swift b/frameworks/Swift/kitura/Sources/TechEmpowerMongoKitten/Mongo.swift deleted file mode 100644 index b4398d0523b..00000000000 --- a/frameworks/Swift/kitura/Sources/TechEmpowerMongoKitten/Mongo.swift +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright IBM Corporation 2018 - * - * 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. - */ - -import Foundation -import LoggerAPI -import Configuration -import MongoKitten -import TechEmpowerCommon - -#if os(Linux) - import Glibc -#else - import Darwin -#endif - -public enum MongoAppError: Error { - case MongoError(String) -} - -// We will load our database configuration from config.json, but this can be -// overridden with the TFB_DB_CONFIG environment variable. -let configurationFilename: String = ProcessInfo.processInfo.environment["TFB_DB_CONFIG"] ?? "config.json" -let manager = ConfigurationManager().load(file: configurationFilename, relativeFrom: .pwd).load(.environmentVariables) - -let dbHost = manager["DB_HOST"] as? String ?? manager["mongodb:host"] as? String ?? "localhost" -let dbPort = Int32(manager["DB_PORT"] as? String != nil ? Int(manager["DB_PORT"] as! String) ?? 27017 : manager["mongodb:port"] as? Int ?? 27017) -let dbName = manager["mongodb:name"] as? String ?? "hello_world" -let dbUser = manager["mongodb:user"] as? String ?? "benchmarkdbuser" -let dbPass = manager["mongodb:password"] as? String ?? "benchmarkdbpass" - -let dbRows = 10000 -let maxValue = 10000 - -var myDatabase: MongoKitten.Database? -var world: MongoKitten.Collection? -var fortune: MongoKitten.Collection? - -func connectToDB() throws { - let connectString = "mongodb://\(dbHost):\(dbPort)/\(dbName)" - Log.info("Connect string = \(connectString)") - //myDatabase = try MongoKitten.Database("mongodb://\(dbUser):\(dbPass)@\(dbHost):\(dbPort)/\(dbName)") - myDatabase = try MongoKitten.Database(connectString) - guard let myDatabase = myDatabase else { - throw AppError.ConnectionError("Nil MongoDB connection to \(connectString)") - } - guard myDatabase.server.isConnected else { - throw AppError.ConnectionError("Not connected to \(connectString)") - } - world = myDatabase["world"] - fortune = myDatabase["fortune"] -} - -// Allow construction of a Fortune from a MongoKitten Document -extension Fortune { - init(document: Document) throws { - if let id = Int(document["_id"]), let message = String(document["message"]) { - self.init(id: id, message: message) - } else { - throw AppError.DataFormatError("Expected fields of Fortune document could not be retreived") - } - } -} - -func getFortunes() throws -> [Fortune] { - guard let fortune = fortune else { - throw MongoAppError.MongoError("Fortune collection not initialized") - } - -// let allFortunes: [Document] = Array(try fortune.find()) - let allFortunes = try fortune.find() - let resultFortunes: [Fortune] = try allFortunes.map { try Fortune.init(document: $0) } - return resultFortunes -} - -// Get a random row (range 1 to 10,000) from DB: id(int),randomNumber(int) -// Convert to object using object-relational mapping (ORM) tool -// Serialize object to JSON - example: {"id":3217,"randomNumber":2149} -func getRandomRow() throws -> [String:Int] { - guard let world = world else { - throw MongoAppError.MongoError("World collection not initialized") - } - - let rnd = RandomRow.randomId - let result = try world.findOne("_id" == rnd) - guard let document = result else { - throw AppError.DataFormatError("World entry id=\(rnd) not found") - } - guard let id = Int(document["_id"]), let randomNumber = Int(document["randomNumber"]) else { - throw AppError.DataFormatError("Expected fields of World document could not be retreived") - } - return ["id":id, "randomNumber":Int(randomNumber)] -} - -// Updates a row of World to a new value. -func updateRandomRow() throws -> [String:Int] { - guard let world = world else { - throw MongoAppError.MongoError("World collection not initialized") - } - - let rnd = RandomRow.randomId - let rndValue = RandomRow.randomValue - let document = try world.findAndUpdate("_id" == rnd, with: ["randomNumber": rndValue]) - guard let id = Int(document["_id"]), let randomNumber = Int(document["randomNumber"]) else { - throw AppError.DataFormatError("Expected fields of World document could not be retreived") - } - return ["id":id, "randomNumber":Int(randomNumber)] -} - - - diff --git a/frameworks/Swift/kitura/Sources/TechEmpowerMongoKitten/main.swift b/frameworks/Swift/kitura/Sources/TechEmpowerMongoKitten/main.swift deleted file mode 100644 index d57d3a7937f..00000000000 --- a/frameworks/Swift/kitura/Sources/TechEmpowerMongoKitten/main.swift +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright IBM Corporation 2018 - * - * 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. - */ - -import Kitura -import LoggerAPI -import HeliumLogger -import MongoKitten -import KituraStencil -import Stencil -//import KituraMustache -import TechEmpowerCommon - -Log.logger = HeliumLogger(.info) - -// Stencil stuff -let ext = Extension() - -// Stencil does not yet support automatic HTML escaping: -// https://github.com/kylef/Stencil/pull/80 -// -ext.registerFilter("htmlencode") { (value: Any?) in - if let value = value as? String { - return value - .replacingOccurrences(of: "&", with: "&") - .replacingOccurrences(of: "<", with: "<") - .replacingOccurrences(of: ">", with: ">") - .replacingOccurrences(of: "'", with: "'") - .replacingOccurrences(of: "\"", with: """) - } - return value -} - -let router = Router() -router.add(templateEngine: StencilTemplateEngine(extension: ext)) -//router.add(templateEngine: MustacheTemplateEngine()) - -// -// TechEmpower test 2: Single database query (raw, no ORM) -// -router.get("/db") { - request, response, next in - response.headers["Server"] = "Kitura" - let dict = try getRandomRow() - try response.status(.OK).send(json: dict).end() -} - -// -// TechEmpower test 3: Multiple database queries (raw, no ORM) -// Get param provides number of queries: /queries?queries=N -// -router.get("/queries") { - request, response, next in - response.headers["Server"] = "Kitura" - let queriesParam = request.queryParameters["queries"] ?? "1" - let numQueries = max(1, min(Int(queriesParam) ?? 1, 500)) // Snap to range of 1-500 as per test spec - var results: [[String:Int]] = [] - for _ in 1...numQueries { - let dict = try getRandomRow() - results.append(dict) - } - // Return JSON representation of array of results - try response.status(.OK).send(json: results).end() -} - -// -// TechEmpower test 4: fortunes (raw, no ORM) -// -router.get("/fortunes") { - request, response, next in - response.headers["Server"] = "Kitura" - response.headers["Content-Type"] = "text/html; charset=UTF-8" - var fortunes = try getFortunes() - fortunes.append(Fortune(id: 0, message: "Additional fortune added at request time.")) - - try response.render("fortunes.stencil", context: ["fortunes": fortunes.sorted()]).end() - //try response.render("fortunes.mustache", context: ["fortunes": fortunes.sorted()]).end() -} - -// -// TechEmpower test 5: updates (raw, no ORM) -// -router.get("/updates") { - request, response, next in - response.headers["Server"] = "Kitura" - let queriesParam = request.queryParameters["queries"] ?? "1" - let numQueries = max(1, min(Int(queriesParam) ?? 1, 500)) // Snap to range of 1-500 as per test spec - var results: [[String:Int]] = [] - for _ in 1...numQueries { - let dict = try updateRandomRow() - results.append(dict) - } - - // Return JSON representation of array of results - try response.status(.OK).send(json: results).end() -} - -// Initialize MongoDB connection -do { - try connectToDB() -} catch { - print("Error connecting to database: \(error)") -} - -Kitura.addHTTPServer(onPort: 8080, with: router) -Kitura.run() diff --git a/frameworks/Swift/kitura/Sources/TechEmpowerPostgres/main.swift b/frameworks/Swift/kitura/Sources/TechEmpowerPostgres/main.swift deleted file mode 100644 index e6bfed0b8b7..00000000000 --- a/frameworks/Swift/kitura/Sources/TechEmpowerPostgres/main.swift +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright IBM Corporation 2018 - * - * 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. - */ - -import Foundation -import Kitura -import LoggerAPI -import HeliumLogger -import KituraStencil -import Stencil -import TechEmpowerCommon -import KueryPostgresRaw - -Log.logger = HeliumLogger(.info) - -// Stencil stuff -let ext = Extension() - -// Stencil does not yet support automatic HTML escaping: -// https://github.com/kylef/Stencil/pull/80 -// -ext.registerFilter("htmlencode") { (value: Any?) in - if let value = value as? String { - return value - .replacingOccurrences(of: "&", with: "&") - .replacingOccurrences(of: "<", with: "<") - .replacingOccurrences(of: ">", with: ">") - .replacingOccurrences(of: "'", with: "'") - .replacingOccurrences(of: "\"", with: """) - } - return value -} - -let router = Router() -router.add(templateEngine: StencilTemplateEngine(extension: ext)) - -// -// TechEmpower test 2: Single database query (raw, no ORM) -// -router.get("/db") { - request, response, next in - response.headers["Server"] = "Kitura" - getRandomRow_Raw { (row, err) in - guard let row = row else { - guard let err = err else { - Log.error("Unknown Error") - try? response.status(.badRequest).send("Unknown error").end() - return - } - Log.error("\(err)") - try? response.status(.badRequest).send("Error: \(err)").end() - return - } - try? response.status(.OK).send(json: row.asDictionary()).end() - } -} - -// -// TechEmpower test 3: Multiple database queries (raw, no ORM) -// Get param provides number of queries: /queries?queries=N -// -router.get("/queries") { - request, response, next in - response.headers["Server"] = "Kitura" - let queriesParam = request.queryParameters["queries"] ?? "1" - let numQueries = max(1, min(Int(queriesParam) ?? 1, 500)) // Snap to range of 1-500 as per test spec - getRandomRows_Raw(count: numQueries) { (rows, err) in - if let rows = rows { - try? response.status(.OK).send(json: rows).end() - } else if let err = err { - try? response.status(.badRequest).send("Error: \(err)").end() - } else { - fatalError("Unexpected: rows and err both nil") - } - } -} - -router.get("/queriesParallel") { - request, response, next in - response.headers["Server"] = "Kitura" - let queriesParam = request.queryParameters["queries"] ?? "1" - let numQueries = max(1, min(Int(queriesParam) ?? 1, 500)) // Snap to range of 1-500 as per test spec - var results: [[String:Int]] = [] - // Used to protect result array from concurrent modification - let updateLock = DispatchSemaphore(value: 1) - // Execute each query. Each callback will append its result to `results` - for _ in 1...numQueries { - getRandomRow_Raw { (row, err) in - guard let row = row else { - guard let err = err else { - Log.error("Unknown Error") - try? response.status(.badRequest).send("Unknown error").end() - return - } - Log.error("\(err)") - try? response.status(.badRequest).send("Error: \(err)").end() - return - } - updateLock.wait() - results.append(row.asDictionary()) - if results.count == numQueries { - // Return JSON representation of array of results - try? response.status(.OK).send(json: results).end() - } - updateLock.signal() - } - } -} - -// -// TechEmpower test 4: fortunes (raw, no ORM) -// -router.get("/fortunes") { - request, response, next in - response.headers["Server"] = "Kitura" - response.headers["Content-Type"] = "text/html; charset=UTF-8" - getFortunes { (fortunes, err) in - guard var fortunes = fortunes else { - guard let err = err else { - Log.error("Unknown Error") - try? response.status(.badRequest).send("Unknown error").end() - return - } - Log.error("\(err)") - try? response.status(.badRequest).send("Error: \(err)").end() - return - } - fortunes.append(Fortune(id: 0, message: "Additional fortune added at request time.")) - do { - try response.render("fortunes.stencil", context: ["fortunes": fortunes.sorted()]).end() - } catch { - print("Error: \(error)") - } - } -} - -// -// TechEmpower test 5: updates (raw, no ORM) -// -router.get("/updates") { - request, response, next in - response.headers["Server"] = "Kitura" - let queriesParam = request.queryParameters["queries"] ?? "1" - let numQueries = max(1, min(Int(queriesParam) ?? 1, 500)) // Snap to range of 1-500 as per test spec - updateRandomRows_Raw(count: numQueries) { (rows, err) in - if let rows = rows { - try? response.status(.OK).send(json: rows).end() - } else if let err = err { - try? response.status(.badRequest).send("Error: \(err)").end() - } else { - fatalError("Unexpected: rows and err both nil") - } - } -} - - -router.get("/updatesParallel") { - request, response, next in - response.headers["Server"] = "Kitura" - let queriesParam = request.queryParameters["queries"] ?? "1" - let numQueries = max(1, min(Int(queriesParam) ?? 1, 500)) // Snap to range of 1-500 as per test spec - var results: [[String:Int]] = [] - // Used to protect result array from concurrent modification - let updateLock = DispatchSemaphore(value: 1) - // Execute each query. Each callback will append its result to `results` - for _ in 1...numQueries { - getRandomRow_Raw { (row, err) in - guard let row = row else { - guard let err = err else { - Log.error("Unknown Error") - try? response.status(.badRequest).send("Unknown error").end() - return - } - Log.error("\(err)") - try? response.status(.badRequest).send("Error: \(err)").end() - return - } - // Execute inner callback for updating the row - updateRow_Raw(id: row.id) { (err) in - if let err = err { - try? response.status(.badRequest).send("Error: \(err)").end() - return - } - updateLock.wait() - results.append(row.asDictionary()) - if results.count == numQueries { - // Return JSON representation of array of results - try? response.status(.OK).send(json: results).end() - } - updateLock.signal() - } - } - } -} - - -Kitura.addHTTPServer(onPort: 8080, with: router) -Kitura.run() diff --git a/frameworks/Swift/kitura/Sources/TechEmpowerPostgresMustache/Fortune+Mustache.swift b/frameworks/Swift/kitura/Sources/TechEmpowerPostgresMustache/Fortune+Mustache.swift deleted file mode 100644 index ba747436c06..00000000000 --- a/frameworks/Swift/kitura/Sources/TechEmpowerPostgresMustache/Fortune+Mustache.swift +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright IBM Corporation 2018 - * - * 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. - */ - -import Mustache -import TechEmpowerCommon - -extension Fortune: MustacheBoxable { - public var mustacheBox: MustacheBox { - return Box(["id": self.id, "message": self.message]) - } -} diff --git a/frameworks/Swift/kitura/Sources/TechEmpowerPostgresMustache/main.swift b/frameworks/Swift/kitura/Sources/TechEmpowerPostgresMustache/main.swift deleted file mode 100644 index 6fa6531c56d..00000000000 --- a/frameworks/Swift/kitura/Sources/TechEmpowerPostgresMustache/main.swift +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright IBM Corporation 2018 - * - * 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. - */ - -import Kitura -import LoggerAPI -import HeliumLogger -import KituraMustache -import TechEmpowerCommon -import KueryPostgresRaw - -Log.logger = HeliumLogger(.info) - -let router = Router() -router.add(templateEngine: MustacheTemplateEngine()) - -// -// TechEmpower test 4: fortunes (raw, no ORM) -// -router.get("/fortunes") { - request, response, next in - response.headers["Server"] = "Kitura" - response.headers["Content-Type"] = "text/html; charset=UTF-8" - getFortunes { (fortunes, err) in - guard var fortunes = fortunes else { - guard let err = err else { - Log.error("Unknown Error") - try? response.status(.badRequest).send("Unknown error").end() - return - } - Log.error("\(err)") - try? response.status(.badRequest).send("Error: \(err)").end() - return - } - fortunes.append(Fortune(id: 0, message: "Additional fortune added at request time.")) - do { - try response.render("fortunes.mustache", context: ["fortunes": fortunes.sorted()]).end() - } catch { - print("Error: \(error)") - } - } -} - -Kitura.addHTTPServer(onPort: 8080, with: router) -Kitura.run() diff --git a/frameworks/Swift/kitura/Sources/TechEmpowerPostgresORM/main.swift b/frameworks/Swift/kitura/Sources/TechEmpowerPostgresORM/main.swift deleted file mode 100644 index 56c1cdd9cb6..00000000000 --- a/frameworks/Swift/kitura/Sources/TechEmpowerPostgresORM/main.swift +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright IBM Corporation 2018 - * - * 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. - */ - -import Foundation -import Kitura -import LoggerAPI -import HeliumLogger -import KituraStencil -import Stencil -import TechEmpowerCommon -import KueryPostgresORM - -Log.logger = HeliumLogger(.info) - -// Stencil stuff -let ext = Extension() - -// Stencil does not yet support automatic HTML escaping: -// https://github.com/kylef/Stencil/pull/80 -// -ext.registerFilter("htmlencode") { (value: Any?) in - if let value = value as? String { - return value - .replacingOccurrences(of: "&", with: "&") - .replacingOccurrences(of: "<", with: "<") - .replacingOccurrences(of: ">", with: ">") - .replacingOccurrences(of: "'", with: "'") - .replacingOccurrences(of: "\"", with: """) - } - return value -} - -let router = Router() -router.add(templateEngine: StencilTemplateEngine(extension: ext)) - -setupORM() - -// -// TechEmpower test 2: Single database query (full ORM) -// -router.get("/db") { - request, response, next in - response.headers["Server"] = "Kitura" - getRandomRow { (row, err) in - guard let row = row else { - guard let err = err else { - Log.error("Unknown Error") - try? response.status(.badRequest).send("Unknown error").end() - return - } - Log.error("\(err)") - try? response.status(.badRequest).send("Error: \(err)").end() - return - } - try? response.status(.OK).send(json: row.asDictionary()).end() - } -} - -// -// TechEmpower test 3: Multiple database queries (full ORM) -// Get param provides number of queries: /queries?queries=N -// -router.get("/queries") { - request, response, next in - response.headers["Server"] = "Kitura" - let queriesParam = request.queryParameters["queries"] ?? "1" - let numQueries = max(1, min(Int(queriesParam) ?? 1, 500)) // Snap to range of 1-500 as per test spec - getRandomRows(count: numQueries) { (rows, err) in - if let rows = rows { - try? response.status(.OK).send(json: rows).end() - } else if let err = err { - try? response.status(.badRequest).send("Error: \(err)").end() - } else { - fatalError("Unexpected: rows and err both nil") - } - } -} - -router.get("/queriesParallel") { - request, response, next in - response.headers["Server"] = "Kitura" - let queriesParam = request.queryParameters["queries"] ?? "1" - let numQueries = max(1, min(Int(queriesParam) ?? 1, 500)) // Snap to range of 1-500 as per test spec - getRandomRowsParallel(count: numQueries) { (rows, err) in - if let rows = rows { - try? response.status(.OK).send(json: rows).end() - } else if let err = err { - try? response.status(.badRequest).send("Error: \(err)").end() - } else { - fatalError("Unexpected: rows and err both nil") - } - } -} - -// -// TechEmpower test 4: fortunes (full ORM) -// -router.get("/fortunes") { - request, response, next in - response.headers["Server"] = "Kitura" - response.headers["Content-Type"] = "text/html; charset=UTF-8" - Fortune.findAll { (fortunes, err) in - if var fortunes = fortunes { - fortunes.append(Fortune(id: 0, message: "Additional fortune added at request time.")) - do { - try response.render("fortunes.stencil", context: ["fortunes": fortunes.sorted()]).end() - } catch { - try? response.status(.internalServerError).send("Error: \(error)").end() - } - } else { - try? response.status(.internalServerError).send("Error: \(err ?? .internalServerError)").end() - } - } -} - -// -// TechEmpower test 5: updates (full ORM) -// -router.get("/updates") { - request, response, next in - response.headers["Server"] = "Kitura" - let queriesParam = request.queryParameters["queries"] ?? "1" - let numQueries = max(1, min(Int(queriesParam) ?? 1, 500)) // Snap to range of 1-500 as per test spec - updateRandomRows(count: numQueries) { (rows, err) in - if let rows = rows { - try? response.status(.OK).send(json: rows).end() - } else if let err = err { - try? response.status(.badRequest).send("Error: \(err)").end() - } else { - fatalError("Unexpected: rows and err both nil") - } - } -} - -router.get("/updatesParallel") { - request, response, next in - response.headers["Server"] = "Kitura" - let queriesParam = request.queryParameters["queries"] ?? "1" - let numQueries = max(1, min(Int(queriesParam) ?? 1, 500)) // Snap to range of 1-500 as per test spec - updateRandomRowsParallel(count: numQueries) { (rows, err) in - if let rows = rows { - try? response.status(.OK).send(json: rows).end() - } else if let err = err { - try? response.status(.badRequest).send("Error: \(err)").end() - } else { - fatalError("Unexpected: rows and err both nil") - } - } -} - - -Kitura.addHTTPServer(onPort: 8080, with: router) -Kitura.run() diff --git a/frameworks/Swift/kitura/Sources/TechEmpowerPostgresORMCodable/main.swift b/frameworks/Swift/kitura/Sources/TechEmpowerPostgresORMCodable/main.swift deleted file mode 100644 index 1e3cd6b05cd..00000000000 --- a/frameworks/Swift/kitura/Sources/TechEmpowerPostgresORMCodable/main.swift +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright IBM Corporation 2018 - * - * 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. - */ - -import Foundation -import Kitura -import LoggerAPI -import HeliumLogger -import KituraStencil -import Stencil -import TechEmpowerCommon -import KueryPostgres -import SwiftKueryORM -import KueryPostgresORM - -Log.logger = HeliumLogger(.info) - -// Stencil stuff -let ext = Extension() - -// Stencil does not yet support automatic HTML escaping: -// https://github.com/kylef/Stencil/pull/80 -// -ext.registerFilter("htmlencode") { (value: Any?) in - if let value = value as? String { - return value - .replacingOccurrences(of: "&", with: "&") - .replacingOccurrences(of: "<", with: "<") - .replacingOccurrences(of: ">", with: ">") - .replacingOccurrences(of: "'", with: "'") - .replacingOccurrences(of: "\"", with: """) - } - return value -} - -let router = Router() -router.add(templateEngine: StencilTemplateEngine(extension: ext)) - -// Configure our ORM Database connection pool as dbConnPool created by KueryPostgres -Database.default = Database(dbConnPool) - -// Define the query parameters we can receive -struct TFBParams: QueryParams { - let queries: Int - - // Override default decode to cater for the query parameter specification: - // If the parameter is missing, is not an integer, or is an integer less - // than 1, the value should be interpreted as 1. - // This means that rather than failing to decode on a non-integer value, we - // should fall back to a value of 1. - public init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - if let value = try? container.decode(Int.self, forKey: CodingKeys.queries) { - self.queries = value - } else { - self.queries = 1 - } - } -} - -// Set Server header on all responses as per TechEmpower spec -router.all("/*") { - _, response, next in - response.headers["Server"] = "Kitura" - next() -} - -// -// TechEmpower test 2: Single database query (full ORM) -// -router.get("/db") { (respondWith: @escaping (RandomRow?, RequestError?) -> Void) in - // Select random row from database range - RandomRow.find(id: RandomRow.randomId, respondWith) -} - -// -// TechEmpower test 3: Multiple database queries (full ORM) -// Get param provides number of queries: /queries?queries=N -// -router.get("/queries") { (params: TFBParams, respondWith: @escaping ([RandomRow]?, RequestError?) -> Void) in - let numQueries = max(1, min(params.queries, 500)) // Snap to range of 1-500 as per test spec - getRandomRows(count: numQueries, completion: respondWith) -} -router.get("/queriesParallel") { (params: TFBParams, respondWith: @escaping ([RandomRow]?, RequestError?) -> Void) in - let numQueries = max(1, min(params.queries, 500)) // Snap to range of 1-500 as per test spec - getRandomRowsParallel(count: numQueries, completion: respondWith) -} - -// -// TechEmpower test 4: fortunes (full ORM) -// TODO: convert to Codable once templating support is available -// -router.get("/fortunes") { - request, response, next in - response.headers["Content-Type"] = "text/html; charset=UTF-8" - Fortune.findAll { (fortunes, err) in - if var fortunes = fortunes { - fortunes.append(Fortune(id: 0, message: "Additional fortune added at request time.")) - do { - try response.render("fortunes.stencil", context: ["fortunes": fortunes.sorted()]).end() - } catch { - try? response.status(.internalServerError).send("Error: \(error)").end() - } - } else { - try? response.status(.internalServerError).send("Error: \(err ?? .internalServerError)").end() - } - } -} - -// -// TechEmpower test 5: updates (full ORM) -// -router.get("/updates") { (params: TFBParams, respondWith: @escaping ([RandomRow]?, RequestError?) -> Void) in - let numQueries = max(1, min(params.queries, 500)) // Snap to range of 1-500 as per test spec - updateRandomRows(count: numQueries, completion: respondWith) -} -router.get("/updatesParallel") { (params: TFBParams, respondWith: @escaping ([RandomRow]?, RequestError?) -> Void) in - let numQueries = max(1, min(params.queries, 500)) // Snap to range of 1-500 as per test spec - updateRandomRowsParallel(count: numQueries, completion: respondWith) -} - - -Kitura.addHTTPServer(onPort: 8080, with: router) -Kitura.run() diff --git a/frameworks/Swift/kitura/Views/fortunes.mustache b/frameworks/Swift/kitura/Views/fortunes.mustache deleted file mode 100644 index b0b428ad908..00000000000 --- a/frameworks/Swift/kitura/Views/fortunes.mustache +++ /dev/null @@ -1,12 +0,0 @@ - - -Fortunes - - - -{{#fortunes}} - -{{/fortunes}} -
idmessage
{{id}}{{message}}
- - diff --git a/frameworks/Swift/kitura/Views/fortunes.stencil b/frameworks/Swift/kitura/Views/fortunes.stencil deleted file mode 100644 index 8076e082f24..00000000000 --- a/frameworks/Swift/kitura/Views/fortunes.stencil +++ /dev/null @@ -1,10 +0,0 @@ - - -Fortunes - - -{% for fortune in fortunes %} -{% endfor %} -
idmessage
{{ fortune.id }}{{ fortune.message | htmlencode }}
- - diff --git a/frameworks/Swift/kitura/benchmark_config.json b/frameworks/Swift/kitura/benchmark_config.json deleted file mode 100644 index e623175df5d..00000000000 --- a/frameworks/Swift/kitura/benchmark_config.json +++ /dev/null @@ -1,246 +0,0 @@ -{ - "framework": "kitura", - "tests": [{ - "default": { - "json_url": "/json", - "plaintext_url": "/plaintext", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "none", - "framework": "Kitura", - "language": "Swift", - "orm": "none", - "platform": "KituraNet", - "webserver": "Kitura", - "os": "Linux", - "database_os": "Linux", - "display_name": "Kitura", - "notes": "", - "tags": ["broken"] - }, - "postgres": { - "db_url": "/db", - "query_url": "/queries?queries=", - "fortune_url": "/fortunes", - "update_url": "/updates?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "Postgres", - "framework": "Kitura", - "language": "Swift", - "orm": "Raw", - "platform": "KituraNet", - "webserver": "Kitura", - "os": "Linux", - "database_os": "Linux", - "display_name": "Kitura", - "notes": "", - "tags": ["broken"] - }, - "postgres-orm": { - "db_url": "/db", - "fortune_url": "/fortunes", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "Postgres", - "framework": "Kitura", - "language": "Swift", - "orm": "Full", - "platform": "KituraNet", - "webserver": "Kitura", - "os": "Linux", - "database_os": "Linux", - "display_name": "Kitura", - "notes": "", - "tags": ["broken"] - }, - "postgres-orm-codable": { - "db_url": "/db", - "query_url": "/queries?queries=", - "update_url": "/updates?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "Postgres", - "framework": "Kitura", - "language": "Swift", - "orm": "Full", - "platform": "KituraNet", - "webserver": "Kitura", - "os": "Linux", - "database_os": "Linux", - "display_name": "Kitura", - "notes": "", - "tags": ["broken"] - }, - "mongodb": { - "db_url": "/db", - "query_url": "/queries?queries=", - "fortune_url": "/fortunes", - "update_url": "/updates?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "MongoDB", - "framework": "Kitura", - "language": "Swift", - "orm": "Raw", - "platform": "KituraNet", - "webserver": "Kitura", - "os": "Linux", - "database_os": "Linux", - "display_name": "Kitura", - "notes": "", - "tags": ["broken"] - }, - "gcd": { - "json_url": "/json", - "plaintext_url": "/plaintext", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "none", - "framework": "Kitura", - "language": "Swift", - "orm": "none", - "platform": "KituraNet", - "webserver": "Kitura", - "os": "Linux", - "database_os": "Linux", - "display_name": "Kitura", - "notes": "", - "tags": ["broken"] - }, - "nio": { - "json_url": "/json", - "plaintext_url": "/plaintext", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "none", - "framework": "Kitura", - "language": "Swift", - "orm": "none", - "platform": "KituraNIO", - "webserver": "Kitura", - "os": "Linux", - "database_os": "Linux", - "display_name": "Kitura", - "notes": "", - "tags": ["broken"] - }, - "gcd-postgres": { - "db_url": "/db", - "fortune_url": "/fortunes", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "Postgres", - "framework": "Kitura", - "language": "Swift", - "orm": "Raw", - "platform": "KituraNet", - "webserver": "Kitura", - "os": "Linux", - "database_os": "Linux", - "display_name": "Kitura", - "notes": "", - "tags": ["broken"] - }, - "nio-postgres": { - "db_url": "/db", - "query_url": "/queries?queries=", - "fortune_url": "/fortunes", - "update_url": "/updates?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "Postgres", - "framework": "Kitura", - "language": "Swift", - "orm": "Raw", - "platform": "KituraNIO", - "webserver": "Kitura", - "os": "Linux", - "database_os": "Linux", - "display_name": "Kitura", - "notes": "", - "tags": ["broken"] - }, - "gcd-postgres-orm": { - "db_url": "/db", - "fortune_url": "/fortunes", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "Postgres", - "framework": "Kitura", - "language": "Swift", - "orm": "Full", - "platform": "KituraNet", - "webserver": "Kitura", - "os": "Linux", - "database_os": "Linux", - "display_name": "Kitura", - "notes": "", - "tags": ["broken"] - }, - "nio-postgres-orm": { - "db_url": "/db", - "fortune_url": "/fortunes", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "Postgres", - "framework": "Kitura", - "language": "Swift", - "orm": "Full", - "platform": "KituraNIO", - "webserver": "Kitura", - "os": "Linux", - "database_os": "Linux", - "display_name": "Kitura", - "notes": "", - "tags": ["broken"] - }, - "gcd-postgres-orm-codable": { - "db_url": "/db", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "Postgres", - "framework": "Kitura", - "language": "Swift", - "orm": "Full", - "platform": "KituraNet", - "webserver": "Kitura", - "os": "Linux", - "database_os": "Linux", - "display_name": "Kitura", - "notes": "", - "tags": ["broken"] - }, - "nio-postgres-orm-codable": { - "db_url": "/db", - "query_url": "/queries?queries=", - "update_url": "/updates?queries=", - "port": 8080, - "approach": "Realistic", - "classification": "Fullstack", - "database": "Postgres", - "framework": "Kitura", - "language": "Swift", - "orm": "Full", - "platform": "KituraNIO", - "webserver": "Kitura", - "os": "Linux", - "database_os": "Linux", - "display_name": "Kitura", - "notes": "", - "tags": ["broken"] - } - }] -} diff --git a/frameworks/Swift/kitura/config.json b/frameworks/Swift/kitura/config.json deleted file mode 100644 index 1c8e7fe38c3..00000000000 --- a/frameworks/Swift/kitura/config.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "db": { - "host": "tfb-database", - "port": 5432, - "name": "hello_world", - "user": "benchmarkdbuser", - "password": "benchmarkdbpass" - }, - "mongodb": { - "host": "tfb-database", - "port": 27017, - "name": "hello_world", - "user": "benchmarkdbuser", - "password": "benchmarkdbpass" - } -} diff --git a/frameworks/Swift/kitura/config.toml b/frameworks/Swift/kitura/config.toml deleted file mode 100644 index 774e2f69587..00000000000 --- a/frameworks/Swift/kitura/config.toml +++ /dev/null @@ -1,178 +0,0 @@ -[framework] -name = "kitura" - -[postgres-orm] -urls.db = "/db" -urls.fortune = "/fortunes" -approach = "Realistic" -classification = "Fullstack" -database = "Postgres" -database_os = "Linux" -os = "Linux" -orm = "Full" -platform = "KituraNet" -webserver = "Kitura" -versus = "None" - -[gcd-postgres-orm-codable] -urls.db = "/db" -approach = "Realistic" -classification = "Fullstack" -database = "Postgres" -database_os = "Linux" -os = "Linux" -orm = "Full" -platform = "KituraNet" -webserver = "Kitura" -versus = "None" - -[gcd] -urls.plaintext = "/plaintext" -urls.json = "/json" -approach = "Realistic" -classification = "Fullstack" -database = "none" -database_os = "Linux" -os = "Linux" -orm = "none" -platform = "KituraNet" -webserver = "Kitura" -versus = "None" - -[main] -urls.plaintext = "/plaintext" -urls.json = "/json" -approach = "Realistic" -classification = "Fullstack" -database = "none" -database_os = "Linux" -os = "Linux" -orm = "none" -platform = "KituraNet" -webserver = "Kitura" -versus = "None" - -[mongodb] -urls.db = "/db" -urls.query = "/queries?queries=" -urls.update = "/updates?queries=" -urls.fortune = "/fortunes" -approach = "Realistic" -classification = "Fullstack" -database = "MongoDB" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "KituraNet" -webserver = "Kitura" -versus = "None" - -[nio] -urls.plaintext = "/plaintext" -urls.json = "/json" -approach = "Realistic" -classification = "Fullstack" -database = "none" -database_os = "Linux" -os = "Linux" -orm = "none" -platform = "KituraNIO" -webserver = "Kitura" -versus = "None" - -[gcd-postgres-orm] -urls.db = "/db" -urls.fortune = "/fortunes" -approach = "Realistic" -classification = "Fullstack" -database = "Postgres" -database_os = "Linux" -os = "Linux" -orm = "Full" -platform = "KituraNet" -webserver = "Kitura" -versus = "None" - -[nio-postgres-orm] -urls.db = "/db" -urls.fortune = "/fortunes" -approach = "Realistic" -classification = "Fullstack" -database = "Postgres" -database_os = "Linux" -os = "Linux" -orm = "Full" -platform = "KituraNIO" -webserver = "Kitura" -versus = "None" - -[nio-postgres] -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 = "Raw" -platform = "KituraNIO" -webserver = "Kitura" -versus = "None" - -[postgres-orm-codable] -urls.db = "/db" -urls.query = "/queries?queries=" -urls.update = "/updates?queries=" -approach = "Realistic" -classification = "Fullstack" -database = "Postgres" -database_os = "Linux" -os = "Linux" -orm = "Full" -platform = "KituraNet" -webserver = "Kitura" -versus = "None" - -[nio-postgres-orm-codable] -urls.db = "/db" -urls.query = "/queries?queries=" -urls.update = "/updates?queries=" -approach = "Realistic" -classification = "Fullstack" -database = "Postgres" -database_os = "Linux" -os = "Linux" -orm = "Full" -platform = "KituraNIO" -webserver = "Kitura" -versus = "None" - -[gcd-postgres] -urls.db = "/db" -urls.fortune = "/fortunes" -approach = "Realistic" -classification = "Fullstack" -database = "Postgres" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "KituraNet" -webserver = "Kitura" -versus = "None" - -[postgres] -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 = "Raw" -platform = "KituraNet" -webserver = "Kitura" -versus = "None" diff --git a/frameworks/Swift/kitura/kitura-gcd-postgres-orm-codable.dockerfile b/frameworks/Swift/kitura/kitura-gcd-postgres-orm-codable.dockerfile deleted file mode 100644 index 2947f1ac419..00000000000 --- a/frameworks/Swift/kitura/kitura-gcd-postgres-orm-codable.dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM swift:4.1 - -ADD ./ /kitura -WORKDIR /kitura -RUN apt-get update -yqq && apt-get install -yqq libpq-dev -RUN swift build -c release -Xswiftc -DGCD_ASYNCH - -EXPOSE 8080 - -CMD .build/release/TechEmpowerPostgresORMCodable diff --git a/frameworks/Swift/kitura/kitura-gcd-postgres-orm.dockerfile b/frameworks/Swift/kitura/kitura-gcd-postgres-orm.dockerfile deleted file mode 100644 index 8a76a84f73c..00000000000 --- a/frameworks/Swift/kitura/kitura-gcd-postgres-orm.dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM swift:4.1 - -ADD ./ /kitura -WORKDIR /kitura -RUN apt-get update -yqq && apt-get install -yqq libpq-dev -RUN swift build -c release -Xswiftc -DGCD_ASYNCH - -EXPOSE 8080 - -CMD .build/release/TechEmpowerPostgresORM diff --git a/frameworks/Swift/kitura/kitura-gcd-postgres.dockerfile b/frameworks/Swift/kitura/kitura-gcd-postgres.dockerfile deleted file mode 100644 index 8f0a3f598dd..00000000000 --- a/frameworks/Swift/kitura/kitura-gcd-postgres.dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM swift:4.1 - -ADD ./ /kitura -WORKDIR /kitura -RUN apt-get update -yqq && apt-get install -yqq libpq-dev -RUN swift build -c release -Xswiftc -DGCD_ASYNCH - -EXPOSE 8080 - -CMD .build/release/TechEmpowerPostgres diff --git a/frameworks/Swift/kitura/kitura-gcd.dockerfile b/frameworks/Swift/kitura/kitura-gcd.dockerfile deleted file mode 100644 index 11f0c6a8674..00000000000 --- a/frameworks/Swift/kitura/kitura-gcd.dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM swift:4.1 - -ADD ./ /kitura -WORKDIR /kitura -RUN apt-get update -yqq && apt-get install -yqq libpq-dev -RUN swift build -c release -Xswiftc -DGCD_ASYNCH - -EXPOSE 8080 - -CMD .build/release/TechEmpower diff --git a/frameworks/Swift/kitura/kitura-mongodb.dockerfile b/frameworks/Swift/kitura/kitura-mongodb.dockerfile deleted file mode 100644 index 8c8a7943d9b..00000000000 --- a/frameworks/Swift/kitura/kitura-mongodb.dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM swift:4.1 - -ADD ./ /kitura -WORKDIR /kitura -RUN apt-get update -yqq && apt-get install -yqq libpq-dev -RUN swift build -c release - -EXPOSE 8080 - -CMD .build/release/TechEmpowerMongoKitten diff --git a/frameworks/Swift/kitura/kitura-nio-postgres-orm-codable.dockerfile b/frameworks/Swift/kitura/kitura-nio-postgres-orm-codable.dockerfile deleted file mode 100644 index dca3f44804e..00000000000 --- a/frameworks/Swift/kitura/kitura-nio-postgres-orm-codable.dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM swift:4.1 - -ADD ./ /kitura -WORKDIR /kitura -RUN apt-get update -yqq && apt-get install -yqq libpq-dev -ENV KITURA_NIO=1 -RUN swift build -c release - -EXPOSE 8080 - -CMD .build/release/TechEmpowerPostgresORMCodable diff --git a/frameworks/Swift/kitura/kitura-nio-postgres-orm.dockerfile b/frameworks/Swift/kitura/kitura-nio-postgres-orm.dockerfile deleted file mode 100644 index 37808bba760..00000000000 --- a/frameworks/Swift/kitura/kitura-nio-postgres-orm.dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM swift:4.1 - -ADD ./ /kitura -WORKDIR /kitura -RUN apt-get update -yqq && apt-get install -yqq libpq-dev -ENV KITURA_NIO=1 -RUN swift build -c release - -EXPOSE 8080 - -CMD .build/release/TechEmpowerPostgresORM diff --git a/frameworks/Swift/kitura/kitura-nio-postgres.dockerfile b/frameworks/Swift/kitura/kitura-nio-postgres.dockerfile deleted file mode 100644 index 0254fda2bdc..00000000000 --- a/frameworks/Swift/kitura/kitura-nio-postgres.dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM swift:4.1 - -ADD ./ /kitura -WORKDIR /kitura -RUN apt-get update -yqq && apt-get install -yqq libpq-dev -ENV KITURA_NIO=1 -RUN swift build -c release - -EXPOSE 8080 - -CMD .build/release/TechEmpowerPostgres diff --git a/frameworks/Swift/kitura/kitura-nio.dockerfile b/frameworks/Swift/kitura/kitura-nio.dockerfile deleted file mode 100644 index c19a4d71cf4..00000000000 --- a/frameworks/Swift/kitura/kitura-nio.dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM swift:4.1 - -ADD ./ /kitura -WORKDIR /kitura -RUN apt-get update -yqq && apt-get install -yqq libpq-dev -ENV KITURA_NIO=1 -RUN swift build -c release - -EXPOSE 8080 - -CMD .build/release/TechEmpower diff --git a/frameworks/Swift/kitura/kitura-postgres-orm-codable.dockerfile b/frameworks/Swift/kitura/kitura-postgres-orm-codable.dockerfile deleted file mode 100644 index 39f69975b95..00000000000 --- a/frameworks/Swift/kitura/kitura-postgres-orm-codable.dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM swift:4.1 - -ADD ./ /kitura -WORKDIR /kitura -RUN apt-get update -yqq && apt-get install -yqq libpq-dev -RUN swift build -c release - -EXPOSE 8080 - -CMD .build/release/TechEmpowerPostgresORMCodable diff --git a/frameworks/Swift/kitura/kitura-postgres-orm.dockerfile b/frameworks/Swift/kitura/kitura-postgres-orm.dockerfile deleted file mode 100644 index 628a987c72f..00000000000 --- a/frameworks/Swift/kitura/kitura-postgres-orm.dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM swift:4.1 - -ADD ./ /kitura -WORKDIR /kitura -RUN apt-get update -yqq && apt-get install -yqq libpq-dev -RUN swift build -c release - -EXPOSE 8080 - -CMD .build/release/TechEmpowerPostgresORM diff --git a/frameworks/Swift/kitura/kitura-postgres.dockerfile b/frameworks/Swift/kitura/kitura-postgres.dockerfile deleted file mode 100644 index b7075dce6a2..00000000000 --- a/frameworks/Swift/kitura/kitura-postgres.dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM swift:4.1 - -ADD ./ /kitura -WORKDIR /kitura -RUN apt-get update -yqq && apt-get install -yqq libpq-dev -RUN swift build -c release - -EXPOSE 8080 - -CMD .build/release/TechEmpowerPostgres diff --git a/frameworks/Swift/kitura/kitura.dockerfile b/frameworks/Swift/kitura/kitura.dockerfile deleted file mode 100644 index b720d4aa1b6..00000000000 --- a/frameworks/Swift/kitura/kitura.dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM swift:4.1 - -ADD ./ /kitura -WORKDIR /kitura -RUN apt-get update -yqq && apt-get install -yqq libpq-dev -RUN swift build -c release - -EXPOSE 8080 - -CMD .build/release/TechEmpower diff --git a/frameworks/Swift/perfect/.gitignore b/frameworks/Swift/perfect/.gitignore deleted file mode 100644 index 94822102415..00000000000 --- a/frameworks/Swift/perfect/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -.DS_Store -.build -build_gcd -.swiftenv -Packages -*.xcodeproj diff --git a/frameworks/Swift/perfect/Package.swift b/frameworks/Swift/perfect/Package.swift deleted file mode 100644 index 1735285d618..00000000000 --- a/frameworks/Swift/perfect/Package.swift +++ /dev/null @@ -1,25 +0,0 @@ -// swift-tools-version:4.0 - -import PackageDescription - -let package = Package( - name: "Perfect-TechEmpower", - products: [ - .executable(name: "Perfect", targets: ["Perfect"]), - .executable(name: "Perfect-MySQL", targets: ["Perfect-MySQL"]), - .executable(name: "Perfect-PostgreSQL", targets: ["Perfect-PostgreSQL"]), - .executable(name: "Perfect-MongoDB", targets: ["Perfect-MongoDB"]) - ], - dependencies: [ - .package(url: "https://github.com/PerfectlySoft/Perfect-HTTPServer.git", from: "3.0.0"), - .package(url:"https://github.com/PerfectlySoft/Perfect-MySQL.git", from: "3.0.0"), - .package(url: "https://github.com/PerfectlySoft/Perfect-PostgreSQL.git", from: "3.0.0"), - .package(url:"https://github.com/PerfectlySoft/Perfect-MongoDB.git", from: "3.0.0") - ], - targets: [ - .target(name: "Perfect", dependencies: ["PerfectHTTPServer"]), - .target(name: "Perfect-MySQL", dependencies: ["PerfectHTTPServer", "PerfectMySQL"]), - .target(name: "Perfect-PostgreSQL", dependencies: ["PerfectHTTPServer", "PerfectPostgreSQL"]), - .target(name: "Perfect-MongoDB", dependencies: ["PerfectHTTPServer", "PerfectMongoDB"]) - ] -) diff --git a/frameworks/Swift/perfect/README.md b/frameworks/Swift/perfect/README.md deleted file mode 100644 index ee78448860f..00000000000 --- a/frameworks/Swift/perfect/README.md +++ /dev/null @@ -1,43 +0,0 @@ -# [Perfect](https://www.perfect.org) Benchmark Test - -This is the [Perfect](https://www.perfect.org) portion of a [benchmarking test suite](https://www.techempower.com/benchmarks/) comparing a variety of web development platforms. - -## Variants - -There is are four versions of the benchmark, three of which use databases: -- `Perfect`: No DB -- `Perfect-MySQL`: Using MySQL -- `Perfect-PostgreSQL`: Using PostgreSQL -- `Perfect-MongoDB`: Using MongoDB - -Each listens on port 8080, and use common URLs described below. - -## Versions and Dependencies - -This version of the benchmark requires Swift 4.1, and uses the following versions of Perfect and dependencies: - -- [Perfect 3.0](https://github.com/PerfectlySoft/Perfect-HTTPServer.git) -- [Perfect-MySQL 3.0](https://github.com/PerfectlySoft/Perfect-MySQL.git) -- [Perfect-PostgreSQL 3.0](https://github.com/PerfectlySoft/Perfect-PostgreSQL.git) -- [Perfect-MongoDB 3.0](https://github.com/PerfectlySoft/Perfect-MongoDB.git) - -## Test URLs -### JSON serialization - -http://localhost:8080/json - -### Plaintext - -http://localhost:8080/plaintext - -### DB Store - on all configurations - -http://localhost:8080/db - -### Queries - on all configurations - -http://localhost:8080/queries/queries=2 - -### Updates - on all configurations - -http://localhost:8080/updates/queries=2 \ No newline at end of file diff --git a/frameworks/Swift/perfect/Sources/Perfect-MongoDB/main.swift b/frameworks/Swift/perfect/Sources/Perfect-MongoDB/main.swift deleted file mode 100644 index 73c8460a17e..00000000000 --- a/frameworks/Swift/perfect/Sources/Perfect-MongoDB/main.swift +++ /dev/null @@ -1,316 +0,0 @@ -import PerfectHTTP -import PerfectHTTPServer -import PerfectLib -import PerfectMongoDB -import Foundation - -let tfbHost = "tfb-database" -let database = "hello_world" -let username = "benchmarkdbuser" -let password = "benchmarkdbpass" - -let client = try! MongoClient(uri: "mongodb://\(tfbHost)") -let db = client.getDatabase(name: database) -let World = db.getCollection(name: "world") -let Fortune = db.getCollection(name: "fortune") - -class LinearCongruntialGenerator { - - var state = 0 //seed of 0 by default - let a, c, m, shift: Int - - init() { - self.a = 214013 - self.c = 2531011 - self.m = Int(pow(2.0, 31.0)) //2^31 or 2147483648 - self.shift = 16 - } - - func random() -> Int { - state = (a * state + c) % m - return state >> shift - } -} - -let numGenerator = LinearCongruntialGenerator() - -func fetchFromWorld(id: String?) -> [String: Any] { - - var rand:Int = 0 - - if id == nil { - rand = numGenerator.random() % 10000 + 1 - } else { - rand = Int(id!)! - } - - if let world = World { - - var json = [String:Any]() - json["id"] = rand - - var fields = [String: Any]() - fields["id"] = 1 - fields["randomNumber"] = 1 - fields["_id"] = 0 - - var fieldString: String = "" - - do { - fieldString = try fields.jsonEncodedString() - } catch { - fieldString = String(describing: fields) - } - - do { - let jsonString = try json.jsonEncodedString() - do { - let results = try world.find(query: BSON( json: jsonString ), fields: BSON( json: fieldString )) - - if let res = results { - for item in res { - let itemString = String(describing: item) - return convertStringToDictionary(str: itemString) - } - } else { - print("results couldn't be unwrapped: ", rand) - } - } catch { - // - } - } catch { - // empty on purpose - } - } else { - // - } - - let emptyObj = [String: Any]() - return emptyObj -} - -func updateOneFromWorld() -> [String: Any] { - - let worldToUpdate = fetchFromWorld(id: nil) - var id = Int() - if worldToUpdate["id"] != nil { - id = worldToUpdate["id"] as! Int - } else { - id = 1 - print("Error trying to fetch a world to update") - } - let newRandom = numGenerator.random() % 10000 - var errorObj = [String: Any]() - - if let world = World { - - var json = [String: Any]() - json["id"] = id - - var fields = [String: Any]() - fields["id"] = 1 - fields["randomNumber"] = 1 - fields["_id"] = 0 - - var update = [String: Any]() - update["randomNumber"] = newRandom - - var fieldString: String = "" - - do { - fieldString = try fields.jsonEncodedString() - } catch { - fieldString = String(describing: fields) - } - - var updateString: String = "" - var jsonString: String = "" - - do { - updateString = try update.jsonEncodedString() - } catch { - updateString = String(describing: update) - } - - do { - jsonString = try json.jsonEncodedString() - } catch { - jsonString = String(describing: json) - } - - do { - let results = try world.findAndModify(query: BSON( json: jsonString ), sort: nil, update: BSON( json: updateString ), fields: BSON( json: fieldString ), remove: false, upsert: false, new: true) - let resultsStr = String(describing: results) - return convertUpdateStringToDictionary(str: resultsStr, id: id) - } catch { - errorObj["id"] = "Error running query findAndModify" - return errorObj - } - } else { - errorObj["id"] = "world is empty" - return errorObj - } -} - -func updatesHandler(request: HTTPRequest, response: HTTPResponse) { - - let queryStr = returnCorrectTuple(queryArr: request.queryParams) - var totalQueries = sanitizeQueryValue(queryString: queryStr) - - var updateArr: Array = [[String: Any]]() - - while 0 < totalQueries { - updateArr.append(updateOneFromWorld()) - totalQueries -= 1 - } - - do { - - response.appendBody(string: try updateArr.jsonEncodedString()) - } catch { - - response.appendBody(string: String(describing: updateArr)) - } - - setHeaders(response: response, contentType: "application/json") - - response.completed() -} - -func multipleDatabaseQueriesHandler(request: HTTPRequest, response: HTTPResponse) { - - let queryStr = returnCorrectTuple(queryArr: request.queryParams) - var totalQueries = sanitizeQueryValue(queryString: queryStr) - - var queryArr = [[String: Any]]() - - while 0 < totalQueries { - - queryArr.append(fetchFromWorld(id: nil)) - totalQueries -= 1 - } - - do { - response.appendBody(string: try queryArr.jsonEncodedString()) - } catch { - response.appendBody(string: String(describing: queryArr)) - } - - setHeaders(response: response, contentType: "application/json") - - response.completed() -} - -func singleDatabaseQueryHandler(request: HTTPRequest, response: HTTPResponse) { - - let res = fetchFromWorld(id: nil) - - do { - response.appendBody(string: try res.jsonEncodedString()) - } catch { - response.appendBody(string: String(describing: res)) - } - - setHeaders(response: response, contentType: "application/json") - response.completed() -} - -// Helpers - -func setHeaders(response: HTTPResponse, contentType: String) { - - response.setHeader(.contentType, value: contentType) - response.setHeader(.custom(name: "Server"), value: "Perfect") - - let currDate: String = getCurrDate() - - response.setHeader(.custom(name: "Date"), value: currDate) -} - -func getCurrDate() -> String { - - let now = getNow() - - do { - let formatted = try formatDate(now, format: "%a, %d %b %Y %H:%M:%S %Z", timezone: nil, locale: nil) - return formatted - } catch { - return "error formatting date string" - } -} - -func returnCorrectTuple(queryArr: [(String, String)]) -> String { - - for tup in queryArr { - if String(describing: tup.0) == "queries" { - return String(describing: tup.1) - } - } - - return "nil" -} - -func sanitizeQueryValue(queryString: String) -> Int { - - if let queryNum = Int(queryString) { - - if queryNum > 0 && queryNum < 500 { - return queryNum - } else if queryNum > 500 { - return 500 - } else { - return 1 - } - } else { - return 1 - } -} - -func spoofHTML(fortunesArr: [[String: Any]]) -> String { - - var htmlToRet = "Fortunes" - - for fortune in fortunesArr { - - htmlToRet += "" - } - - htmlToRet += "
idmessage
\(fortune["id"]!)\(fortune["message"]!)
"; - - return htmlToRet -} - -func convertStringToDictionary(str: String) -> [String: Any] { - - let strOfWordsArray = str.components(separatedBy: " ") - - var returnObj = [String: Any]() - - returnObj["id"] = Int(strOfWordsArray[3].dropLast()) - returnObj["randomNumber"] = Int(strOfWordsArray[6]) - - return returnObj -} - -func convertUpdateStringToDictionary(str: String, id: Int) -> [String: Any] { - - let strOfWordsArray = str.components(separatedBy: " ") - - var returnObj = [String: Any]() - returnObj["id"] = id - returnObj["randomNumber"] = Int(strOfWordsArray[16]) - - return returnObj -} - -var routes = Routes() -routes.add(method: .get, uri: "/updates", handler: updatesHandler) -routes.add(method: .get, uri: "/queries", handler: multipleDatabaseQueriesHandler) -routes.add(method: .get, uri: "/db", handler: singleDatabaseQueryHandler) -routes.add(method: .get, uri: "/**", - handler: StaticFileHandler(documentRoot: "./webroot", allowResponseFilters: true).handleRequest) -try HTTPServer.launch(name: "localhost", - port: 8080, - routes: routes, - responseFilters: [ - (PerfectHTTPServer.HTTPFilter.contentCompression(data: [:]), HTTPFilterPriority.high)]) diff --git a/frameworks/Swift/perfect/Sources/Perfect-MySQL/main.swift b/frameworks/Swift/perfect/Sources/Perfect-MySQL/main.swift deleted file mode 100644 index 0fc5d5cdc92..00000000000 --- a/frameworks/Swift/perfect/Sources/Perfect-MySQL/main.swift +++ /dev/null @@ -1,313 +0,0 @@ -import PerfectHTTP -import PerfectHTTPServer -import PerfectLib -import PerfectMySQL -import Foundation - -let tfbHost = "tfb-database" -let database = "hello_world" -let username = "benchmarkdbuser" -let password = "benchmarkdbpass" - -let mysql = MySQL() -let connected = mysql.connect(host: tfbHost, user: username, password: password) -let _ = mysql.selectDatabase(named: database) - -class LinearCongruntialGenerator { - - var state = 0 - let a, c, m, shift: Int - - init() { - self.a = 214013 - self.c = 2531011 - self.m = Int(pow(2.0, 31.0)) - self.shift = 16 - } - - func random() -> Int { - state = (a * state + c) % m - return state >> shift - } -} - -let numGenerator = LinearCongruntialGenerator() - -func fetchFromFortune() -> [[String: String]] { - - var arrOfFortunes = [[String: String]]() - let querySuccess = mysql.query(statement: "SELECT id, message FROM fortune") - - guard querySuccess else { - - let errorObject = ["id": "Failed to execute query"] - arrOfFortunes.append(errorObject) - - return arrOfFortunes - } - - let results = mysql.storeResults()! - - results.forEachRow { row in - if let id = row[0], let message = row[1] { - - let resObj = ["id": String(describing: id), "message": message] - arrOfFortunes.append(resObj) - } else { - print("not correct values returned: ", row) - } - } - - return arrOfFortunes -} - -func fetchFromWorld(id: String?) -> [String:Any] { - - var returnObj = [String: Any]() - var errorObject = [String: Any]() - var rand:Int = 0 - - if id == nil { - rand = numGenerator.random() % 10000 + 1 - } else { - rand = Int(id!)! - } - - let querySuccess = mysql.query(statement: "SELECT id, randomNumber FROM World WHERE id = \(rand)") - - guard querySuccess else { - - errorObject["id"] = "Failed to execute query" - - return errorObject - } - - let results = mysql.storeResults()! - - results.forEachRow { row in - - if let id = row[0], let randomNumber = row[1] { - - returnObj["id"] = id - returnObj["randomNumber"] = randomNumber - } else { - - returnObj["id"] = "No return value" - returnObj["randomNumber"] = "what happened?" - } - } - - return returnObj -} - -func updateOneFromWorld() -> [String: Any] { - - var returnObj = [String: Any]() - var errorObject = [String: Any]() - let worldToUpdate = fetchFromWorld(id: nil) - let id: String = worldToUpdate["id"] as! String - let newRandom = numGenerator.random() % 10000 - - let querySuccess = mysql.query(statement: "UPDATE World SET randomNumber = \(newRandom) WHERE id = \(id)") - - guard querySuccess else { - errorObject["id"] = "Failed to execute query" - return errorObject - } - - if let results = mysql.storeResults() { - - results.forEachRow { row in - if let id = row[0], let randomNumber = row[1] { - returnObj["id"] = id - returnObj["randomNumber"] = randomNumber - } else { - returnObj["id"] = "No return value" - returnObj["randomNumber"] = "what happened?" - } - } - return returnObj - } else { - returnObj["id"] = id - returnObj["randomNumber"] = newRandom - return returnObj - } -} - -func fortunesHandler(request: HTTPRequest, response: HTTPResponse) { - - var arrOfFortunes = fetchFromFortune() - - let newObj: [String: String] = ["id": "0", "message": "Additional fortune added at request time."] - - arrOfFortunes.append(newObj) - - let sortedArr = arrOfFortunes.sorted(by: ({ $0["message"]! < $1["message"]! })) - - let htmlToRet = spoofHTML(fortunesArr: sortedArr) - - response.appendBody(string: htmlToRet) - - setHeaders(response: response, contentType: "text/html") - response.setHeader(.custom(name: "CustomLength"), value: String(describing: htmlToRet.count + 32)) - - response.completed() -} - -func updatesHandler(request: HTTPRequest, response: HTTPResponse) { - - let queryStr = returnCorrectTuple(queryArr: request.queryParams) - var totalQueries = sanitizeQueryValue(queryString: queryStr) - - var updateArr: Array = [[String: Any]]() - - while 0 < totalQueries { - updateArr.append(updateOneFromWorld()) - totalQueries -= 1 - } - - do { - - response.appendBody(string: try updateArr.jsonEncodedString()) - } catch { - - response.appendBody(string: String(describing: updateArr)) - } - - setHeaders(response: response, contentType: "application/json") - - response.completed() -} - -func multipleDatabaseQueriesHandler(request: HTTPRequest, response: HTTPResponse) { - - let queryStr = returnCorrectTuple(queryArr: request.queryParams) - var totalQueries = sanitizeQueryValue(queryString: queryStr) - - var queryArr: Array = [[String: Any]]() - - while 0 < totalQueries { - - queryArr.append(fetchFromWorld(id: nil)) - totalQueries -= 1 - } - - do { - - response.appendBody(string: try queryArr.jsonEncodedString()) - } catch { - - response.appendBody(string: String(describing: queryArr)) - } - - setHeaders(response: response, contentType: "application/json") - - response.completed() -} - -func singleDatabaseQueryHandler(request: HTTPRequest, response: HTTPResponse) { - - let res = fetchFromWorld(id: nil) - - let errorPayload: [String: Any] = [ - "error": "Could not set body!" - ] - - var responseString: String = "" - var errorString: String = "" - do { - errorString = try errorPayload.jsonEncodedString() - } catch { - // Nothing to do here - we already have an empty value - } - - do { - responseString = try res.jsonEncodedString() - response.appendBody(string: responseString) - } catch { - response.status = HTTPResponseStatus.internalServerError - response.appendBody(string: errorString) - } - - - setHeaders(response: response, contentType: "application/json") - response.completed() -} - -// Helpers - -func setHeaders(response: HTTPResponse, contentType: String) { - - response.setHeader(.contentType, value: contentType) - response.setHeader(.custom(name: "Server"), value: "Perfect") - - let currDate: String = getCurrDate() - - response.setHeader(.custom(name: "Date"), value: currDate) -} - -func getCurrDate() -> String { - - let now = getNow() - - do { - let formatted = try formatDate(now, format: "%a, %d %b %Y %H:%M:%S %Z", timezone: nil, locale: nil) - return formatted - } catch { - return "error formatting date string" - } -} - -func returnCorrectTuple(queryArr: [(String, String)]) -> String { - - for tup in queryArr { - if String(describing: tup.0) == "queries" { - return String(describing: tup.1) - } - } - - return "nil" -} - -func sanitizeQueryValue(queryString: String) -> Int { - - if let queryNum = Int(queryString) { - - if queryNum > 0 && queryNum < 500 { - return queryNum - } else if queryNum > 500 { - return 500 - } else { - return 1 - } - } else { - return 1 - } -} - -func spoofHTML(fortunesArr: [[String: Any]]) -> String { - - var htmlToRet = "Fortunes" - - for fortune in fortunesArr { - - htmlToRet += "" - } - - htmlToRet += "
idmessage
\(fortune["id"]!)\(fortune["message"]!)
"; - - return htmlToRet -} - -var routes = Routes() -routes.add(method: .get, uri: "/fortunes", handler: fortunesHandler) -routes.add(method: .get, uri: "/updates", handler: updatesHandler) -routes.add(method: .get, uri: "/queries", handler: multipleDatabaseQueriesHandler) -routes.add(method: .get, uri: "/db", handler: singleDatabaseQueryHandler) -routes.add(method: .get, uri: "/**", - handler: StaticFileHandler(documentRoot: "./webroot", allowResponseFilters: true).handleRequest) -try HTTPServer.launch(name: "localhost", - port: 8080, - routes: routes, - responseFilters: [ - (PerfectHTTPServer.HTTPFilter.contentCompression(data: [:]), HTTPFilterPriority.high)]) diff --git a/frameworks/Swift/perfect/Sources/Perfect-PostgreSQL/main.swift b/frameworks/Swift/perfect/Sources/Perfect-PostgreSQL/main.swift deleted file mode 100644 index bbb10b19b26..00000000000 --- a/frameworks/Swift/perfect/Sources/Perfect-PostgreSQL/main.swift +++ /dev/null @@ -1,224 +0,0 @@ -import PerfectHTTP -import PerfectHTTPServer -import PerfectLib -import PerfectPostgreSQL -import Foundation - -let tfbHost = "tfb-database" -let database = "hello_world" -let username = "benchmarkdbuser" -let password = "benchmarkdbpass" - -let p = PGConnection() -let status = p.connectdb("postgresql://\(username):\(password)@\(tfbHost):5432/\(database)") - -class LinearCongruntialGenerator { - - var state = 0 //seed of 0 by default - let a, c, m, shift: Int - - init() { - self.a = 214013 - self.c = 2531011 - self.m = Int(pow(2.0, 31.0)) //2^31 or 2147483648 - self.shift = 16 - } - - func random() -> Int { - state = (a * state + c) % m - return state >> shift - } -} - -let numGenerator = LinearCongruntialGenerator() - -func fetchFromWorld(id: String?) -> [String:Any] { - - var returnObj = [String: Any]() - var rand:Int = 0 - - if id == nil { - rand = numGenerator.random() % 10000 - } else { - rand = Int(id!)! - } - - let results = p.exec(statement: "select id, randomNumber from world where id = \(rand)") - - returnObj["id"] = results.getFieldString(tupleIndex: 0, fieldIndex: 0)! - returnObj["randomNumber"] = results.getFieldString(tupleIndex: 0, fieldIndex: 1)! - - return returnObj -} - -func updateOneFromWorld() -> [String: Any] { - - var returnObj = [String: Any]() - let worldToUpdate = fetchFromWorld(id: nil) - let rand = numGenerator.random() % 10000 + 1 - let id: String = worldToUpdate["id"] as! String - - let _ = p.exec(statement: "UPDATE world SET randomNumber = \(rand) WHERE id = \(id)") - - returnObj["id"] = id - returnObj["randomNumber"] = rand - - return returnObj -} - -func updatesHandler(request: HTTPRequest, response: HTTPResponse) { - - let queryStr = returnCorrectTuple(queryArr: request.queryParams) - var totalQueries = sanitizeQueryValue(queryString: queryStr) - - var updateArr: Array = [[String: Any]]() - - while 0 < totalQueries { - updateArr.append(updateOneFromWorld()) - totalQueries -= 1 - } - - do { - - response.appendBody(string: try updateArr.jsonEncodedString()) - } catch { - - response.appendBody(string: String(describing: updateArr)) - } - - setHeaders(response: response, contentType: "application/json") - - response.completed() -} - -func multipleDatabaseQueriesHandler(request: HTTPRequest, response: HTTPResponse) { - - let queryStr = returnCorrectTuple(queryArr: request.queryParams) - var totalQueries = sanitizeQueryValue(queryString: queryStr) - - var queryArr: Array = [[String: Any]]() - - while 0 < totalQueries { - - queryArr.append(fetchFromWorld(id: nil)) - totalQueries -= 1 - } - - do { - - response.appendBody(string: try queryArr.jsonEncodedString()) - } catch { - - response.appendBody(string: String(describing: queryArr)) - } - - setHeaders(response: response, contentType: "application/json") - - response.completed() -} - -func singleDatabaseQueryHandler(request: HTTPRequest, response: HTTPResponse) { - - let res = fetchFromWorld(id: nil) - - let errorPayload: [String: Any] = [ - "error": "Could not set body!" - ] - - var responseString: String = "" - var errorString: String = "" - do { - errorString = try errorPayload.jsonEncodedString() - } catch { - // Nothing to do here - we already have an empty value - } - - do { - responseString = try res.jsonEncodedString() - response.appendBody(string: responseString) - } catch { - response.status = HTTPResponseStatus.internalServerError - response.appendBody(string: errorString) - } - - - setHeaders(response: response, contentType: "application/json") - response.completed() -} - -// Helpers - -func setHeaders(response: HTTPResponse, contentType: String) { - - response.setHeader(.contentType, value: contentType) - response.setHeader(.custom(name: "Server"), value: "Perfect") - - let currDate: String = getCurrDate() - - response.setHeader(.custom(name: "Date"), value: currDate) -} - -func getCurrDate() -> String { - - let now = getNow() - - do { - let formatted = try formatDate(now, format: "%a, %d %b %Y %H:%M:%S %Z", timezone: nil, locale: nil) - return formatted - } catch { - return "error formatting date string" - } -} - -func returnCorrectTuple(queryArr: [(String, String)]) -> String { - - for tup in queryArr { - if String(describing: tup.0) == "queries" { - return String(describing: tup.1) - } - } - - return "nil" -} - -func sanitizeQueryValue(queryString: String) -> Int { - - if let queryNum = Int(queryString) { - - if queryNum > 0 && queryNum < 500 { - return queryNum - } else if queryNum > 500 { - return 500 - } else { - return 1 - } - } else { - return 1 - } -} - -func spoofHTML(fortunesArr: [[String: Any]]) -> String { - - var htmlToRet = "Fortunes" - - for fortune in fortunesArr { - - htmlToRet += "" - } - - htmlToRet += "
idmessage
\(fortune["id"]!)\(fortune["message"]!)
"; - - return htmlToRet -} - -var routes = Routes() -routes.add(method: .get, uri: "/updates", handler: updatesHandler) -routes.add(method: .get, uri: "/queries", handler: multipleDatabaseQueriesHandler) -routes.add(method: .get, uri: "/db", handler: singleDatabaseQueryHandler) -routes.add(method: .get, uri: "/**", - handler: StaticFileHandler(documentRoot: "./webroot", allowResponseFilters: true).handleRequest) -try HTTPServer.launch(name: "localhost", - port: 8080, - routes: routes, - responseFilters: [ - (PerfectHTTPServer.HTTPFilter.contentCompression(data: [:]), HTTPFilterPriority.high)]) diff --git a/frameworks/Swift/perfect/Sources/Perfect/main.swift b/frameworks/Swift/perfect/Sources/Perfect/main.swift deleted file mode 100644 index 2df4bb928e5..00000000000 --- a/frameworks/Swift/perfect/Sources/Perfect/main.swift +++ /dev/null @@ -1,78 +0,0 @@ -import PerfectHTTP -import PerfectHTTPServer -import PerfectLib -import Foundation - -func plaintextHandler(request: HTTPRequest, response: HTTPResponse) { - - response.appendBody(string: "Hello, World!") - - setHeaders(response: response, contentType: "text/plain") - - response.completed() -} - -func jsonHandler(request: HTTPRequest, response: HTTPResponse) { - - var helloDictionary: [String: String] = [:] - helloDictionary["message"] = "Hello, World!" - - let errorPayload: [String: Any] = [ - "error": "Could not set body!" - ] - - var responseString: String = "" - var errorString: String = "" - do { - errorString = try errorPayload.jsonEncodedString() - } catch { - // Nothing to do here - we already have an empty value - } - - do { - responseString = try helloDictionary.jsonEncodedString() - response.appendBody(string: responseString) - } catch { - response.status = HTTPResponseStatus.internalServerError - response.appendBody(string: errorString) - } - - - setHeaders(response: response, contentType: "application/json") - response.completed() -} - -// Helpers - -func setHeaders(response: HTTPResponse, contentType: String) { - - response.setHeader(.contentType, value: contentType) - response.setHeader(.custom(name: "Server"), value: "Perfect") - - let currDate: String = getCurrDate() - - response.setHeader(.custom(name: "Date"), value: currDate) -} - -func getCurrDate() -> String { - - let now = getNow() - - do { - let formatted = try formatDate(now, format: "%a, %d %b %Y %H:%M:%S %Z", timezone: nil, locale: nil) - return formatted - } catch { - return "error formatting date string" - } -} - -var routes = Routes() -routes.add(method: .get, uri: "/json", handler: jsonHandler) -routes.add(method: .get, uri: "/plaintext", handler: plaintextHandler) -routes.add(method: .get, uri: "/**", - handler: StaticFileHandler(documentRoot: "./webroot", allowResponseFilters: true).handleRequest) -try HTTPServer.launch(name: "localhost", - port: 8080, - routes: routes, - responseFilters: [ - (PerfectHTTPServer.HTTPFilter.contentCompression(data: [:]), HTTPFilterPriority.high)]) diff --git a/frameworks/Swift/perfect/benchmark_config.json b/frameworks/Swift/perfect/benchmark_config.json deleted file mode 100644 index 28fdd30639e..00000000000 --- a/frameworks/Swift/perfect/benchmark_config.json +++ /dev/null @@ -1,80 +0,0 @@ -{ - "framework": "perfect", - "tests": [{ - "default": { - "json_url": "/json", - "plaintext_url": "/plaintext", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "None", - "framework": "Perfect", - "language": "Swift", - "orm": "Raw", - "platform": "Perfect", - "webserver": "Perfect", - "os": "Linux", - "database_os": "Linux", - "display_name": "Perfect", - "notes": "", - "tags": ["broken"] - }, - "mysql": { - "update_url": "/updates?queries=", - "query_url": "/queries?queries=", - "db_url": "/db", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "MySQL", - "framework": "Perfect", - "language": "Swift", - "orm": "Raw", - "platform": "Perfect", - "webserver": "Perfect", - "os": "Linux", - "database_os": "Linux", - "display_name": "Perfect", - "notes": "", - "tags": ["broken"] - }, - "postgresql": { - "update_url": "/updates?queries=", - "query_url": "/queries?queries=", - "db_url": "/db", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "Postgres", - "framework": "Perfect", - "language": "Swift", - "orm": "Raw", - "platform": "Perfect", - "webserver": "Perfect", - "os": "Linux", - "database_os": "Linux", - "display_name": "Perfect", - "notes": "", - "tags": ["broken"] - }, - "mongodb": { - "update_url": "/updates?queries=", - "query_url": "/queries?queries=", - "db_url": "/db", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "MongoDB", - "framework": "Perfect", - "language": "Swift", - "orm": "Raw", - "platform": "Perfect", - "webserver": "Perfect", - "os": "Linux", - "database_os": "Linux", - "display_name": "Perfect", - "notes": "", - "tags": ["broken"] - } - }] -} diff --git a/frameworks/Swift/perfect/config.toml b/frameworks/Swift/perfect/config.toml deleted file mode 100644 index ca5f8416743..00000000000 --- a/frameworks/Swift/perfect/config.toml +++ /dev/null @@ -1,57 +0,0 @@ -[framework] -name = "perfect" - -[main] -urls.plaintext = "/plaintext" -urls.json = "/json" -approach = "Realistic" -classification = "Micro" -database = "None" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "Perfect" -webserver = "Perfect" -versus = "None" - -[mongodb] -urls.db = "/db" -urls.query = "/queries?queries=" -urls.update = "/updates?queries=" -approach = "Realistic" -classification = "Micro" -database = "MongoDB" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "Perfect" -webserver = "Perfect" -versus = "None" - -[postgresql] -urls.db = "/db" -urls.query = "/queries?queries=" -urls.update = "/updates?queries=" -approach = "Realistic" -classification = "Micro" -database = "Postgres" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "Perfect" -webserver = "Perfect" -versus = "None" - -[mysql] -urls.db = "/db" -urls.query = "/queries?queries=" -urls.update = "/updates?queries=" -approach = "Realistic" -classification = "Micro" -database = "MySQL" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "Perfect" -webserver = "Perfect" -versus = "None" diff --git a/frameworks/Swift/perfect/perfect-mongodb.dockerfile b/frameworks/Swift/perfect/perfect-mongodb.dockerfile deleted file mode 100644 index c56325691a6..00000000000 --- a/frameworks/Swift/perfect/perfect-mongodb.dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM swift:4.1 - -ADD . /perfect -WORKDIR /perfect -RUN apt-get update -yqq && apt-get install -yqq libpq-dev && apt-get install -y xsltproc docbook-xsl uuid-dev clang pkg-config libicu-dev libpython2.7 libxml2-dev wget git libssl-dev uuid-dev libsqlite3-dev libpq-dev libmysqlclient-dev libbson-dev libmongoc-dev libcurl4-openssl-dev && apt-get -y install libmysqlclient-dev libmongoc-1.0-0 libbson-1.0 -RUN swift build - -EXPOSE 8080 - -CMD .build/debug/Perfect-MongoDB diff --git a/frameworks/Swift/perfect/perfect-mysql.dockerfile b/frameworks/Swift/perfect/perfect-mysql.dockerfile deleted file mode 100644 index dfc23b3745b..00000000000 --- a/frameworks/Swift/perfect/perfect-mysql.dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM swift:4.1 - -ADD . /perfect -WORKDIR /perfect -RUN apt-get update -yqq && apt-get install -yqq libpq-dev && apt-get install -y xsltproc docbook-xsl uuid-dev clang pkg-config libicu-dev libpython2.7 libxml2-dev wget git libssl-dev uuid-dev libsqlite3-dev libpq-dev libmysqlclient-dev libbson-dev libmongoc-dev libcurl4-openssl-dev && apt-get -y install libmysqlclient-dev libmongoc-1.0-0 libbson-1.0 -RUN swift build - -EXPOSE 8080 - -CMD .build/debug/Perfect-MySQL diff --git a/frameworks/Swift/perfect/perfect-postgresql.dockerfile b/frameworks/Swift/perfect/perfect-postgresql.dockerfile deleted file mode 100644 index 11c863eac8a..00000000000 --- a/frameworks/Swift/perfect/perfect-postgresql.dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM swift:4.1 - -ADD . /perfect -WORKDIR /perfect -RUN apt-get update -yqq && apt-get install -yqq libpq-dev && apt-get install -y xsltproc docbook-xsl uuid-dev clang pkg-config libicu-dev libpython2.7 libxml2-dev wget git libssl-dev uuid-dev libsqlite3-dev libpq-dev libmysqlclient-dev libbson-dev libmongoc-dev libcurl4-openssl-dev && apt-get -y install libmysqlclient-dev libmongoc-1.0-0 libbson-1.0 -RUN swift build - -EXPOSE 8080 - -CMD .build/debug/Perfect-PostgreSQL diff --git a/frameworks/Swift/perfect/perfect.dockerfile b/frameworks/Swift/perfect/perfect.dockerfile deleted file mode 100644 index f597873a513..00000000000 --- a/frameworks/Swift/perfect/perfect.dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM swift:4.1 - -ADD . /perfect -WORKDIR /perfect -RUN apt-get update -yqq && apt-get install -yqq libpq-dev && apt-get install -y xsltproc docbook-xsl uuid-dev clang pkg-config libicu-dev libpython2.7 libxml2-dev wget git libssl-dev uuid-dev libsqlite3-dev libpq-dev libmysqlclient-dev libbson-dev libmongoc-dev libcurl4-openssl-dev && apt-get -y install libmysqlclient-dev libmongoc-1.0-0 libbson-1.0 -RUN swift build - -EXPOSE 8080 - -CMD .build/debug/Perfect diff --git a/frameworks/Swift/swift-nio/.gitignore b/frameworks/Swift/swift-nio/.gitignore deleted file mode 100644 index 1f4e5903663..00000000000 --- a/frameworks/Swift/swift-nio/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -.DS_Store -.build/ -.vscode/ -/*.xcodeproj -xcuserdata/ -.swiftpm/ -DerivedData/ -Package.resolved diff --git a/frameworks/Swift/swift-nio/config.toml b/frameworks/Swift/swift-nio/config.toml deleted file mode 100644 index 495bb4f6d2f..00000000000 --- a/frameworks/Swift/swift-nio/config.toml +++ /dev/null @@ -1,15 +0,0 @@ -[framework] -name = "swift-nio" - -[main] -urls.plaintext = "/p" -urls.json = "/j" -approach = "Realistic" -classification = "Platform" -database = "None" -database_os = "Linux" -os = "Linux" -orm = "Raw" -platform = "None" -webserver = "None" -versus = "" diff --git a/frameworks/Swift/swift-nio/swift-nio.dockerfile b/frameworks/Swift/swift-nio/swift-nio.dockerfile index 5b54a7a210f..aabc8a12334 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:5.9 as build +FROM swift:6.1 AS build WORKDIR /build # Copy entire repo into container @@ -15,7 +15,7 @@ RUN swift build \ # ================================ # Run image # ================================ -FROM swift:5.9-slim +FROM swift:6.1-slim WORKDIR /run # Install Swift dependencies diff --git a/frameworks/Swift/vapor/.gitignore b/frameworks/Swift/vapor/.gitignore deleted file mode 100644 index 1d982c0de86..00000000000 --- a/frameworks/Swift/vapor/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -.DS_Store -.build/ -/*.xcodeproj -xcuserdata/ -.swiftpm/ -DerivedData/ -Package.resolved diff --git a/frameworks/Swift/vapor/benchmark_config.json b/frameworks/Swift/vapor/benchmark_config.json index 65ea06b8726..00b6bb943dc 100755 --- a/frameworks/Swift/vapor/benchmark_config.json +++ b/frameworks/Swift/vapor/benchmark_config.json @@ -16,7 +16,7 @@ "database_os": "Linux", "display_name": "Vapor", "notes": "", - "versus": "None" + "versus": "swift-nio" }, "fluent": { "db_url": "/db", @@ -93,6 +93,29 @@ "display_name": "Vapor", "notes": "", "versus": "None" + }, + "swifql": { + "plaintext_url": "/plaintext", + "json_url": "/json", + "db_url": "/db", + "query_url": "/queries?queries=", + "update_url": "/updates?queries=", + "fortune_url": "/fortunes", + "database": "Postgres", + "orm": "Micro", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "framework": "Vapor", + "language": "Swift", + "flavor": "None", + "platform": "None", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "Vapor", + "notes": "", + "versus": "None" } }] } diff --git a/frameworks/Swift/vapor/config.toml b/frameworks/Swift/vapor/config.toml index e629702ef66..24db8e89c90 100644 --- a/frameworks/Swift/vapor/config.toml +++ b/frameworks/Swift/vapor/config.toml @@ -51,3 +51,20 @@ orm = "Micro" platform = "None" webserver = "None" versus = "None" + +[swifql] +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 = "None" +webserver = "None" +versus = "None" \ No newline at end of file diff --git a/frameworks/Swift/vapor/vapor-fluent.dockerfile b/frameworks/Swift/vapor/vapor-fluent.dockerfile index 5b883e65713..4a9d3782f6a 100644 --- a/frameworks/Swift/vapor/vapor-fluent.dockerfile +++ b/frameworks/Swift/vapor/vapor-fluent.dockerfile @@ -1,7 +1,7 @@ # ================================ # Build image # ================================ -FROM swift:5.9 as build +FROM swift:5.10 as build WORKDIR /build # Copy entire repo into container @@ -15,7 +15,7 @@ RUN swift build \ # ================================ # Run image # ================================ -FROM swift:5.9-slim +FROM swift:5.10-slim WORKDIR /run # Copy build artifacts diff --git a/frameworks/Swift/vapor/vapor-mongo-fluent.dockerfile b/frameworks/Swift/vapor/vapor-mongo-fluent.dockerfile deleted file mode 100644 index 792a810d8f4..00000000000 --- a/frameworks/Swift/vapor/vapor-mongo-fluent.dockerfile +++ /dev/null @@ -1,29 +0,0 @@ -# ================================ -# Build image -# ================================ -FROM swift:5.9 as build -WORKDIR /build - -# Copy entire repo into container -COPY ./vapor-mongo-fluent . - -# Compile with optimizations -RUN swift build \ - -c release \ - -Xswiftc -enforce-exclusivity=unchecked - -# ================================ -# Run image -# ================================ -FROM swift:5.9-slim -WORKDIR /run - -# Copy build artifacts -COPY --from=build /build/.build/release /run - -# Copy Swift runtime libraries -COPY --from=build /usr/lib/swift/ /usr/lib/swift/ - -EXPOSE 8080 - -ENTRYPOINT ["./app", "serve", "--env", "production", "--hostname", "0.0.0.0", "--port", "8080"] diff --git a/frameworks/Swift/vapor/vapor-mongo-fluent/Package.swift b/frameworks/Swift/vapor/vapor-mongo-fluent/Package.swift deleted file mode 100644 index 88ae0f29ed9..00000000000 --- a/frameworks/Swift/vapor/vapor-mongo-fluent/Package.swift +++ /dev/null @@ -1,29 +0,0 @@ -// swift-tools-version:5.5 -import PackageDescription - -let package = Package( - name: "vapor-fluent", - platforms: [ - .macOS(.v12) - ], - products: [ - .executable(name: "app", targets: ["App"]) - ], - dependencies: [ - .package(url: "https://github.com/vapor/vapor.git", from: "4.52.2"), - .package(url: "https://github.com/vapor/fluent.git", from: "4.4.0"), - .package(url: "https://github.com/vapor/fluent-mongo-driver.git", from: "1.0.2"), - .package(url: "https://github.com/orlandos-nl/MongoKitten.git", from: "6.7.1") - ], - targets: [ - .executableTarget( - name: "App", - dependencies: [ - .product(name: "Fluent", package: "fluent"), - .product(name: "FluentMongoDriver", package: "fluent-mongo-driver"), - .product(name: "Vapor", package: "vapor"), - .product(name: "MongoKitten", package: "MongoKitten"), - ], - path: "Sources"), - ] -) \ No newline at end of file diff --git a/frameworks/Swift/vapor/vapor-mongo-fluent/Sources/Utilities.swift b/frameworks/Swift/vapor/vapor-mongo-fluent/Sources/Utilities.swift deleted file mode 100644 index 7b5bb1c2878..00000000000 --- a/frameworks/Swift/vapor/vapor-mongo-fluent/Sources/Utilities.swift +++ /dev/null @@ -1,25 +0,0 @@ -import Vapor - -extension Int { - func bounded(to range: ClosedRange) -> Int { - switch self { - case ...range.lowerBound: - return range.lowerBound - case range.upperBound...: - return range.upperBound - default: - return self - } - } -} - -extension System { - // tfb-server (aka, citrine) uses 28 hyper-threaded cores - // postgresql.conf specifies max_connections = 2000 - // - // 2000 / (28 * 2) = 35.7 (theoretical max) - // - // https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Environment#citrine-self-hosted - // https://github.com/TechEmpower/FrameworkBenchmarks/blob/master/toolset/databases/postgres/postgresql.conf#L64 - static var maxConnectionsPerEventLoop: Int { 32 } -} diff --git a/frameworks/Swift/vapor/vapor-mongo-fluent/Sources/World.swift b/frameworks/Swift/vapor/vapor-mongo-fluent/Sources/World.swift deleted file mode 100644 index ef7f1314013..00000000000 --- a/frameworks/Swift/vapor/vapor-mongo-fluent/Sources/World.swift +++ /dev/null @@ -1,14 +0,0 @@ -import Fluent -import Vapor - -final class World: Model, Content { - static let schema = "world" - - @ID(custom: "id") - var id: Float? - - @Field(key: "randomNumber") - var randomNumber: Float - - init() { } -} diff --git a/frameworks/Swift/vapor/vapor-mongo-fluent/Sources/main.swift b/frameworks/Swift/vapor/vapor-mongo-fluent/Sources/main.swift deleted file mode 100644 index a7beb273bce..00000000000 --- a/frameworks/Swift/vapor/vapor-mongo-fluent/Sources/main.swift +++ /dev/null @@ -1,52 +0,0 @@ -import Fluent -import FluentMongoDriver -import Vapor - -var env = try Environment.detect() -try LoggingSystem.bootstrap(from: &env) - -let connectionString = "mongodb://tfb-database:27017/hello_world" - -let app = Application(env) - -app.http.server.configuration.serverName = "Vapor" - -app.logger.notice("💧 VAPOR") -app.logger.notice("System.coreCount: \(System.coreCount)") -app.logger.notice("System.maxConnectionsPerEventLoop: \(System.maxConnectionsPerEventLoop)") - -try app.databases.use(.mongo( - connectionString: connectionString), - as: .mongo) - -app.get("db") { req async throws -> World in - guard let world = try await World.find(Float(.random(in: 1...10_000)), on: req.db) else { - throw Abort(.notFound) - } - - return world -} - -app.get("queries") { req async throws -> [World] in - let queries = (req.query["queries"] ?? 1).bounded(to: 1...500) - - var worlds: [World] = [] - - for _ in queries { - guard let world = try await World.find(Float(.random(in: 1...10_000)), on: req.db) else { - throw Abort(.notFound) - } - - worlds.append(world) - } - - return worlds -} - -extension Int: Sequence { - public func makeIterator() -> CountableRange.Iterator { - return (0.. + +Fortunes + + + +#for(fortune in fortunes): +#endfor
idmessage
#(fortune.id)#(fortune.message)
+ + \ No newline at end of file diff --git a/frameworks/Swift/vapor/vapor-swifql/Sources/Extensions/IkigaJSONCoders+ContentCoders.swift b/frameworks/Swift/vapor/vapor-swifql/Sources/Extensions/IkigaJSONCoders+ContentCoders.swift new file mode 100644 index 00000000000..676ff7285b6 --- /dev/null +++ b/frameworks/Swift/vapor/vapor-swifql/Sources/Extensions/IkigaJSONCoders+ContentCoders.swift @@ -0,0 +1,56 @@ +// +// IkigaJSONCoders+ContentCoders.swift +// +// +// Created by Yakov Shapovalov on 04.07.2024. +// + +import IkigaJSON +import Vapor + +extension IkigaJSONEncoder: ContentEncoder { + public func encode( + _ encodable: E, + to body: inout ByteBuffer, + headers: inout HTTPHeaders + ) throws { + headers.contentType = .json + try self.encodeAndWrite(encodable, into: &body) + } + + public func encode(_ encodable: E, to body: inout ByteBuffer, headers: inout HTTPHeaders, userInfo: [CodingUserInfoKey : Sendable]) throws where E : Encodable { + var encoder = self + encoder.userInfo = userInfo + headers.contentType = .json + try encoder.encodeAndWrite(encodable, into: &body) + } + + public func encode(_ encodable: E, to body: inout ByteBuffer, headers: inout HTTPHeaders, userInfo: [CodingUserInfoKey : Any]) throws where E : Encodable { + var encoder = self + encoder.userInfo = userInfo + headers.contentType = .json + try encoder.encodeAndWrite(encodable, into: &body) + } +} + +extension IkigaJSONDecoder: ContentDecoder { + public func decode( + _ decodable: D.Type, + from body: ByteBuffer, + headers: HTTPHeaders + ) throws -> D { + return try self.decode(D.self, from: body) + } + + public func decode(_ decodable: D.Type, from body: ByteBuffer, headers: HTTPHeaders, userInfo: [CodingUserInfoKey : Sendable]) throws -> D where D : Decodable { + let decoder = IkigaJSONDecoder(settings: settings) + decoder.settings.userInfo = userInfo + return try decoder.decode(D.self, from: body) + } + + public func decode(_ decodable: D.Type, from body: ByteBuffer, headers: HTTPHeaders, userInfo: [CodingUserInfoKey : Any]) throws -> D where D : Decodable { + let decoder = IkigaJSONDecoder(settings: settings) + decoder.settings.userInfo = userInfo + return try decoder.decode(D.self, from: body) + } +} diff --git a/frameworks/Swift/vapor/vapor-swifql/Sources/Extensions/Models+Content.swift b/frameworks/Swift/vapor/vapor-swifql/Sources/Extensions/Models+Content.swift new file mode 100644 index 00000000000..8fdae4b378f --- /dev/null +++ b/frameworks/Swift/vapor/vapor-swifql/Sources/Extensions/Models+Content.swift @@ -0,0 +1,11 @@ +// +// Models+Content.swift +// +// +// Created by Yakov Shapovalov on 04.07.2024. +// + +import Vapor + +extension World: Content {} +extension Fortune: Content {} diff --git a/frameworks/Swift/vapor/vapor-swifql/Sources/Extensions/Utils.swift b/frameworks/Swift/vapor/vapor-swifql/Sources/Extensions/Utils.swift new file mode 100644 index 00000000000..d370b15e291 --- /dev/null +++ b/frameworks/Swift/vapor/vapor-swifql/Sources/Extensions/Utils.swift @@ -0,0 +1,18 @@ +extension Int { + func bounded(to range: ClosedRange) -> Int { + switch self { + case ...range.lowerBound: + return range.lowerBound + case range.upperBound...: + return range.upperBound + default: + return self + } + } +} + +extension Int: Sequence { + public func makeIterator() -> CountableRange.Iterator { + return (0.. World in + guard let world: World = try await req.postgres.connection(to: .Db, { conn in + World.select + .where(\World.$id == Int.random(in: 1...10_000)) + .execute(on: conn) + .first(decoding: World.self) + }).get() else { + throw Abort(.notFound) + } + return world + } + + app.get("queries") { req async throws -> [World] in + let queries: Int = (req.query["queries"] ?? 1).bounded(to: 1...500) + + var worlds: [World] = [] + + for _ in queries { + guard let world: World = try await req.postgres.connection(to: .Db, { conn in + World.select + .where(\World.$id == Int.random(in: 1...10_000)) + .execute(on: conn) + .first(decoding: World.self) + }).get() else { + throw Abort(.notFound) + } + + worlds.append(world) + } + return worlds + } + + app.get("updates") { req async throws -> [World] in + let queries = (req.query["queries"] ?? 1).bounded(to: 1...500) + + var worlds: [World] = [] + + for _ in queries { + let world = try await req.postgres.connection(to: .Db, { conn in + World.select.where(\World.$id == Int.random(in: 1...10_000)).execute(on: conn).first(decoding: World.self).flatMap { world in + world!.randomnumber = .random(in: 1...10_000) + return world!.update(on: \.$id, on: conn) + } + }).get() + + worlds.append(world) + } + + return worlds + + } + + app.get("fortunes") { req async throws -> View in + var fortunes: [Fortune] = try await req.postgres.connection(to: .Db, {conn in + Fortune.select.execute(on: conn).all(decoding: Fortune.self) + }) + .get() + + fortunes.append(Fortune(id: 0, message: "Additional fortune added at request time.")) + + fortunes.sort(by: { + $0.message < $1.message + }) + + return try await req.view.render("fortune", ["fortunes": fortunes]) + } +} + diff --git a/frameworks/Swift/vapor/vapor-swifql/Sources/main.swift b/frameworks/Swift/vapor/vapor-swifql/Sources/main.swift new file mode 100644 index 00000000000..81feddfbc02 --- /dev/null +++ b/frameworks/Swift/vapor/vapor-swifql/Sources/main.swift @@ -0,0 +1,16 @@ +import Vapor +import PostgresBridge +import Logging + +@main +enum App { + static func main() throws { + var env = try Environment.detect() + try LoggingSystem.bootstrap(from: &env) + + let app = Application(env) + defer { app.shutdown() } + + try configure(app) + } +} diff --git a/frameworks/Swift/vapor/vapor.dockerfile b/frameworks/Swift/vapor/vapor.dockerfile index 19bf11d5940..afe3fd54be6 100644 --- a/frameworks/Swift/vapor/vapor.dockerfile +++ b/frameworks/Swift/vapor/vapor.dockerfile @@ -1,7 +1,7 @@ # ================================ # Build image # ================================ -FROM swift:5.9 as build +FROM swift:5.10 as build WORKDIR /build # Copy entire repo into container @@ -15,7 +15,7 @@ RUN swift build \ # ================================ # Run image # ================================ -FROM swift:5.9-slim +FROM swift:5.10-slim WORKDIR /run # Copy build artifacts diff --git a/frameworks/TypeScript/brahma-firelight/.gitignore b/frameworks/TypeScript/brahma-firelight/.gitignore new file mode 100644 index 00000000000..a14702c409d --- /dev/null +++ b/frameworks/TypeScript/brahma-firelight/.gitignore @@ -0,0 +1,34 @@ +# dependencies (bun install) +node_modules + +# output +out +dist +*.tgz + +# code coverage +coverage +*.lcov + +# logs +logs +_.log +report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# caches +.eslintcache +.cache +*.tsbuildinfo + +# IntelliJ based IDEs +.idea + +# Finder (MacOS) folder config +.DS_Store diff --git a/frameworks/TypeScript/brahma-firelight/README.md b/frameworks/TypeScript/brahma-firelight/README.md new file mode 100644 index 00000000000..40053a4be24 --- /dev/null +++ b/frameworks/TypeScript/brahma-firelight/README.md @@ -0,0 +1,25 @@ + +# 🗿 Brahma-JS (brahma-firelight) + +Express-style framework ⚡ powered by Rust (Tokio + Hyper). +Plug-n-play for **Node.js**, **Deno**, and **Bun** — no setup, just install and harness the true power of RUST. + +--- + +### 🔗 Links +- Repo: [github.com/Shyam20001/rsjs](https://github.com/Shyam20001/rsjs) +- Site: [shyam20001.github.io/rsjs](https://shyam20001.github.io/rsjs) + +--- + +### ⚙️ Commands +```bash +bun install +bun run build +bun start +# Dev mode: +bun run dev +```` + +Runs on **0.0.0.0:8080** exposing `/plaintext` and `/json` endpoints. + diff --git a/frameworks/TypeScript/brahma-firelight/benchmark_config.json b/frameworks/TypeScript/brahma-firelight/benchmark_config.json new file mode 100644 index 00000000000..60db94104a9 --- /dev/null +++ b/frameworks/TypeScript/brahma-firelight/benchmark_config.json @@ -0,0 +1,23 @@ +{ + "framework": "brahma-firelight", + "tests": [ + { + "default": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "framework": "brahma-firelight", + "language": "TypeScript", + "flavor": "bun", + "platform": "bun", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "brahma-firelight", + "versus": "nodejs" + } + } + ] +} diff --git a/frameworks/TypeScript/brahma-firelight/brahma-firelight.dockerfile b/frameworks/TypeScript/brahma-firelight/brahma-firelight.dockerfile new file mode 100644 index 00000000000..4ae04a5efbf --- /dev/null +++ b/frameworks/TypeScript/brahma-firelight/brahma-firelight.dockerfile @@ -0,0 +1,25 @@ +FROM oven/bun:1.3 AS builder +WORKDIR /app + +COPY package.json bun.lock ./ + +RUN bun ci + +COPY . . +RUN bun run build + +FROM oven/bun:1.3 AS runtime +WORKDIR /app + +ENV NODE_ENV=production +ENV PORT=8080 + +COPY --from=builder /app/dist ./dist +COPY --from=builder /app/node_modules ./node_modules +COPY --from=builder /app/package.json ./package.json + +ENV NODE_ENV=production + +EXPOSE 8080 + +ENTRYPOINT ["bun", "dist/main.js"] diff --git a/frameworks/TypeScript/brahma-firelight/bun.lock b/frameworks/TypeScript/brahma-firelight/bun.lock new file mode 100644 index 00000000000..067ff9b71e3 --- /dev/null +++ b/frameworks/TypeScript/brahma-firelight/bun.lock @@ -0,0 +1,34 @@ +{ + "lockfileVersion": 1, + "workspaces": { + "": { + "name": "brahma-firelight", + "dependencies": { + "brahma-firelight": "^1.5.18", + }, + "devDependencies": { + "@types/bun": "latest", + }, + "peerDependencies": { + "typescript": "^5", + }, + }, + }, + "packages": { + "@types/bun": ["@types/bun@1.3.1", "", { "dependencies": { "bun-types": "1.3.1" } }, "sha512-4jNMk2/K9YJtfqwoAa28c8wK+T7nvJFOjxI4h/7sORWcypRNxBpr+TPNaCfVWq70tLCJsqoFwcf0oI0JU/fvMQ=="], + + "@types/node": ["@types/node@24.9.2", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-uWN8YqxXxqFMX2RqGOrumsKeti4LlmIMIyV0lgut4jx7KQBcBiW6vkDtIBvHnHIquwNfJhk8v2OtmO8zXWHfPA=="], + + "@types/react": ["@types/react@19.2.2", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA=="], + + "brahma-firelight": ["brahma-firelight@1.5.18", "", {}, "sha512-/raDDeb6/AAHYPfvTi4vWA79BjsHwh5Eg63GWJPwWzyip3mvY0tIsNeMqHit4XBdyJZ9t0UgtsvNaHGx3zqFGw=="], + + "bun-types": ["bun-types@1.3.1", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-NMrcy7smratanWJ2mMXdpatalovtxVggkj11bScuWuiOoXTiKIu2eVS1/7qbyI/4yHedtsn175n4Sm4JcdHLXw=="], + + "csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="], + + "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], + + "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], + } +} diff --git a/frameworks/TypeScript/brahma-firelight/config.toml b/frameworks/TypeScript/brahma-firelight/config.toml new file mode 100644 index 00000000000..c48a28eaa14 --- /dev/null +++ b/frameworks/TypeScript/brahma-firelight/config.toml @@ -0,0 +1,15 @@ +[framework] +name = "brahma-firelight" + +[main] +urls.plaintext = "/plaintext" +urls.json = "/json" +approach = "Realistic" +classification = "Micro" +database_os = "Linux" +database = "None" +os = "Linux" +orm = "Raw" +platform = "bun" +webserver = "None" +versus = "nodejs" diff --git a/frameworks/TypeScript/brahma-firelight/package.json b/frameworks/TypeScript/brahma-firelight/package.json new file mode 100644 index 00000000000..c7b49a791fd --- /dev/null +++ b/frameworks/TypeScript/brahma-firelight/package.json @@ -0,0 +1,19 @@ +{ + "name": "brahma-firelight", + "type": "module", + "main": "src/index.ts", + "scripts": { + "dev": "bun --hot src/main.ts", + "build": "bun build src/main.ts --packages external --sourcemap --outdir dist --minify", + "start": "bun dist/main.js" + }, + "devDependencies": { + "@types/bun": "latest" + }, + "peerDependencies": { + "typescript": "^5" + }, + "dependencies": { + "brahma-firelight": "^1.5.18" + } +} \ No newline at end of file diff --git a/frameworks/TypeScript/brahma-firelight/src/main.ts b/frameworks/TypeScript/brahma-firelight/src/main.ts new file mode 100644 index 00000000000..3583f916605 --- /dev/null +++ b/frameworks/TypeScript/brahma-firelight/src/main.ts @@ -0,0 +1,60 @@ +import { createApp, type Response, type Request, type App, type NextFunction, type Handler } from "brahma-firelight"; +import cluster from "node:cluster"; +import os from "node:os"; + +const app: App = createApp(); + +// Server Config Middleware +const serverInfo: Handler = (_req: Request, res: Response, next?: NextFunction) => { + res.setHeader("Server", "brahma-firelight"); + res.setHeader("Connection", "keep-alive") + next?.(); +}; + +// JSON compute +app.get("/json", serverInfo, (_req: Request, res: Response) => { + res.json({ message: "Hello, World!" }); +}); + +// PLAIN-TEXT +app.get("/plaintext", serverInfo, (_req: Request, res: Response) => { + res.text("Hello, World!"); +}); + +// Port & Host +const PORT = process.env.PORT || 8080; +const HOST = process.env.HOST || "0.0.0.0"; + +// Single CORE +//app.listen(HOST, +PORT); + +// Multi CORE (cluster with max cpus available) +if (cluster.isPrimary) { + const cpuCount = os.cpus().length; + console.log(`Primary ${process.pid} running → forking ${cpuCount} workers...`); + + for (let i = 0; i < cpuCount; i++) { + cluster.fork(); + } + + cluster.on("exit", (worker) => { + console.log(`Worker ${worker.process.pid} died → restarting...`); + cluster.fork(); + }); +} else { + app.listen(HOST, +PORT); +} + +// // Enable built in Graceful Shutdown (optional for production use) + +// process.on('SIGINT', async () => { +// console.log('SIGINT → shutting down...'); +// await app.close(2000); // wait up to 2s for requests +// process.exit(0); +// }); + +// process.on('SIGTERM', async () => { +// console.log('SIGTERM → shutting down...'); +// await app.close(2000); +// process.exit(0); +// }); \ No newline at end of file diff --git a/frameworks/TypeScript/brahma-firelight/tsconfig.json b/frameworks/TypeScript/brahma-firelight/tsconfig.json new file mode 100644 index 00000000000..976e9d12d50 --- /dev/null +++ b/frameworks/TypeScript/brahma-firelight/tsconfig.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + // Environment setup & latest features + "lib": [ + "ESNext" + ], + "forceConsistentCasingInFileNames": true, + "target": "ESNext", + "module": "es6", + "moduleDetection": "force", + "jsx": "react-jsx", + "allowJs": true, + // Bundler mode + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "noEmit": true, + // Best practices + "strict": true, + "skipLibCheck": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedIndexedAccess": true, + "noImplicitOverride": true, + // Some stricter flags (disabled by default) + "noUnusedLocals": false, + "noUnusedParameters": false, + "noPropertyAccessFromIndexSignature": false + } +} \ No newline at end of file diff --git a/frameworks/TypeScript/bun/bun.dockerfile b/frameworks/TypeScript/bun/bun.dockerfile index 7692c8c82ae..ecf6ead2bbc 100644 --- a/frameworks/TypeScript/bun/bun.dockerfile +++ b/frameworks/TypeScript/bun/bun.dockerfile @@ -1,13 +1,15 @@ -FROM oven/bun:1.0 +FROM oven/bun:1.1 EXPOSE 8080 WORKDIR /app -USER bun - COPY ./src . ENV NODE_ENV=production +RUN bun build --compile --minify --outfile server . + +USER bun + CMD ["bun", "spawn.ts"] diff --git a/frameworks/TypeScript/bun/src/index.ts b/frameworks/TypeScript/bun/src/index.ts index be72a268363..45c0f303291 100644 --- a/frameworks/TypeScript/bun/src/index.ts +++ b/frameworks/TypeScript/bun/src/index.ts @@ -1,5 +1,5 @@ -const HELLO_WORLD_STR = "Hello, World!"; -const options: ResponseInit = { headers: { "Server": "Bun" } }; +const plainOptions: ResponseInit = { headers: { "Server": "Bun" } }; +const jsonOptions: ResponseInit = { headers: { "Server": "Bun", "Content-Type": "application/json" } }; const server = Bun.serve({ port: 8080, @@ -7,16 +7,16 @@ const server = Bun.serve({ fetch(req: Request) { const pathname = req.url.slice(req.url.indexOf("/", 8)); - if (pathname === "/json") { - return Response.json({ message: HELLO_WORLD_STR }, options); + if (pathname == "/json") { + return new Response(JSON.stringify({ message: "Hello, World!" }), jsonOptions); } - if (pathname === "/plaintext") { - return new Response(HELLO_WORLD_STR, options); + if (pathname == "/plaintext") { + return new Response("Hello, World!", plainOptions); } return new Response("", { status: 404 }) }, }); -console.log(`Listening on localhost:${server.port}`); +console.log(`Listening on ${server.url}\n`); diff --git a/frameworks/TypeScript/bun/src/spawn.ts b/frameworks/TypeScript/bun/src/spawn.ts index b3df7f03253..a6d990c1b67 100644 --- a/frameworks/TypeScript/bun/src/spawn.ts +++ b/frameworks/TypeScript/bun/src/spawn.ts @@ -1,9 +1,18 @@ -import os from "node:os"; +const cpus = navigator.hardwareConcurrency; +const buns = new Array(cpus); -const numCPUs = os.cpus().length; -for (let i = 0; i < numCPUs; i++) { - Bun.spawn(["bun", "index.ts"], { +for (let i = 0; i < cpus; i++) { + buns[i] = Bun.spawn(["./server"], { stdio: ["inherit", "inherit", "inherit"], env: { ...process.env }, }); } + +function kill() { + for (const bun of buns) { + bun.kill(); + } +} + +process.on("SIGINT", kill); +process.on("exit", kill); \ No newline at end of file diff --git a/frameworks/TypeScript/deno/deno.dockerfile b/frameworks/TypeScript/deno/deno.dockerfile index 0fccdf30e5a..cfb43644c10 100644 --- a/frameworks/TypeScript/deno/deno.dockerfile +++ b/frameworks/TypeScript/deno/deno.dockerfile @@ -1,4 +1,4 @@ -FROM denoland/deno:1.36.4 +FROM denoland/deno:1.46.1 EXPOSE 8080 @@ -12,4 +12,4 @@ RUN deno cache main.ts EXPOSE 8080 -CMD ["run", "--allow-net", "--unstable", "main.ts"] +CMD ["deno", "serve", "--parallel", "--port", "8080", "--host", "0.0.0.0", "-A", "main.ts"] diff --git a/frameworks/TypeScript/deno/src/main.ts b/frameworks/TypeScript/deno/src/main.ts index da62d6dfae6..3e6f71506bd 100644 --- a/frameworks/TypeScript/deno/src/main.ts +++ b/frameworks/TypeScript/deno/src/main.ts @@ -1,29 +1,15 @@ -const options = { - // Date and Content-Type headers are automatically set. - headers: { - "Server": "Deno", - }, -}; +const HELLO_WORLD_STR = "Hello, World!"; +const options: ResponseInit = { headers: { "Server": "Deno" } }; -type HandlerFn = (req: Request) => Promise | Response; - -const handlers: Record = { - "/json": () => Response.json({ message: "Hello, World!" }, options), - "/plaintext": () => new Response("Hello, World!", options), -}; - -Deno.serve({ - handler: (req: Request) => { +export default { + fetch: (req: Request) => { const path = req.url.slice(req.url.indexOf("/", 8)); - const fn = handlers[path]; - return fn - ? fn(req) - : new Response("404 Not Found", { status: 404, ...options }); - }, - onError(err) { - console.error(err); - Deno.exit(9); + if (path == "/plaintext") { + return new Response(HELLO_WORLD_STR, options); + } else if (path == "/json") { + return Response.json({ message: HELLO_WORLD_STR }, options); + } else { + return new Response("404 Not Found", { status: 404, ...options }); + } }, - port: 8080, - hostname: "0.0.0.0", -}); +}; diff --git a/frameworks/TypeScript/ditsmod/.gitignore b/frameworks/TypeScript/ditsmod/.gitignore index b7c122d83c3..d525fa34c07 100644 --- a/frameworks/TypeScript/ditsmod/.gitignore +++ b/frameworks/TypeScript/ditsmod/.gitignore @@ -5,3 +5,4 @@ dist* .pnp* nodemon.json package-lock.json +bun.lockb diff --git a/frameworks/TypeScript/ditsmod/benchmark_config.json b/frameworks/TypeScript/ditsmod/benchmark_config.json index 42122a11d69..39c4bce56cf 100755 --- a/frameworks/TypeScript/ditsmod/benchmark_config.json +++ b/frameworks/TypeScript/ditsmod/benchmark_config.json @@ -3,6 +3,7 @@ "tests": [ { "default": { + "dockerfile": "ditsmod.dockerfile", "json_url": "/json", "plaintext_url": "/plaintext", "port": 8080, @@ -17,31 +18,12 @@ "webserver": "None", "os": "Linux", "database_os": "Linux", - "display_name": "Ditsmod", - "notes": "", - "versus": "nodejs" - }, - "simplified-di": { - "dockerfile": "ditsmod.dockerfile", - "json_url": "/json2", - "plaintext_url": "/plaintext2", - "port": 8080, - "approach": "Realistic", - "classification": "Micro", - "database": "None", - "framework": "Ditsmod", - "language": "TypeScript", - "flavor": "None", - "orm": "None", - "platform": "nodejs", - "webserver": "None", - "os": "Linux", - "database_os": "Linux", - "display_name": "ditsmod [simplified use of di]", + "display_name": "ditsmod v3.0", "notes": "Simplified use of Dependency Injection (no request level injector).", "versus": "nodejs" }, "postgres": { + "dockerfile": "ditsmod-postgres.dockerfile", "db_url": "/db", "query_url": "/queries?queries=", "update_url": "/updates?queries=", @@ -59,11 +41,12 @@ "webserver": "None", "os": "Linux", "database_os": "Linux", - "display_name": "ditsmod [postgres]", - "notes": "", + "display_name": "ditsmod v3.0 [postgres]", + "notes": "Simplified use of Dependency Injection (no request level injector).", "versus": "nodejs" }, "mysql": { + "dockerfile": "ditsmod-mysql.dockerfile", "db_url": "/db", "query_url": "/queries?queries=", "update_url": "/updates?queries=", @@ -81,55 +64,75 @@ "webserver": "None", "os": "Linux", "database_os": "Linux", - "display_name": "ditsmod [mysql]", - "notes": "", + "display_name": "ditsmod v3.0 [mysql]", + "notes": "Simplified use of Dependency Injection (no request level injector).", "versus": "nodejs" }, - "postgres2": { - "dockerfile": "ditsmod-postgres.dockerfile", - "db_url": "/db2", - "query_url": "/queries2?queries=", - "update_url": "/updates2?queries=", - "cached_query_url": "/cached-queries2?count=", - "fortune_url": "/fortunes2", + "bun": { + "dockerfile": "ditsmod-bun.dockerfile", + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "None", + "framework": "ditsmod-bun", + "language": "TypeScript", + "flavor": "None", + "orm": "None", + "platform": "bun", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "ditsmod-bun v3.0", + "notes": "Simplified use of Dependency Injection (no request level injector).", + "versus": "bun" + }, + "postgres-bun": { + "dockerfile": "ditsmod-bun-postgres.dockerfile", + "db_url": "/db", + "query_url": "/queries?queries=", + "update_url": "/updates?queries=", + "cached_query_url": "/cached-queries?count=", + "fortune_url": "/fortunes", "port": 8080, "approach": "Realistic", "classification": "Micro", "database": "Postgres", - "framework": "Ditsmod", + "framework": "ditsmod-bun", "language": "TypeScript", "flavor": "None", "orm": "Raw", - "platform": "nodejs", + "platform": "bun", "webserver": "None", "os": "Linux", "database_os": "Linux", - "display_name": "ditsmod [postgres & simplified use of di]", + "display_name": "ditsmod-bun v3.0 [postgres]", "notes": "Simplified use of Dependency Injection (no request level injector).", - "versus": "nodejs" + "versus": "bun" }, - "mysql2": { - "dockerfile": "ditsmod-mysql.dockerfile", - "db_url": "/db2", - "query_url": "/queries2?queries=", - "update_url": "/updates2?queries=", - "cached_query_url": "/cached-queries2?count=", - "fortune_url": "/fortunes2", + "mysql-bun": { + "dockerfile": "ditsmod-bun-mysql.dockerfile", + "db_url": "/db", + "query_url": "/queries?queries=", + "update_url": "/updates?queries=", + "cached_query_url": "/cached-queries?count=", + "fortune_url": "/fortunes", "port": 8080, "approach": "Realistic", "classification": "Micro", "database": "MySQL", - "framework": "Ditsmod", + "framework": "ditsmod-bun", "language": "TypeScript", "flavor": "None", "orm": "Raw", - "platform": "nodejs", + "platform": "bun", "webserver": "None", "os": "Linux", "database_os": "Linux", - "display_name": "ditsmod [mysql & simplified use of di]", + "display_name": "ditsmod-bun v3.0 [mysql]", "notes": "Simplified use of Dependency Injection (no request level injector).", - "versus": "nodejs" + "versus": "bun" } } ] diff --git a/frameworks/TypeScript/ditsmod/ditsmod-bun-mysql.dockerfile b/frameworks/TypeScript/ditsmod/ditsmod-bun-mysql.dockerfile new file mode 100644 index 00000000000..d0f44000dc7 --- /dev/null +++ b/frameworks/TypeScript/ditsmod/ditsmod-bun-mysql.dockerfile @@ -0,0 +1,16 @@ +FROM oven/bun:1.1 + +COPY ./ ./ + +RUN bun install +RUN bun run build + +ENV NODE_ENV production +ENV DATABASE mysql +ENV MYSQL_HOST tfb-database +ENV MYSQL_USER benchmarkdbuser +ENV MYSQL_PSWD benchmarkdbpass +ENV MYSQL_DBNAME hello_world + +EXPOSE 8080 +CMD rm node_modules/@ditsmod/*/tsconfig.json && bun dist/main.js diff --git a/frameworks/TypeScript/ditsmod/ditsmod-bun-postgres.dockerfile b/frameworks/TypeScript/ditsmod/ditsmod-bun-postgres.dockerfile new file mode 100644 index 00000000000..1bcc29a8b2f --- /dev/null +++ b/frameworks/TypeScript/ditsmod/ditsmod-bun-postgres.dockerfile @@ -0,0 +1,16 @@ +FROM oven/bun:1.1 + +COPY ./ ./ + +RUN bun install +RUN bun run build + +ENV NODE_ENV production +ENV DATABASE postgres +ENV PG_HOST tfb-database +ENV PG_USER benchmarkdbuser +ENV PG_PSWD benchmarkdbpass +ENV PG_DBNAME hello_world + +EXPOSE 8080 +CMD rm node_modules/@ditsmod/*/tsconfig.json && bun dist/main.js diff --git a/frameworks/TypeScript/ditsmod/ditsmod-bun.dockerfile b/frameworks/TypeScript/ditsmod/ditsmod-bun.dockerfile new file mode 100644 index 00000000000..8f0268556af --- /dev/null +++ b/frameworks/TypeScript/ditsmod/ditsmod-bun.dockerfile @@ -0,0 +1,11 @@ +FROM oven/bun:1.1 + +COPY ./ ./ + +RUN bun install +RUN bun run build + +ENV NODE_ENV production + +EXPOSE 8080 +CMD rm node_modules/@ditsmod/*/tsconfig.json && bun dist/main.js diff --git a/frameworks/TypeScript/ditsmod/ditsmod-mysql.dockerfile b/frameworks/TypeScript/ditsmod/ditsmod-mysql.dockerfile index 4136e2ae860..95ad40e9ac8 100644 --- a/frameworks/TypeScript/ditsmod/ditsmod-mysql.dockerfile +++ b/frameworks/TypeScript/ditsmod/ditsmod-mysql.dockerfile @@ -1,4 +1,4 @@ -FROM node:18.17.1-slim +FROM node:20.16-slim COPY ./ ./ diff --git a/frameworks/TypeScript/ditsmod/ditsmod-postgres.dockerfile b/frameworks/TypeScript/ditsmod/ditsmod-postgres.dockerfile index 5ef79595757..89ecc3e80a8 100644 --- a/frameworks/TypeScript/ditsmod/ditsmod-postgres.dockerfile +++ b/frameworks/TypeScript/ditsmod/ditsmod-postgres.dockerfile @@ -1,4 +1,4 @@ -FROM node:18.17.1-slim +FROM node:20.16-slim COPY ./ ./ diff --git a/frameworks/TypeScript/ditsmod/ditsmod.dockerfile b/frameworks/TypeScript/ditsmod/ditsmod.dockerfile index 882239148ce..0b21155188a 100644 --- a/frameworks/TypeScript/ditsmod/ditsmod.dockerfile +++ b/frameworks/TypeScript/ditsmod/ditsmod.dockerfile @@ -1,4 +1,4 @@ -FROM node:18.17.1-slim +FROM node:20.16-slim COPY ./ ./ diff --git a/frameworks/TypeScript/ditsmod/package.json b/frameworks/TypeScript/ditsmod/package.json index 962d11cc65f..99f331cf416 100755 --- a/frameworks/TypeScript/ditsmod/package.json +++ b/frameworks/TypeScript/ditsmod/package.json @@ -10,27 +10,23 @@ "build": "tsc -b tsconfig.build.json", "clean": "rm -rf dist*" }, - "imports": { - "#routed/*": "./dist/app/modules/routed/*", - "#service/*": "./dist/app/modules/service/*", - "#utils/*": "./dist/app/utils/*" - }, "keywords": [], "author": "Костя Третяк", "license": "MIT", "dependencies": { - "@ditsmod/core": "~2.51.1", - "@ditsmod/routing": "~2.1.0", + "@ditsmod/core": "3.0.0-alpha.3", + "@ditsmod/routing": "3.0.0-alpha.3", "handlebars": "^4.7.8", - "lru-cache": "^10.0.1", - "mariadb": "^3.2.1", - "postgres": "^3.3.5" + "lru-cache": "^11.0.2", + "mariadb": "^3.4.0", + "postgres": "^3.4.5" }, "devDependencies": { "@types/eslint": "^8.44.2", "@types/node": "^20.5.7", "@typescript-eslint/eslint-plugin": "^6.5.0", "@typescript-eslint/parser": "^6.5.0", + "bun-types": "^1.1.22", "eslint": "^8.48.0", "prettier": "^3.0.2", "typescript": "^5.2.2" diff --git a/frameworks/TypeScript/ditsmod/src/app/app.module.ts b/frameworks/TypeScript/ditsmod/src/app/app.module.ts index 4874719f9cc..36d599d9698 100644 --- a/frameworks/TypeScript/ditsmod/src/app/app.module.ts +++ b/frameworks/TypeScript/ditsmod/src/app/app.module.ts @@ -1,8 +1,13 @@ -import { Providers, rootModule } from '@ditsmod/core'; -import { SimpleModule } from '#routed/simple/simple.module.js'; +import { InjectionToken, Providers, rootModule } from '@ditsmod/core'; +import { PRE_ROUTER_EXTENSIONS, RoutingModule } from '@ditsmod/routing'; + +import { OneController } from './one.controller.js'; +import { InitExtension } from './init.extension.js'; @rootModule({ - appends: [SimpleModule], - providersPerApp: [...new Providers().useLogConfig({ level: 'off' })], + imports: [RoutingModule], + providersPerApp: new Providers().useLogConfig({ level: 'off' }), + extensions: [{ extension: InitExtension, group: new InjectionToken('test'), beforeGroups: [PRE_ROUTER_EXTENSIONS] }], + controllers: [OneController], }) export class AppModule {} diff --git a/frameworks/TypeScript/ditsmod/src/app/modules/service/db/db.service.ts b/frameworks/TypeScript/ditsmod/src/app/db.service.ts similarity index 96% rename from frameworks/TypeScript/ditsmod/src/app/modules/service/db/db.service.ts rename to frameworks/TypeScript/ditsmod/src/app/db.service.ts index 61c9b5bbfbd..1267c11f360 100644 --- a/frameworks/TypeScript/ditsmod/src/app/modules/service/db/db.service.ts +++ b/frameworks/TypeScript/ditsmod/src/app/db.service.ts @@ -1,8 +1,8 @@ import { injectable } from '@ditsmod/core'; import { LRUCache } from 'lru-cache'; -import { getNumberOfObjects, getRandomNumber } from '#utils/helper.js'; import { ModelService, World } from './types.js'; +import { getNumberOfObjects, getRandomNumber } from './helper.js'; @injectable() export class DbService { diff --git a/frameworks/TypeScript/ditsmod/src/app/utils/helper.ts b/frameworks/TypeScript/ditsmod/src/app/helper.ts similarity index 90% rename from frameworks/TypeScript/ditsmod/src/app/utils/helper.ts rename to frameworks/TypeScript/ditsmod/src/app/helper.ts index 33a0cb20ad6..3adcffe4fef 100644 --- a/frameworks/TypeScript/ditsmod/src/app/utils/helper.ts +++ b/frameworks/TypeScript/ditsmod/src/app/helper.ts @@ -1,4 +1,4 @@ -import { Fortune } from '#service/db/types.js'; +import { Fortune } from './types.js'; export function getRandomNumber() { return Math.floor(Math.random() * 10000) + 1; diff --git a/frameworks/TypeScript/ditsmod/src/app/modules/service/db/init.extension.ts b/frameworks/TypeScript/ditsmod/src/app/init.extension.ts similarity index 76% rename from frameworks/TypeScript/ditsmod/src/app/modules/service/db/init.extension.ts rename to frameworks/TypeScript/ditsmod/src/app/init.extension.ts index 45ae1da68ed..7775328edfa 100644 --- a/frameworks/TypeScript/ditsmod/src/app/modules/service/db/init.extension.ts +++ b/frameworks/TypeScript/ditsmod/src/app/init.extension.ts @@ -5,18 +5,12 @@ import { ModelService } from './types.js'; @injectable() export class InitExtension implements Extension { - #inited: boolean; - constructor( private perAppService: PerAppService, private logger: Logger, ) {} - async init(): Promise { - if (this.#inited) { - return; - } - + async stage1(): Promise { const dbType = process.env.DATABASE as 'mysql' | 'postgres'; if (dbType == 'mysql') { @@ -28,13 +22,13 @@ export class InitExtension implements Extension { } else { this.logger.log('warn', `Unknown database "${dbType}"`); } - - this.#inited = true; } protected async setDbService(useClass: Class) { - const injector = this.perAppService.injector.resolveAndCreateChild([{ token: ModelService, useClass }]); - const dbService = injector.pull(DbService) as DbService; + const dbService = this.perAppService.injector + .resolveAndCreateChild([DbService, { token: ModelService, useClass }]) + .get(DbService) as DbService; + await dbService.setWorldsToCache(); this.perAppService.providers.push({ token: DbService, useValue: dbService }); } diff --git a/frameworks/TypeScript/ditsmod/src/app/modules/routed/simple/db.controller.ts b/frameworks/TypeScript/ditsmod/src/app/modules/routed/simple/db.controller.ts deleted file mode 100644 index ac39c4bc715..00000000000 --- a/frameworks/TypeScript/ditsmod/src/app/modules/routed/simple/db.controller.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { AnyObj, controller, inject, QUERY_PARAMS, Res, route } from '@ditsmod/core'; - -import { DbService } from '#service/db/db.service.js'; -import { getRandomNumber } from '#utils/helper.js'; - -@controller() -export class DbController { - constructor( - private res: Res, - private dbService: DbService, - ) { - res.nodeRes.setHeader('Server', 'Ditsmod'); - } - - @route('GET', 'db') - async getSingleQuery() { - const id = getRandomNumber(); - const result = await this.dbService.findOneWorld(id); - this.res.sendJson(result); - } - - @route('GET', 'queries') - async getMultiQueries(@inject(QUERY_PARAMS) queryParams: AnyObj) { - const result = await this.dbService.getMultiQueries(queryParams.queries); - this.res.sendJson(result); - } - - @route('GET', 'cached-queries') - async getCachedWorlds(@inject(QUERY_PARAMS) queryParams: AnyObj) { - const result = await this.dbService.getMultiQueries(queryParams.count, false); - this.res.sendJson(result); - } - - @route('GET', 'updates') - async getUpdates(@inject(QUERY_PARAMS) queryParams: AnyObj) { - const worlds = await this.dbService.saveWorlds(queryParams.queries); - this.res.sendJson(worlds); - } -} diff --git a/frameworks/TypeScript/ditsmod/src/app/modules/routed/simple/db.controller2.ts b/frameworks/TypeScript/ditsmod/src/app/modules/routed/simple/db.controller2.ts deleted file mode 100644 index cef38bd4d0b..00000000000 --- a/frameworks/TypeScript/ditsmod/src/app/modules/routed/simple/db.controller2.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { AnyObj, controller, RequestContext, SingletonRequestContext, route } from '@ditsmod/core'; - -import { DbService } from '#service/db/db.service.js'; -import { getRandomNumber } from '#utils/helper.js'; - -@controller({ isSingleton: true }) -export class DbController2 { - constructor(private dbService: DbService) {} - - @route('GET', 'db2') - async getSingleQuery(ctx: RequestContext) { - const id = getRandomNumber(); - const result = await this.dbService.findOneWorld(id); - this.sendJson(ctx, result); - } - - @route('GET', 'queries2') - async getMultiQueries(ctx: SingletonRequestContext) { - const result = await this.dbService.getMultiQueries(ctx.queryParams!.queries); - this.sendJson(ctx, result); - } - - @route('GET', 'cached-queries2') - async getCachedWorlds(ctx: SingletonRequestContext) { - const result = await this.dbService.getMultiQueries(ctx.queryParams!.count, false); - this.sendJson(ctx, result); - } - - @route('GET', 'updates2') - async getUpdates(ctx: SingletonRequestContext) { - const worlds = await this.dbService.saveWorlds(ctx.queryParams!.queries); - this.sendJson(ctx, worlds); - } - - protected sendJson(ctx: RequestContext, value: AnyObj) { - ctx.nodeRes.setHeader('Server', 'Ditsmod'); - ctx.nodeRes.setHeader('Content-Type', 'application/json; charset=utf-8'); - ctx.nodeRes.end(JSON.stringify(value)); - } -} diff --git a/frameworks/TypeScript/ditsmod/src/app/modules/routed/simple/fortune.controller.ts b/frameworks/TypeScript/ditsmod/src/app/modules/routed/simple/fortune.controller.ts deleted file mode 100644 index 64c6b087cc5..00000000000 --- a/frameworks/TypeScript/ditsmod/src/app/modules/routed/simple/fortune.controller.ts +++ /dev/null @@ -1,41 +0,0 @@ -import Handlebars from 'handlebars'; -import { NODE_RES, NodeResponse, controller, inject, route } from '@ditsmod/core'; - -import { additionalFortune, compare } from '#utils/helper.js'; -import { DbService } from '#service/db/db.service.js'; - -const tmpl = Handlebars.compile( - [ - '', - '', - 'Fortunes', - '', - '', - '', - '', - '', - '', - '{{#fortunes}}', - '', - '', - '', - '', - '{{/fortunes}}', - '
idmessage
{{id}}{{message}}
', - '', - '', - ].join(''), -); - -@controller() -export class FortuneController { - @route('GET', 'fortunes') - async fortunes(@inject(NODE_RES) nodeRes: NodeResponse, dbService: DbService) { - const fortunes = await dbService.findAllFortunes(); - fortunes.push(additionalFortune); - fortunes.sort(compare); - nodeRes.setHeader('Server', 'Ditsmod'); - nodeRes.setHeader('Content-Type', 'text/html; charset=utf-8'); - nodeRes.end(tmpl({ fortunes })); - } -} diff --git a/frameworks/TypeScript/ditsmod/src/app/modules/routed/simple/fortune.controller2.ts b/frameworks/TypeScript/ditsmod/src/app/modules/routed/simple/fortune.controller2.ts deleted file mode 100644 index 5100a0dcb54..00000000000 --- a/frameworks/TypeScript/ditsmod/src/app/modules/routed/simple/fortune.controller2.ts +++ /dev/null @@ -1,43 +0,0 @@ -import Handlebars from 'handlebars'; -import { RequestContext, controller, route } from '@ditsmod/core'; - -import { additionalFortune, compare } from '#utils/helper.js'; -import { DbService } from '#service/db/db.service.js'; - -const tmpl = Handlebars.compile( - [ - '', - '', - 'Fortunes', - '', - '', - '', - '', - '', - '', - '{{#fortunes}}', - '', - '', - '', - '', - '{{/fortunes}}', - '
idmessage
{{id}}{{message}}
', - '', - '', - ].join(''), -); - -@controller({ isSingleton: true }) -export class FortuneController2 { - constructor(private dbService: DbService) {} - - @route('GET', 'fortunes2') - async fortunes(ctx: RequestContext) { - const fortunes = await this.dbService.findAllFortunes(); - fortunes.push(additionalFortune); - fortunes.sort(compare); - ctx.nodeRes.setHeader('Server', 'Ditsmod'); - ctx.nodeRes.setHeader('Content-Type', 'text/html; charset=utf-8'); - ctx.nodeRes.end(tmpl({ fortunes })); - } -} diff --git a/frameworks/TypeScript/ditsmod/src/app/modules/routed/simple/simple.module.ts b/frameworks/TypeScript/ditsmod/src/app/modules/routed/simple/simple.module.ts deleted file mode 100644 index 123681d91aa..00000000000 --- a/frameworks/TypeScript/ditsmod/src/app/modules/routed/simple/simple.module.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { featureModule } from '@ditsmod/core'; -import { RoutingModule } from '@ditsmod/routing'; - -import { DbModule } from '#service/db/db.module.js'; -import { WithoutDbController } from './without-db.controller.js'; -import { DbController } from './db.controller.js'; -import { FortuneController } from './fortune.controller.js'; -import { SingletonController } from './singleton.controller.js'; -import { DbController2 } from './db.controller2.js'; -import { FortuneController2 } from './fortune.controller2.js'; - -@featureModule({ - imports: [RoutingModule, DbModule], - controllers: [ - WithoutDbController, - DbController, - DbController2, - FortuneController, - FortuneController2, - SingletonController, - ], -}) -export class SimpleModule {} diff --git a/frameworks/TypeScript/ditsmod/src/app/modules/routed/simple/singleton.controller.ts b/frameworks/TypeScript/ditsmod/src/app/modules/routed/simple/singleton.controller.ts deleted file mode 100644 index 3661775e536..00000000000 --- a/frameworks/TypeScript/ditsmod/src/app/modules/routed/simple/singleton.controller.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { controller, route, SingletonRequestContext } from '@ditsmod/core'; - -@controller({ isSingleton: true }) -export class SingletonController { - @route('GET', 'plaintext2') - getHello(ctx: SingletonRequestContext) { - ctx.nodeRes.setHeader('Server', 'Ditsmod'); - ctx.nodeRes.setHeader('Content-Type', 'text/plain; charset=utf-8'); - ctx.nodeRes.end('Hello, World!'); - } - - @route('GET', 'json2') - getJson(ctx: SingletonRequestContext) { - ctx.nodeRes.setHeader('Server', 'Ditsmod'); - ctx.nodeRes.setHeader('Content-Type', 'application/json; charset=utf-8'); - ctx.nodeRes.end(JSON.stringify({ message: 'Hello, World!' })); - } -} diff --git a/frameworks/TypeScript/ditsmod/src/app/modules/routed/simple/without-db.controller.ts b/frameworks/TypeScript/ditsmod/src/app/modules/routed/simple/without-db.controller.ts deleted file mode 100644 index 9ff5246609f..00000000000 --- a/frameworks/TypeScript/ditsmod/src/app/modules/routed/simple/without-db.controller.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { controller, Res, route } from '@ditsmod/core'; - -@controller() -export class WithoutDbController { - constructor(private res: Res) { - res.nodeRes.setHeader('Server', 'Ditsmod'); - } - - @route('GET', 'plaintext') - getHello() { - this.res.send('Hello, World!'); - } - - @route('GET', 'json') - getJson() { - this.res.sendJson({ message: 'Hello, World!' }); - } -} diff --git a/frameworks/TypeScript/ditsmod/src/app/modules/service/db/db.module.ts b/frameworks/TypeScript/ditsmod/src/app/modules/service/db/db.module.ts deleted file mode 100644 index 08de21fb22a..00000000000 --- a/frameworks/TypeScript/ditsmod/src/app/modules/service/db/db.module.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { featureModule } from '@ditsmod/core'; -import { PRE_ROUTER_EXTENSIONS } from '@ditsmod/routing'; - -import { DbService } from './db.service.js'; -import { InitExtension } from './init.extension.js'; -import { DB_INIT_EXTENSIONS } from './tokens.js'; -import { ModelService } from './types.js'; - -@featureModule({ - providersPerApp: [DbService, ModelService], - extensions: [{ extension: InitExtension, groupToken: DB_INIT_EXTENSIONS, nextToken: PRE_ROUTER_EXTENSIONS }], -}) -export class DbModule {} diff --git a/frameworks/TypeScript/ditsmod/src/app/modules/service/db/tokens.ts b/frameworks/TypeScript/ditsmod/src/app/modules/service/db/tokens.ts deleted file mode 100644 index 2eac6cb9303..00000000000 --- a/frameworks/TypeScript/ditsmod/src/app/modules/service/db/tokens.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { Extension, InjectionToken } from '@ditsmod/core'; - -/** - * A group of extensions intended for preparatory work for the database module. - */ -export const DB_INIT_EXTENSIONS = new InjectionToken[]>('DB_INIT_EXTENSIONS'); diff --git a/frameworks/TypeScript/ditsmod/src/app/modules/service/db/mysql.service.ts b/frameworks/TypeScript/ditsmod/src/app/mysql.service.ts similarity index 100% rename from frameworks/TypeScript/ditsmod/src/app/modules/service/db/mysql.service.ts rename to frameworks/TypeScript/ditsmod/src/app/mysql.service.ts diff --git a/frameworks/TypeScript/ditsmod/src/app/one.controller.ts b/frameworks/TypeScript/ditsmod/src/app/one.controller.ts new file mode 100644 index 00000000000..72adaa1f616 --- /dev/null +++ b/frameworks/TypeScript/ditsmod/src/app/one.controller.ts @@ -0,0 +1,87 @@ +import { AnyObj, controller, RequestContext, optional } from '@ditsmod/core'; +import { route } from '@ditsmod/routing'; +import Handlebars from 'handlebars'; + +import { DbService } from './db.service.js'; +import { additionalFortune, compare, getRandomNumber } from './helper.js'; + +const tmpl = Handlebars.compile( + [ + '', + '', + 'Fortunes', + '', + '', + '', + '', + '', + '', + '{{#fortunes}}', + '', + '', + '', + '', + '{{/fortunes}}', + '
idmessage
{{id}}{{message}}
', + '', + '', + ].join(''), +); + +@controller({ scope: 'ctx' }) +export class OneController { + constructor(@optional() private dbService: DbService) {} + + @route('GET', 'db') + async getSingleQuery(ctx: RequestContext) { + const id = getRandomNumber(); + const result = await this.dbService.findOneWorld(id); + this.sendJson(ctx, result); + } + + @route('GET', 'queries') + async getMultiQueries(ctx: RequestContext) { + const result = await this.dbService.getMultiQueries(ctx.queryParams!.queries); + this.sendJson(ctx, result); + } + + @route('GET', 'cached-queries') + async getCachedWorlds(ctx: RequestContext) { + const result = await this.dbService.getMultiQueries(ctx.queryParams!.count, false); + this.sendJson(ctx, result); + } + + @route('GET', 'updates') + async getUpdates(ctx: RequestContext) { + const worlds = await this.dbService.saveWorlds(ctx.queryParams!.queries); + this.sendJson(ctx, worlds); + } + + @route('GET', 'fortunes') + async fortunes(ctx: RequestContext) { + const fortunes = await this.dbService.findAllFortunes(); + fortunes.push(additionalFortune); + fortunes.sort(compare); + ctx.rawRes.setHeader('Server', 'Ditsmod'); + ctx.rawRes.setHeader('Content-Type', 'text/html; charset=utf-8'); + ctx.rawRes.end(tmpl({ fortunes })); + } + + @route('GET', 'plaintext') + getHello(ctx: RequestContext) { + ctx.rawRes.setHeader('Server', 'Ditsmod'); + ctx.rawRes.setHeader('Content-Type', 'text/plain; charset=utf-8'); + ctx.rawRes.end('Hello, World!'); + } + + @route('GET', 'json') + getJson(ctx: RequestContext) { + this.sendJson(ctx, { message: 'Hello, World!' }); + } + + protected sendJson(ctx: RequestContext, value: AnyObj) { + ctx.rawRes.setHeader('Server', 'Ditsmod'); + ctx.rawRes.setHeader('Content-Type', 'application/json; charset=utf-8'); + ctx.rawRes.end(JSON.stringify(value)); + } +} diff --git a/frameworks/TypeScript/ditsmod/src/app/modules/service/db/postgres.service.ts b/frameworks/TypeScript/ditsmod/src/app/postgres.service.ts similarity index 100% rename from frameworks/TypeScript/ditsmod/src/app/modules/service/db/postgres.service.ts rename to frameworks/TypeScript/ditsmod/src/app/postgres.service.ts diff --git a/frameworks/TypeScript/ditsmod/src/app/modules/service/db/types.ts b/frameworks/TypeScript/ditsmod/src/app/types.ts similarity index 100% rename from frameworks/TypeScript/ditsmod/src/app/modules/service/db/types.ts rename to frameworks/TypeScript/ditsmod/src/app/types.ts diff --git a/frameworks/TypeScript/ditsmod/src/main.ts b/frameworks/TypeScript/ditsmod/src/main.ts index 46f535f2c75..b42ba0a5b64 100644 --- a/frameworks/TypeScript/ditsmod/src/main.ts +++ b/frameworks/TypeScript/ditsmod/src/main.ts @@ -13,6 +13,6 @@ if (numCpus > 1 && cluster.isPrimary) { } } else { const serverOptions: ServerOptions = { keepAlive: true, keepAliveTimeout: 0 }; - const app = await new Application().bootstrap(AppModule, { serverOptions }); + const app = await Application.create(AppModule, { serverOptions }); app.server.listen(8080, '0.0.0.0'); } diff --git a/frameworks/TypeScript/ditsmod/tsconfig.json b/frameworks/TypeScript/ditsmod/tsconfig.json index 27c048aa781..34983f83409 100644 --- a/frameworks/TypeScript/ditsmod/tsconfig.json +++ b/frameworks/TypeScript/ditsmod/tsconfig.json @@ -16,14 +16,11 @@ "noImplicitAny": true, "strictPropertyInitialization": false, "allowJs": false, - "paths": { - "#routed/*": ["./src/app/modules/routed/*"], - "#service/*": ["./src/app/modules/service/*"], - "#utils/*": ["./src/app/utils/*"], - } + "types": ["bun-types"], }, "include": [ "src", - "test" + "test", + "./spawn.ts" ] } diff --git a/frameworks/TypeScript/elysia/benchmark_config.json b/frameworks/TypeScript/elysia/benchmark_config.json index 1a0652745db..04e9073cbe8 100755 --- a/frameworks/TypeScript/elysia/benchmark_config.json +++ b/frameworks/TypeScript/elysia/benchmark_config.json @@ -62,6 +62,29 @@ "display_name": "Elysia [smol] [PostgreSQL]", "notes": "", "versus": "nodejs" + }, + "compiled": { + "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": "elysia", + "language": "TypeScript", + "flavor": "None", + "orm": "Raw", + "platform": "bun", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "Elysia [Compiled]", + "notes": "", + "versus": "nodejs" } } ] diff --git a/frameworks/TypeScript/elysia/bun.lockb b/frameworks/TypeScript/elysia/bun.lockb index a5f94fd2531..8b08fa7e91b 100755 Binary files a/frameworks/TypeScript/elysia/bun.lockb and b/frameworks/TypeScript/elysia/bun.lockb differ diff --git a/frameworks/TypeScript/elysia/elysia-compiled.dockerfile b/frameworks/TypeScript/elysia/elysia-compiled.dockerfile new file mode 100644 index 00000000000..59e5454e46e --- /dev/null +++ b/frameworks/TypeScript/elysia/elysia-compiled.dockerfile @@ -0,0 +1,15 @@ +FROM oven/bun:1.2 + +EXPOSE 8080 + +COPY . . + +ENV NODE_ENV production + +RUN bun install --production + +ENV DATABASE postgres + +RUN bun run compile + +CMD ["./server"] diff --git a/frameworks/TypeScript/elysia/elysia-postgres.dockerfile b/frameworks/TypeScript/elysia/elysia-postgres.dockerfile index e3fda732c79..2058fa4cfee 100644 --- a/frameworks/TypeScript/elysia/elysia-postgres.dockerfile +++ b/frameworks/TypeScript/elysia/elysia-postgres.dockerfile @@ -1,4 +1,4 @@ -FROM oven/bun:1.0 +FROM oven/bun:1.2 EXPOSE 8080 @@ -8,8 +8,8 @@ ENV NODE_ENV production RUN bun install --production -RUN bun run build - ENV DATABASE postgres -CMD ["bun", "spawn.ts"] +RUN bun run build + +CMD ["bun", "./dist/index.js"] diff --git a/frameworks/TypeScript/elysia/elysia-smol-postgres.dockerfile b/frameworks/TypeScript/elysia/elysia-smol-postgres.dockerfile index c222841c81a..91ccad74351 100644 --- a/frameworks/TypeScript/elysia/elysia-smol-postgres.dockerfile +++ b/frameworks/TypeScript/elysia/elysia-smol-postgres.dockerfile @@ -1,4 +1,4 @@ -FROM oven/bun:1.0 +FROM oven/bun:1.2 EXPOSE 8080 @@ -6,12 +6,12 @@ COPY . . ENV NODE_ENV production -RUN bun install --production - -RUN bun run build +RUN bun install ENV DATABASE postgres +RUN bun run build + RUN sed -i 's/smol = false/smol = true/g' bunfig.toml -CMD ["bun", "spawn.ts"] +CMD ["bun", "./dist/index.js"] diff --git a/frameworks/TypeScript/elysia/elysia.dockerfile b/frameworks/TypeScript/elysia/elysia.dockerfile index c05d3f41878..ae30a0d5764 100644 --- a/frameworks/TypeScript/elysia/elysia.dockerfile +++ b/frameworks/TypeScript/elysia/elysia.dockerfile @@ -1,4 +1,4 @@ -FROM oven/bun:1.0 +FROM oven/bun:1.2 EXPOSE 8080 @@ -10,4 +10,4 @@ RUN bun install --production RUN bun run build -CMD ["bun", "spawn.ts"] +CMD ["bun", "./dist/index.js"] diff --git a/frameworks/TypeScript/elysia/package.json b/frameworks/TypeScript/elysia/package.json index 082042b5f55..9d38195023f 100644 --- a/frameworks/TypeScript/elysia/package.json +++ b/frameworks/TypeScript/elysia/package.json @@ -3,15 +3,17 @@ "version": "0.0.1", "module": "src/index.js", "devDependencies": { - "bun-types": "latest" + "@types/bun": "^1.1.14", + "typescript": "^5.7.2" }, "scripts": { "dev": "bun run --watch src/index.ts", "start": "bun run src/index.ts", - "build": "bun build --target=bun --minify src/index.ts --outdir=build" + "build": "bun build --minify --target bun --outdir dist src/index.ts", + "compile": "bun build --compile --minify --target bun --outfile server src/index.ts" }, "dependencies": { - "elysia": "^0.7.17", - "postgres": "^3.4.1" + "elysia": "^1.2.9", + "postgres": "^3.4.5" } } diff --git a/frameworks/TypeScript/elysia/spawn.ts b/frameworks/TypeScript/elysia/spawn.ts deleted file mode 100644 index ae02e7169a7..00000000000 --- a/frameworks/TypeScript/elysia/spawn.ts +++ /dev/null @@ -1,10 +0,0 @@ -import os from 'node:os'; - -// @ts-ignore -const numCPUs = os.availableParallelism(); -for (let i = 0; i < numCPUs; i++) { - Bun.spawn(['bun', 'build/index.js'], { - stdio: ['inherit', 'inherit', 'inherit'], - env: { ...process.env }, - }); -} diff --git a/frameworks/TypeScript/elysia/src/db-handlers.ts b/frameworks/TypeScript/elysia/src/db-handlers.ts index 0e099d6d8b6..6674829bfd9 100644 --- a/frameworks/TypeScript/elysia/src/db-handlers.ts +++ b/frameworks/TypeScript/elysia/src/db-handlers.ts @@ -1,84 +1,67 @@ -import Elysia from 'elysia'; -import * as postgres from './postgres'; -import { Fortune, World } from './types'; - -const deps = new Elysia({ - name: 'deps', -}) - .decorate('db', postgres) - .decorate('generateRandomNumber', () => Math.ceil(Math.random() * 10000)) - .decorate('html', (fortunes: Fortune[]) => { - const n = fortunes.length; - - let html = ''; - for (let i = 0; i < n; i++) { - html += `${fortunes[i].id}${Bun.escapeHTML( - fortunes[i].message - )}`; - } - - return `Fortunes${html}
idmessage
`; - }); - -const dbHandlers = new Elysia({ - name: 'db-handlers', -}) - .use(deps) - .get( - '/db', - async ({ db, generateRandomNumber }) => - await db.find(generateRandomNumber()) - ) - .get( - '/fortunes', - async ({ db, html }) => { - const fortunes = await db.fortunes(); - - fortunes.push({ - id: 0, - message: 'Additional fortune added at request time.', - }); - - fortunes.sort((a, b) => (a.message < b.message ? -1 : 1)); - - return html(fortunes); - }, - { - afterHandle({ set }) { - set.headers['content-type'] = 'text/html; charset=utf-8'; - }, - } - ) - .derive(({ query }) => ({ - numberOfObjects: Math.min(parseInt(query.queries || '1') || 1, 500), - })) - .get('/queries', async ({ db, generateRandomNumber, numberOfObjects }) => { - const worldPromises = new Array>(numberOfObjects); - - for (let i = 0; i < numberOfObjects; i++) { - worldPromises[i] = db.find(generateRandomNumber()); - } - - const worlds = await Promise.all(worldPromises); - - return worlds; - }) - .get('/updates', async ({ db, generateRandomNumber, numberOfObjects }) => { - const worldPromises = new Array>(numberOfObjects); - - for (let i = 0; i < numberOfObjects; i++) { - worldPromises[i] = db.find(generateRandomNumber()); - } - - const worlds = await Promise.all(worldPromises); - - for (let i = 0; i < numberOfObjects; i++) { - worlds[i].randomNumber = generateRandomNumber(); - } - - await db.bulkUpdate(worlds); - - return worlds; - }); - -export default dbHandlers; +import { Elysia, t } from "elysia"; +import * as db from "./postgres"; +import { Fortune } from "./types"; + +export function rand() { + return Math.ceil(Math.random() * 10000); +} + +function parseQueriesNumber(q?: string) { + // NaN is falsy, fallback to one. + return Math.min(+q! || 1, 500); +} + +export const dbHandlers = new Elysia() + .headers({ + server: "Elysia", + }) + // ? Mark as async for Promise result to prevent double Elysia's mapResponse execution + .get("/db", async () => db.find(rand())) + .get("/fortunes", async (c) => { + const fortunes = await db.fortunes(); + + fortunes.push({ + id: 0, + message: "Additional fortune added at request time.", + }); + + fortunes.sort((a, b) => { + if (a.message < b.message) return -1; + + return 1; + }); + + c.set.headers["content-type"] = "text/html; charset=utf-8"; + + const n = fortunes.length; + + let html = ""; + for (let i = 0; i < n; i++) { + html += `${fortunes[i].id}${Bun.escapeHTML( + fortunes[i].message, + )}`; + } + + return `Fortunes${html}
idmessage
`; + }) + // ? Mark as async for Promise result to prevent double Elysia's mapResponse execution + .get("/queries", async (c) => { + const num = parseQueriesNumber(c.query.queries); + const worldPromises = new Array(num); + + for (let i = 0; i < num; i++) worldPromises[i] = db.find(rand()); + + return Promise.all(worldPromises); + }) + .get("/updates", async (c) => { + const num = parseQueriesNumber(c.query.queries); + const worldPromises = new Array(num); + + for (let i = 0; i < num; i++) + worldPromises[i] = db.findThenRand(rand()); + + const worlds = await Promise.all(worldPromises); + + await db.bulkUpdate(worlds); + return worlds; + }); diff --git a/frameworks/TypeScript/elysia/src/index.ts b/frameworks/TypeScript/elysia/src/index.ts index dc0f0c8d20f..b34edbde4b7 100644 --- a/frameworks/TypeScript/elysia/src/index.ts +++ b/frameworks/TypeScript/elysia/src/index.ts @@ -1,25 +1,20 @@ -import { Elysia } from 'elysia'; -import dbHandlers from './db-handlers'; +import cluster from "node:cluster"; +import os from "node:os"; +import process from "node:process"; -const app = new Elysia({ - serve: { - // @ts-ignore - reusePort: true, - }, -}) - .onAfterHandle(({ set }) => { - set.headers['server'] = 'Elysia'; - }) - .decorate('HELLO_WORLD_STR', 'Hello, World!') - .get('/plaintext', ({ HELLO_WORLD_STR }) => HELLO_WORLD_STR) - .get('/json', ({ HELLO_WORLD_STR }) => ({ message: HELLO_WORLD_STR })); +if (cluster.isPrimary) { + console.log(`Primary ${process.pid} is running`); -if (process.env.DATABASE) { - app.use(dbHandlers); -} - -app.listen(8080); + const numCPUs = os.availableParallelism(); + for (let i = 0; i < numCPUs; i++) { + cluster.fork(); + } -console.info( - `🦊 Elysia is running at ${app.server?.hostname}:${app.server?.port}` -); + cluster.on("exit", (worker) => { + console.log(`worker ${worker.process.pid} died`); + process.exit(1); + }); +} else { + await import("./server"); + console.log(`Worker ${process.pid} started`); +} diff --git a/frameworks/TypeScript/elysia/src/postgres.ts b/frameworks/TypeScript/elysia/src/postgres.ts index ae101fc0867..ee09e073712 100644 --- a/frameworks/TypeScript/elysia/src/postgres.ts +++ b/frameworks/TypeScript/elysia/src/postgres.ts @@ -1,27 +1,36 @@ -import postgres from 'postgres'; -import { Fortune, World } from './types'; +import { SQL } from "bun"; +import { rand } from "./db-handlers"; +import type { Fortune, World } from "./types"; -const sql = postgres({ - host: 'tfb-database', - user: 'benchmarkdbuser', - password: 'benchmarkdbpass', - database: 'hello_world', - max: 1, +const sql = new SQL({ + url: "postgres://benchmarkdbuser:benchmarkdbpass@tfb-database:5432/hello_world", + 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: number) => - await sql`SELECT id, randomNumber FROM world WHERE id = ${id}`.then( - (arr) => arr[0] - ); +export const find = (id: number) => + sql`SELECT id, randomNumber FROM world WHERE id = ${id}`.then( + (arr) => arr[0], + ); -export const bulkUpdate = async (worlds: World[]) => - await sql`UPDATE world SET randomNumber = (update_data.randomNumber)::int - FROM (VALUES ${sql( - worlds - .map((world) => [world.id, world.randomNumber]) - .sort((a, b) => (a[0] < b[0] ? -1 : 1)) - )}) AS update_data (id, randomNumber) - WHERE world.id = (update_data.id)::int`; +export const findThenRand = (id: number) => + sql`SELECT id, randomNumber FROM world WHERE id = ${id}`.then( + (arr) => { + arr[0].randomNumber = rand(); + return arr[0]; + }, + ); + +export const bulkUpdate = (worlds: World[]) => { + worlds = worlds.toSorted((a, b) => a.id - b.id); + + const values = new Array(worlds.length); + for (let i = 0; i < worlds.length; i++) { + values[i] = [worlds[i].id, worlds[i].randomNumber]; + } + + return sql`UPDATE world SET randomNumber = (update_data.randomNumber)::int + FROM (VALUES ${sql(values)}) AS update_data (id, randomNumber) + WHERE world.id = (update_data.id)::int`; +}; diff --git a/frameworks/TypeScript/elysia/src/server.ts b/frameworks/TypeScript/elysia/src/server.ts new file mode 100644 index 00000000000..7c2c46d224d --- /dev/null +++ b/frameworks/TypeScript/elysia/src/server.ts @@ -0,0 +1,20 @@ +import { Elysia } from "elysia"; +import { dbHandlers } from "./db-handlers"; + +const app = new Elysia() + .headers({ + server: "Elysia", + }) + .get("/plaintext", "Hello, World!") + // As state on xiv in https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview#requirements + // The serialization to JSON must not be cached; + // the computational effort to serialize an object to JSON must occur within the scope of handling each request. + .get("/json", () => ({ message: "Hello, World!" })) + .use((app) => { + if (Bun.env.DATABASE) app.use(dbHandlers); + + return app; + }) + .listen(8080); + +console.info(`🦊 Elysia is running at ${app.server!.url}`); diff --git a/frameworks/TypeScript/elysia/src/types.ts b/frameworks/TypeScript/elysia/src/types.ts index a40a9a0c7b2..6863ea8f4aa 100644 --- a/frameworks/TypeScript/elysia/src/types.ts +++ b/frameworks/TypeScript/elysia/src/types.ts @@ -1,9 +1,9 @@ -export type Fortune = { - id: number; - message: string; -}; +export interface Fortune { + id: number + message: string +} -export type World = { - id: number; - randomNumber: number; -}; +export interface World { + id: number + randomNumber: number +} diff --git a/frameworks/TypeScript/nest/benchmark_config.json b/frameworks/TypeScript/nest/benchmark_config.json index bf98c12c49e..bb13940c076 100644 --- a/frameworks/TypeScript/nest/benchmark_config.json +++ b/frameworks/TypeScript/nest/benchmark_config.json @@ -20,6 +20,7 @@ "database": "Postgres", "database_os": "Linux", "display_name": "nestjs", + "platform": "nodejs", "versus": "nodejs" }, "mysql": { @@ -38,6 +39,7 @@ "database": "MySQL", "database_os": "Linux", "display_name": "nestjs mysql", + "platform": "nodejs", "versus": "nodejs" }, "mongo": { @@ -56,6 +58,7 @@ "database": "MongoDB", "database_os": "Linux", "display_name": "nestjs", + "platform": "nodejs", "versus": "nodejs" }, "fastify": { @@ -76,6 +79,7 @@ "os": "Linux", "database_os": "Linux", "display_name": "nestjs fastify", + "platform": "nodejs", "versus": "nodejs" }, "fastify-mysql": { @@ -94,6 +98,7 @@ "os": "Linux", "database_os": "Linux", "display_name": "nestjs fastify mysql", + "platform": "nodejs", "versus": "nodejs" }, "fastify-mongo": { @@ -112,6 +117,7 @@ "os": "Linux", "database_os": "Linux", "display_name": "nestjs fastify mongo", + "platform": "nodejs", "versus": "nodejs" } } diff --git a/frameworks/TypeScript/nest/nestjs-fastify-mongo.dockerfile b/frameworks/TypeScript/nest/nestjs-fastify-mongo.dockerfile index 687e3662d7d..d55bacee6a7 100644 --- a/frameworks/TypeScript/nest/nestjs-fastify-mongo.dockerfile +++ b/frameworks/TypeScript/nest/nestjs-fastify-mongo.dockerfile @@ -1,4 +1,4 @@ -FROM node:18.12.1-slim +FROM node:20.16-slim COPY ./ ./ @@ -10,4 +10,4 @@ ENV DATABASE_CONFIGURATION_PROFILE mongodb ENV FRAMEWORK fastify EXPOSE 8080 -CMD ["node", "dist/main"] \ No newline at end of file +CMD ["node", "dist/main"] diff --git a/frameworks/TypeScript/nest/nestjs-fastify-mysql.dockerfile b/frameworks/TypeScript/nest/nestjs-fastify-mysql.dockerfile index 55f3872b71d..40b0da005c4 100644 --- a/frameworks/TypeScript/nest/nestjs-fastify-mysql.dockerfile +++ b/frameworks/TypeScript/nest/nestjs-fastify-mysql.dockerfile @@ -1,4 +1,4 @@ -FROM node:18.12.1-slim +FROM node:20.16-slim COPY ./ ./ @@ -10,4 +10,4 @@ ENV DATABASE_CONFIGURATION_PROFILE mysql ENV FRAMEWORK fastify EXPOSE 8080 -CMD ["node", "dist/main"] \ No newline at end of file +CMD ["node", "dist/main"] diff --git a/frameworks/TypeScript/nest/nestjs-fastify.dockerfile b/frameworks/TypeScript/nest/nestjs-fastify.dockerfile index 6eb139b3d2c..485c360794e 100644 --- a/frameworks/TypeScript/nest/nestjs-fastify.dockerfile +++ b/frameworks/TypeScript/nest/nestjs-fastify.dockerfile @@ -1,4 +1,4 @@ -FROM node:18.12.1-slim +FROM node:20.16-slim COPY ./ ./ @@ -10,4 +10,4 @@ ENV DATABASE_CONFIGURATION_PROFILE postgres ENV FRAMEWORK fastify EXPOSE 8080 -CMD ["node", "dist/main"] \ No newline at end of file +CMD ["node", "dist/main"] diff --git a/frameworks/TypeScript/nest/nestjs-mongo.dockerfile b/frameworks/TypeScript/nest/nestjs-mongo.dockerfile index 7b2e842f411..a59ac0c9e14 100644 --- a/frameworks/TypeScript/nest/nestjs-mongo.dockerfile +++ b/frameworks/TypeScript/nest/nestjs-mongo.dockerfile @@ -1,4 +1,4 @@ -FROM node:18.12.1-slim +FROM node:20.16-slim COPY ./ ./ @@ -10,4 +10,4 @@ ENV DATABASE_CONFIGURATION_PROFILE mongodb ENV FRAMEWORK express EXPOSE 8080 -CMD ["node", "dist/main"] \ No newline at end of file +CMD ["node", "dist/main"] diff --git a/frameworks/TypeScript/nest/nestjs-mysql.dockerfile b/frameworks/TypeScript/nest/nestjs-mysql.dockerfile index 42865fe49c9..9ff806b92a8 100644 --- a/frameworks/TypeScript/nest/nestjs-mysql.dockerfile +++ b/frameworks/TypeScript/nest/nestjs-mysql.dockerfile @@ -1,4 +1,4 @@ -FROM node:18.12.1-slim +FROM node:20.16-slim COPY ./ ./ @@ -10,4 +10,4 @@ ENV DATABASE_CONFIGURATION_PROFILE mysql ENV FRAMEWORK express EXPOSE 8080 -CMD ["node", "dist/main"] \ No newline at end of file +CMD ["node", "dist/main"] diff --git a/frameworks/TypeScript/nest/nestjs.dockerfile b/frameworks/TypeScript/nest/nestjs.dockerfile index 8c97367cc10..1ea6fd1581e 100644 --- a/frameworks/TypeScript/nest/nestjs.dockerfile +++ b/frameworks/TypeScript/nest/nestjs.dockerfile @@ -1,4 +1,4 @@ -FROM node:18.12.1-slim +FROM node:20.16-slim COPY ./ ./ @@ -10,4 +10,4 @@ ENV DATABASE_CONFIGURATION_PROFILE postgres ENV FRAMEWORK express EXPOSE 8080 -CMD ["node", "dist/main"] \ No newline at end of file +CMD ["node", "dist/main"] diff --git a/frameworks/TypeScript/nest/package.json b/frameworks/TypeScript/nest/package.json index 219569e19e4..8b84a7e2ccc 100644 --- a/frameworks/TypeScript/nest/package.json +++ b/frameworks/TypeScript/nest/package.json @@ -21,12 +21,12 @@ "@nestjs/platform-fastify": "6.11.11", "@nestjs/typeorm": "7.1.5", "cache-manager": "3.1.0", - "fastify": "2.12.1", + "fastify": "2.15.1", "fastify-formbody": "3.1.0", - "handlebars": "4.7.3", + "handlebars": "4.7.7", "hbs": "4.1.0", "mongodb": "3.5.4", - "mysql2": "2.1.0", + "mysql2": "3.9.8", "pg": "8.5.1", "point-of-view": "3.7.2", "reflect-metadata": "0.1.13", diff --git a/frameworks/TypeScript/nest/src/main.ts b/frameworks/TypeScript/nest/src/main.ts index 82fa61ea07d..a095bfb746b 100644 --- a/frameworks/TypeScript/nest/src/main.ts +++ b/frameworks/TypeScript/nest/src/main.ts @@ -23,6 +23,7 @@ async function bootstrapExpress() { app = await NestFactory.create(SqlModule, { logger: false, }); + app.getHttpServer().keepAliveTimeout = 0; } app.setBaseViewsDir(join(__dirname, '..', 'views')); @@ -40,12 +41,14 @@ async function bootstrapFastify() { new FastifyAdapter(), { logger: false }, ); + app.getHttpServer().keepAliveTimeout = 0; } else { app = await NestFactory.create( SqlModule, new FastifyAdapter(), { logger: false }, ); + app.getHttpServer().keepAliveTimeout = 0; } app.setViewEngine({ diff --git a/frameworks/TypeScript/nextjs/.dockerignore b/frameworks/TypeScript/nextjs/.dockerignore new file mode 100644 index 00000000000..db6a874b260 --- /dev/null +++ b/frameworks/TypeScript/nextjs/.dockerignore @@ -0,0 +1,7 @@ +*.dockerfile +.dockerignore +node_modules +npm-debug.log +README.md +.next +.git diff --git a/frameworks/TypeScript/nextjs/.gitignore b/frameworks/TypeScript/nextjs/.gitignore new file mode 100644 index 00000000000..5ef6a520780 --- /dev/null +++ b/frameworks/TypeScript/nextjs/.gitignore @@ -0,0 +1,41 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/versions + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# env files (can opt-in for committing if needed) +.env* + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/frameworks/TypeScript/nextjs/README.md b/frameworks/TypeScript/nextjs/README.md new file mode 100644 index 00000000000..10411041b28 --- /dev/null +++ b/frameworks/TypeScript/nextjs/README.md @@ -0,0 +1,29 @@ +# Next.js Benchmarking Test + +## Test source files and URLs + +| Test | Source Code | URL | +| --- | --- | --- | +| [JSON Serialization][] | [`app/json/route.ts`][] | http://localhost:3000/json | +| [Single Database Query][] | [`app/db/route.ts`][] | http://localhost:3000/db | +| [Multiple Database Queries][] | [`app/queries/route.ts`][] | http://localhost:3000/queries?queries= | +| [Fortunes][] | [`app/fortunes/page.tsx`][] | http://localhost:3000/fortunes | +| [Database Updates][] | [`app/updates/route.ts`][] | http://localhost:3000/updates?queries= | +| [Plaintext][] | [`app/plaintext/route.ts`][] | http://localhost:3000/plaintext | +| [Caching][] | [`app/cached-queries/route.ts`][] | http://localhost:3000/cached-queries?queries= | + +[JSON Serialization]: https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview#json-serialization +[Single Database Query]: https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview#single-database-query +[Multiple Database Queries]: https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview#multiple-database-queries +[Fortunes]: https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview#fortunes +[Database Updates]: https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview#database-updates +[Plaintext]: https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview#plaintext +[Caching]: https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview#caching + +[`app/json/route.ts`]: ./app/json/route.ts +[`app/db/route.ts`]: ./app/db/route.ts +[`app/queries/route.ts`]: ./app/queries/route.ts +[`app/fortunes/page.tsx`]: ./app/fortunes/page.tsx +[`app/updates/route.ts`]: ./app/updates/route.ts +[`app/plaintext/route.ts`]: ./app/plaintext/route.ts +[`app/cached-queries/route.ts`]: ./app/cached-queries/route.ts diff --git a/frameworks/TypeScript/nextjs/app/cached-queries/route.ts b/frameworks/TypeScript/nextjs/app/cached-queries/route.ts new file mode 100644 index 00000000000..148891d3249 --- /dev/null +++ b/frameworks/TypeScript/nextjs/app/cached-queries/route.ts @@ -0,0 +1,18 @@ +import { findWorld as uncached_findWorld, World } from "@/lib/db" +import { unstable_cache } from "next/cache" +import { NextRequest } from "next/server" + +const findWorld = unstable_cache(uncached_findWorld) + +export async function GET(request: NextRequest) { + const queriesParam = request.nextUrl.searchParams.get("queries") + const queriesCount = Math.min(Math.max(Number(queriesParam) || 1, 1), 500) + const results = Array(queriesCount) + + for (let i = 0; i < queriesCount; i += 1) { + const id = 1 + Math.floor(Math.random() * 10000) + results[i] = await findWorld(id) + } + + return Response.json(results) +} diff --git a/frameworks/TypeScript/nextjs/app/db/route.ts b/frameworks/TypeScript/nextjs/app/db/route.ts new file mode 100644 index 00000000000..1ff5e98fe72 --- /dev/null +++ b/frameworks/TypeScript/nextjs/app/db/route.ts @@ -0,0 +1,6 @@ +import { findWorld } from "@/lib/db" + +export async function GET() { + const id = 1 + Math.floor(Math.random() * 10000) + return Response.json(await findWorld(id)) +} diff --git a/frameworks/TypeScript/nextjs/app/favicon.ico b/frameworks/TypeScript/nextjs/app/favicon.ico new file mode 100644 index 00000000000..718d6fea483 Binary files /dev/null and b/frameworks/TypeScript/nextjs/app/favicon.ico differ diff --git a/frameworks/TypeScript/nextjs/app/fortunes/page.tsx b/frameworks/TypeScript/nextjs/app/fortunes/page.tsx new file mode 100644 index 00000000000..95f2633e9b7 --- /dev/null +++ b/frameworks/TypeScript/nextjs/app/fortunes/page.tsx @@ -0,0 +1,31 @@ +import { db } from "@/lib/db" + +// Prevent database queries during build phase. +export const dynamic = "force-dynamic" + +export default async function Page() { + const fortunes = await db.selectFrom("Fortune").selectAll().execute() + fortunes.push({ id: 0, message: "Additional fortune added at request time." }) + fortunes.sort((a, b) => a.message.localeCompare(b.message)) + + return <> + Fortunes + + + + + + + + + + {fortunes.map(fortune => + + + + + )} + +
idmessage
{fortune.id}{fortune.message}
+ +} diff --git a/frameworks/TypeScript/nextjs/app/json/route.ts b/frameworks/TypeScript/nextjs/app/json/route.ts new file mode 100644 index 00000000000..c4b7c31fba3 --- /dev/null +++ b/frameworks/TypeScript/nextjs/app/json/route.ts @@ -0,0 +1,3 @@ +export async function GET() { + return Response.json({ message: "Hello, World!" }) +} diff --git a/frameworks/TypeScript/nextjs/app/layout.tsx b/frameworks/TypeScript/nextjs/app/layout.tsx new file mode 100644 index 00000000000..0703997a627 --- /dev/null +++ b/frameworks/TypeScript/nextjs/app/layout.tsx @@ -0,0 +1,13 @@ +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + return ( + + + {children} + + + ); +} diff --git a/frameworks/TypeScript/nextjs/app/page.tsx b/frameworks/TypeScript/nextjs/app/page.tsx new file mode 100644 index 00000000000..b772bfb7bbc --- /dev/null +++ b/frameworks/TypeScript/nextjs/app/page.tsx @@ -0,0 +1,3 @@ +export default function Home() { + return +} diff --git a/frameworks/TypeScript/nextjs/app/plaintext/route.ts b/frameworks/TypeScript/nextjs/app/plaintext/route.ts new file mode 100644 index 00000000000..62ee50bc6ce --- /dev/null +++ b/frameworks/TypeScript/nextjs/app/plaintext/route.ts @@ -0,0 +1,3 @@ +export function GET() { + return new Response("Hello, World!") +} diff --git a/frameworks/TypeScript/nextjs/app/queries/route.ts b/frameworks/TypeScript/nextjs/app/queries/route.ts new file mode 100644 index 00000000000..bea89efb67b --- /dev/null +++ b/frameworks/TypeScript/nextjs/app/queries/route.ts @@ -0,0 +1,15 @@ +import { findWorld, World } from "@/lib/db" +import { NextRequest } from "next/server" + +export async function GET(request: NextRequest) { + const queriesParam = request.nextUrl.searchParams.get("queries") + const queriesCount = Math.min(Math.max(Number(queriesParam) || 1, 1), 500) + const promises = Array>(queriesCount) + + for (let i = 0; i < queriesCount; i += 1) { + const id = 1 + Math.floor(Math.random() * 10000) + promises[i] = findWorld(id) + } + + return Response.json(await Promise.all(promises)) +} diff --git a/frameworks/TypeScript/nextjs/app/updates/route.ts b/frameworks/TypeScript/nextjs/app/updates/route.ts new file mode 100644 index 00000000000..4eebbc71ffe --- /dev/null +++ b/frameworks/TypeScript/nextjs/app/updates/route.ts @@ -0,0 +1,26 @@ +import { db, findWorld, upsertWorlds, World } from "@/lib/db" +import { NextRequest } from "next/server" + +export async function GET(request: NextRequest) { + const queriesParam = request.nextUrl.searchParams.get("queries") + const queriesCount = Math.min(Math.max(Number(queriesParam) || 1, 1), 500) + + const ids = new Set() + while (ids.size < queriesCount) { + ids.add(1 + Math.floor(Math.random() * 10000)) + } + + const promises = new Array>() + for (const id of ids) { + promises.push(findWorld(id)) + } + + const results = await Promise.all(promises) as World[] + for (const result of results) { + result.randomNumber = 1 + Math.floor(Math.random() * 10000) + } + + await upsertWorlds(results) + + return Response.json(results) +} diff --git a/frameworks/TypeScript/nextjs/benchmark_config.json b/frameworks/TypeScript/nextjs/benchmark_config.json new file mode 100644 index 00000000000..72980fe5922 --- /dev/null +++ b/frameworks/TypeScript/nextjs/benchmark_config.json @@ -0,0 +1,30 @@ +{ + "framework": "nextjs", + "tests": [ + { + "default": { + "display_name": "Next.js", + "versus": "nodejs", + "classification": "Platform", + "language": "TypeScript", + "platform": "nodejs", + "framework": "nextjs", + "os": "Linux", + "webserver": "None", + "database": "postgres", + "database_os": "Linux", + "orm": "Micro", + "approach": "Realistic", + "notes": "", + "port": 3000, + "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?queries=" + } + } + ] +} diff --git a/frameworks/TypeScript/nextjs/lib/db.ts b/frameworks/TypeScript/nextjs/lib/db.ts new file mode 100644 index 00000000000..5552ab826c9 --- /dev/null +++ b/frameworks/TypeScript/nextjs/lib/db.ts @@ -0,0 +1,27 @@ +import { Kysely, PostgresDialect } from "kysely" +import { Pool } from "pg" +import { Database, WorldRow } from "./schema.js" + +export const db = new Kysely({ + dialect: new PostgresDialect({ + pool: new Pool({ connectionString: process.env.DATABASE_URL }), + }), +}) + +export type World = { + [key in keyof WorldRow as key extends "randomnumber" ? "randomNumber" : key]: WorldRow[key] +} + +export async function findWorld(id: number): Promise { + return db.selectFrom("World"). + where("id", "=", id). + select(["id", "randomnumber as randomNumber"]). + executeTakeFirst() +} + +export async function upsertWorlds(worlds: World[]) { + const values = worlds.map(world => ({ id: world.id, randomnumber: world.randomNumber })) + return db.insertInto("World").values(values).onConflict(oc => + oc.column("id").doUpdateSet({ randomnumber: eb => eb.ref("excluded.randomnumber") }) + ).execute() +} diff --git a/frameworks/TypeScript/nextjs/lib/schema.ts b/frameworks/TypeScript/nextjs/lib/schema.ts new file mode 100644 index 00000000000..990108f8d24 --- /dev/null +++ b/frameworks/TypeScript/nextjs/lib/schema.ts @@ -0,0 +1,22 @@ +import { Generated, Insertable, Selectable, Updateable } from "kysely" + +export interface Database { + World: WorldTable + Fortune: FortuneTable +} + +export interface WorldTable { + id: Generated + randomnumber: number +} + +export type WorldRow = Selectable +export type NewWorld = Insertable +export type WorldUpdate = Updateable + +export interface FortuneTable { + id: Generated + message: string +} + +export type Fortune = Selectable diff --git a/frameworks/TypeScript/nextjs/next.config.ts b/frameworks/TypeScript/nextjs/next.config.ts new file mode 100644 index 00000000000..7d67e37baf8 --- /dev/null +++ b/frameworks/TypeScript/nextjs/next.config.ts @@ -0,0 +1,18 @@ +import type { NextConfig } from "next"; + +const nextConfig: NextConfig = { + output: "standalone", + + async headers() { + return [ + { + source: "/(.*?)", + headers: [ + { key: "Server", value: "Next.js" }, + ], + }, + ] + }, +}; + +export default nextConfig; diff --git a/frameworks/TypeScript/nextjs/nextjs.dockerfile b/frameworks/TypeScript/nextjs/nextjs.dockerfile new file mode 100644 index 00000000000..9f68f27e4b1 --- /dev/null +++ b/frameworks/TypeScript/nextjs/nextjs.dockerfile @@ -0,0 +1,20 @@ +FROM node:22-slim + +ENV NEXT_TELEMETRY_DISABLED="1" +ENV DATABASE_URL="postgres://benchmarkdbuser:benchmarkdbpass@tfb-database/hello_world" + +EXPOSE 3000 + +WORKDIR /nextjs + +COPY package.json package-lock.json ./ +RUN npm ci + +COPY ./ ./ +RUN npm run build \ + && cp -r public .next/standalone/ \ + && cp -r .next/static .next/standalone/.next/ + +ENV NODE_ENV="production" + +CMD ["node", ".next/standalone/server.js"] diff --git a/frameworks/TypeScript/nextjs/package-lock.json b/frameworks/TypeScript/nextjs/package-lock.json new file mode 100644 index 00000000000..68185dc81d0 --- /dev/null +++ b/frameworks/TypeScript/nextjs/package-lock.json @@ -0,0 +1,1198 @@ +{ + "name": "next-techempower-benchmarks", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "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" + }, + "devDependencies": { + "@types/node": "^20", + "@types/pg": "^8.11.10", + "@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", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "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==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.0.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==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.0.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==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "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==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "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==", + "cpu": [ + "arm" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "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==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "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==", + "cpu": [ + "s390x" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "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==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "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==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "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==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "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==", + "cpu": [ + "arm" + ], + "license": "Apache-2.0", + "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-arm": "1.0.5" + } + }, + "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==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "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-arm64": "1.0.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==", + "cpu": [ + "s390x" + ], + "license": "Apache-2.0", + "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-s390x": "1.0.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==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "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-x64": "1.0.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==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "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-linuxmusl-arm64": "1.0.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==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "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-linuxmusl-x64": "1.0.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==", + "cpu": [ + "wasm32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.2.0" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "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==", + "cpu": [ + "ia32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "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==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "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" + }, + "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==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "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==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "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==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "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==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "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==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "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==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "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==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "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==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "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" + }, + "node_modules/@swc/helpers": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", + "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.19.2" + } + }, + "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==", + "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" + } + }, + "node_modules/@types/react": { + "version": "19.0.2", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.0.2.tgz", + "integrity": "sha512-USU8ZI/xyKJwFTpjSVIrSeHBVAGagkHQKPNbxeWwql/vDmnTIBgx+TJnhFnj1NXgz8XfprU0egV2dROLGpsBEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.0.2", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.0.2.tgz", + "integrity": "sha512-c1s+7TKFaDRRxr1TxccIX2u7sfCnc3RxkVyBIUA2lCpyqCF+QoAwQ/CBg7bsMdVwP120HEH143VQezKtef5nCg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.0.0" + } + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001690", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001690.tgz", + "integrity": "sha512-5ExiE3qQN6oF8Clf8ifIDcMRCRE/dMGcETG/XGMD8/XiXm6HXQgQTh1yZYLXXpSOsEUlJm1Xr7kGULZTuGtP/w==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "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", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "dev": true, + "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", + "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", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.8", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", + "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "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", + "dependencies": { + "@next/env": "15.2.4", + "@swc/counter": "0.1.3", + "@swc/helpers": "0.5.15", + "busboy": "1.6.0", + "caniuse-lite": "^1.0.30001579", + "postcss": "8.4.31", + "styled-jsx": "5.1.6" + }, + "bin": { + "next": "dist/bin/next" + }, + "engines": { + "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" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.1.0", + "@playwright/test": "^1.41.2", + "babel-plugin-react-compiler": "*", + "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "sass": "^1.3.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + }, + "@playwright/test": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + }, + "sass": { + "optional": true + } + } + }, + "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", + "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" + }, + "engines": { + "node": ">= 8.0.0" + }, + "optionalDependencies": { + "pg-cloudflare": "^1.1.1" + }, + "peerDependencies": { + "pg-native": ">=3.0.1" + }, + "peerDependenciesMeta": { + "pg-native": { + "optional": true + } + } + }, + "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", + "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" + }, + "node_modules/pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "license": "ISC", + "engines": { + "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", + "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" + }, + "node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "license": "MIT", + "dependencies": { + "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" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "license": "MIT", + "dependencies": { + "split2": "^4.1.0" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/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==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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==", + "license": "MIT", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "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", + "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", + "dependencies": { + "scheduler": "^0.25.0" + }, + "peerDependencies": { + "react": "^19.0.0" + } + }, + "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" + }, + "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", + "optional": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "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==", + "hasInstallScript": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "color": "^4.2.3", + "detect-libc": "^2.0.3", + "semver": "^7.6.3" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "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" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/styled-jsx": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", + "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==", + "license": "MIT", + "dependencies": { + "client-only": "0.0.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "peerDependencies": { + "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "babel-plugin-macros": { + "optional": true + } + } + }, + "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" + }, + "node_modules/typescript": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", + "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "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" + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + } + } +} diff --git a/frameworks/TypeScript/nextjs/package.json b/frameworks/TypeScript/nextjs/package.json new file mode 100644 index 00000000000..d1e98eb62e3 --- /dev/null +++ b/frameworks/TypeScript/nextjs/package.json @@ -0,0 +1,25 @@ +{ + "name": "next-techempower-benchmarks", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev --turbopack", + "build": "next build", + "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" + }, + "devDependencies": { + "@types/node": "^20", + "@types/pg": "^8.11.10", + "@types/react": "^19", + "@types/react-dom": "^19", + "typescript": "^5" + } +} diff --git a/frameworks/TypeScript/nextjs/public/.keep b/frameworks/TypeScript/nextjs/public/.keep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/frameworks/TypeScript/nextjs/tsconfig.json b/frameworks/TypeScript/nextjs/tsconfig.json new file mode 100644 index 00000000000..d8b93235f20 --- /dev/null +++ b/frameworks/TypeScript/nextjs/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "target": "ES2017", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true, + "plugins": [ + { + "name": "next" + } + ], + "paths": { + "@/*": ["./*"] + } + }, + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], + "exclude": ["node_modules"] +} diff --git a/frameworks/TypeScript/oak/README.md b/frameworks/TypeScript/oak/README.md index 4cd56cbd62c..9a5dc9d02da 100755 --- a/frameworks/TypeScript/oak/README.md +++ b/frameworks/TypeScript/oak/README.md @@ -2,13 +2,13 @@ ### Test Type Implementation Source Code -- [PLAINTEXT](src/routes.ts#L15) -- [JSON](src/routes.ts#L16) -- [DB](src/routes.ts#L17) -- [QUERY](src/routes.ts#L24) -- [UPDATE](src/routes.ts#L37) -- [FORTUNES](src/routes.ts#L53) -- [CACHED QUERY](src/routes.ts#L67) +- [PLAINTEXT](src/routes.ts#L18) +- [JSON](src/routes.ts#L19) +- [DB](src/routes.ts#L25) +- [QUERY](src/routes.ts#L29) +- [UPDATE](src/routes.ts#L39) +- [FORTUNES](src/routes.ts#L59) +- [CACHED QUERY](src/routes.ts#L73) ## Important Libraries @@ -16,7 +16,7 @@ The tests were run with: - [deno](https://deno.land) - [oak](https://deno.land/x/oak/) -- [cotton](https://deno.land/x/cotton/) +- [Postgres.js](https://github.com/porsager/postgres/) ## Test URLs @@ -34,11 +34,11 @@ http://localhost:8080/db ### QUERY -http://localhost:8080/query?q= +http://localhost:8080/queries?q= ### UPDATE -http://localhost:8080/update?q= +http://localhost:8080/updates?q= ### FORTUNES @@ -46,4 +46,4 @@ http://localhost:8080/fortunes ### CACHED QUERY -http://localhost:8080/cached_query?q= \ No newline at end of file +http://localhost:8080/cached_queries?q= \ No newline at end of file diff --git a/frameworks/TypeScript/oak/benchmark_config.json b/frameworks/TypeScript/oak/benchmark_config.json index aa9486a9c51..0cfab7d20af 100755 --- a/frameworks/TypeScript/oak/benchmark_config.json +++ b/frameworks/TypeScript/oak/benchmark_config.json @@ -3,6 +3,25 @@ "tests": [ { "default": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "None", + "framework": "oak", + "language": "TypeScript", + "flavor": "deno", + "orm": "None", + "platform": "deno", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "oak", + "notes": "", + "versus": "nodejs" + }, + "postgresjs": { "json_url": "/json", "plaintext_url": "/plaintext", "db_url": "/db", @@ -12,20 +31,19 @@ "cached_query_url": "/cached_queries?q=", "port": 8080, "approach": "Realistic", - "classification": "Platform", + "classification": "Micro", "database": "postgres", - "framework": "None", - "language": "Typescript", + "database_os": "Linux", + "framework": "oak", + "language": "TypeScript", "flavor": "deno", - "orm": "Micro", + "orm": "Raw", "platform": "deno", "webserver": "None", "os": "Linux", - "database_os": "Linux", - "display_name": "oak", + "display_name": "oak [postgresjs]", "notes": "", - "versus": "nodejs", - "tags": ["broken"] + "versus": "nodejs" } } ] diff --git a/frameworks/TypeScript/oak/deno.json b/frameworks/TypeScript/oak/deno.json new file mode 100644 index 00000000000..27f10ea36d7 --- /dev/null +++ b/frameworks/TypeScript/oak/deno.json @@ -0,0 +1,8 @@ +{ + "imports": { + "oak": "jsr:@oak/oak@17.1.4", + "postgres": "https://deno.land/x/postgresjs@v3.4.5/mod.js", + "lru-cache": "jsr:@std/cache@0.2.0/lru-cache", + "html": "https://deno.land/x/literal_html@1.1.0/mod.ts" + } +} diff --git a/frameworks/TypeScript/oak/deno.lock b/frameworks/TypeScript/oak/deno.lock new file mode 100644 index 00000000000..49179a1be72 --- /dev/null +++ b/frameworks/TypeScript/oak/deno.lock @@ -0,0 +1,391 @@ +{ + "version": "4", + "specifiers": { + "jsr:@oak/commons@1": "1.0.1", + "jsr:@oak/oak@17.1.4": "17.1.4", + "jsr:@std/assert@1": "1.0.13", + "jsr:@std/bytes@1": "1.0.5", + "jsr:@std/cache@0.2.0": "0.2.0", + "jsr:@std/crypto@1": "1.0.4", + "jsr:@std/encoding@1": "1.0.10", + "jsr:@std/encoding@^1.0.10": "1.0.10", + "jsr:@std/http@1": "1.0.15", + "jsr:@std/media-types@1": "1.1.0", + "jsr:@std/path@1": "1.0.9", + "npm:path-to-regexp@^6.3.0": "6.3.0" + }, + "jsr": { + "@oak/commons@1.0.1": { + "integrity": "889ff210f0b4292591721be07244ecb1b5c118742f5273c70cf30d7cd4184d0c", + "dependencies": [ + "jsr:@std/assert", + "jsr:@std/bytes", + "jsr:@std/crypto", + "jsr:@std/encoding@1", + "jsr:@std/http", + "jsr:@std/media-types" + ] + }, + "@oak/oak@17.1.4": { + "integrity": "60530b582bf276ff741e39cc664026781aa08dd5f2bc5134d756cc427bf2c13e", + "dependencies": [ + "jsr:@oak/commons", + "jsr:@std/assert", + "jsr:@std/bytes", + "jsr:@std/http", + "jsr:@std/media-types", + "jsr:@std/path", + "npm:path-to-regexp" + ] + }, + "@std/assert@1.0.13": { + "integrity": "ae0d31e41919b12c656c742b22522c32fb26ed0cba32975cb0de2a273cb68b29" + }, + "@std/bytes@1.0.5": { + "integrity": "4465dd739d7963d964c809202ebea6d5c6b8e3829ef25c6a224290fbb8a1021e" + }, + "@std/cache@0.2.0": { + "integrity": "63a2ccd5a9e7c03e430f7d34dfcfd0d0cfc90731a1eaf8208f4c66e418fc3035" + }, + "@std/crypto@1.0.4": { + "integrity": "cee245c453bd5366207f4d8aa25ea3e9c86cecad2be3fefcaa6cb17203d79340" + }, + "@std/encoding@1.0.10": { + "integrity": "8783c6384a2d13abd5e9e87a7ae0520a30e9f56aeeaa3bdf910a3eaaf5c811a1" + }, + "@std/http@1.0.15": { + "integrity": "435a4934b4e196e82a8233f724da525f7b7112f3566502f28815e94764c19159", + "dependencies": [ + "jsr:@std/encoding@^1.0.10" + ] + }, + "@std/media-types@1.1.0": { + "integrity": "c9d093f0c05c3512932b330e3cc1fe1d627b301db33a4c2c2185c02471d6eaa4" + }, + "@std/path@1.0.9": { + "integrity": "260a49f11edd3db93dd38350bf9cd1b4d1366afa98e81b86167b4e3dd750129e" + } + }, + "npm": { + "path-to-regexp@6.3.0": { + "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==" + } + }, + "remote": { + "https://deno.land/std@0.132.0/_deno_unstable.ts": "23a1a36928f1b6d3b0170aaa67de09af12aa998525f608ff7331b9fb364cbde6", + "https://deno.land/std@0.132.0/_util/assert.ts": "e94f2eb37cebd7f199952e242c77654e43333c1ac4c5c700e929ea3aa5489f74", + "https://deno.land/std@0.132.0/_util/os.ts": "49b92edea1e82ba295ec946de8ffd956ed123e2948d9bd1d3e901b04e4307617", + "https://deno.land/std@0.132.0/_wasm_crypto/crypto.mjs": "3b383eb715e8bfe61b4450ef0644b2653429c88d494807c86c5235979f62e56b", + "https://deno.land/std@0.132.0/_wasm_crypto/crypto.wasm.mjs": "0ad9ecc0d03ca8a083d9109db22e7507f019f63cf55b82ea618ab58855617577", + "https://deno.land/std@0.132.0/_wasm_crypto/mod.ts": "30a93c8b6b6c5b269e96a3e95d2c045d86a496814a8737443b77cad941d6a0b5", + "https://deno.land/std@0.132.0/async/abortable.ts": "87aa7230be8360c24ad437212311c9e8d4328854baec27b4c7abb26e85515c06", + "https://deno.land/std@0.132.0/async/deadline.ts": "48ac998d7564969f3e6ec6b6f9bf0217ebd00239b1b2292feba61272d5dd58d0", + "https://deno.land/std@0.132.0/async/debounce.ts": "564273ef242bcfcda19a439132f940db8694173abffc159ea34f07d18fc42620", + "https://deno.land/std@0.132.0/async/deferred.ts": "bc18e28108252c9f67dfca2bbc4587c3cbf3aeb6e155f8c864ca8ecff992b98a", + "https://deno.land/std@0.132.0/async/delay.ts": "cbbdf1c87d1aed8edc7bae13592fb3e27e3106e0748f089c263390d4f49e5f6c", + "https://deno.land/std@0.132.0/async/mod.ts": "2240c6841157738414331f47dee09bb8c0482c5b1980b6e3234dd03515c8132f", + "https://deno.land/std@0.132.0/async/mux_async_iterator.ts": "f4d1d259b0c694d381770ddaaa4b799a94843eba80c17f4a2ec2949168e52d1e", + "https://deno.land/std@0.132.0/async/pool.ts": "97b0dd27c69544e374df857a40902e74e39532f226005543eabacb551e277082", + "https://deno.land/std@0.132.0/async/tee.ts": "1341feb1f5b1a96f8628d0f8fc07d8c43d3813423f18a63bf1b4785568d21b1f", + "https://deno.land/std@0.132.0/bytes/bytes_list.ts": "67eb118e0b7891d2f389dad4add35856f4ad5faab46318ff99653456c23b025d", + "https://deno.land/std@0.132.0/bytes/equals.ts": "fc16dff2090cced02497f16483de123dfa91e591029f985029193dfaa9d894c9", + "https://deno.land/std@0.132.0/bytes/mod.ts": "d3b455c0dbd4804644159d1e25946ade5ee385d2359894de49e2c6101b18b7a9", + "https://deno.land/std@0.132.0/encoding/base64.ts": "c8c16b4adaa60d7a8eee047c73ece26844435e8f7f1328d74593dbb2dd58ea4f", + "https://deno.land/std@0.132.0/encoding/base64url.ts": "55f9d13df02efac10c6f96169daa3e702606a64e8aa27c0295f645f198c27130", + "https://deno.land/std@0.132.0/encoding/hex.ts": "7f023e1e51cfd6b189682e602e8640939e7be71a300a2fcf3daf8f84dc609bbc", + "https://deno.land/std@0.132.0/flags/mod.ts": "430cf2d1c26e00286373b2647ebdca637f7558505e88e9c108a4742cd184c916", + "https://deno.land/std@0.132.0/fmt/colors.ts": "30455035d6d728394781c10755351742dd731e3db6771b1843f9b9e490104d37", + "https://deno.land/std@0.132.0/fmt/printf.ts": "e2c0f72146aed1efecf0c39ab928b26ae493a2278f670a871a0fbdcf36ff3379", + "https://deno.land/std@0.132.0/fs/eol.ts": "b92f0b88036de507e7e6fbedbe8f666835ea9dcbf5ac85917fa1fadc919f83a5", + "https://deno.land/std@0.132.0/fs/exists.ts": "cb734d872f8554ea40b8bff77ad33d4143c1187eac621a55bf37781a43c56f6d", + "https://deno.land/std@0.132.0/hash/sha256.ts": "803846c7a5a8a5a97f31defeb37d72f519086c880837129934f5d6f72102a8e8", + "https://deno.land/std@0.132.0/io/buffer.ts": "bd0c4bf53db4b4be916ca5963e454bddfd3fcd45039041ea161dbf826817822b", + "https://deno.land/std@0.132.0/node/_buffer.mjs": "f4a7df481d4eed06dc0151b833177d8ef74fc3a96dd4d2b073e690b6ced9474d", + "https://deno.land/std@0.132.0/node/_core.ts": "568d277be2e086af996cbdd599fec569f5280e9a494335ca23ad392b130d7bb9", + "https://deno.land/std@0.132.0/node/_crypto/constants.ts": "49011c87be4e45407ef5e99e96bde3f08656ebd8e6dfc99048c703dd0ce53952", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/asn1.js/base/buffer.js": "73beb8294eb29bd61458bbaaeeb51dfad4ec9c9868a62207a061d908f1637261", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/asn1.js/base/node.js": "4b777980d2a23088698fd2ff065bb311a2c713497d359e674cb6ef6baf267a0f", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/asn1.js/base/reporter.js": "8e4886e8ae311c9a92caf58bbbd8670326ceeae97430f4884e558e4acf8e8598", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/asn1.js/constants/der.js": "354b255479bff22a31d25bf08b217a295071700e37d0991cc05cac9f95e5e7ca", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/asn1.js/decoders/der.js": "c6faf66761daa43fbf79221308443893587c317774047b508a04c570713b76fb", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/asn1.js/decoders/pem.js": "8316ef7ce2ce478bc3dc1e9df1b75225d1eb8fb5d1378f8adf0cf19ecea5b501", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/asn1.js/encoders/der.js": "408336c88d17c5605ea64081261cf42267d8f9fda90098cb560aa6635bb00877", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/asn1.js/encoders/pem.js": "42a00c925b68c0858d6de0ba41ab89935b39fae9117bbf72a9abb2f4b755a2e7", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/asn1.js/mod.js": "7b78859707be10a0a1e4faccdd28cd5a4f71ad74a3e7bebda030757da97cd232", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/bn.js/bn.js": "abd1badd659fd0ae54e6a421a573a25aef4e795edc392178360cf716b144286d", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/browserify_aes/aes.js": "1cf4c354c5bb341ffc9ab7207f471229835b021947225bce2e1642f26643847a", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/browserify_aes/auth_cipher.js": "19b4dbb903e8406eb733176e6318d5e1a3bd382b67b72f7cf8e1c46cc6321ba4", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/browserify_aes/decrypter.js": "05c1676942fd8e95837115bc2d1371bcf62e9bf19f6c3348870961fc64ddad0b", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/browserify_aes/encrypter.js": "93ec98ab26fbeb5969eae2943e42fb66780f377b9b0ff0ecc32a9ed11201b142", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/browserify_aes/ghash.js": "667b64845764a84f0096ef8cf7debed1a5f15ac9af26b379848237be57da399a", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/browserify_aes/incr32.js": "4a7f0107753e4390b4ccc4dbd5200c5527d43f894f768e131903df30a09dfd67", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/browserify_aes/mod.js": "d8eb88e7a317467831473621f32e60d7db9d981f6a2ae45d2fb2af170eab2d22", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/browserify_aes/modes/cbc.js": "9790799cff181a074686c885708cb8eb473aeb3c86ff2e8d0ff911ae6c1e4431", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/browserify_aes/modes/cfb.js": "a4e36ede6f26d8559d8f0528a134592761c706145a641bd9ad1100763e831cdb", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/browserify_aes/modes/cfb1.js": "c6372f4973a68ca742682e81d1165e8869aaabf0091a8b963d4d60e5ee8e6f6a", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/browserify_aes/modes/cfb8.js": "bd29eebb89199b056ff2441f7fb5e0300f458e13dcaaddbb8bc00cbdb199db67", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/browserify_aes/modes/ctr.js": "9c2cbac1fc8f9b58334faacb98e6c57e8c3712f673ea4cf2d528a2894998ab2f", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/browserify_aes/modes/ecb.js": "9629d193433688f0cfc432eca52838db0fb28d9eb4f45563df952bde50b59763", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/browserify_aes/modes/mod.js": "7d8516ef8a20565539eb17cad5bb70add02ac06d1891e8f47cb981c22821787e", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/browserify_aes/modes/ofb.js": "c23abaa6f1ec5343e9d7ba61d702acb3d81a0bd3d34dd2004e36975dc043d6ff", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/browserify_aes/stream_cipher.js": "a533a03a2214c6b5934ce85a59eb1e04239fd6f429017c7ca3c443ec7e07e68f", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/browserify_aes/xor.ts": "4417711c026eb9a07475067cd31fa601e88c2d6ababd606d33d1e74da6fcfd09", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/browserify_rsa.js": "de8c98d2379a70d8c239b4886e2b3a11c7204eec39ae6b65d978d0d516ee6b08", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/cipher_base.js": "f565ad9daf3b3dd3b68381bed848da94fb093a9e4e5a48c92f47e26cc229df39", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/evp_bytes_to_key.ts": "8bd9fa445576b3e39586bdbef7c907f1dfda201bf22602d2ca1c6d760366311e", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/parse_asn1/asn1.js": "4f33b0197ffbe9cff62e5bad266e6b40d55874ea653552bb32ed251ad091f70a", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/parse_asn1/certificate.js": "aab306870830a81ad188db8fa8e037d7f5dd6c5abdabbd9739558245d1a12224", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/parse_asn1/fix_proc.js": "af3052b76f441878e102ffcfc7420692e65777af765e96f786310ae1acf7f76a", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/parse_asn1/mod.js": "e923a13b27089a99eeb578d2ffb9b4cfe8ce690918fec05d0024fa126f3e1ce3", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/public_encrypt/mgf.js": "5b81dc1680829b564fc5a00b842fb9c88916e4639b4fa27fa8bb6b759d272371", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/public_encrypt/mod.js": "eb8b64d7a58ee3823c1b642e799cc7ed1257d99f4d4aefa2b4796dd112ec094a", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/public_encrypt/private_decrypt.js": "0050df879f7c1338132c45056835f64e32140e2a2d5d03c1366ccce64855f632", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/public_encrypt/public_encrypt.js": "0132cb4fb8f72593278474884195b9c52b4e9ba33d8ddd22116d07a07f47005a", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/public_encrypt/with_public.js": "7373dac9b53b8331ccf3521c854a131dcb304a2e4d34cd116649118f7919ed0c", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/public_encrypt/xor.js": "900c6fc8b95e1861d796193c41988f5f70a09c7059e42887a243d0113ecaf0fd", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/randombytes.ts": "f465cd8e114a3c110297e0143445b12125d729b25bada5bd88d5b30cf612d7dd", + "https://deno.land/std@0.132.0/node/_crypto/hash.ts": "6a84a079412d09ead27b900590f0bede9924bc7ce522b8b7d55183a2aaf63a68", + "https://deno.land/std@0.132.0/node/_crypto/pbkdf2.ts": "00af38578729b3060371dfee70dae502a5848b4cc4787c48f634195cab1ce89a", + "https://deno.land/std@0.132.0/node/_crypto/randomBytes.ts": "04e276bcbfa55b3502c7169deab3f2bf58bbc5e9727634f8a150eff734338e90", + "https://deno.land/std@0.132.0/node/_crypto/randomFill.ts": "019ff2a8330c3ede6e65af28c5a8e3dee9d404975749c8dadf6ba11ccc28528e", + "https://deno.land/std@0.132.0/node/_crypto/randomInt.ts": "2db981c2baf4ddac07b6da71f90677f4acf4dc2d93f351563fdd084d645b8413", + "https://deno.land/std@0.132.0/node/_crypto/scrypt.ts": "caf07a6b8afa6ac582f80f99ed7dc7fefd5476fcd2aad771b8440e5b883d6d70", + "https://deno.land/std@0.132.0/node/_crypto/timingSafeEqual.ts": "4a4ef17e482889d9d82138d5ffc0e787c32c04b1f12b28d076b1a69ceca46af1", + "https://deno.land/std@0.132.0/node/_crypto/types.ts": "d3fae758c5b62f63d8126c76eec31a5559a2f34305defb5fe2a7d9034057ff54", + "https://deno.land/std@0.132.0/node/_dns/_utils.ts": "42494c8b8fa1c13eb134c5696744f77197717fa857e4d05147f2395a739b0a40", + "https://deno.land/std@0.132.0/node/_events.mjs": "d7d56df4b9f69e445064bad5e5558978fb18c18c439bbb62fa13149b40d7fb99", + "https://deno.land/std@0.132.0/node/_fixed_queue.ts": "455b3c484de48e810b13bdf95cd1658ecb1ba6bcb8b9315ffe994efcde3ba5f5", + "https://deno.land/std@0.132.0/node/_fs/_fs_access.ts": "0700488320d37208d000b94767ab37208d469550767edab69b65b09a330f245d", + "https://deno.land/std@0.132.0/node/_fs/_fs_appendFile.ts": "5dca59d7f2ec33316d75da3d6a12d39f5c35b429bddf83f4b2c030b3a289d4b3", + "https://deno.land/std@0.132.0/node/_fs/_fs_chmod.ts": "8fc25677b82a2643686e6f8270a8f1bee87dd60986334591450699e199dac7d5", + "https://deno.land/std@0.132.0/node/_fs/_fs_chown.ts": "57858c54d376648fc3c8cf5a8ad4f7f19fb153b75fac3ed41df0332d757e7de9", + "https://deno.land/std@0.132.0/node/_fs/_fs_close.ts": "785a9d1a6d615e8aa9f5a4ac50c9a131931f8b0e17b3d4671cd1fd25a5c10f2b", + "https://deno.land/std@0.132.0/node/_fs/_fs_common.ts": "6a373d1583d9ec5cc7a8ff1072d77dc999e35282a320b7477038a2b209c304d3", + "https://deno.land/std@0.132.0/node/_fs/_fs_constants.ts": "5c20b190fc6b7cfdaf12a30ba545fc787db2c7bbe87ed5b890da99578116a339", + "https://deno.land/std@0.132.0/node/_fs/_fs_copy.ts": "675eb02a2dfc20dab1186bf6ed0a33b1abae656f440bc0a3ce74f385e0052eef", + "https://deno.land/std@0.132.0/node/_fs/_fs_dir.ts": "8a05f72e32dd568b41ef45f8f55f1f54e9a306a7588475fa7014289cd12872d9", + "https://deno.land/std@0.132.0/node/_fs/_fs_dirent.ts": "649c0a794e7b8d930cdd7e6a168b404aa0448bf784e0cfbe1bd6d25b99052273", + "https://deno.land/std@0.132.0/node/_fs/_fs_exists.ts": "83e9ca6ea1ab3c6c7c3fc45f3c1287ee88839f08140ac11056441537450055bb", + "https://deno.land/std@0.132.0/node/_fs/_fs_fdatasync.ts": "bbd078fea6c62c64d898101d697aefbfbb722797a75e328a82c2a4f2e7eb963d", + "https://deno.land/std@0.132.0/node/_fs/_fs_fstat.ts": "559ff6ff094337db37b0f3108aeaecf42672795af45b206adbd90105afebf9c6", + "https://deno.land/std@0.132.0/node/_fs/_fs_fsync.ts": "590be69ce5363dd4f8867f244cfabe8df89d40f86bbbe44fd00d69411d0b798e", + "https://deno.land/std@0.132.0/node/_fs/_fs_ftruncate.ts": "8eb2a9fcf026bd9b85dc07a22bc452c48db4be05ab83f5f2b6a0549e15c1f75f", + "https://deno.land/std@0.132.0/node/_fs/_fs_futimes.ts": "c753cb9e9f129a11d1110ed43905b8966ac2a1d362ed69d5a34bb44513b00082", + "https://deno.land/std@0.132.0/node/_fs/_fs_link.ts": "3f9ccce31c2e56284fbcf2c65ec2e6fed1d9e67a9997410223486ac5092888e3", + "https://deno.land/std@0.132.0/node/_fs/_fs_lstat.ts": "571cea559d270e3b2e7fc585b0eb051899f6d0e54b1786f5e2cee3e9f71e7f27", + "https://deno.land/std@0.132.0/node/_fs/_fs_mkdir.ts": "68421a23b6d3c2d0142a6d0b3ccdd87903f9c8f98d6754aba554ab4c6b435bb8", + "https://deno.land/std@0.132.0/node/_fs/_fs_mkdtemp.ts": "86eaec96c63ea178c749fa856115a345e9797baecad22297b9ef98e3d62b90e2", + "https://deno.land/std@0.132.0/node/_fs/_fs_open.ts": "b1ca72addd2723b2a5a876378e72609fbe168adad2006f5d7b4f1868beef65ca", + "https://deno.land/std@0.132.0/node/_fs/_fs_read.ts": "3b4ef96aad20f3f29a859125ebeac8c9461574743f70c2a7ef301b8505f7d036", + "https://deno.land/std@0.132.0/node/_fs/_fs_readFile.ts": "3eae6c930e08c1279d400c0f5a008e6d96949ff3a4f5bf7d43e1b94b94ce3854", + "https://deno.land/std@0.132.0/node/_fs/_fs_readdir.ts": "a546f01387b7c49ddc1bd78d0e123a9668c710c56cffb4d9577ef46703cab463", + "https://deno.land/std@0.132.0/node/_fs/_fs_readlink.ts": "00553cd155f3bea565ffe43d7f0c10d75e895455562e1e8ea153e8f4e7ac04c7", + "https://deno.land/std@0.132.0/node/_fs/_fs_realpath.ts": "3ec236e4ad3c171203043422939973b6a948200ec4802425db41fa60c860dde9", + "https://deno.land/std@0.132.0/node/_fs/_fs_rename.ts": "3be71e8f43275c349b7abb9343b6e6764df09fabcbd2d316f8ac170ea556c645", + "https://deno.land/std@0.132.0/node/_fs/_fs_rm.ts": "a9328f99d925d7c74d31361d466ca33475aa7c6d1d6f037a49ce1ed996f0a0b4", + "https://deno.land/std@0.132.0/node/_fs/_fs_rmdir.ts": "b74007891357e709b37e6721eb355a1c4f25575995bb7c961a3c40f03ebc624c", + "https://deno.land/std@0.132.0/node/_fs/_fs_stat.ts": "bd47ce0bfc2b867392abc6ec95878ab4f6dddb94af73903d6fa1a02ba3e26af8", + "https://deno.land/std@0.132.0/node/_fs/_fs_streams.ts": "0e54bd4e41b462a701d6729ea17db01624aa48109e402fea8eecf13be324cf16", + "https://deno.land/std@0.132.0/node/_fs/_fs_symlink.ts": "0bddc37c5092f847634bd41cee0b643b9c03fc541c0e635cf35da1fcb4d0f7fa", + "https://deno.land/std@0.132.0/node/_fs/_fs_truncate.ts": "e2d380f7a81f69c4d4db30c442558ba8d8dea561e5097af41022bb5724e494e5", + "https://deno.land/std@0.132.0/node/_fs/_fs_unlink.ts": "c537ca98e507972d65f0b113a179b5f5083f0da3e6f9fae29895fd2a9660c18a", + "https://deno.land/std@0.132.0/node/_fs/_fs_utimes.ts": "c4446b7e39bf6977eca4364360501a97b96db9ea41e0cdf49abddab73481a175", + "https://deno.land/std@0.132.0/node/_fs/_fs_watch.ts": "2338de777458021d39cb9f0a5f3ea1bd9109a7ca2c2ad6ec41029df1753838f8", + "https://deno.land/std@0.132.0/node/_fs/_fs_write.mjs": "8c130b8b9522e1e4b08e687eb27939240260c115fda1e38e99c57b4f3af6481f", + "https://deno.land/std@0.132.0/node/_fs/_fs_writeFile.ts": "79d176021c8ceae0d956763a33834166ebc3f1691ed9219a21674b2374f115c3", + "https://deno.land/std@0.132.0/node/_fs/_fs_writev.mjs": "274df0a109010862c8f8b320dc7784de9bd9425fe2a6afd05f1f06f547a25cba", + "https://deno.land/std@0.132.0/node/_next_tick.ts": "64c361f6bca21df2a72dd77b84bd49d80d97a694dd3080703bc78f52146351d1", + "https://deno.land/std@0.132.0/node/_options.ts": "27f3c1269a700d330cc046cf748aa9178b8fc39d1473de625688e07cb0eb9d28", + "https://deno.land/std@0.132.0/node/_process/exiting.ts": "bc9694769139ffc596f962087155a8bfef10101d03423b9dcbc51ce6e1f88fce", + "https://deno.land/std@0.132.0/node/_process/process.ts": "84644b184053835670f79652d1ce3312c9ad079c211e6207ebefeedf159352a3", + "https://deno.land/std@0.132.0/node/_process/stdio.mjs": "971c3b086040d8521562155db13f22f9971d5c42c852b2081d4d2f0d8b6ab6bd", + "https://deno.land/std@0.132.0/node/_process/streams.mjs": "555062e177ad05f887147651fdda25fa55098475fcf142c8d162b8fe14097bbb", + "https://deno.land/std@0.132.0/node/_stream.mjs": "07f6cbabaad0382fb4b9a25e70ac3093a44022b859247f64726746e6373f1c91", + "https://deno.land/std@0.132.0/node/_util/_util_callbackify.ts": "79928ad80df3e469f7dcdb198118a7436d18a9f6c08bd7a4382332ad25a718cf", + "https://deno.land/std@0.132.0/node/_utils.ts": "c2c352e83c4c96f5ff994b1c8246bff2abcb21bfc3f1c06162cb3af1d201e615", + "https://deno.land/std@0.132.0/node/buffer.ts": "fbecbf3f237fa49bec96e97ecf56a7b92d48037b3d11219288e68943cc921600", + "https://deno.land/std@0.132.0/node/crypto.ts": "fffbc3fc3dcc16ea986d3e89eed5f70db7dfef2c18d1205a8c8fe5327ee0192d", + "https://deno.land/std@0.132.0/node/dns.ts": "ae2abd1bc8ac79543fe4d702f2aa3607101dc788b6eeba06e06436cb42ee3779", + "https://deno.land/std@0.132.0/node/events.ts": "a1d40fc0dbccc944379ef968b80ea08f9fce579e88b5057fdb64e4f0812476dd", + "https://deno.land/std@0.132.0/node/fs.ts": "21a3189c460bd37ac3f6734e040587125b7c8435c0a9da4e6c57544a3aca81c2", + "https://deno.land/std@0.132.0/node/internal/assert.mjs": "118327c8866266534b30d3a36ad978204af7336dc2db3158b8167192918d4e06", + "https://deno.land/std@0.132.0/node/internal/async_hooks.ts": "8eca5b80f58ffb259e9b3a73536dc2fe2e67d07fd24bfe2aee325a4aa435edb3", + "https://deno.land/std@0.132.0/node/internal/blob.mjs": "52080b2f40b114203df67f8a6650f9fe3c653912b8b3ef2f31f029853df4db53", + "https://deno.land/std@0.132.0/node/internal/buffer.mjs": "6662fe7fe517329453545be34cea27a24f8ccd6d09afd4f609f11ade2b6dfca7", + "https://deno.land/std@0.132.0/node/internal/crypto/keys.ts": "16ce7b15a9fc5e4e3dee8fde75dae12f3d722558d5a1a6e65a9b4f86d64a21e9", + "https://deno.land/std@0.132.0/node/internal/crypto/util.mjs": "1de55a47fdbed6721b467a77ba48fdd1550c10b5eee77bbdb602eaffee365a5e", + "https://deno.land/std@0.132.0/node/internal/dtrace.ts": "50dd0e77b0269e47ff673bdb9ad0ef0ea3a3c53ac30c1695883ce4748e04ca14", + "https://deno.land/std@0.132.0/node/internal/error_codes.ts": "ac03c4eae33de3a69d6c98e8678003207eecf75a6900eb847e3fea3c8c9e6d8f", + "https://deno.land/std@0.132.0/node/internal/errors.ts": "25f91691225b001660e6e64745ecd336fbf562cf0185e8896ff013c2d0226794", + "https://deno.land/std@0.132.0/node/internal/fs/streams.ts": "c925db185efdf56c35cde8270c07d61698b80603a90e07caf1cb4ff80abf195b", + "https://deno.land/std@0.132.0/node/internal/fs/utils.mjs": "2a571ecbd169b444f07b7193306f108fdcb4bfd9b394b33716ad05edf30e899e", + "https://deno.land/std@0.132.0/node/internal/hide_stack_frames.ts": "a91962ec84610bc7ec86022c4593cdf688156a5910c07b5bcd71994225c13a03", + "https://deno.land/std@0.132.0/node/internal/idna.ts": "a8bdd28431f06630d8aad85d3cb8fd862459107af228c8805373ad2080f1c587", + "https://deno.land/std@0.132.0/node/internal/net.ts": "1239886cd2508a68624c2dae8abf895e8aa3bb15a748955349f9ac5539032238", + "https://deno.land/std@0.132.0/node/internal/normalize_encoding.mjs": "3779ec8a7adf5d963b0224f9b85d1bc974a2ec2db0e858396b5d3c2c92138a0a", + "https://deno.land/std@0.132.0/node/internal/process/per_thread.mjs": "a42b1dcfb009ad5039144a999a35a429e76112f9322febbe353eda9d1879d936", + "https://deno.land/std@0.132.0/node/internal/querystring.ts": "c3b23674a379f696e505606ddce9c6feabe9fc497b280c56705c340f4028fe74", + "https://deno.land/std@0.132.0/node/internal/stream_base_commons.ts": "934a9e69f46f2de644956edfa9fb040af7861e326fe5325dab38ef9caf2940bc", + "https://deno.land/std@0.132.0/node/internal/streams/_utils.ts": "77fceaa766679847e4d4c3c96b2573c00a790298d90551e8e4df1d5e0fdaad3b", + "https://deno.land/std@0.132.0/node/internal/streams/add-abort-signal.mjs": "5623b83fa64d439cc4a1f09ae47ec1db29512cc03479389614d8f62a37902f5e", + "https://deno.land/std@0.132.0/node/internal/streams/buffer_list.mjs": "c6a7b29204fae025ff5e9383332acaea5d44bc7c522a407a79b8f7a6bc6c312d", + "https://deno.land/std@0.132.0/node/internal/streams/compose.mjs": "b522daab35a80ae62296012a4254fd7edfc0366080ffe63ddda4e38fe6b6803e", + "https://deno.land/std@0.132.0/node/internal/streams/destroy.mjs": "9c9bbeb172a437041d529829f433df72cf0b63ae49f3ee6080a55ffbef7572ad", + "https://deno.land/std@0.132.0/node/internal/streams/duplex.mjs": "b014087cd04f79b8a4028d8b9423b987e07bbfacf3b5df518cb752ac3657580f", + "https://deno.land/std@0.132.0/node/internal/streams/end-of-stream.mjs": "38be76eaceac231dfde643e72bc0940625446bf6d1dbd995c91c5ba9fd59b338", + "https://deno.land/std@0.132.0/node/internal/streams/from.mjs": "134255c698ed63b33199911eb8e042f8f67e9682409bb11552e6120041ed1872", + "https://deno.land/std@0.132.0/node/internal/streams/legacy.mjs": "6ea28db95d4503447473e62f0b23ff473bfe1751223c33a3c5816652e93b257a", + "https://deno.land/std@0.132.0/node/internal/streams/passthrough.mjs": "a51074193b959f3103d94de41e23a78dfcff532bdba53af9146b86340d85eded", + "https://deno.land/std@0.132.0/node/internal/streams/pipeline.mjs": "9890b121759ede869174ef70c011fde964ca94d81f2ed97b8622d7cb17b49285", + "https://deno.land/std@0.132.0/node/internal/streams/readable.mjs": "a70c41171ae25c556b52785b0c178328014bd33d8c0e4d229d4adaac7414b6ca", + "https://deno.land/std@0.132.0/node/internal/streams/state.mjs": "9ef917392a9d8005a6e038260c5fd31518d2753aea0bc9e39824c199310434cb", + "https://deno.land/std@0.132.0/node/internal/streams/transform.mjs": "3b361abad2ac78f7ccb6f305012bafdc0e983dfa4bb6ecddb4626e34a781a5f5", + "https://deno.land/std@0.132.0/node/internal/streams/utils.mjs": "06c21d0db0d51f1bf1e3225a661c3c29909be80355d268e64ee5922fc5eb6c5e", + "https://deno.land/std@0.132.0/node/internal/streams/writable.mjs": "ad4e2b176ffdf752c8e678ead3a514679a5a8d652f4acf797115dceb798744d5", + "https://deno.land/std@0.132.0/node/internal/timers.mjs": "b43e24580cec2dd50f795e4342251a79515c0db21630c25b40fdc380a78b74e7", + "https://deno.land/std@0.132.0/node/internal/url.ts": "eacef0ace4f4c5394e9818a81499f4871b2a993d1bd3b902047e44a381ef0e22", + "https://deno.land/std@0.132.0/node/internal/util.mjs": "2f0c8ff553c175ea6e4ed13d7cd7cd6b86dc093dc2f783c6c3dfc63f60a0943e", + "https://deno.land/std@0.132.0/node/internal/util/comparisons.ts": "680b55fe8bdf1613633bc469fa0440f43162c76dbe36af9aa2966310e1bb9f6e", + "https://deno.land/std@0.132.0/node/internal/util/debuglog.ts": "99e91bdf26f6c67861031f684817e1705a5bc300e81346585b396f413387edfb", + "https://deno.land/std@0.132.0/node/internal/util/inspect.mjs": "d1c2569c66a3dab45eec03208f22ad4351482527859c0011a28a6c797288a0aa", + "https://deno.land/std@0.132.0/node/internal/util/types.ts": "b2dacb8f1f5d28a51c4da5c5b75172b7fcf694073ce95ca141323657e18b0c60", + "https://deno.land/std@0.132.0/node/internal/validators.mjs": "a7e82eafb7deb85c332d5f8d9ffef052f46a42d4a121eada4a54232451acc49a", + "https://deno.land/std@0.132.0/node/internal_binding/_libuv_winerror.ts": "801e05c2742ae6cd42a5f0fd555a255a7308a65732551e962e5345f55eedc519", + "https://deno.land/std@0.132.0/node/internal_binding/_node.ts": "e4075ba8a37aef4eb5b592c8e3807c39cb49ca8653faf8e01a43421938076c1b", + "https://deno.land/std@0.132.0/node/internal_binding/_utils.ts": "1c50883b5751a9ea1b38951e62ed63bacfdc9d69ea665292edfa28e1b1c5bd94", + "https://deno.land/std@0.132.0/node/internal_binding/_winerror.ts": "8811d4be66f918c165370b619259c1f35e8c3e458b8539db64c704fbde0a7cd2", + "https://deno.land/std@0.132.0/node/internal_binding/async_wrap.ts": "f06b8a403ad871248eb064190d27bf6fefdbe948991e71a18d7077390d5773f9", + "https://deno.land/std@0.132.0/node/internal_binding/buffer.ts": "722c62b85f966e0777b2d98c021b60e75d7f2c2dabc43413ef37d60dbd13a5d9", + "https://deno.land/std@0.132.0/node/internal_binding/cares_wrap.ts": "25b7b5d56612b2985260b673021828d6511a1c83b4c1927f5732cad2f2a718af", + "https://deno.land/std@0.132.0/node/internal_binding/config.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/connection_wrap.ts": "0380444ee94d5bd7b0b09921223d16729c9762a94e80b7f51eda49c7f42e6d0a", + "https://deno.land/std@0.132.0/node/internal_binding/constants.ts": "aff06aac49eda4234bd3a2b0b8e1fbfc67824e281c532ff9960831ab503014cc", + "https://deno.land/std@0.132.0/node/internal_binding/contextify.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/credentials.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/crypto.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/errors.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/fs.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/fs_dir.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/fs_event_wrap.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/handle_wrap.ts": "e59df84b1fb1b9823b09774b3e512d9c0029b4557400d09dd02cd7661c2c4830", + "https://deno.land/std@0.132.0/node/internal_binding/heap_utils.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/http_parser.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/icu.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/inspector.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/js_stream.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/messaging.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/mod.ts": "f68e74e8eed84eaa6b0de24f0f4c47735ed46866d7ee1c5a5e7c0667b4f0540f", + "https://deno.land/std@0.132.0/node/internal_binding/module_wrap.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/native_module.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/natives.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/node_file.ts": "c96ee0b2af319a3916de950a6c4b0d5fb00d09395c51cd239c54d95d62567aaf", + "https://deno.land/std@0.132.0/node/internal_binding/node_options.ts": "3cd5706153d28a4f5944b8b162c1c61b7b8e368a448fb1a2cff9f7957d3db360", + "https://deno.land/std@0.132.0/node/internal_binding/options.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/os.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/performance.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/pipe_wrap.ts": "00e942327f8e1c4b74a5888a82f0e16ba775cd09af804f96b6f6849b7eab1719", + "https://deno.land/std@0.132.0/node/internal_binding/process_methods.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/report.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/serdes.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/signal_wrap.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/spawn_sync.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/stream_wrap.ts": "d6e96f4b89d82ad5cc9b243c3d3880c9d85086165da54a7d85821a63491e5abf", + "https://deno.land/std@0.132.0/node/internal_binding/string_decoder.ts": "5cb1863763d1e9b458bc21d6f976f16d9c18b3b3f57eaf0ade120aee38fba227", + "https://deno.land/std@0.132.0/node/internal_binding/symbols.ts": "51cfca9bb6132d42071d4e9e6b68a340a7f274041cfcba3ad02900886e972a6c", + "https://deno.land/std@0.132.0/node/internal_binding/task_queue.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/tcp_wrap.ts": "10c64d5e092a8bff99cfe05adea716e4e52f4158662a5821790953e47e2cc21c", + "https://deno.land/std@0.132.0/node/internal_binding/timers.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/tls_wrap.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/trace_events.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/tty_wrap.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/types.ts": "4c26fb74ba2e45de553c15014c916df6789529a93171e450d5afb016b4c765e7", + "https://deno.land/std@0.132.0/node/internal_binding/udp_wrap.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/url.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/util.ts": "90364292e2bd598ab5d105b48ca49817b6708f2d1d9cbaf08b2b3ab5ca4c90a7", + "https://deno.land/std@0.132.0/node/internal_binding/uv.ts": "3821bc5e676d6955d68f581988c961d77dd28190aba5a9c59f16001a4deb34ba", + "https://deno.land/std@0.132.0/node/internal_binding/v8.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/worker.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/zlib.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/net.ts": "dfcb7e412abb3d5c55edde7d823b0ccb9601f7d40555ae3c862810c78b176185", + "https://deno.land/std@0.132.0/node/os.ts": "943d3294a7a00f39491148cd2097cdbf101233a421262223bb20ae702c059df5", + "https://deno.land/std@0.132.0/node/path.ts": "c65858e9cbb52dbc0dd348eefcdc41e82906c39cfa7982f2d4d805e828414b8c", + "https://deno.land/std@0.132.0/node/path/_constants.ts": "bd26f24a052b7d6b746151f4a236d29ab3c2096883bb6449c2fa499494406672", + "https://deno.land/std@0.132.0/node/path/_interface.ts": "6034ee29f6f295460ec82db1a94df9269aecbb0eceb81be72e9d843f8e8a97e6", + "https://deno.land/std@0.132.0/node/path/_util.ts": "9d4735fc05f8f1fb94406450e84e23fd201dc3fef5298b009e44cfa4e797b8f0", + "https://deno.land/std@0.132.0/node/path/common.ts": "f41a38a0719a1e85aa11c6ba3bea5e37c15dd009d705bd8873f94c833568cbc4", + "https://deno.land/std@0.132.0/node/path/glob.ts": "d6b64a24f148855a6e8057a171a2f9910c39e492e4ccec482005205b28eb4533", + "https://deno.land/std@0.132.0/node/path/mod.ts": "62e21dc6e1fe2e9742fce85de631a7b067d968544fe66954578e6d73c97369a2", + "https://deno.land/std@0.132.0/node/path/posix.ts": "9dd5fc83c4ae0e0b700bef43c88c67e276840c187a66d4d6a661440cf1fecc52", + "https://deno.land/std@0.132.0/node/path/separator.ts": "c908c9c28ebe7f1fea67daaccf84b63af90d882fe986f9fa03af9563a852723a", + "https://deno.land/std@0.132.0/node/path/win32.ts": "f869ee449b6dee69b13e2d1f8f7f1d01c7ae1e67fa573eab789429929f7a3864", + "https://deno.land/std@0.132.0/node/process.ts": "699f47f2f177556e17e2f7d0dcd3705ff5065cbdf72029e534c1540404d6f501", + "https://deno.land/std@0.132.0/node/querystring.ts": "967b8a7b00a73ebe373666deb3a7e501f164bac27bb342fde7221ecbb3522689", + "https://deno.land/std@0.132.0/node/stream.ts": "d127faa074a9e3886e4a01dcfe9f9a6a4b5641f76f6acc356e8ded7da5dc2c81", + "https://deno.land/std@0.132.0/node/stream/promises.mjs": "b263c09f2d6bd715dc514fab3f99cca84f442e2d23e87adbe76e32ea46fc87e6", + "https://deno.land/std@0.132.0/node/string_decoder.ts": "51ce85a173d2e36ac580d418bb48b804adb41732fc8bd85f7d5d27b7accbc61f", + "https://deno.land/std@0.132.0/node/timers.ts": "2d66fcd21e37acf76c3a699a97230da57cc21382c8e885b3c5377b37efd0f06c", + "https://deno.land/std@0.132.0/node/url.ts": "bc0bde2774854b6a377c4c61fa73e5a28283cbeb7f8703479f44e471219c33a8", + "https://deno.land/std@0.132.0/node/util.ts": "7fd6933b37af89a8e64d73dc6ee1732455a59e7e6d0965311fbd73cd634ea630", + "https://deno.land/std@0.132.0/node/util/types.mjs": "f9288198cacd374b41bae7e92a23179d3160f4c0eaf14e19be3a4e7057219a60", + "https://deno.land/std@0.132.0/path/_constants.ts": "df1db3ffa6dd6d1252cc9617e5d72165cd2483df90e93833e13580687b6083c3", + "https://deno.land/std@0.132.0/path/_interface.ts": "ee3b431a336b80cf445441109d089b70d87d5e248f4f90ff906820889ecf8d09", + "https://deno.land/std@0.132.0/path/_util.ts": "c1e9686d0164e29f7d880b2158971d805b6e0efc3110d0b3e24e4b8af2190d2b", + "https://deno.land/std@0.132.0/path/common.ts": "bee563630abd2d97f99d83c96c2fa0cca7cee103e8cb4e7699ec4d5db7bd2633", + "https://deno.land/std@0.132.0/path/glob.ts": "cb5255638de1048973c3e69e420c77dc04f75755524cb3b2e160fe9277d939ee", + "https://deno.land/std@0.132.0/path/mod.ts": "4275129bb766f0e475ecc5246aa35689eeade419d72a48355203f31802640be7", + "https://deno.land/std@0.132.0/path/posix.ts": "663e4a6fe30a145f56aa41a22d95114c4c5582d8b57d2d7c9ed27ad2c47636bb", + "https://deno.land/std@0.132.0/path/separator.ts": "fe1816cb765a8068afb3e8f13ad272351c85cbc739af56dacfc7d93d710fe0f9", + "https://deno.land/std@0.132.0/path/win32.ts": "e7bdf63e8d9982b4d8a01ef5689425c93310ece950e517476e22af10f41a136e", + "https://deno.land/std@0.132.0/streams/conversion.ts": "712585bfa0172a97fb68dd46e784ae8ad59d11b88079d6a4ab098ff42e697d21", + "https://deno.land/std@0.132.0/testing/_diff.ts": "9d849cd6877694152e01775b2d93f9d6b7aef7e24bfe3bfafc4d7a1ac8e9f392", + "https://deno.land/std@0.132.0/testing/asserts.ts": "b0ef969032882b1f7eb1c7571e313214baa1485f7b61cf35807b2434e254365c", + "https://deno.land/x/literal_html@1.1.0/mod.ts": "52b0de822cc5529d6051584fe98c5b8d75f2bfb063f1df86df7b07513cc353a2", + "https://deno.land/x/oak@v17.1.4/application.ts": "69fb6462eed013562ee61239e60ea77e5df3abb2b0df34568593b9774d72e98f", + "https://deno.land/x/oak@v17.1.4/body.ts": "f91d8e0298abbabe6acb543d1090e2a41aa665375918a575d72bd6b98b538e40", + "https://deno.land/x/oak@v17.1.4/context.ts": "e04c3d67d68ee01a279aeded457b0d66255450593dacab22251e7eb0cf6a92e5", + "https://deno.land/x/oak@v17.1.4/deps.ts": "c71a9421d2ead7803468cd40559cf122ee91d4e81e8a3a98706956f6654e2550", + "https://deno.land/x/oak@v17.1.4/http_server_bun.ts": "c7f3eb6464d4f047fcc9335e632ffb6bfc24e5ef7dc9a53017a6e453d4197e4b", + "https://deno.land/x/oak@v17.1.4/http_server_native.ts": "34bab402cc9b6fdf53706699ac2c2ab88faf5c14be2ae18aa105bdc4fd6a8471", + "https://deno.land/x/oak@v17.1.4/http_server_native_request.ts": "aa98a2f4bbf6f7651c62eb0332a95a1b0faff1d76f7a07fa8bd600766eb24488", + "https://deno.land/x/oak@v17.1.4/http_server_node.ts": "bfbf7585fcda5a1464cd0f904ec97cbb4d67367757f3ed8cdc99a590a94b34e1", + "https://deno.land/x/oak@v17.1.4/middleware.ts": "a701caf9d872b93d26759f77c7ad545cb29bc3d197c8375b79b2fbe7e9e60958", + "https://deno.land/x/oak@v17.1.4/middleware/etag.ts": "f5cf8eb2a7c99ae7e11a4e31dc60beda398aec7a08be343e0de6b632f8064e4d", + "https://deno.land/x/oak@v17.1.4/middleware/proxy.ts": "e611b7d45f58a1b2caa1cb6c435774822d7b56aa136b8dbb8691fb52d07c5182", + "https://deno.land/x/oak@v17.1.4/middleware/serve.ts": "66f1e405ac006bfa863e8852092e03951b93dd4ba8381996a719d93d00aa62fe", + "https://deno.land/x/oak@v17.1.4/mod.ts": "1f42341a6138310eceaf7b8e9b72be4d2a913817d1e823090dee4e7d27c68e98", + "https://deno.land/x/oak@v17.1.4/node_shims.ts": "e411aef698dca26dfc577d8581ddab678f528bd52bf681337f3c3bcc73845a0a", + "https://deno.land/x/oak@v17.1.4/request.ts": "5123fd70841a540809702059527a192d22f78042db1bfc4a01eebd77ec25b0fb", + "https://deno.land/x/oak@v17.1.4/response.ts": "483f8ddd7618325e6ac28f88a3ea9926a09b3c90fa53b481a7a5202d23a0755f", + "https://deno.land/x/oak@v17.1.4/router.ts": "e8eb2f88806dfdd303f3a663fefb7d9e614342bf40738692e9ef4b2243e1bccd", + "https://deno.land/x/oak@v17.1.4/send.ts": "42faed583f218ed85d5da7704f36b385537947ec4de6125e20ad8acbfe8d8f68", + "https://deno.land/x/oak@v17.1.4/testing.ts": "d6489e78d689da08b9896cd0b9b9add243466b407ce6fd63d38e29f8c0a19f5c", + "https://deno.land/x/oak@v17.1.4/types.ts": "0e74c6c46e0fcfddd87e90fe0216c4ae50c73b113e06d3bdc4283afc7b2570d6", + "https://deno.land/x/oak@v17.1.4/utils/clone_state.ts": "5a0784d802b86cc3dbf415dfd286025f03a261b3a8f9b3b6fd671be8e51ff027", + "https://deno.land/x/oak@v17.1.4/utils/consts.ts": "9e14324837558d7af3d4bfc8ba5f13216a0b5d2f8dac14a3a782bc1bbfb756ef", + "https://deno.land/x/oak@v17.1.4/utils/create_promise_with_resolvers.ts": "f7eeaf65ffa7b6cef03b8dc3fa3a3e35ae5553c6abf1a2260d7797e076acd63a", + "https://deno.land/x/oak@v17.1.4/utils/decode.ts": "434802a09534a26cc8b8cd009ecc422b4695d22859021fe34f8093784b2483b7", + "https://deno.land/x/oak@v17.1.4/utils/decode_component.ts": "d68e6da33bf6e733d218c0b7ce7112520640e836f4cfa2760c4aee8facf1c581", + "https://deno.land/x/oak@v17.1.4/utils/encode_url.ts": "16b213d70f5e211fb3633f97c704f9613d2f8033669d59e0c9ca4fc26551fad6", + "https://deno.land/x/oak@v17.1.4/utils/resolve_path.ts": "aa39d54a003b38fee55f340a0cba3f93a7af85b8ddd5fbfb049a98fc0109b36d", + "https://deno.land/x/oak@v17.1.4/utils/streams.ts": "c85ae197f5046d58d5a3e42221254a6c8e63172f9f01b77631e480e1dcc90e05", + "https://deno.land/x/oak@v17.1.4/utils/type_guards.ts": "92ab7dae4bc5ce10206fb21ca13bedd13a4638848be15f9752146aedeab1fea4", + "https://deno.land/x/postgresjs@v3.4.5/mod.js": "cb68f17d6d90df318934deccdb469d740be0888e7a597a9e7eea7100ce36a252", + "https://deno.land/x/postgresjs@v3.4.5/polyfills.js": "318eb01f2b4cc33a46c59f3ddc11f22a56d6b1db8b7719b2ad7decee63a5bd47", + "https://deno.land/x/postgresjs@v3.4.5/src/bytes.js": "f2de43bdc8fa5dc4b169f2c70d5d8b053a3dea8f85ef011d7b27dec69e14ebb7", + "https://deno.land/x/postgresjs@v3.4.5/src/connection.js": "e63062451fb6a7284c14540b3f268d1373c3028fb0f3b234056ad56569190e8f", + "https://deno.land/x/postgresjs@v3.4.5/src/errors.js": "85cfbed9a5ab0db41ab8e97b806c881af29807dfe99bc656fdf1a18c1c13b6c6", + "https://deno.land/x/postgresjs@v3.4.5/src/index.js": "9dca008e765675f8218d4e2e3ccc75359cc2240f7be4e80bf6735e92b5562e3a", + "https://deno.land/x/postgresjs@v3.4.5/src/large.js": "f3e770cdb7cc695f7b50687b4c6c4b7252129515486ec8def98b7582ee7c54ef", + "https://deno.land/x/postgresjs@v3.4.5/src/query.js": "67c45a5151032aa46b587abc15381fe4efd97c696e5c1b53082b8161309c4ee2", + "https://deno.land/x/postgresjs@v3.4.5/src/queue.js": "15e6345adb6708bf3b99ad39fc2231c2fb61de5f6cba4b7a7a6be881482a4ec3", + "https://deno.land/x/postgresjs@v3.4.5/src/result.js": "001ff5e0c8d634674f483d07fbcd620a797e3101f842d6c20ca3ace936260465", + "https://deno.land/x/postgresjs@v3.4.5/src/subscribe.js": "9e4d0c3e573a6048e77ee2f15abbd5bcd17da9ca85a78c914553472c6d6c169b", + "https://deno.land/x/postgresjs@v3.4.5/src/types.js": "471f4a6c35412aa202a7c177c0a7e5a7c3bd225f01bbde67c947894c1b8bf6ed" + }, + "workspace": { + "dependencies": [ + "jsr:@oak/oak@17.1.4", + "jsr:@std/cache@0.2.0" + ] + } +} diff --git a/frameworks/TypeScript/oak/oak-postgresjs.dockerfile b/frameworks/TypeScript/oak/oak-postgresjs.dockerfile new file mode 100644 index 00000000000..6ad423e49c7 --- /dev/null +++ b/frameworks/TypeScript/oak/oak-postgresjs.dockerfile @@ -0,0 +1,19 @@ +FROM denoland/deno:2.3.1 + +EXPOSE 8080 + +WORKDIR /app + +USER deno + +ENV PG_NAME hello_world +ENV PG_HOST tfb-database +ENV PG_USER benchmarkdbuser +ENV PG_PSWD benchmarkdbpass +ENV DATABASE postgres + +COPY . . + +RUN deno install --entrypoint ./src/main.ts + +CMD ["deno", "serve", "--parallel", "--port", "8080", "--host", "0.0.0.0", "-A", "./src/main.ts"] diff --git a/frameworks/TypeScript/oak/oak.dockerfile b/frameworks/TypeScript/oak/oak.dockerfile index a1a1e14d90a..647757427ce 100644 --- a/frameworks/TypeScript/oak/oak.dockerfile +++ b/frameworks/TypeScript/oak/oak.dockerfile @@ -1,4 +1,4 @@ -FROM denoland/deno +FROM denoland/deno:2.3.1 EXPOSE 8080 @@ -6,7 +6,8 @@ WORKDIR /app USER deno -COPY ./src/deps.ts . -RUN deno cache deps.ts -ADD ./src . -CMD [ "run", "--allow-all", "main.ts" ] +COPY . . + +RUN deno install --entrypoint ./src/main.ts + +CMD ["deno", "serve", "--parallel", "--port", "8080", "--host", "0.0.0.0", "-A", "./src/main.ts"] diff --git a/frameworks/TypeScript/oak/src/deps.ts b/frameworks/TypeScript/oak/src/deps.ts deleted file mode 100644 index 56d02e49232..00000000000 --- a/frameworks/TypeScript/oak/src/deps.ts +++ /dev/null @@ -1,20 +0,0 @@ -export { - Application, - Context, - Router, - Status, -} from "https://deno.land/x/oak@v12.1.0/mod.ts"; -export { getQuery } from "https://deno.land/x/oak@v12.1.0/helpers.ts"; -export type { ResponseBody } from "https://deno.land/x/oak@v12.1.0/response.ts"; - -export { - Column, - connect, - DataType, - Manager, - Model, - Primary, -} from "https://deno.land/x/cotton@v0.7.5/mod.ts"; -export type { DatabaseResult } from "https://deno.land/x/cotton@v0.7.5/src/adapters/adapter.ts"; - -export { html } from "https://deno.land/x/literal_html@1.1.0/mod.ts"; diff --git a/frameworks/TypeScript/oak/src/helpers.ts b/frameworks/TypeScript/oak/src/helpers.ts index b016e6be7d5..74c61998352 100644 --- a/frameworks/TypeScript/oak/src/helpers.ts +++ b/frameworks/TypeScript/oak/src/helpers.ts @@ -1,4 +1,5 @@ -import { Context, ResponseBody, Status } from "./deps.ts"; +import { Context, Status } from "oak"; +import { ResponseBody } from "oak/response"; export function Ok(ctx: Context, body: ResponseBody) { ctx.response.status = Status.OK; diff --git a/frameworks/TypeScript/oak/src/main.ts b/frameworks/TypeScript/oak/src/main.ts index ac2896cf3ec..961a05088be 100644 --- a/frameworks/TypeScript/oak/src/main.ts +++ b/frameworks/TypeScript/oak/src/main.ts @@ -1,10 +1,7 @@ -import { Application, DatabaseResult, Manager } from "./deps.ts"; +import { Application } from "oak"; import { router } from "./routes.ts"; -import { getDbClient } from "./utils.ts"; -const app = new Application< - { manager: Manager; cached_worlds: DatabaseResult[] } ->(); +const app = new Application(); // headers app.use(async (ctx, next) => { @@ -13,15 +10,7 @@ app.use(async (ctx, next) => { await next(); }); -// database handling -app.use(async (ctx, next) => { - const db = await getDbClient(); - ctx.state.manager = db.getManager(); - await next(); - await db.disconnect(); -}); - app.use(router.routes()); app.use(router.allowedMethods()); -await app.listen({ port: 8080 }); +export default { fetch: app.fetch }; diff --git a/frameworks/TypeScript/oak/src/models.ts b/frameworks/TypeScript/oak/src/models.ts deleted file mode 100644 index e55761f6af2..00000000000 --- a/frameworks/TypeScript/oak/src/models.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Column, DataType, Model, Primary } from "./deps.ts"; - -@Model() -export class World { - @Primary() - id!: number; - - @Column({ type: DataType.Number }) - randomnumber!: number; -} - -@Model() -export class Fortune { - @Primary() - id!: number; - - @Column({ type: DataType.String }) - message!: string; -} diff --git a/frameworks/TypeScript/oak/src/postgres.ts b/frameworks/TypeScript/oak/src/postgres.ts new file mode 100644 index 00000000000..ff54f003019 --- /dev/null +++ b/frameworks/TypeScript/oak/src/postgres.ts @@ -0,0 +1,35 @@ +import postgres from 'postgres'; +import type { World, Fortune } from './types.ts'; + +const sql = postgres({ + host: Deno.env.get("PG_HOST"), + user: Deno.env.get("PG_USER"), + database: Deno.env.get("PG_NAME"), + password: Deno.env.get("PG_PSWD"), + max: 1 +}); + +export function allFortunes() { + return sql`select id, message from fortune`; +} + +export function getAllWorlds() { + return sql`SELECT id, randomNumber FROM world`; +} + +export async function getWorld(id: number) { + const result = await sql`select id, randomNumber from world where id = ${id}`; + return result[0]; +} + +export async function bulkUpdate(worlds: World[]) { + const values = sql( + worlds + .map((world) => [world.id, world.randomnumber]) + .sort((a, b) => (a[0] < b[0] ? -1 : 1)) + ); + + await sql`update world set randomNumber = (update_data.randomNumber)::int + from (values ${values}) as update_data (id, randomNumber) + where world.id = (update_data.id)::int`; +} diff --git a/frameworks/TypeScript/oak/src/routes.ts b/frameworks/TypeScript/oak/src/routes.ts index 461ffbda991..68ba897039f 100644 --- a/frameworks/TypeScript/oak/src/routes.ts +++ b/frameworks/TypeScript/oak/src/routes.ts @@ -1,57 +1,63 @@ -import { Fortune, World } from "./models.ts"; +import { Router } from "oak"; +import { LruCache } from "lru-cache"; import { NotFound, Ok } from "./helpers.ts"; +import type { Fortune, World } from "./types.ts"; import { - getDbClient, parseQuery, randomNumber, renderTemplate, } from "./utils.ts"; -import { Router } from "./deps.ts"; - -const cached_worlds = await (await getDbClient()).getManager().query(World) - .limit(10000).all(); +import { + getWorld, + bulkUpdate, + allFortunes, + getAllWorlds +} from "./postgres.ts"; export const router = new Router() .get("/plaintext", (ctx) => Ok(ctx, "Hello, World!")) - .get("/json", (ctx) => Ok(ctx, { message: "Hello, World!" })) - .get("/db", async (ctx) => { - const world = await ctx.state.manager.query(World).where( - "id", - randomNumber(), - ).first(); + .get("/json", (ctx) => Ok(ctx, { message: "Hello, World!" })); + +if (Deno.env.has("DATABASE")) { + const cache = new LruCache(10_000); + (await getAllWorlds()).forEach(world => cache.set(world.id, world)); + + router.get("/db", async (ctx) => { + const world = await getWorld(randomNumber()); Ok(ctx, world); }) .get("/queries", async (ctx) => { - const worlds = []; + const worldsPromises = []; const queries = parseQuery(ctx); for (let i = 0; i < queries; i++) { - const world = await ctx.state.manager.query(World).where( - "id", - randomNumber(), - ).first(); - worlds.push(world); + worldsPromises.push(getWorld(randomNumber())); } + const worlds = await Promise.all(worldsPromises); Ok(ctx, worlds); }) .get("/updates", async (ctx) => { - const worlds = []; + const worldsPromises: Promise[] = []; const queries = parseQuery(ctx); for (let i = 0; i < queries; i++) { - const world = await ctx.state.manager.query(World).where( - "id", - randomNumber(), - ).first(); + const world = getWorld(randomNumber()); + worldsPromises.push(world); + } + + const worlds = await Promise.all(worldsPromises); + + const newWorlds = worlds.map((world) => { world.randomnumber = randomNumber(); - worlds.push(world); + return world; + }); - await ctx.state.manager.save(world); - } - Ok(ctx, worlds); + await bulkUpdate(newWorlds); + + Ok(ctx, newWorlds); }) .get("/fortunes", async (ctx) => { - const fortunes: Fortune[] = await ctx.state.manager.query(Fortune).all(); + const fortunes = await allFortunes(); fortunes.push({ id: 0, message: "Additional fortune added at request time.", @@ -69,8 +75,10 @@ export const router = new Router() const worlds = []; for (let i = 0; i < queries; i++) { - worlds.push(cached_worlds[randomNumber()]); + worlds.push(cache.get(randomNumber())); } Ok(ctx, worlds); }) - .get("/(.*)", (ctx) => NotFound(ctx)); +} + +router.get("/(.*)", (ctx) => NotFound(ctx)); diff --git a/frameworks/TypeScript/oak/src/types.ts b/frameworks/TypeScript/oak/src/types.ts new file mode 100644 index 00000000000..3151435cd66 --- /dev/null +++ b/frameworks/TypeScript/oak/src/types.ts @@ -0,0 +1,9 @@ +export interface World { + id: number; + randomnumber: number; +} + +export interface Fortune { + id: number; + message: string; +} \ No newline at end of file diff --git a/frameworks/TypeScript/oak/src/utils.ts b/frameworks/TypeScript/oak/src/utils.ts index dd097b36393..26acdf5817f 100644 --- a/frameworks/TypeScript/oak/src/utils.ts +++ b/frameworks/TypeScript/oak/src/utils.ts @@ -1,12 +1,18 @@ -import { connect, Context, getQuery, html } from "./deps.ts"; -import { Fortune } from "./models.ts"; +import { html } from "html"; +import { Context } from "oak"; +import type { Fortune } from "./types.ts"; export const randomNumber = () => { return Math.floor(Math.random() * 10000 + 1); }; export const parseQuery = (ctx: Context) => { - return Math.min(parseInt(getQuery(ctx).q) || 1, 500); + const queryParam = ctx.request.url.searchParams.get('q') ?? '1'; + const parseValue = parseInt(queryParam, 10); + if (isNaN(parseValue) || parseValue < 1) { + return 1; + } + return Math.min(parseValue, 500); }; export const renderTemplate = (fortunes: Fortune[]) => { @@ -28,14 +34,3 @@ export const renderTemplate = (fortunes: Fortune[]) => { `; }; - -export async function getDbClient() { - return await connect({ - type: "postgres", - port: 5432, - database: "hello_world", - hostname: "tfb-database", - username: "benchmarkdbuser", - password: "benchmarkdbpass", - }); -} diff --git a/frameworks/TypeScript/oak/tsconfig.json b/frameworks/TypeScript/oak/tsconfig.json deleted file mode 100644 index 6dacb8cc2c5..00000000000 --- a/frameworks/TypeScript/oak/tsconfig.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "compilerOptions": { - "experimentalDecorators": true, - "emitDecoratorMetadata": true - } -} diff --git a/frameworks/Ur/urweb/README.md b/frameworks/Ur/urweb/README.md index e529333fe96..534c52cbc18 100644 --- a/frameworks/Ur/urweb/README.md +++ b/frameworks/Ur/urweb/README.md @@ -19,5 +19,3 @@ To compile a standalone executable running on port 8080, run `urweb bench`. See `bench.ur` is the main source file. `bench.urs` is the signature file describing the module's exported functions. `bench.urp` is the project file giving compilation directives. `benchmark_config.json` includes metadata for the framework comparison. - -`__init__.py` and `setup.py` are for starting and stopping the Ur/Web server. `setup_mysql.py` is a variant using MySQL instead of PostgreSQL. diff --git a/frameworks/Ur/urweb/bench.ur b/frameworks/Ur/urweb/bench.ur index d181a79c81c..fed47ba1132 100644 --- a/frameworks/Ur/urweb/bench.ur +++ b/frameworks/Ur/urweb/bench.ur @@ -133,3 +133,9 @@ fun updates s = fun plaintext () = returnText "Hello, World!" + +(** * Test type 7: Cached queries *) + +val cached_queries = queries +(* It's really the same code as the uncached queries test! + * We just compile with a different flag to enable caching. *) diff --git a/frameworks/Ur/urweb/bench.urs b/frameworks/Ur/urweb/bench.urs index 83b12c39ae2..a363ac346c3 100644 --- a/frameworks/Ur/urweb/bench.urs +++ b/frameworks/Ur/urweb/bench.urs @@ -4,3 +4,4 @@ val queries : string -> transaction page val fortunes : unit -> transaction page val updates : string -> transaction page val plaintext : unit -> transaction page +val cached_queries : string -> transaction page diff --git a/frameworks/Ur/urweb/benchmark_config.json b/frameworks/Ur/urweb/benchmark_config.json index 389b8517ce2..23aca3bb682 100644 --- a/frameworks/Ur/urweb/benchmark_config.json +++ b/frameworks/Ur/urweb/benchmark_config.json @@ -1,5 +1,6 @@ { "framework": "urweb", + "maintainers": ["achlipala"], "tests": [{ "default": { "display_name": "urweb", @@ -42,7 +43,7 @@ }, "cache": { "setup_file": "setup-postgresql", - "cached_query_url": "/queries/", + "cached_query_url": "/cached_queries/", "port": 8080, "approach": "Realistic", "classification": "Fullstack", @@ -53,12 +54,11 @@ "platform": "Ur/Web", "webserver": "None", "os": "Linux", - "database_os": "Linux", - "tags": ["broken"] + "database_os": "Linux" }, "mysql-cache": { "setup_file": "setup-mysql", - "cached_query_url": "/queries/", + "cached_query_url": "/cached_queries/", "port": 8080, "approach": "Realistic", "classification": "Fullstack", @@ -69,8 +69,7 @@ "platform": "Ur/Web", "webserver": "None", "os": "Linux", - "database_os": "Linux", - "tags": ["broken"] + "database_os": "Linux" } }] } diff --git a/frameworks/Ur/urweb/config.toml b/frameworks/Ur/urweb/config.toml index cf30140d712..26827637aa3 100644 --- a/frameworks/Ur/urweb/config.toml +++ b/frameworks/Ur/urweb/config.toml @@ -19,7 +19,7 @@ webserver = "None" versus = "None" [mysql-cache] -urls.cached_query = "/queries/" +urls.cached_query = "/cached_queries/" approach = "Realistic" classification = "Fullstack" database = "MySQL" @@ -31,7 +31,7 @@ webserver = "None" versus = "None" [cache] -urls.cached_query = "/queries/" +urls.cached_query = "/cached_queries/" approach = "Realistic" classification = "Fullstack" database = "Postgres" diff --git a/frameworks/Ur/urweb/urweb-cache.dockerfile b/frameworks/Ur/urweb/urweb-cache.dockerfile index 762f7cb1c36..f4acd21176c 100644 --- a/frameworks/Ur/urweb/urweb-cache.dockerfile +++ b/frameworks/Ur/urweb/urweb-cache.dockerfile @@ -1,9 +1,9 @@ -FROM ubuntu:18.04 +FROM ubuntu:24.04 ADD ./ /urweb WORKDIR /urweb -RUN apt-get update -yqq && apt-get install -yqq urweb +RUN apt-get update -yqq && apt-get install -yqq sudo git gcc make autoconf automake libtool mlton libpq-dev libssl-dev uthash-dev libicu-dev && git clone https://github.com/urweb/urweb.git && cd urweb && ./autogen.sh && ./configure && make -j && sudo make install RUN urweb -sqlcache -db "dbname=hello_world user=benchmarkdbuser password=benchmarkdbpass host=tfb-database" bench diff --git a/frameworks/Ur/urweb/urweb-mysql-cache.dockerfile b/frameworks/Ur/urweb/urweb-mysql-cache.dockerfile index 5655af62e58..2a21638a218 100644 --- a/frameworks/Ur/urweb/urweb-mysql-cache.dockerfile +++ b/frameworks/Ur/urweb/urweb-mysql-cache.dockerfile @@ -1,9 +1,9 @@ -FROM ubuntu:18.04 +FROM ubuntu:24.04 ADD ./ /urweb WORKDIR /urweb -RUN apt-get update -yqq && apt-get install -yqq urweb +RUN apt-get update -yqq && apt-get install -yqq sudo git gcc make autoconf automake libtool mlton libmysqlclient-dev libssl-dev uthash-dev libicu-dev && git clone https://github.com/urweb/urweb.git && cd urweb && ./autogen.sh && ./configure && make -j && sudo make install RUN urweb -sqlcache -dbms mysql -db "dbname=hello_world user=benchmarkdbuser password=benchmarkdbpass host=tfb-database" bench diff --git a/frameworks/Ur/urweb/urweb-mysql.dockerfile b/frameworks/Ur/urweb/urweb-mysql.dockerfile index cfa770970c0..3559a0ce988 100644 --- a/frameworks/Ur/urweb/urweb-mysql.dockerfile +++ b/frameworks/Ur/urweb/urweb-mysql.dockerfile @@ -1,9 +1,9 @@ -FROM ubuntu:18.04 +FROM ubuntu:24.04 ADD ./ /urweb WORKDIR /urweb -RUN apt-get update -yqq && apt-get install -yqq urweb +RUN apt-get update -yqq && apt-get install -yqq sudo git gcc make autoconf automake libtool mlton libmysqlclient-dev libssl-dev uthash-dev libicu-dev && git clone https://github.com/urweb/urweb.git && cd urweb && ./autogen.sh && ./configure && make -j && sudo make install RUN urweb -dbms mysql -db "dbname=hello_world user=benchmarkdbuser password=benchmarkdbpass host=tfb-database" bench diff --git a/frameworks/Ur/urweb/urweb.dockerfile b/frameworks/Ur/urweb/urweb.dockerfile index 998ee242cd1..8976e26a1c6 100644 --- a/frameworks/Ur/urweb/urweb.dockerfile +++ b/frameworks/Ur/urweb/urweb.dockerfile @@ -1,9 +1,9 @@ -FROM ubuntu:18.04 +FROM ubuntu:24.04 ADD ./ /urweb WORKDIR /urweb -RUN apt-get update -yqq && apt-get install -yqq urweb +RUN apt-get update -yqq && apt-get install -yqq sudo git gcc make autoconf automake libtool mlton libpq-dev libssl-dev uthash-dev libicu-dev && git clone https://github.com/urweb/urweb.git && cd urweb && ./autogen.sh && ./configure && make -j && sudo make install RUN urweb -db "dbname=hello_world user=benchmarkdbuser password=benchmarkdbpass host=tfb-database" bench diff --git a/frameworks/V/veb/README.md b/frameworks/V/veb/README.md new file mode 100755 index 00000000000..467345c1431 --- /dev/null +++ b/frameworks/V/veb/README.md @@ -0,0 +1,35 @@ +# [veb](https://modules.vlang.io/veb.html) Benchmarking Test + +Veb is the default V language web framework. This test uses veb and V native ORM. + +### Test Type Implementation Source Code + +All tests in a 95 lines [main.v] and a html [template](fortunes.html) +### Database + +PostgresQL + +## Test URLs +### JSON + +http://localhost:8080/json + +### PLAINTEXT + +http://localhost:8080/plaintext + +### DB + +http://localhost:8080/db + +### QUERY + +http://localhost:8080/query?q= + +### UPDATE + +http://localhost:8080/update?queries= + +### FORTUNES + +http://localhost:8080/fortunes diff --git a/frameworks/V/veb/benchmark_config.json b/frameworks/V/veb/benchmark_config.json new file mode 100755 index 00000000000..e5ca19da42c --- /dev/null +++ b/frameworks/V/veb/benchmark_config.json @@ -0,0 +1,30 @@ +{ + "framework": "veb", + "tests": [ + { + "default": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "db_url": "/db", + "query_url": "/queries?q=", + "fortune_url": "/fortunes", + "update_url": "/update?q=", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "database": "Postgres", + "framework": "veb", + "language": "V", + "flavor": "None", + "orm": "Micro", + "platform": "None", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "veb", + "notes": "", + "versus": "None" + } + } + ] +} diff --git a/frameworks/V/veb/config.toml b/frameworks/V/veb/config.toml new file mode 100644 index 00000000000..ea461db93e4 --- /dev/null +++ b/frameworks/V/veb/config.toml @@ -0,0 +1,19 @@ +[framework] +name = "veb" + +[main] +urls.plaintext = "/plaintext" +urls.json = "/json" +urls.db = "/db" +urls.query = "/queries?q=" +urls.update = "/update?q=" +urls.fortune = "/fortunes" +approach = "Realistic" +classification = "Fullstack" +database = "Postgres" +database_os = "Linux" +os = "Linux" +orm = "Micro" +platform = "None" +webserver = "None" +versus = "None" diff --git a/frameworks/V/veb/fortunes.html b/frameworks/V/veb/fortunes.html new file mode 100644 index 00000000000..51e1d42989a --- /dev/null +++ b/frameworks/V/veb/fortunes.html @@ -0,0 +1,12 @@ + + +Fortunes + + + +@for m in fortunes + +@end +
idmessage
@m.id@m.message
+ + \ No newline at end of file diff --git a/frameworks/V/veb/main.v b/frameworks/V/veb/main.v new file mode 100644 index 00000000000..1fa0b3e5d0f --- /dev/null +++ b/frameworks/V/veb/main.v @@ -0,0 +1,103 @@ +import veb +import time +import rand +import db.pg + +pub fn (app &App) plaintext(mut ctx Context) veb.Result { + s := 'Hello, World!' + return ctx.text(s) +} + +pub fn (app &App) json(mut ctx Context) veb.Result { + obj := {'message': 'Hello, World!'} + return ctx.json(obj) +} + +struct World { + id int @[primary; sql: serial] +mut: + randomnumber int +} + +pub fn (app &App) db(mut ctx Context) veb.Result { + r := rand.int_in_range(1, 10000) or { return ctx.text('rand error') } + mut world := sql app.db { + select from World where id == r + } or { return ctx.text('db error') } + return ctx.json(world.first()) +} + +pub fn (app &App) queries(mut ctx Context) veb.Result { + mut q := ctx.query['q'].int() + if q < 1 { q = 1 } else if q > 500 { q = 500 } + mut world := []World{} + for _ in 0..q { + r := rand.int_in_range(1, 10000) or { return ctx.text('rand error') } + world << sql app.db { + select from World where id == r + } or { return ctx.text('db error') } + } + return ctx.json(world) +} + +pub fn (app &App) update(mut ctx Context) veb.Result { + mut q := ctx.query['q'].int() + if q < 1 { q = 1 } else if q > 500 { q = 500 } + mut world := []World{} + for _ in 0..q { + r := rand.int_in_range(1, 10000) or { return ctx.text('rand error') } + world << sql app.db { + select from World where id == r + } or { return ctx.text('db error') } + world.last().randomnumber = rand.int_in_range(1, 10000) or { return ctx.text('rand error') } + sql app.db { + update World set randomnumber = world.last().randomnumber where id == world.last().id + } or { return ctx.text('db error') } + } + return ctx.json(world) +} + +struct Fortune { + id int @[primary; sql: serial] + message string +} + +pub fn (app &App) fortunes(mut ctx Context) veb.Result { + mut fortunes := sql app.db { + select from Fortune + } or { return ctx.text('db error') } + fortunes.insert(0, Fortune{id: 0, message: 'Additional fortune added at request time.'}) + fortunes.sort(a.message < b.message) + ctx.content_type = 'text/html; charset=utf-8' + return $veb.html() +} + +pub struct Context { + veb.Context +} + +pub struct App { + veb.Middleware[Context] +pub mut: + db pg.DB +} + +pub fn header(mut ctx Context) bool { + ctx.set_header(.date, time.now().as_utc().custom_format('ddd, DD MMM YYYY HH:MM:ss') + ' GMT') + ctx.set_header(.server, 'veb') + return true +} + +fn main() { + mut app := &App{ + db: pg.connect(pg.Config{ + host: 'tfb-database' + port: 5432 + user: 'benchmarkdbuser' + password: 'benchmarkdbpass' + dbname: 'hello_world' + }) ! + } + app.use(handler: header) + veb.run[App, Context](mut app, 8080) +} diff --git a/frameworks/V/veb/run.sh b/frameworks/V/veb/run.sh new file mode 100644 index 00000000000..5979570b9dc --- /dev/null +++ b/frameworks/V/veb/run.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +for i in $(seq 0 $(nproc)); do + taskset -c $i ./main & +done + +wait diff --git a/frameworks/V/veb/veb.dockerfile b/frameworks/V/veb/veb.dockerfile new file mode 100644 index 00000000000..d3313b4515e --- /dev/null +++ b/frameworks/V/veb/veb.dockerfile @@ -0,0 +1,9 @@ +FROM thevlang/vlang:debian-dev +RUN apt update && apt install -y libpq-dev + +WORKDIR /app +COPY ./main.v run.sh fortunes.html ./ +RUN v -prod -cflags '-std=gnu11 -Wall -O3 -march=native -mtune=native -flto' main.v + +EXPOSE 8080 +CMD sh run.sh diff --git a/frameworks/VB/aspnetcore/Benchmarks/Benchmarks.vbproj b/frameworks/VB/aspnetcore/Benchmarks/Benchmarks.vbproj index fe9d3cbf5b6..59613d54879 100644 --- a/frameworks/VB/aspnetcore/Benchmarks/Benchmarks.vbproj +++ b/frameworks/VB/aspnetcore/Benchmarks/Benchmarks.vbproj @@ -11,7 +11,7 @@ - + diff --git a/frameworks/Zig/httpz/.gitignore b/frameworks/Zig/httpz/.gitignore new file mode 100644 index 00000000000..d8c8979f82c --- /dev/null +++ b/frameworks/Zig/httpz/.gitignore @@ -0,0 +1,2 @@ +.zig-cache +zig-out diff --git a/frameworks/Zig/httpz/README.md b/frameworks/Zig/httpz/README.md new file mode 100644 index 00000000000..e83169efe17 --- /dev/null +++ b/frameworks/Zig/httpz/README.md @@ -0,0 +1,25 @@ + +# [Httpz](https://github.com/karlseguin/http.zig) - An HTTP/1.1 server for Zig + +## Description + +Native Zig framework and zig http replacement + +## 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/httpz/benchmark_config.json b/frameworks/Zig/httpz/benchmark_config.json new file mode 100644 index 00000000000..e36c9c17a1c --- /dev/null +++ b/frameworks/Zig/httpz/benchmark_config.json @@ -0,0 +1,26 @@ +{ + "framework": "httpz", + "tests": [{ + "default": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "db_url": "/db", + "fortune_url": "/fortunes", + "port": 3000, + "approach": "Realistic", + "classification": "Fullstack", + "database": "Postgres", + "framework": "httpz", + "language": "Zig", + "flavor": "None", + "orm": "raw", + "platform": "None", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "Httpz (Zig)", + "notes": "", + "versus": "" + } + }] +} diff --git a/frameworks/Zig/httpz/build.zig b/frameworks/Zig/httpz/build.zig new file mode 100644 index 00000000000..16a4bb64845 --- /dev/null +++ b/frameworks/Zig/httpz/build.zig @@ -0,0 +1,51 @@ +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 exe = b.addExecutable(.{ + .name = "httpz", + .root_source_file = b.path("src/main.zig"), + .target = target, + .optimize = optimize, + }); + + const httpz_module = b.dependency("httpz", dep_opts).module("httpz"); + const pg_module = b.dependency("pg", dep_opts).module("pg"); + const datetimez_module = b.dependency("datetimez", dep_opts).module("zig-datetime"); + + exe.root_module.addImport("httpz", httpz_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/httpz/build.zig.zon b/frameworks/Zig/httpz/build.zig.zon new file mode 100644 index 00000000000..83c29e48929 --- /dev/null +++ b/frameworks/Zig/httpz/build.zig.zon @@ -0,0 +1,15 @@ +.{ .name = "Zap testing", .version = "0.1.1", .paths = .{ + "build.zig", + "build.zig.zon", + "src", +}, .dependencies = .{ + .pg = .{ .url = "https://github.com/karlseguin/pg.zig/archive/239a4468163a49d8c0d03285632eabe96003e9e2.tar.gz", .hash = "1220a1d7e51e2fa45e547c76a9e099c09d06e14b0b9bfc6baa89367f56f1ded399a0" }, + .httpz = .{ + .url = "git+https://github.com/karlseguin/http.zig?ref=zig-0.13#7d2ddae87af9b110783085c0ea6b03985faa4584", + .hash = "12208c1f2c5f730c4c03aabeb0632ade7e21914af03e6510311b449458198d0835d6", + }, + .datetimez = .{ + .url = "git+https://github.com/frmdstryr/zig-datetime#70aebf28fb3e137cd84123a9349d157a74708721", + .hash = "122077215ce36e125a490e59ec1748ffd4f6ba00d4d14f7308978e5360711d72d77f", + }, +} } diff --git a/frameworks/Zig/httpz/httpz.dockerfile b/frameworks/Zig/httpz/httpz.dockerfile new file mode 100644 index 00000000000..ea4f9a7f76d --- /dev/null +++ b/frameworks/Zig/httpz/httpz.dockerfile @@ -0,0 +1,28 @@ +FROM debian:12.9 + +ENV PG_USER=benchmarkdbuser +ENV PG_PASS=benchmarkdbpass +ENV PG_DB=hello_world +ENV PG_HOST=tfb-database +ENV PG_PORT=5432 + +WORKDIR /app + +COPY src src +COPY build.zig.zon build.zig.zon +COPY build.zig build.zig + +ARG ZIG_VER=0.13.0 + +RUN apt-get update && apt-get install -y curl xz-utils ca-certificates + +RUN curl https://ziglang.org/download/${ZIG_VER}/zig-linux-$(uname -m)-${ZIG_VER}.tar.xz -o zig-linux.tar.xz && \ + tar xf zig-linux.tar.xz && \ + mv zig-linux-$(uname -m)-${ZIG_VER}/ /opt/zig + +RUN /opt/zig/zig build -Doptimize=ReleaseFast + +EXPOSE 3000 +RUN ls + +CMD ["zig-out/bin/httpz"] diff --git a/frameworks/Zig/httpz/src/endpoints.zig b/frameworks/Zig/httpz/src/endpoints.zig new file mode 100644 index 00000000000..b8cfe9757fb --- /dev/null +++ b/frameworks/Zig/httpz/src/endpoints.zig @@ -0,0 +1,147 @@ +const std = @import("std"); +const httpz = @import("httpz"); +const pg = @import("pg"); +const datetimez = @import("datetimez"); + +pub var date_str: []u8 = ""; + +pub const Global = struct { + pool: *pg.Pool, + rand: *std.rand.Random, +}; + +const World = struct { + id: i32, + randomNumber: i32, +}; + +const Fortune = struct { + id: i32, + message: []const u8, +}; + +pub fn plaintext(_: *Global, _: *httpz.Request, res: *httpz.Response) !void { + try setHeaders(res.arena, res); + + res.content_type = .TEXT; + res.body = "Hello, World!"; +} + +pub fn json(_: *Global, _: *httpz.Request, res: *httpz.Response) !void { + try setHeaders(res.arena, res); + + try res.json(.{ .message = "Hello, World!" }, .{}); +} + +pub fn db(global: *Global, _: *httpz.Request, res: *httpz.Response) !void { + try setHeaders(res.arena, 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, _: *httpz.Request, res: *httpz.Response) !void { + try setHeaders(res.arena, res); + + const fortunes_html = try getFortunesHtml(res.arena, global.pool); + + 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(allocator: std.mem.Allocator, res: *httpz.Response) !void { + res.header("Server", "Httpz"); + + //const now = datetimez.datetime.Date.now(); + //const time = datetimez.datetime.Time.now(); + + // Wed, 17 Apr 2013 12:00:00 GMT + // Return date in ISO format YYYY-MM-DD + //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"; + //const now_str = try std.fmt.allocPrint(allocator, TB_DATE_FMT, .{ now.weekdayName()[0..3], now.day, now.monthName()[0..3], now.year, time.hour, time.minute, time.second }); + + //defer allocator.free(now_str); + + res.header("Date", try allocator.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"); + + 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/httpz/src/main.zig b/frameworks/Zig/httpz/src/main.zig new file mode 100644 index 00000000000..dd5b3966b2f --- /dev/null +++ b/frameworks/Zig/httpz/src/main.zig @@ -0,0 +1,151 @@ +const std = @import("std"); +const builtin = @import("builtin"); +const httpz = @import("httpz"); +const pg = @import("pg"); +const datetimez = @import("datetimez"); +const pool = @import("pool.zig"); + +const endpoints = @import("endpoints.zig"); + +var server: httpz.ServerCtx(*endpoints.Global, *endpoints.Global) = undefined; + +pub fn main() !void { + const cpu_count = try std.Thread.getCpuCount(); + var gpa = std.heap.GeneralPurposeAllocator(.{ + .thread_safe = true, + }){}; + + const allocator = gpa.allocator(); + + var pg_pool = try pool.initPool(allocator); + defer pg_pool.deinit(); + + const date_thread = try std.Thread.spawn(.{}, struct { + fn update() !void { + const ally = std.heap.page_allocator; + while (true) { + const now = datetimez.datetime.Date.now(); + const time = datetimez.datetime.Time.now(); + + // Wed, 17 Apr 2013 12:00:00 GMT + // Return date in ISO format YYYY-MM-DD + 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"; + endpoints.date_str = try std.fmt.allocPrint(ally, TB_DATE_FMT, .{ now.weekdayName()[0..3], now.day, now.monthName()[0..3], now.year, time.hour, time.minute, time.second }); + std.time.sleep(std.time.ns_per_ms * 980); + } + } + }.update, .{}); + + date_thread.detach(); + + var prng = std.rand.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 workers = @as(u16, @intCast(16 * cpu_count)); + + server = try httpz.ServerApp(*endpoints.Global).init(allocator, .{ + .port = port, + .address = "0.0.0.0", + .workers = .{ + // Number of worker threads + // (blocking mode: handled differently) + .count = workers, + + // Maximum number of concurrent connection each worker can handle + // (blocking mode: currently ignored) + .max_conn = 8_192, + + // Minimum number of connection states each worker should maintain + // (blocking mode: currently ignored) + .min_conn = 64, + + // A pool of larger buffers that can be used for any data larger than configured + // static buffers. For example, if response headers don't fit in in + // $response.header_buffer_size, a buffer will be pulled from here. + // This is per-worker. + + // Size of bytes retained for the connection arena between use. This will + // result in up to `count * min_conn * retain_allocated_bytes` of memory usage. + .retain_allocated_bytes = 4096, + }, + + // configures the threadpool which processes requests. The threadpool is + // where your application code runs. + .thread_pool = .{ + // Number threads. If you're handlers are doing a lot of i/o, a higher + // number might provide better throughput + // (blocking mode: handled differently) + .count = 256, + + // The maximum number of pending requests that the thread pool will accept + // This applies back pressure to the above workers and ensures that, under load + // pending requests get precedence over processing new requests. + .backlog = 2048, + }, + .request = .{ + // Maximum number of headers to accept. + // Additional headers will be silently ignored. + .max_header_count = 32, + + // Maximum number of URL parameters to accept. + // Additional parameters will be silently ignored. + .max_param_count = 0, + + // Maximum number of query string parameters to accept. + // Additional parameters will be silently ignored. + .max_query_count = 0, + + // Maximum number of x-www-form-urlencoded fields to support. + // Additional parameters will be silently ignored. This must be + // set to a value greater than 0 (the default) if you're going + // to use the req.formData() method. + .max_form_count = 0, + + // Maximum number of multipart/form-data fields to support. + // Additional parameters will be silently ignored. This must be + // set to a value greater than 0 (the default) if you're going + // to use the req.multiFormData() method. + .max_multiform_count = 0, + }, + }, &global); + defer server.deinit(); + + // now that our server is up, we register our intent to handle SIGINT + try std.posix.sigaction(std.posix.SIG.INT, &.{ + .handler = .{ .handler = shutdown }, + .mask = std.posix.empty_sigset, + .flags = 0, + }, null); + + var router = server.router(); + router.get("/json", endpoints.json); + router.get("/plaintext", endpoints.plaintext); + router.get("/db", endpoints.db); + router.get("/fortunes", endpoints.fortune); + + std.debug.print("Httpz using {d} workers listening at 0.0.0.0:{d}\n", .{ workers, port }); + + try server.listen(); +} + +fn shutdown(_: c_int) callconv(.C) void { + server.stop(); +} + +fn notFound(_: *httpz.Request, res: *httpz.Response) !void { + res.status = 404; + res.body = "Not Found"; +} + +fn errorHandler(req: *httpz.Request, res: *httpz.Response, err: anyerror) void { + res.status = 500; + res.body = "Internal Server Error"; + std.log.warn("httpz: unhandled exception for request: {s}\nErr: {}", .{ req.url.raw, err }); +} diff --git a/frameworks/Zig/httpz/src/pool.zig b/frameworks/Zig/httpz/src/pool.zig new file mode 100644 index 00000000000..91867be7906 --- /dev/null +++ b/frameworks/Zig/httpz/src/pool.zig @@ -0,0 +1,87 @@ +const std = @import("std"); +const regex = @import("regex"); +const pg = @import("pg"); + +const Allocator = std.mem.Allocator; +const Pool = pg.Pool; +const ArrayList = std.ArrayList; + +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 = 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/zap/.gitignore b/frameworks/Zig/zap/.gitignore new file mode 100644 index 00000000000..170dc0f1403 --- /dev/null +++ b/frameworks/Zig/zap/.gitignore @@ -0,0 +1,2 @@ +zig-cache/**/*', +zig-out: 'zig-out/**/*', diff --git a/frameworks/Zig/zap/README.md b/frameworks/Zig/zap/README.md new file mode 100644 index 00000000000..71117a3400c --- /dev/null +++ b/frameworks/Zig/zap/README.md @@ -0,0 +1,25 @@ + +# [Zap](https://github.com/zigzap/zap) - Blazingly fast backends in zig + +## Description + +Zap is the zig microframework for web applications. + +## 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/zap/benchmark_config.json b/frameworks/Zig/zap/benchmark_config.json new file mode 100644 index 00000000000..0b77f27d77d --- /dev/null +++ b/frameworks/Zig/zap/benchmark_config.json @@ -0,0 +1,26 @@ +{ + "framework": "zap", + "tests": [{ + "default": { + "json_url": "/json", + "db_url": "/db", + "fortune_url": "/fortunes", + "plaintext_url": "/plaintext", + "port": 3000, + "approach": "Realistic", + "classification": "Fullstack", + "database": "Postgres", + "framework": "Zap", + "language": "Zig", + "flavor": "None", + "orm": "Full", + "platform": "None", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "Zap (Zig)", + "notes": "", + "versus": "" + } + }] +} diff --git a/frameworks/Zig/zap/build-nginx-conf.sh b/frameworks/Zig/zap/build-nginx-conf.sh new file mode 100644 index 00000000000..ecb55c80bfa --- /dev/null +++ b/frameworks/Zig/zap/build-nginx-conf.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +CPU_COUNT=$(nproc) +P=3000 +END=$(($P+$CPU_COUNT)) +CONF="" + +while [ $P -lt $END ]; do + CONF+="\t\tserver 127.0.0.1:$P;\n" + let P=P+1 +done + +sed -i "s|# replace|$CONF|g" nginx.conf diff --git a/frameworks/Zig/zap/build.zig b/frameworks/Zig/zap/build.zig new file mode 100644 index 00000000000..2da55a07981 --- /dev/null +++ b/frameworks/Zig/zap/build.zig @@ -0,0 +1,80 @@ +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. + 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"), + .target = target, + .optimize = optimize, + }); + + const zap = b.dependency("zap", .{ + .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")); + + // 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 new file mode 100644 index 00000000000..3f492b7d954 --- /dev/null +++ b/frameworks/Zig/zap/build.zig.zon @@ -0,0 +1,12 @@ +.{ .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", + }, + .pg = .{ .url = "https://github.com/karlseguin/pg.zig/archive/239a4468163a49d8c0d03285632eabe96003e9e2.tar.gz", + .hash = "1220a1d7e51e2fa45e547c76a9e099c09d06e14b0b9bfc6baa89367f56f1ded399a0" }, +} } diff --git a/frameworks/Zig/zap/nginx.conf b/frameworks/Zig/zap/nginx.conf new file mode 100644 index 00000000000..f394b2ad206 --- /dev/null +++ b/frameworks/Zig/zap/nginx.conf @@ -0,0 +1,33 @@ +error_log stderr; +worker_processes auto; + +events { + worker_connections 65535; + multi_accept off; +} + +http { + default_type application/octet-stream; + client_body_temp_path /tmp; + access_log off; + + sendfile on; + tcp_nopush on; + keepalive_requests 100000; + keepalive_timeout 65; + + upstream workers { + # replace + } + + server { + listen 8080; + server_name tfb-server; + + location / { + proxy_http_version 1.1; + proxy_set_header Connection ""; + proxy_pass http://workers; + } + } +} diff --git a/frameworks/Zig/zap/src/endpoints.zig b/frameworks/Zig/zap/src/endpoints.zig new file mode 100644 index 00000000000..44a3afc43e2 --- /dev/null +++ b/frameworks/Zig/zap/src/endpoints.zig @@ -0,0 +1,339 @@ +const std = @import("std"); +const zap = @import("zap"); +const pg = @import("pg"); + +const Mustache = @import("zap").Mustache; +const Thread = std.Thread; +const Mutex = Thread.Mutex; + +const middleware = @import("middleware.zig"); + +const Message = struct { + message: []const u8, +}; + +const World = struct { + id: i32, + randomNumber: i32, +}; + +const Fortune = struct { + id: i32, + message: []const u8, +}; + +pub const FortunesEndpoint = struct { + ep: zap.Endpoint = undefined, + mustache: Mustache, + mutex: Mutex, + + const Self = @This(); + + pub fn init() Self { + const template = "Fortunes{{#fortunes}}{{/fortunes}}
idmessage
{{id}}{{message}}
"; + const mustache = Mustache.fromData(template) catch unreachable; + + return .{ + .ep = zap.Endpoint.init(.{ + .path = "/fortunes", + .get = get, + }), + .mustache = mustache, + .mutex = Mutex{}, + }; + } + + pub fn deinit(self: *Self) void { + 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 { + 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(); + + 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 = 0, .message = "Additional fortune added at request time." }; + try fortunes.append(fortune); + + const fortunes_slice = try fortunes.toOwnedSlice(); + std.mem.sort(Fortune, fortunes_slice, {}, cmpFortuneByMessage); + + return fortunes_slice; + } + + fn getFortunesHtml(self: *Self, pool: *pg.Pool) ![]const u8 { + const fortunes = try getFortunes(pool); + + self.mutex.lock(); + const ret = self.mustache.build(.{ .fortunes = fortunes }); + defer ret.deinit(); + 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; + + var pool: *pg.Pool = undefined; + + const maybe_context: ?*middleware.Context = req.getUserContext(middleware.Context); + if (maybe_context) |context| { + if (context.pg) |cpg| { + pool = cpg.pool; + } + } + + const fortunes_html = getFortunesHtml(self, pool) catch return; + + req.sendBody(fortunes_html) catch return; + + return; + } +}; + +pub const DbEndpoint = struct { + ep: zap.Endpoint = undefined, + 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; + + var random_number: u32 = 0; + var pool: *pg.Pool = undefined; + + const maybe_context: ?*middleware.Context = req.getUserContext(middleware.Context); + if (maybe_context) |context| { + if (context.prng) |prng| { + if (context.pg) |cpg| { + pool = cpg.pool; + + self.mutex.lock(); + random_number = 1 + (prng.rnd.random().uintAtMost(u32, 9999)); + self.mutex.unlock(); + } + } + } + + if (random_number == 0) { + 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; + + return; + } + + fn getJson(pool: *pg.Pool, random_number: u32) ![]const u8{ + 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 {}; + + const world = World{ .id = row.get(i32, 0), .randomNumber = 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"; + } + + return json_to_send; + } +}; + +pub const PlaintextEndpoint = struct { + ep: zap.Endpoint = undefined, + 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; + } + + 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 const JsonEndpoint = struct { + ep: zap.Endpoint = undefined, + 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; + } + + 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; + + 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; + } +}; + +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(); + + var i: usize = 0; + while (i < input.len) { + if (std.mem.startsWith(u8, input[i..], " ")) { + try output.append(' '); + i += 5; + } else if (std.mem.startsWith(u8, input[i..], """)) { + try output.append('"'); + i += 5; + } else if (std.mem.startsWith(u8, input[i..], "&")) { + try output.append('&'); + i += 5; + } else if (std.mem.startsWith(u8, input[i..], "'")) { + try output.append('\''); + i += 5; + } else if (std.mem.startsWith(u8, input[i..], "(")) { + try output.append('('); + i += 5; + } else if (std.mem.startsWith(u8, input[i..], ")")) { + try output.append(')'); + i += 5; + } else if (std.mem.startsWith(u8, input[i..], "+")) { + try output.append('+'); + i += 5; + } else if (std.mem.startsWith(u8, input[i..], ",")) { + try output.append(','); + i += 5; + } else if (std.mem.startsWith(u8, input[i..], ".")) { + try output.append('.'); + i += 5; + } else if (std.mem.startsWith(u8, input[i..], "/")) { + try output.append('/'); + i += 5; + } else if (std.mem.startsWith(u8, input[i..], ":")) { + try output.append(':'); + i += 5; + } else if (std.mem.startsWith(u8, input[i..], ";")) { + try output.append(';'); + i += 5; + } else { + try output.append(input[i]); + i += 1; + } + } + + return output.toOwnedSlice(); +} diff --git a/frameworks/Zig/zap/src/main.zig b/frameworks/Zig/zap/src/main.zig new file mode 100644 index 00000000000..e2792726f04 --- /dev/null +++ b/frameworks/Zig/zap/src/main.zig @@ -0,0 +1,110 @@ +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; + +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(); + + var zap_port: []u8 = undefined; + var arg_string = try std.fmt.allocPrint(allocator, "{s}", .{"0"}); + defer allocator.free(arg_string); + + var args = try std.process.argsWithAllocator(allocator); + defer args.deinit(); + while (args.next()) |arg| { + arg_string = try std.fmt.allocPrint(allocator, "{s}", .{arg}); + + zap_port = arg_string; // use arg + } + + var port = try std.fmt.parseInt(u16, zap_port, 0); + + if (port == 0) { + port = 3000; + } + + var pg_pool = try pool.initPool(allocator); + defer pg_pool.deinit(); + + var prng = std.rand.DefaultPrng.init(@as(u64, @bitCast(std.time.milliTimestamp()))); + + middleware.SharedAllocator.init(allocator); + + // create the endpoint + 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. + ); + + var plaintextEndpointHandler = zap.Middleware.EndpointHandler(middleware.Handler, middleware.Context).init( + plaintextEndpoint.endpoint(), + jsonEndpointHandler.getHandler(), + false, + ); + + 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 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 headerHandler = middleware.HeaderMiddleWare.init(dbEndpointHandler.getHandler()); + var prngHandler = middleware.RandomMiddleWare.init(headerHandler.getHandler(), &prng); + var pgHandler = middleware.PgMiddleWare.init(prngHandler.getHandler(), pg_pool); + + var listener = try zap.Middleware.Listener(middleware.Context).init( + .{ + .on_request = null, // must be 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}); + + // start worker threads + zap.start(.{ + .threads = threads, + .workers = 1, + }); +} diff --git a/frameworks/Zig/zap/src/middleware.zig b/frameworks/Zig/zap/src/middleware.zig new file mode 100644 index 00000000000..99fb9255c0c --- /dev/null +++ b/frameworks/Zig/zap/src/middleware.zig @@ -0,0 +1,129 @@ +const std = @import("std"); +const zap = @import("zap"); +const pg = @import("pg"); + +// just a way to share our allocator via callback +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; + } + + // static function we can pass to the listener later + pub fn getAllocator() std.mem.Allocator { + return allocator; + } +}; + +// create a combined context struct +pub const Context = struct { + prng: ?RandomMiddleWare.Prng = null, + pg: ?PgMiddleWare.Pg = null, +}; + +pub const Handler = zap.Middleware.Handler(Context); + +pub const HeaderMiddleWare = struct { + handler: Handler, + + const Self = @This(); + + pub fn init(other: ?*Handler) Self { + return .{ + .handler = Handler.init(onRequest, other), + }; + } + + // we need the handler as a common interface to chain stuff + pub fn getHandler(self: *Self) *Handler { + return &self.handler; + } + + // note that the first parameter is of type *Handler, not *Self !!! + 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; + + // continue in the chain + return handler.handleOther(req, context); + } +}; + +pub const RandomMiddleWare = struct { + handler: Handler, + rnd: *std.rand.DefaultPrng, + + const Self = @This(); + + const Prng = struct { + rnd: *std.rand.DefaultPrng = undefined, + }; + + pub fn init(other: ?*Handler, rnd: *std.rand.DefaultPrng) Self { + return .{ + .handler = Handler.init(onRequest, other), + .rnd = rnd, + }; + } + + // we need the handler as a common interface to chain stuff + pub fn getHandler(self: *Self) *Handler { + return &self.handler; + } + + // note that the first parameter is of type *Handler, not *Self !!! + 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); + + context.prng = Prng{ .rnd = self.rnd }; + + // continue in the chain + return handler.handleOther(req, context); + } +}; + +pub const PgMiddleWare = struct { + handler: Handler, + pool: *pg.Pool, + + const Self = @This(); + + const Pg = struct { + pool: *pg.Pool = undefined, + }; + + pub fn init(other: ?*Handler, pool: *pg.Pool) Self { + return .{ + .handler = Handler.init(onRequest, other), + .pool = pool, + }; + } + + // we need the handler as a common interface to chain stuff + pub fn getHandler(self: *Self) *Handler { + return &self.handler; + } + + // note that the first parameter is of type *Handler, not *Self !!! + 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); + + // do our work: fill in the user field of the context + context.pg = Pg{ .pool = self.pool }; + + // continue in the chain + return handler.handleOther(req, context); + } +}; diff --git a/frameworks/Zig/zap/src/pool.zig b/frameworks/Zig/zap/src/pool.zig new file mode 100644 index 00000000000..6615ae217ce --- /dev/null +++ b/frameworks/Zig/zap/src/pool.zig @@ -0,0 +1,89 @@ +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, + .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/zap/start-servers.sh b/frameworks/Zig/zap/start-servers.sh new file mode 100644 index 00000000000..b5cf175de41 --- /dev/null +++ b/frameworks/Zig/zap/start-servers.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +CPU_COUNT=$(nproc) +P=3000 +END=$(($P+$CPU_COUNT)) + +while [ $P -lt $END ]; do + zap $P & + let P=P+1 +done diff --git a/frameworks/Zig/zap/zap.dockerfile b/frameworks/Zig/zap/zap.dockerfile new file mode 100644 index 00000000000..71123f4f3e7 --- /dev/null +++ b/frameworks/Zig/zap/zap.dockerfile @@ -0,0 +1,30 @@ +FROM fedora:40 AS build + +WORKDIR /zap + +ENV PG_USER=benchmarkdbuser +ENV PG_PASS=benchmarkdbpass +ENV PG_DB=hello_world +ENV PG_HOST=tfb-database +ENV PG_PORT=5432 + +COPY src src +COPY build.zig.zon build.zig.zon +COPY build.zig build.zig +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 dnf install -y zig nginx +RUN zig version +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 diff --git a/frameworks/Zig/zinc/.gitignore b/frameworks/Zig/zinc/.gitignore new file mode 100644 index 00000000000..170dc0f1403 --- /dev/null +++ b/frameworks/Zig/zinc/.gitignore @@ -0,0 +1,2 @@ +zig-cache/**/*', +zig-out: 'zig-out/**/*', diff --git a/frameworks/Zig/zinc/README.md b/frameworks/Zig/zinc/README.md new file mode 100755 index 00000000000..acf0f93bbcb --- /dev/null +++ b/frameworks/Zig/zinc/README.md @@ -0,0 +1,32 @@ +# [Zinc](https://zinc.zon.dev) web framework + +## Description + +Zinc is a web framework written in pure Zig with a focus on high performance, usability, security, and extensibility. + +* [Documentation](https://zinc.zon.dev/) + +### Some features are: +- **Fast** +- **Custom allocator** +- **Multithreading** +- **Middleware** +- **Routes grouping** +- **Rendering built-in** +- **Extensible** +- **Suite of unit tests** +- **Usability** + +## Important Libraries +The tests were run with: +* [Software](https://zinc.zon.dev/) +* [Example](https://github.com/zon-dev/zinc-examples) + +## Test URLs +### JSON + +http://localhost:8080/json + +### PLAINTEXT + +http://localhost:8080/plaintext diff --git a/frameworks/Zig/zinc/benchmark_config.json b/frameworks/Zig/zinc/benchmark_config.json new file mode 100755 index 00000000000..2e2e874ba2d --- /dev/null +++ b/frameworks/Zig/zinc/benchmark_config.json @@ -0,0 +1,26 @@ +{ + "framework": "zinc", + "tests": [ + { + "default": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 3000, + "approach": "Realistic", + "classification": "Fullstack", + "database": "None", + "framework": "Zinc", + "language": "Zig", + "flavor": "None", + "orm": "None", + "platform": "None", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "Zinc", + "notes": "", + "versus": "None" + } + } + ] +} diff --git a/frameworks/Zig/zinc/build.zig b/frameworks/Zig/zinc/build.zig new file mode 100644 index 00000000000..e5be63940e5 --- /dev/null +++ b/frameworks/Zig/zinc/build.zig @@ -0,0 +1,78 @@ +const std = @import("std"); + +// 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. + const target = b.standardTargetOptions(.{}); + + // Standard optimization options allow the person running `zig build` to select + // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not + // set a preferred release mode, allowing the user to decide how to optimize. + const optimize = b.standardOptimizeOption(.{}); + + const exe = b.addExecutable(.{ + .name = "zinc", + .root_source_file = b.path("src/main.zig"), + .target = target, + .optimize = optimize, + }); + + const zinc = b.dependency("zinc", .{ + .target = target, + .optimize = optimize, + }); + exe.root_module.addImport("zinc", zinc.module("zinc")); + + const datetime = b.dependency("zig-datetime", .{ + .target = target, + .optimize = optimize, + }); + exe.root_module.addImport("datetime", datetime.module("zig-datetime")); + + // 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); + + const exe_unit_tests = b.addTest(.{ + .root_source_file = b.path("src/main.zig"), + .target = target, + .optimize = optimize, + }); + + const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests); + + // Similar to creating the run step earlier, this exposes a `test` step to + // the `zig build --help` menu, providing a way for the user to request + // running the unit tests. + const test_step = b.step("test", "Run unit tests"); + test_step.dependOn(&run_exe_unit_tests.step); +} diff --git a/frameworks/Zig/zinc/build.zig.zon b/frameworks/Zig/zinc/build.zig.zon new file mode 100644 index 00000000000..9a4c8f302cf --- /dev/null +++ b/frameworks/Zig/zinc/build.zig.zon @@ -0,0 +1,27 @@ +.{ + .name = "zinc", + .version = "0.1.0", + .dependencies = .{ + .zinc = .{ + .url = "https://github.com/zon-dev/zinc/archive/refs/tags/0.1.0-beta.5.tar.gz", + .hash = "12201444aa36b4a83f262f319e7c17ccdcff9fbde2efbeb5fc94f1a07eda0d99428e", + }, + .@"zig-datetime" = .{ + .url = "git+https://github.com/frmdstryr/zig-datetime#70aebf28fb3e137cd84123a9349d157a74708721", + .hash = "122077215ce36e125a490e59ec1748ffd4f6ba00d4d14f7308978e5360711d72d77f", + }, + .pg = .{ + .url = "git+https://github.com/karlseguin/pg.zig#21db2306aff657802f9cb10a1e7f8fe9c33e7990", + .hash = "1220df8995ceea78a4a37a505fc779ded75725d0606c33fded26103953524dde1619", + }, + .mustache = .{ + .url = "git+https://github.com/batiati/mustache-zig#ac358646ab9e6123285b90c947ecd40f7966d531", + .hash = "1220cd6e1b49bdd0a568682957dab9a6864554755908f7de990ec7c050f58cf41da2", + }, + }, + .paths = .{ + "build.zig", + "build.zig.zon", + "src", + }, +} diff --git a/frameworks/Zig/zinc/run.sh b/frameworks/Zig/zinc/run.sh new file mode 100644 index 00000000000..639c542fc3e --- /dev/null +++ b/frameworks/Zig/zinc/run.sh @@ -0,0 +1,3 @@ +echo "Waiting for Zinc framework to start..." + +zinc \ No newline at end of file diff --git a/frameworks/Zig/zinc/src/main.zig b/frameworks/Zig/zinc/src/main.zig new file mode 100644 index 00000000000..f06104dc4f1 --- /dev/null +++ b/frameworks/Zig/zinc/src/main.zig @@ -0,0 +1,43 @@ +const std = @import("std"); +const zinc = @import("zinc"); +const Datetime = @import("datetime").datetime.Datetime; + +pub fn main() !void { + var gpa = std.heap.GeneralPurposeAllocator(.{ .thread_safe = true }){}; + defer _ = gpa.deinit(); + const allocator = gpa.allocator(); + + var z = try zinc.init(.{ + .port = 3000, + .allocator = allocator, + .num_threads = 16 * @as(u8, @intCast(std.Thread.getCpuCount() catch 1)), + }); + defer z.deinit(); + + var router = z.getRouter(); + try router.use(&.{setupHeader}); + try router.get("/json", json); + try router.get("/plaintext", plaintext); + + try z.run(); +} + +fn plaintext(ctx: *zinc.Context) anyerror!void { + try ctx.setHeader("Content-Type", "text/plain; charset=utf-8"); + try ctx.setBody("Hello, world!"); +} + +fn json(ctx: *zinc.Context) anyerror!void { + try ctx.json(.{ .message = "Hello, World!" }, .{}); +} + +fn setupHeader(ctx: *zinc.Context) anyerror!void { + try ctx.setHeader("Server", "Zinc"); + + const now = Datetime.now(); + const now_str = try now.formatHttp(ctx.allocator); + // defer ctx.allocator.free(now_str); + + // The time is now: Fri, 20 Dec 2019 22:03:02 UTC + try ctx.setHeader("date", now_str); +} diff --git a/frameworks/Zig/zinc/zinc.dockerfile b/frameworks/Zig/zinc/zinc.dockerfile new file mode 100644 index 00000000000..11b64881d2c --- /dev/null +++ b/frameworks/Zig/zinc/zinc.dockerfile @@ -0,0 +1,21 @@ +FROM fedora:40 AS build + +WORKDIR /zinc + +COPY src src +COPY run.sh run.sh + +COPY build.zig.zon build.zig.zon +COPY build.zig build.zig + +RUN dnf install -y zig +RUN zig version +RUN zig build -Doptimize=ReleaseFast +RUN cp /zinc/zig-out/bin/zinc /usr/local/bin + +EXPOSE 3000 +ARG BENCHMARK_ENV +ARG TFB_TEST_DATABASE +ARG TFB_TEST_NAME + +CMD ["sh", "run.sh"] diff --git a/frameworks/Zig/zzz/.gitignore b/frameworks/Zig/zzz/.gitignore new file mode 100644 index 00000000000..4d2782fa13c --- /dev/null +++ b/frameworks/Zig/zzz/.gitignore @@ -0,0 +1,2 @@ +.zig-out +.zig-cache diff --git a/frameworks/Zig/zzz/README.md b/frameworks/Zig/zzz/README.md new file mode 100644 index 00000000000..cf8c5c06ce2 --- /dev/null +++ b/frameworks/Zig/zzz/README.md @@ -0,0 +1,18 @@ + +# [ZZZ](https://github.com/tardy-org/zzz) - Web Framework. + +## Description + +ZZZ is a framework for writing performant and reliable networked services in Zig. It supports both HTTP and HTTPS. + +## Test URLs + +### Test 1: JSON Encoding + + http://localhost:8080/json + +### Test 2: Plaintext + + http://localhost:8080/plaintext + + diff --git a/frameworks/Zig/zzz/benchmark_config.json b/frameworks/Zig/zzz/benchmark_config.json new file mode 100644 index 00000000000..84a86305ebe --- /dev/null +++ b/frameworks/Zig/zzz/benchmark_config.json @@ -0,0 +1,24 @@ +{ + "framework": "zzz", + "tests": [{ + "default": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "None", + "framework": "zzz", + "language": "Zig", + "flavor": "None", + "orm": "None", + "platform": "None", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "ZZZ (Zig)", + "notes": "", + "versus": "" + } + }] +} diff --git a/frameworks/Zig/zzz/build.zig b/frameworks/Zig/zzz/build.zig new file mode 100644 index 00000000000..44345668450 --- /dev/null +++ b/frameworks/Zig/zzz/build.zig @@ -0,0 +1,22 @@ +const std = @import("std"); + +pub fn build(b: *std.Build) void { + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); + const root_source_file = b.path("src/main.zig"); + + const zzz = b.dependency("zzz", .{ + .target = target, + .optimize = optimize, + }); + + const exe = b.addExecutable(.{ + .name = "zzz", + .target = target, + .optimize = optimize, + .root_source_file = root_source_file, + .strip = true, + }); + exe.root_module.addImport("zzz", zzz.module("zzz")); + b.installArtifact(exe); +} diff --git a/frameworks/Zig/zzz/build.zig.zon b/frameworks/Zig/zzz/build.zig.zon new file mode 100644 index 00000000000..58f2a17b2b1 --- /dev/null +++ b/frameworks/Zig/zzz/build.zig.zon @@ -0,0 +1,17 @@ +.{ + .name = .zzz_bench, + .version = "0.0.0", + .fingerprint = 0xab2ef1c28b2bcc91, + .minimum_zig_version = "0.14.0", + .dependencies = .{ + .zzz = .{ + .url = "git+https://github.com/tardy-org/zzz#18ec7f1129ce4d0573b7c67f011b4d05c7b195d4", + .hash = "zzz-0.3.0-4HoaJrBQAgCXB_66nre0nvYZmAXMxj__gS8sFjpR68Hs", + }, + }, + .paths = .{ + "src/", + "build.zig", + "build.zig.zon", + }, +} diff --git a/frameworks/Zig/zzz/src/main.zig b/frameworks/Zig/zzz/src/main.zig new file mode 100644 index 00000000000..bfe20def8a0 --- /dev/null +++ b/frameworks/Zig/zzz/src/main.zig @@ -0,0 +1,114 @@ +const std = @import("std"); +const builtin = @import("builtin"); +const zzz = @import("zzz"); +const http = zzz.HTTP; +const tardy = zzz.tardy; +const Tardy = tardy.Tardy(.auto); +const Runtime = tardy.Runtime; +const Socket = tardy.Socket; +const Server = http.Server; +const Router = http.Router; +const Context = http.Context; +const Route = http.Route; +const Respond = http.Respond; + +const Message = struct { message: []const u8 }; +var date: [29]u8 = undefined; + +pub fn main() !void { + const host: []const u8 = "0.0.0.0"; + const port: u16 = 8080; + + var gpa = std.heap.GeneralPurposeAllocator(.{}){}; + + const allocator, const is_debug = switch (builtin.mode) { + .Debug, .ReleaseSafe => .{ gpa.allocator(), true }, + .ReleaseSmall, .ReleaseFast => .{ std.heap.smp_allocator, false }, + }; + + defer { + if (is_debug and gpa.deinit() == .leak) { + @panic("Memory leak has occurred!"); + } + } + + var t = try Tardy.init(allocator, .{ + .threading = .all, + }); + defer t.deinit(); + + var router = try Router.init(allocator, &.{ + Route.init("/plaintext").get({}, homeHandler).layer(), + Route.init("/json").get({}, jsonHandler).layer(), + }, .{}); + defer router.deinit(allocator); + + var socket = try Socket.init(.{ .tcp = .{ .host = host, .port = port } }); + defer socket.close_blocking(); + try socket.bind(); + try socket.listen(4096); + + const EntryParams = struct { + router: *const Router, + socket: Socket, + }; + + try t.entry( + EntryParams{ .router = &router, .socket = socket }, + struct { + fn entry(rt: *Runtime, p: EntryParams) !void { + if (rt.id == 0) try rt.spawn(.{rt}, updateDate, 1024 * 1024 * 4); + var server = Server.init(.{ + .capture_count_max = 0, + }); + try server.serve(rt, p.router, .{ .normal = p.socket }); + } + }.entry, + ); +} + +pub fn homeHandler(ctx: *const Context, _: void) !Respond { + return ctx.response.apply(.{ + .mime = http.Mime.TEXT, + .body = "Hello, World!", + .status = .OK, + .headers = &.{ + .{ "Date", try ctx.allocator.dupe(u8, date[0..]) }, + }, + }); +} + +pub fn jsonHandler(ctx: *const Context, _: void) !Respond { + return ctx.response.apply(.{ + .mime = http.Mime.JSON, + .body = try std.json.stringifyAlloc(ctx.allocator, Message{ .message = "Hello, World!" }, .{}), + .status = .OK, + .headers = &.{ + .{ "Date", try ctx.allocator.dupe(u8, date[0..]) }, + }, + }); +} + +pub fn updateDate(rt: *Runtime) !void { + const format = std.fmt.comptimePrint( + "{s}, {s} {s} {s} {s}:{s}:{s} GMT", + .{ + "{[day_name]s}", + "{[day]d:0>2}", + "{[month]s}", + "{[year]d}", + "{[hour]d:0>2}", + "{[minute]d:0>2}", + "{[second]d:0>2}", + }, + ); + while (true) { + var d = http.Date.init(std.time.timestamp()); + + const http_date = d.to_http_date(); + + _ = try std.fmt.bufPrint(&date, format, http_date); + + try tardy.Timer.delay(rt, .{ .nanos = std.time.ns_per_ms * 900 }); + } +} diff --git a/frameworks/Zig/zzz/zzz.dockerfile b/frameworks/Zig/zzz/zzz.dockerfile new file mode 100644 index 00000000000..514196a7497 --- /dev/null +++ b/frameworks/Zig/zzz/zzz.dockerfile @@ -0,0 +1,37 @@ +FROM debian:12-slim AS build + +RUN useradd -m ziguser + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + wget xz-utils \ + ca-certificates && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* + +ARG ZIG_VER=0.14.0 +RUN wget https://ziglang.org/download/${ZIG_VER}/zig-linux-$(uname -m)-${ZIG_VER}.tar.xz + +RUN tar -xvf zig-linux-$(uname -m)-${ZIG_VER}.tar.xz + +RUN mv zig-linux-$(uname -m)-${ZIG_VER} /usr/local/zig + +ENV PATH="/usr/local/zig:$PATH" + +WORKDIR /home/ziguser +COPY src src +COPY build.zig build.zig +COPY build.zig.zon build.zig.zon + +USER ziguser + +RUN zig build -Doptimize=ReleaseFast -Dcpu=native + +FROM debian:12-slim + +RUN apt-get -qq update +RUN apt-get -qy install ca-certificates + +COPY --from=build /home/ziguser/zig-out/bin/zzz /server +EXPOSE 8080 +ENTRYPOINT ./server diff --git a/toolset/__init__.py b/toolset/__init__.py old mode 100755 new mode 100644 diff --git a/toolset/benchmark/benchmarker.py b/toolset/benchmark/benchmarker.py index 3d6f1533ced..edf66ce24d4 100644 --- a/toolset/benchmark/benchmarker.py +++ b/toolset/benchmark/benchmarker.py @@ -1,3 +1,6 @@ +import threading + +from docker.models.containers import Container from toolset.utils.output_helper import log, FNULL from toolset.utils.docker_helper import DockerHelper from toolset.utils.time_logger import TimeLogger @@ -29,12 +32,11 @@ def __init__(self, config): # a list of all tests for this run self.tests = self.metadata.tests_to_run() - + if self.config.reverse_order: + self.tests.reverse() self.results = Results(self) self.docker_helper = DockerHelper(self) - self.last_test = False - ########################################################################################## # Public methods ########################################################################################## @@ -60,8 +62,6 @@ def run(self): with open(os.path.join(self.results.directory, 'benchmark.log'), 'w') as benchmark_log: for test in self.tests: - if self.tests.index(test) + 1 == len(self.tests): - self.last_test = True log("Running Test: %s" % test.name, border='-') with self.config.quiet_out.enable(): if not self.__run_test(test, benchmark_log): @@ -97,13 +97,17 @@ def __exit_test(self, success, prefix, file, message=None): color=Fore.RED if success else '') self.time_logger.log_test_end(log_prefix=prefix, file=file) if self.config.mode == "benchmark": - # Sleep for 60 seconds to ensure all host connects are closed - log("Clean up: Sleep 60 seconds...", prefix=prefix, file=file) - time.sleep(60) + total_tcp_sockets = subprocess.check_output("ss -s | grep TCP: | awk '{print $2}'", shell=True, text=True) + log("Total TCP sockets: " + total_tcp_sockets, prefix=prefix, file=file) + + if int(total_tcp_sockets) > 5000: + # Sleep for 60 seconds to ensure all host connects are closed + log("Clean up: Sleep 60 seconds...", prefix=prefix, file=file) + time.sleep(60) + # After benchmarks are complete for all test types in this test, # let's clean up leftover test images (techempower/tfb.test.test-name) self.docker_helper.clean() - return success def __run_test(self, test, benchmark_log): @@ -262,12 +266,6 @@ def benchmark_type(test_type): log("BENCHMARKING %s ... " % test_type.upper(), file=benchmark_log) test = framework_test.runTests[test_type] - raw_file = self.results.get_raw_file(framework_test.name, - test_type) - if not os.path.exists(raw_file): - # Open to create the empty file - with open(raw_file, 'w'): - pass if not test.failed: # Begin resource usage metrics collection @@ -280,8 +278,8 @@ def benchmark_type(test_type): framework_test.port, test.get_url())) - self.docker_helper.benchmark(script, script_variables, - raw_file) + benchmark_container = self.docker_helper.benchmark(script, script_variables) + self.__log_container_output(benchmark_container, framework_test, test_type) # End resource usage metrics collection self.__end_logging() @@ -322,3 +320,31 @@ def __end_logging(self): self.subprocess_handle.terminate() self.subprocess_handle.communicate() + def __log_container_output(self, container: Container, framework_test, test_type) -> None: + def save_docker_logs(stream): + raw_file_path = self.results.get_raw_file(framework_test.name, test_type) + with open(raw_file_path, 'w') as file: + for line in stream: + log(line.decode(), file=file) + + def save_docker_stats(stream): + docker_file_path = self.results.get_docker_stats_file(framework_test.name, test_type) + with open(docker_file_path, 'w') as file: + file.write('[\n') + is_first_line = True + for line in stream: + if is_first_line: + is_first_line = False + else: + file.write(',') + file.write(line.decode()) + file.write(']') + + threads = [ + threading.Thread(target=lambda: save_docker_logs(container.logs(stream=True))), + threading.Thread(target=lambda: save_docker_stats(container.stats(stream=True))) + ] + + [thread.start() for thread in threads] + [thread.join() for thread in threads] + diff --git a/toolset/continuous/tfb-shutdown.sh b/toolset/continuous/tfb-shutdown.sh old mode 100644 new mode 100755 diff --git a/toolset/continuous/tfb-startup.sh b/toolset/continuous/tfb-startup.sh old mode 100644 new mode 100755 index 6a92e506f97..438f3deba51 --- a/toolset/continuous/tfb-startup.sh +++ b/toolset/continuous/tfb-startup.sh @@ -20,6 +20,14 @@ git clone \ echo "moving to tfb directory" cd $TFB_REPOPARENT/$TFB_REPONAME +if [ -e "${TFB_REPOPARENT}/tfb-reverse-order" ]; then + export TFB_RUN_ORDER="reverse" + sudo rm -rf "${TFB_REPOPARENT}/tfb-reverse-order" +else + unset TFB_RUN_ORDER + touch "${TFB_REPOPARENT}/tfb-reverse-order" +fi + echo "building tfb docker image" docker build -t techempower/tfb \ --build-arg USER_ID=$(id -u) \ @@ -38,6 +46,7 @@ docker run \ --results-name "$TFB_RUN_NAME" \ --results-environment "$TFB_ENVIRONMENT" \ --results-upload-uri "$TFB_UPLOAD_URI" \ + $(if [ "$TFB_RUN_ORDER" = "reverse" ]; then echo "--reverse-order"; fi) \ --quiet echo "zipping the results" diff --git a/toolset/databases/__init__.py b/toolset/databases/__init__.py index c70a972bf9e..e474436b3ec 100644 --- a/toolset/databases/__init__.py +++ b/toolset/databases/__init__.py @@ -1,4 +1,4 @@ -import imp +import importlib import re from colorama import Fore @@ -14,14 +14,16 @@ # regex that grabs the characters between "toolset/database/" # and the final "/" in the db folder string to get the db name db_name = re.findall(r'.+\/(.+)\/$', folder, re.M)[0] - # ignore generate __pycache__ folder + # ignore generated __pycache__ folder if db_name == '__pycache__': continue - db = imp.load_source("Database", "%s%s.py" % (folder, db_name)) + spec = importlib.util.spec_from_file_location("Database", "%s%s.py" % (folder, db_name)) + db = importlib.util.module_from_spec(spec) + spec.loader.exec_module(db) if not hasattr(db.Database, "get_current_world_table")\ or not hasattr(db.Database, "test_connection"): - log("Database %s does not implement the required methods" + db_name, + log("Database %s does not implement the required methods" % (db_name), color=Fore.RED) databases[db_name] = db.Database diff --git a/toolset/databases/abstract_database.py b/toolset/databases/abstract_database.py index 8f7b4d83e2c..27be6107edb 100644 --- a/toolset/databases/abstract_database.py +++ b/toolset/databases/abstract_database.py @@ -11,7 +11,7 @@ class AbstractDatabase: ''' #margin of tolerance on the results (rows read or updated only) margin = 1.011 - + @classmethod @abc.abstractmethod def get_connection(cls, config): @@ -94,13 +94,13 @@ def verify_queries(cls, config, table_name, url, concurrency=512, count=2, check process = subprocess.run(shlex.split( "siege -c %s -r %s %s -R %s/.siegerc" % (concurrency, count, url, path)), stdout = subprocess.PIPE, stderr = subprocess.STDOUT, timeout=20, text=True - ) + ) except subprocess.TimeoutExpired as e: print("Verification failed: %s" % (e)) else: output = process.stdout #Search for failed transactions - match = re.search('Failed transactions:.*?(\d+)\n', output, re.MULTILINE) + match = re.search(r'Failed transactions:.*?(\d+)\n', output, re.MULTILINE) if match: trans_failures = int(match.group(1)) print(output) diff --git a/toolset/databases/mongodb/create.js b/toolset/databases/mongodb/create.js index c34e2530232..2ef4f9f589a 100644 --- a/toolset/databases/mongodb/create.js +++ b/toolset/databases/mongodb/create.js @@ -1,4 +1,3 @@ -disableTelemetry() db = db.getSiblingDB('hello_world') db.world.drop() for (var i = 1; i <= 10000; i++) { diff --git a/toolset/databases/mongodb/mongodb.dockerfile b/toolset/databases/mongodb/mongodb.dockerfile index 1dc7f21cca7..11480684535 100644 --- a/toolset/databases/mongodb/mongodb.dockerfile +++ b/toolset/databases/mongodb/mongodb.dockerfile @@ -1,4 +1,4 @@ -FROM mongo:6.0 +FROM mongo:8.0 ENV MONGO_INITDB_DATABASE=hello_world diff --git a/toolset/databases/mongodb/mongodb.py b/toolset/databases/mongodb/mongodb.py index 0fdc005bbf5..f6ddcad3b29 100644 --- a/toolset/databases/mongodb/mongodb.py +++ b/toolset/databases/mongodb/mongodb.py @@ -1,3 +1,4 @@ +import bson import pymongo import traceback @@ -44,7 +45,7 @@ def test_connection(cls, config): connection = cls.get_connection(config) db = connection.hello_world db.world.find() - db.close() + connection.close() return True except: return False @@ -52,19 +53,19 @@ def test_connection(cls, config): @classmethod def get_queries(cls, config): co = cls.get_connection(config) - status = co.admin.command(pymongo.son_manipulator.SON([('serverStatus', 1)])) + status = co.admin.command(bson.son.SON([('serverStatus', 1)])) return int(status["opcounters"]["query"]) + int(status["opcounters"]["update"]) #get_queries returns all the queries @classmethod def get_rows(cls, config): co = cls.get_connection(config) - status = co.admin.command(pymongo.son_manipulator.SON([('serverStatus', 1)])) + status = co.admin.command(bson.son.SON([('serverStatus', 1)])) return int(status["opcounters"]["query"]) * cls.get_rows_per_query(co) @classmethod def get_rows_updated(cls, config): co = cls.get_connection(config) - status = co.admin.command(pymongo.son_manipulator.SON([('serverStatus', 1)])) + status = co.admin.command(bson.son.SON([('serverStatus', 1)])) return int(status["opcounters"]["update"]) * cls.get_rows_per_query(co) @classmethod diff --git a/toolset/databases/mysql/create.sql b/toolset/databases/mysql/create.sql index 94cb995deb3..d97fb37f490 100644 --- a/toolset/databases/mysql/create.sql +++ b/toolset/databases/mysql/create.sql @@ -2,14 +2,14 @@ # http://stackoverflow.com/questions/37719818/the-server-time-zone-value-aest-is-unrecognized-or-represents-more-than-one-ti SET GLOBAL time_zone = '+00:00'; -CREATE USER IF NOT EXISTS 'benchmarkdbuser'@'%' IDENTIFIED WITH mysql_native_password BY 'benchmarkdbpass'; -CREATE USER IF NOT EXISTS 'benchmarkdbuser'@'localhost' IDENTIFIED WITH mysql_native_password BY 'benchmarkdbpass'; +CREATE USER IF NOT EXISTS 'benchmarkdbuser'@'%' IDENTIFIED WITH caching_sha2_password BY 'benchmarkdbpass'; +CREATE USER IF NOT EXISTS 'benchmarkdbuser'@'localhost' IDENTIFIED WITH caching_sha2_password BY 'benchmarkdbpass'; -- GitHub Actions/CI run the database server on the same system as the benchmarks. -- Because we setup MySQL with the skip-name-resolve option, the IP address 127.0.0.1 might not be resolved to localhost -- anymore. This does not seem to matter, as long as Unix sockets are being used (e.g. when setting up the docker image), -- because the host is set to be localhost implicitly, but it matters for local TCP connections. -CREATE USER IF NOT EXISTS 'benchmarkdbuser'@'127.0.0.1' IDENTIFIED WITH mysql_native_password BY 'benchmarkdbpass'; +CREATE USER IF NOT EXISTS 'benchmarkdbuser'@'127.0.0.1' IDENTIFIED WITH caching_sha2_password BY 'benchmarkdbpass'; # modified from SO answer http://stackoverflow.com/questions/5125096/for-loop-in-mysql CREATE DATABASE IF NOT EXISTS hello_world; diff --git a/toolset/databases/mysql/my.cnf b/toolset/databases/mysql/my.cnf index 9cf0b18c5e1..e1a401ae2d9 100644 --- a/toolset/databases/mysql/my.cnf +++ b/toolset/databases/mysql/my.cnf @@ -16,7 +16,8 @@ default-character-set=utf8 # * Basic Settings # default-storage-engine = innodb -default_authentication_plugin = mysql_native_password +#mysql_native_password = ON # disabled in v9 +#default_authentication_plugin = mysql_native_password user = mysql pid-file = /var/run/mysqld/mysqld.pid diff --git a/toolset/databases/mysql/mysql.dockerfile b/toolset/databases/mysql/mysql.dockerfile index 01a58b4234c..b5c5b6a67bb 100644 --- a/toolset/databases/mysql/mysql.dockerfile +++ b/toolset/databases/mysql/mysql.dockerfile @@ -1,4 +1,4 @@ -FROM mysql:8.0 +FROM mysql:9.0 ENV MYSQL_ROOT_PASSWORD=root ENV MYSQL_USER=benchmarkdbuser diff --git a/toolset/databases/postgres/config.sh b/toolset/databases/postgres/config.sh old mode 100644 new mode 100755 index ba42d10eec9..ea3d95e4b7c --- a/toolset/databases/postgres/config.sh +++ b/toolset/databases/postgres/config.sh @@ -1 +1,5 @@ -cat /tmp/postgresql.conf >> $PGDATA/postgresql.conf +#!/bin/bash + +set -e + +cat /tmp/postgresql.conf >> "${PGDATA}/postgresql.conf" diff --git a/toolset/databases/postgres/create-postgres-database.sql b/toolset/databases/postgres/create-postgres-database.sql deleted file mode 100644 index 9a8a08ec2ab..00000000000 --- a/toolset/databases/postgres/create-postgres-database.sql +++ /dev/null @@ -1,5 +0,0 @@ -CREATE USER benchmarkdbuser WITH PASSWORD 'benchmarkdbpass'; - -ALTER USER benchmarkdbuser WITH SUPERUSER; - -CREATE DATABASE hello_world WITH TEMPLATE = template0 ENCODING 'UTF8'; diff --git a/toolset/databases/postgres/pg_hba.conf b/toolset/databases/postgres/pg_hba.conf deleted file mode 100644 index ac4b3621dc2..00000000000 --- a/toolset/databases/postgres/pg_hba.conf +++ /dev/null @@ -1,100 +0,0 @@ -# PostgreSQL Client Authentication Configuration File -# =================================================== -# -# Refer to the "Client Authentication" section in the PostgreSQL -# documentation for a complete description of this file. A short -# synopsis follows. -# -# This file controls: which hosts are allowed to connect, how clients -# are authenticated, which PostgreSQL user names they can use, which -# databases they can access. Records take one of these forms: -# -# local DATABASE USER METHOD [OPTIONS] -# host DATABASE USER ADDRESS METHOD [OPTIONS] -# hostssl DATABASE USER ADDRESS METHOD [OPTIONS] -# hostnossl DATABASE USER ADDRESS METHOD [OPTIONS] -# -# (The uppercase items must be replaced by actual values.) -# -# The first field is the connection type: "local" is a Unix-domain -# socket, "host" is either a plain or SSL-encrypted TCP/IP socket, -# "hostssl" is an SSL-encrypted TCP/IP socket, and "hostnossl" is a -# plain TCP/IP socket. -# -# DATABASE can be "all", "sameuser", "samerole", "replication", a -# database name, or a comma-separated list thereof. The "all" -# keyword does not match "replication". Access to replication -# must be enabled in a separate record (see example below). -# -# USER can be "all", a user name, a group name prefixed with "+", or a -# comma-separated list thereof. In both the DATABASE and USER fields -# you can also write a file name prefixed with "@" to include names -# from a separate file. -# -# ADDRESS specifies the set of hosts the record matches. It can be a -# host name, or it is made up of an IP address and a CIDR mask that is -# an integer (between 0 and 32 (IPv4) or 128 (IPv6) inclusive) that -# specifies the number of significant bits in the mask. A host name -# that starts with a dot (.) matches a suffix of the actual host name. -# Alternatively, you can write an IP address and netmask in separate -# columns to specify the set of hosts. Instead of a CIDR-address, you -# can write "samehost" to match any of the server's own IP addresses, -# or "samenet" to match any address in any subnet that the server is -# directly connected to. -# -# METHOD can be "trust", "reject", "md5", "password", "gss", "sspi", -# "krb5", "ident", "peer", "pam", "ldap", "radius" or "cert". Note that -# "password" sends passwords in clear text; "md5" is preferred since -# it sends encrypted passwords. -# -# OPTIONS are a set of options for the authentication in the format -# NAME=VALUE. The available options depend on the different -# authentication methods -- refer to the "Client Authentication" -# section in the documentation for a list of which options are -# available for which authentication methods. -# -# Database and user names containing spaces, commas, quotes and other -# special characters must be quoted. Quoting one of the keywords -# "all", "sameuser", "samerole" or "replication" makes the name lose -# its special character, and just match a database or username with -# that name. -# -# This file is read on server startup and when the postmaster receives -# a SIGHUP signal. If you edit the file on a running system, you have -# to SIGHUP the postmaster for the changes to take effect. You can -# use "pg_ctl reload" to do that. - -# Put your actual configuration here -# ---------------------------------- -# -# If you want to allow non-local connections, you need to add more -# "host" records. In that case you will also need to make PostgreSQL -# listen on a non-local interface via the listen_addresses -# configuration parameter, or via the -i or -h command line switches. - - - - -# DO NOT DISABLE! -# If you change this first entry you will need to make sure that the -# database superuser can access the database using some other method. -# Noninteractive access to all databases is required during automatic -# maintenance (custom daily cronjobs, replication, and similar tasks). -# -# Database administrative login by Unix domain socket -local all postgres peer - -# TYPE DATABASE USER ADDRESS METHOD - -# "local" is for Unix domain socket connections only -local all all peer -# IPv4 local connections: -host all all 127.0.0.1/32 md5 -# IPv6 local connections: -host all all ::1/128 md5 -# Allow replication connections from localhost, by a user with the -# replication privilege. -#local replication postgres peer -#host replication postgres 127.0.0.1/32 md5 -#host replication postgres ::1/128 md5 -host all all 0.0.0.0/0 md5 diff --git a/toolset/databases/postgres/postgres.dockerfile b/toolset/databases/postgres/postgres.dockerfile index 836e4465e8b..0573b85b2ca 100644 --- a/toolset/databases/postgres/postgres.dockerfile +++ b/toolset/databases/postgres/postgres.dockerfile @@ -1,16 +1,10 @@ -FROM postgres:15-bullseye +FROM postgres:18-trixie -ENV POSTGRES_USER=benchmarkdbuser -ENV POSTGRES_PASSWORD=benchmarkdbpass -ENV POSTGRES_DB=hello_world +ENV PGDATA=/ssd/postgresql \ + POSTGRES_DB=hello_world \ + POSTGRES_PASSWORD=benchmarkdbpass \ + POSTGRES_USER=benchmarkdbuser -ENV POSTGRES_HOST_AUTH_METHOD=md5 -ENV POSTGRES_INITDB_ARGS=--auth-host=md5 -ENV PGDATA=/ssd/postgresql - -COPY postgresql-min.conf /tmp/postgresql.conf - -COPY create-postgres.sql /docker-entrypoint-initdb.d/ -COPY config.sh /docker-entrypoint-initdb.d/ - -COPY 60-postgresql-shm.conf /etc/sysctl.d/60-postgresql-shm.conf +COPY 60-postgresql-shm.conf /etc/sysctl.d/ +COPY config.sh create-postgres.sql /docker-entrypoint-initdb.d/ +COPY postgresql.conf /tmp/ diff --git a/toolset/databases/postgres/postgresql-min.conf b/toolset/databases/postgres/postgresql-min.conf deleted file mode 100644 index 1e91048d027..00000000000 --- a/toolset/databases/postgres/postgresql-min.conf +++ /dev/null @@ -1,143 +0,0 @@ -# See postgresql.conf.sample for a full conf file - -listen_addresses = '*' # what IP address(es) to listen on; -max_connections = 2000 # (change requires restart) - -ssl = false # (change requires restart) - -# - Memory - -# values from: http://blog.pgaddict.com/posts/performance-since-postgresql-7-4-to-9-4-pgbench -# details: http://www.postgresql.org/docs/9.4/static/runtime-config-resource.html -# http://www.postgresql.org/docs/9.4/static/runtime-config-wal.html -# http://www.postgresql.org/docs/9.4/static/runtime-config-query.html -shared_buffers = 256MB # min 128kB -work_mem = 64MB # min 64kB -maintenance_work_mem = 512MB # min 1MB -# checkpoint_segments = 64 -checkpoint_completion_target = 0.9 -effective_cache_size = 8GB - -# when executed on the SSD (otherwise 4) -random_page_cost = 2 - -shared_preload_libraries = 'pg_stat_statements' # (change requires restart) -pg_stat_statements.track = all -pg_stat_statements.max = 500000 -track_activity_query_size = 2048 - -#------------------------------------------------------------------------------ -# WRITE AHEAD LOG -#------------------------------------------------------------------------------ - -# - Settings - - -wal_level = minimal # minimal, archive, or hot_standby - -# WARNING: disabling synchronous commit may be dangerous in certain cases. -# See http://www.postgresql.org/docs/current/static/runtime-config-wal.html -# for details. -synchronous_commit = off - -#------------------------------------------------------------------------------ -# REPLICATION -#------------------------------------------------------------------------------ - -# - Master Server - - -# These settings are ignored on a standby server - -max_wal_senders = 0 # max number of walsender processes - # (change requires restart) - -#------------------------------------------------------------------------------ -# ERROR REPORTING AND LOGGING -#------------------------------------------------------------------------------ - -log_line_prefix = '%t ' # special values: - # %a = application name - # %u = user name - # %d = database name - # %r = remote host and port - # %h = remote host - # %p = process ID - # %t = timestamp without milliseconds - # %m = timestamp with milliseconds - # %i = command tag - # %e = SQL state - # %c = session ID - # %l = session line number - # %s = session start timestamp - # %v = virtual transaction ID - # %x = transaction ID (0 if none) - # %q = stop here in non-session - # processes - # %% = '%' - # e.g. '<%u%%%d> ' - -#------------------------------------------------------------------------------ -# CLIENT CONNECTION DEFAULTS -#------------------------------------------------------------------------------ - -# - Statement Behavior - - -#search_path = '"$user",public' # schema names -#default_tablespace = '' # a tablespace name, '' uses the default -#temp_tablespaces = '' # a list of tablespace names, '' uses - # only default tablespace -#check_function_bodies = on -#default_transaction_isolation = 'read committed' -#default_transaction_read_only = off -#default_transaction_deferrable = off -#session_replication_role = 'origin' -#statement_timeout = 0 # in milliseconds, 0 is disabled -#vacuum_freeze_min_age = 50000000 -#vacuum_freeze_table_age = 150000000 -#bytea_output = 'hex' # hex, escape -#xmlbinary = 'base64' -#xmloption = 'content' - -# - Locale and Formatting - - -#datestyle = 'iso, mdy' -#intervalstyle = 'postgres' -#timezone = '(defaults to server environment setting)' -#timezone_abbreviations = 'Default' # Select the set of available time zone - # abbreviations. Currently, there are - # Default - # Australia - # India - # You can create your own file in - # share/timezonesets/. -#extra_float_digits = 0 # min -15, max 3 -#client_encoding = sql_ascii # actually, defaults to database - # encoding - -# These settings are initialized by initdb, but they can be changed. -#lc_messages = 'en_US.UTF-8' # locale for system error message - # strings -#lc_monetary = 'en_US.UTF-8' # locale for monetary formatting -#lc_numeric = 'en_US.UTF-8' # locale for number formatting -#lc_time = 'en_US.UTF-8' # locale for time formatting - -# default configuration for text search -#default_text_search_config = 'pg_catalog.english' - -# - Other Defaults - - -#dynamic_library_path = '$libdir' -#local_preload_libraries = '' - - -#------------------------------------------------------------------------------ -# LOCK MANAGEMENT -#------------------------------------------------------------------------------ - -#deadlock_timeout = 1s -#max_locks_per_transaction = 64 # min 10 - # (change requires restart) -# Note: Each lock table slot uses ~270 bytes of shared memory, and there are -# max_locks_per_transaction * (max_connections + max_prepared_transactions) -# lock table slots. -max_pred_locks_per_transaction = 256 # min 10 - # (change requires restart) - diff --git a/toolset/databases/postgres/postgresql.conf b/toolset/databases/postgres/postgresql.conf index fd90cd2b15b..72c94956692 100644 --- a/toolset/databases/postgres/postgresql.conf +++ b/toolset/databases/postgres/postgresql.conf @@ -1,577 +1,35 @@ -# ----------------------------- -# PostgreSQL configuration file -# ----------------------------- -# -# This file consists of lines of the form: -# -# name = value -# -# (The "=" is optional.) Whitespace may be used. Comments are introduced with -# "#" anywhere on a line. The complete list of parameter names and allowed -# values can be found in the PostgreSQL documentation. -# -# The commented-out settings shown in this file represent the default values. -# Re-commenting a setting is NOT sufficient to revert it to the default value; -# you need to reload the server. -# -# This file is read on server startup and when the server receives a SIGHUP -# signal. If you edit the file on a running system, you have to SIGHUP the -# server for the changes to take effect, or use "pg_ctl reload". Some -# parameters, which are marked below, require a server shutdown and restart to -# take effect. -# -# Any parameter can also be given as a command-line option to the server, e.g., -# "postgres -c log_connections=on". Some parameters can be changed at run time -# with the "SET" SQL command. -# -# Memory units: kB = kilobytes Time units: ms = milliseconds -# MB = megabytes s = seconds -# GB = gigabytes min = minutes -# h = hours -# d = days +# For a full conf file see: +# https://github.com/TechEmpower/FrameworkBenchmarks/blob/d8f043d183d1ccbba41157bd57314ef61059edb8/toolset/databases/postgres/postgresql.conf.sample +listen_addresses = '*' +max_connections = 2000 +ssl = false -#------------------------------------------------------------------------------ -# FILE LOCATIONS -#------------------------------------------------------------------------------ - -# The default values of these variables are driven from the -D command-line -# option or PGDATA environment variable, represented here as ConfigDir. - -data_directory = '/ssd/postgresql' # use data in another directory - # (change requires restart) -hba_file = '/etc/postgresql/PG_VERSION/main/pg_hba.conf' # host-based authentication file - # (change requires restart) -ident_file = '/etc/postgresql/PG_VERSION/main/pg_ident.conf' # ident configuration file - # (change requires restart) - -# If external_pid_file is not explicitly set, no extra PID file is written. -external_pid_file = '/var/run/postgresql/PG_VERSION-main.pid' # write an extra PID file - # (change requires restart) - - -#------------------------------------------------------------------------------ -# CONNECTIONS AND AUTHENTICATION -#------------------------------------------------------------------------------ - -# - Connection Settings - - -listen_addresses = '*' # what IP address(es) to listen on; - # comma-separated list of addresses; - # defaults to 'localhost', '*' = all - # (change requires restart) -port = 5432 # (change requires restart) -max_connections = 2000 # (change requires restart) -# Note: Increasing max_connections costs ~400 bytes of shared memory per -# connection slot, plus lock space (see max_locks_per_transaction). -#superuser_reserved_connections = 3 # (change requires restart) -unix_socket_directories = '/var/run/postgresql' # (change requires restart) -#unix_socket_group = '' # (change requires restart) -#unix_socket_permissions = 0777 # begin with 0 to use octal notation - # (change requires restart) -#bonjour = off # advertise server via Bonjour - # (change requires restart) -#bonjour_name = '' # defaults to the computer name - # (change requires restart) - -# - Security and Authentication - - -#authentication_timeout = 1min # 1s-600s -ssl = false # (change requires restart) -#ssl_ciphers = 'ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH' # allowed SSL ciphers - # (change requires restart) -#ssl_renegotiation_limit = 512MB # amount of data between renegotiations -password_encryption = md5 -#db_user_namespace = off - -# Kerberos and GSSAPI -#krb_server_keyfile = '' -#krb_srvname = 'postgres' # (Kerberos only) -#krb_caseins_users = off - -# - TCP Keepalives - -# see "man 7 tcp" for details - -#tcp_keepalives_idle = 0 # TCP_KEEPIDLE, in seconds; - # 0 selects the system default -#tcp_keepalives_interval = 0 # TCP_KEEPINTVL, in seconds; - # 0 selects the system default -#tcp_keepalives_count = 0 # TCP_KEEPCNT; - # 0 selects the system default - - -#------------------------------------------------------------------------------ -# RESOURCE USAGE (except WAL) -#------------------------------------------------------------------------------ - -# - Memory - # values from: http://blog.pgaddict.com/posts/performance-since-postgresql-7-4-to-9-4-pgbench # details: http://www.postgresql.org/docs/9.4/static/runtime-config-resource.html # http://www.postgresql.org/docs/9.4/static/runtime-config-wal.html # http://www.postgresql.org/docs/9.4/static/runtime-config-query.html -shared_buffers = 256MB # min 128kB -work_mem = 64MB # min 64kB -maintenance_work_mem = 512MB # min 1MB -# checkpoint_segments = 64 -checkpoint_completion_target = 0.9 -effective_cache_size = 8GB - -# when executed on the SSD (otherwise 4) -random_page_cost = 2 - -#shared_buffers = 32MB # min 128kB - # (change requires restart) -#temp_buffers = 8MB # min 800kB -#max_prepared_transactions = 0 # zero disables the feature - # (change requires restart) -# Note: Increasing max_prepared_transactions costs ~600 bytes of shared memory -# per transaction slot, plus lock space (see max_locks_per_transaction). -# It is not advisable to set max_prepared_transactions nonzero unless you -# actively intend to use prepared transactions. -#work_mem = 1MB # min 64kB -#maintenance_work_mem = 16MB # min 1MB -#max_stack_depth = 2MB # min 100kB - -# - Kernel Resource Usage - - -#max_files_per_process = 1000 # min 25 - # (change requires restart) -shared_preload_libraries = 'pg_stat_statements' # (change requires restart) -pg_stat_statements.track = all -pg_stat_statements.max = 500000 -track_activity_query_size = 2048 - -# - Cost-Based Vacuum Delay - - -#vacuum_cost_delay = 0ms # 0-100 milliseconds -#vacuum_cost_page_hit = 1 # 0-10000 credits -#vacuum_cost_page_miss = 10 # 0-10000 credits -#vacuum_cost_page_dirty = 20 # 0-10000 credits -#vacuum_cost_limit = 200 # 1-10000 credits - -# - Background Writer - -#bgwriter_delay = 200ms # 10-10000ms between rounds -#bgwriter_lru_maxpages = 100 # 0-1000 max buffers written/round -#bgwriter_lru_multiplier = 2.0 # 0-10.0 multipler on buffers scanned/round - -# - Asynchronous Behavior - - -#effective_io_concurrency = 1 # 1-1000. 0 disables prefetching - - -#------------------------------------------------------------------------------ -# WRITE AHEAD LOG -#------------------------------------------------------------------------------ - -# - Settings - - -wal_level = minimal # minimal, archive, or hot_standby - # (change requires restart) -#fsync = on # turns forced synchronization on or off +shared_buffers = 256MB +work_mem = 64MB +maintenance_work_mem = 512MB +wal_level = minimal # WARNING: disabling synchronous commit may be dangerous in certain cases. # See http://www.postgresql.org/docs/current/static/runtime-config-wal.html # for details. synchronous_commit = off -#wal_sync_method = fsync # the default is the first option - # supported by the operating system: - # open_datasync - # fdatasync (default on Linux) - # fsync - # fsync_writethrough - # open_sync -#full_page_writes = on # recover from partial page writes -#wal_buffers = -1 # min 32kB, -1 sets based on shared_buffers - # (change requires restart) -#wal_writer_delay = 200ms # 1-10000 milliseconds - -#commit_delay = 0 # range 0-100000, in microseconds -#commit_siblings = 5 # range 1-1000 - -# - Checkpoints - - -#checkpoint_segments = 3 # in logfile segments, min 1, 16MB each -#checkpoint_timeout = 5min # range 30s-1h -#checkpoint_completion_target = 0.5 # checkpoint target duration, 0.0 - 1.0 -#checkpoint_warning = 30s # 0 disables - -# - Archiving - - -#archive_mode = off # allows archiving to be done - # (change requires restart) -#archive_command = '' # command to use to archive a logfile segment -#archive_timeout = 0 # force a logfile segment switch after this - # number of seconds; 0 disables - - -#------------------------------------------------------------------------------ -# REPLICATION -#------------------------------------------------------------------------------ - -# - Master Server - - -# These settings are ignored on a standby server - -max_wal_senders = 0 # max number of walsender processes - # (change requires restart) -#wal_sender_delay = 1s # walsender cycle time, 1-10000 milliseconds -#wal_keep_segments = 0 # in logfile segments, 16MB each; 0 disables -#vacuum_defer_cleanup_age = 0 # number of xacts by which cleanup is delayed -#replication_timeout = 60s # in milliseconds; 0 disables -#synchronous_standby_names = '' # standby servers that provide sync rep - # comma-separated list of application_name - # from standby(s); '*' = all - -# - Standby Servers - - -# These settings are ignored on a master server - -#hot_standby = off # "on" allows queries during recovery - # (change requires restart) -#max_standby_archive_delay = 30s # max delay before canceling queries - # when reading WAL from archive; - # -1 allows indefinite delay -#max_standby_streaming_delay = 30s # max delay before canceling queries - # when reading streaming WAL; - # -1 allows indefinite delay -#wal_receiver_status_interval = 10s # send replies at least this often - # 0 disables -#hot_standby_feedback = off # send info from standby to prevent - # query conflicts - - -#------------------------------------------------------------------------------ -# QUERY TUNING -#------------------------------------------------------------------------------ - -# - Planner Method Configuration - - -#enable_bitmapscan = on -#enable_hashagg = on -#enable_hashjoin = on -#enable_indexscan = on -#enable_material = on -#enable_mergejoin = on -#enable_nestloop = on -#enable_seqscan = on -#enable_sort = on -#enable_tidscan = on - -# - Planner Cost Constants - - -#seq_page_cost = 1.0 # measured on an arbitrary scale -#random_page_cost = 4.0 # same scale as above -#cpu_tuple_cost = 0.01 # same scale as above -#cpu_index_tuple_cost = 0.005 # same scale as above -#cpu_operator_cost = 0.0025 # same scale as above -#effective_cache_size = 128MB - -# - Genetic Query Optimizer - - -#geqo = on -#geqo_threshold = 12 -#geqo_effort = 5 # range 1-10 -#geqo_pool_size = 0 # selects default based on effort -#geqo_generations = 0 # selects default based on effort -#geqo_selection_bias = 2.0 # range 1.5-2.0 -#geqo_seed = 0.0 # range 0.0-1.0 - -# - Other Planner Options - - -#default_statistics_target = 100 # range 1-10000 -#constraint_exclusion = partition # on, off, or partition -#cursor_tuple_fraction = 0.1 # range 0.0-1.0 -#from_collapse_limit = 8 -#join_collapse_limit = 8 # 1 disables collapsing of explicit - # JOIN clauses - - -#------------------------------------------------------------------------------ -# ERROR REPORTING AND LOGGING -#------------------------------------------------------------------------------ - -# - Where to Log - - -#log_destination = 'stderr' # Valid values are combinations of - # stderr, csvlog, syslog, and eventlog, - # depending on platform. csvlog - # requires logging_collector to be on. - -# This is used when logging to stderr: -#logging_collector = off # Enable capturing of stderr and csvlog - # into log files. Required to be on for - # csvlogs. - # (change requires restart) - -# These are only used if logging_collector is on: -#log_directory = 'pg_log' # directory where log files are written, - # can be absolute or relative to PGDATA -#log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log' # log file name pattern, - # can include strftime() escapes -#log_file_mode = 0600 # creation mode for log files, - # begin with 0 to use octal notation -#log_truncate_on_rotation = off # If on, an existing log file with the - # same name as the new log file will be - # truncated rather than appended to. - # But such truncation only occurs on - # time-driven rotation, not on restarts - # or size-driven rotation. Default is - # off, meaning append to existing files - # in all cases. -#log_rotation_age = 1d # Automatic rotation of logfiles will - # happen after that time. 0 disables. -#log_rotation_size = 10MB # Automatic rotation of logfiles will - # happen after that much log output. - # 0 disables. - -# These are relevant when logging to syslog: -#syslog_facility = 'LOCAL0' -#syslog_ident = 'postgres' - -#silent_mode = off # Run server silently. - # DO NOT USE without syslog or - # logging_collector - # (change requires restart) - - -# - When to Log - - -#client_min_messages = notice # values in order of decreasing detail: - # debug5 - # debug4 - # debug3 - # debug2 - # debug1 - # log - # notice - # warning - # error - -#log_min_messages = warning # values in order of decreasing detail: - # debug5 - # debug4 - # debug3 - # debug2 - # debug1 - # info - # notice - # warning - # error - # log - # fatal - # panic - -#log_min_error_statement = error # values in order of decreasing detail: - # debug5 - # debug4 - # debug3 - # debug2 - # debug1 - # info - # notice - # warning - # error - # log - # fatal - # panic (effectively off) - -#log_min_duration_statement = -1 # -1 is disabled, 0 logs all statements - # and their durations, > 0 logs only - # statements running at least this number - # of milliseconds - - -# - What to Log - - -#debug_print_parse = off -#debug_print_rewritten = off -#debug_print_plan = off -#debug_pretty_print = on -#log_checkpoints = off -#log_connections = off -#log_disconnections = off -#log_duration = off -#log_error_verbosity = default # terse, default, or verbose messages -#log_hostname = off -log_line_prefix = '%t ' # special values: - # %a = application name - # %u = user name - # %d = database name - # %r = remote host and port - # %h = remote host - # %p = process ID - # %t = timestamp without milliseconds - # %m = timestamp with milliseconds - # %i = command tag - # %e = SQL state - # %c = session ID - # %l = session line number - # %s = session start timestamp - # %v = virtual transaction ID - # %x = transaction ID (0 if none) - # %q = stop here in non-session - # processes - # %% = '%' - # e.g. '<%u%%%d> ' -#log_lock_waits = off # log lock waits >= deadlock_timeout -#log_statement = 'none' # none, ddl, mod, all -#log_temp_files = -1 # log temporary files equal or larger - # than the specified size in kilobytes; - # -1 disables, 0 logs all temp files -#log_timezone = '(defaults to server environment setting)' - - -#------------------------------------------------------------------------------ -# RUNTIME STATISTICS -#------------------------------------------------------------------------------ - -# - Query/Index Statistics Collector - - -#track_activities = on -#track_counts = on -#track_functions = none # none, pl, all -#track_activity_query_size = 1024 # (change requires restart) -#update_process_title = on -#stats_temp_directory = 'pg_stat_tmp' - - -# - Statistics Monitoring - - -#log_parser_stats = off -#log_planner_stats = off -#log_executor_stats = off -#log_statement_stats = off - - -#------------------------------------------------------------------------------ -# AUTOVACUUM PARAMETERS -#------------------------------------------------------------------------------ - -#autovacuum = on # Enable autovacuum subprocess? 'on' - # requires track_counts to also be on. -#log_autovacuum_min_duration = -1 # -1 disables, 0 logs all actions and - # their durations, > 0 logs only - # actions running at least this number - # of milliseconds. -#autovacuum_max_workers = 3 # max number of autovacuum subprocesses - # (change requires restart) -#autovacuum_naptime = 1min # time between autovacuum runs -#autovacuum_vacuum_threshold = 50 # min number of row updates before - # vacuum -#autovacuum_analyze_threshold = 50 # min number of row updates before - # analyze -#autovacuum_vacuum_scale_factor = 0.2 # fraction of table size before vacuum -#autovacuum_analyze_scale_factor = 0.1 # fraction of table size before analyze -#autovacuum_freeze_max_age = 200000000 # maximum XID age before forced vacuum - # (change requires restart) -#autovacuum_vacuum_cost_delay = 20ms # default vacuum cost delay for - # autovacuum, in milliseconds; - # -1 means use vacuum_cost_delay -#autovacuum_vacuum_cost_limit = -1 # default vacuum cost limit for - # autovacuum, -1 means use - # vacuum_cost_limit - - -#------------------------------------------------------------------------------ -# CLIENT CONNECTION DEFAULTS -#------------------------------------------------------------------------------ - -# - Statement Behavior - - -#search_path = '"$user",public' # schema names -#default_tablespace = '' # a tablespace name, '' uses the default -#temp_tablespaces = '' # a list of tablespace names, '' uses - # only default tablespace -#check_function_bodies = on -#default_transaction_isolation = 'read committed' -#default_transaction_read_only = off -#default_transaction_deferrable = off -#session_replication_role = 'origin' -#statement_timeout = 0 # in milliseconds, 0 is disabled -#vacuum_freeze_min_age = 50000000 -#vacuum_freeze_table_age = 150000000 -#bytea_output = 'hex' # hex, escape -#xmlbinary = 'base64' -#xmloption = 'content' - -# - Locale and Formatting - - -datestyle = 'iso, mdy' -#intervalstyle = 'postgres' -#timezone = '(defaults to server environment setting)' -#timezone_abbreviations = 'Default' # Select the set of available time zone - # abbreviations. Currently, there are - # Default - # Australia - # India - # You can create your own file in - # share/timezonesets/. -#extra_float_digits = 0 # min -15, max 3 -#client_encoding = sql_ascii # actually, defaults to database - # encoding - -# These settings are initialized by initdb, but they can be changed. -lc_messages = 'en_US.UTF-8' # locale for system error message - # strings -lc_monetary = 'en_US.UTF-8' # locale for monetary formatting -lc_numeric = 'en_US.UTF-8' # locale for number formatting -lc_time = 'en_US.UTF-8' # locale for time formatting - -# default configuration for text search -default_text_search_config = 'pg_catalog.english' - -# - Other Defaults - - -#dynamic_library_path = '$libdir' -#local_preload_libraries = '' - - -#------------------------------------------------------------------------------ -# LOCK MANAGEMENT -#------------------------------------------------------------------------------ - -#deadlock_timeout = 1s -#max_locks_per_transaction = 64 # min 10 - # (change requires restart) -# Note: Each lock table slot uses ~270 bytes of shared memory, and there are -# max_locks_per_transaction * (max_connections + max_prepared_transactions) -# lock table slots. -max_pred_locks_per_transaction = 256 # min 10 - # (change requires restart) - -#------------------------------------------------------------------------------ -# VERSION/PLATFORM COMPATIBILITY -#------------------------------------------------------------------------------ - -# - Previous PostgreSQL Versions - - -#array_nulls = on -#backslash_quote = safe_encoding # on, off, or safe_encoding -#default_with_oids = off -#escape_string_warning = on -#lo_compat_privileges = off -#quote_all_identifiers = off -#sql_inheritance = on -#standard_conforming_strings = on -#synchronize_seqscans = on - -# - Other Platforms and Clients - - -#transform_null_equals = off - - -#------------------------------------------------------------------------------ -# ERROR HANDLING -#------------------------------------------------------------------------------ - -#exit_on_error = off # terminate session on any error? -#restart_after_crash = on # reinitialize after backend crash? - +checkpoint_completion_target = 0.9 +max_wal_senders = 0 -#------------------------------------------------------------------------------ -# CUSTOMIZED OPTIONS -#------------------------------------------------------------------------------ +# when executed on the SSD (otherwise 4) +random_page_cost = 2 -#custom_variable_classes = '' # list of custom variable class names +effective_cache_size = 8GB +log_line_prefix = '%t ' +track_activity_query_size = 2048 +shared_preload_libraries = 'pg_stat_statements' +pg_stat_statements.track = all +pg_stat_statements.max = 500000 +max_pred_locks_per_transaction = 256 diff --git a/toolset/databases/postgres/postgresql.conf.sample b/toolset/databases/postgres/postgresql.conf.sample deleted file mode 100644 index ed322b6f46c..00000000000 --- a/toolset/databases/postgres/postgresql.conf.sample +++ /dev/null @@ -1,813 +0,0 @@ -# ----------------------------- -# PostgreSQL configuration file -# ----------------------------- -# -# This file consists of lines of the form: -# -# name = value -# -# (The "=" is optional.) Whitespace may be used. Comments are introduced with -# "#" anywhere on a line. The complete list of parameter names and allowed -# values can be found in the PostgreSQL documentation. -# -# The commented-out settings shown in this file represent the default values. -# Re-commenting a setting is NOT sufficient to revert it to the default value; -# you need to reload the server. -# -# This file is read on server startup and when the server receives a SIGHUP -# signal. If you edit the file on a running system, you have to SIGHUP the -# server for the changes to take effect, run "pg_ctl reload", or execute -# "SELECT pg_reload_conf()". Some parameters, which are marked below, -# require a server shutdown and restart to take effect. -# -# Any parameter can also be given as a command-line option to the server, e.g., -# "postgres -c log_connections=on". Some parameters can be changed at run time -# with the "SET" SQL command. -# -# Memory units: B = bytes Time units: us = microseconds -# kB = kilobytes ms = milliseconds -# MB = megabytes s = seconds -# GB = gigabytes min = minutes -# TB = terabytes h = hours -# d = days - - -#------------------------------------------------------------------------------ -# FILE LOCATIONS -#------------------------------------------------------------------------------ - -# The default values of these variables are driven from the -D command-line -# option or PGDATA environment variable, represented here as ConfigDir. - -#data_directory = 'ConfigDir' # use data in another directory - # (change requires restart) -#hba_file = 'ConfigDir/pg_hba.conf' # host-based authentication file - # (change requires restart) -#ident_file = 'ConfigDir/pg_ident.conf' # ident configuration file - # (change requires restart) - -# If external_pid_file is not explicitly set, no extra PID file is written. -#external_pid_file = '' # write an extra PID file - # (change requires restart) - - -#------------------------------------------------------------------------------ -# CONNECTIONS AND AUTHENTICATION -#------------------------------------------------------------------------------ - -# - Connection Settings - - -#listen_addresses = 'localhost' # what IP address(es) to listen on; - # comma-separated list of addresses; - # defaults to 'localhost'; use '*' for all - # (change requires restart) -#port = 5432 # (change requires restart) -#max_connections = 100 # (change requires restart) -#reserved_connections = 0 # (change requires restart) -#superuser_reserved_connections = 3 # (change requires restart) -#unix_socket_directories = '/tmp' # comma-separated list of directories - # (change requires restart) -#unix_socket_group = '' # (change requires restart) -#unix_socket_permissions = 0777 # begin with 0 to use octal notation - # (change requires restart) -#bonjour = off # advertise server via Bonjour - # (change requires restart) -#bonjour_name = '' # defaults to the computer name - # (change requires restart) - -# - TCP settings - -# see "man tcp" for details - -#tcp_keepalives_idle = 0 # TCP_KEEPIDLE, in seconds; - # 0 selects the system default -#tcp_keepalives_interval = 0 # TCP_KEEPINTVL, in seconds; - # 0 selects the system default -#tcp_keepalives_count = 0 # TCP_KEEPCNT; - # 0 selects the system default -#tcp_user_timeout = 0 # TCP_USER_TIMEOUT, in milliseconds; - # 0 selects the system default - -#client_connection_check_interval = 0 # time between checks for client - # disconnection while running queries; - # 0 for never - -# - Authentication - - -#authentication_timeout = 1min # 1s-600s -#password_encryption = scram-sha-256 # scram-sha-256 or md5 -#db_user_namespace = off - -# GSSAPI using Kerberos -#krb_server_keyfile = 'FILE:${sysconfdir}/krb5.keytab' -#krb_caseins_users = off - -# - SSL - - -#ssl = off -#ssl_ca_file = '' -#ssl_cert_file = 'server.crt' -#ssl_crl_file = '' -#ssl_crl_dir = '' -#ssl_key_file = 'server.key' -#ssl_ciphers = 'HIGH:MEDIUM:+3DES:!aNULL' # allowed SSL ciphers -#ssl_prefer_server_ciphers = on -#ssl_ecdh_curve = 'prime256v1' -#ssl_min_protocol_version = 'TLSv1.2' -#ssl_max_protocol_version = '' -#ssl_dh_params_file = '' -#ssl_passphrase_command = '' -#ssl_passphrase_command_supports_reload = off - - -#------------------------------------------------------------------------------ -# RESOURCE USAGE (except WAL) -#------------------------------------------------------------------------------ - -# - Memory - - -#shared_buffers = 128MB # min 128kB - # (change requires restart) -#huge_pages = try # on, off, or try - # (change requires restart) -#huge_page_size = 0 # zero for system default - # (change requires restart) -#temp_buffers = 8MB # min 800kB -#max_prepared_transactions = 0 # zero disables the feature - # (change requires restart) -# Caution: it is not advisable to set max_prepared_transactions nonzero unless -# you actively intend to use prepared transactions. -#work_mem = 4MB # min 64kB -#hash_mem_multiplier = 2.0 # 1-1000.0 multiplier on hash table work_mem -#maintenance_work_mem = 64MB # min 1MB -#autovacuum_work_mem = -1 # min 1MB, or -1 to use maintenance_work_mem -#logical_decoding_work_mem = 64MB # min 64kB -#max_stack_depth = 2MB # min 100kB -#shared_memory_type = mmap # the default is the first option - # supported by the operating system: - # mmap - # sysv - # windows - # (change requires restart) -#dynamic_shared_memory_type = posix # the default is usually the first option - # supported by the operating system: - # posix - # sysv - # windows - # mmap - # (change requires restart) -#min_dynamic_shared_memory = 0MB # (change requires restart) - -# - Disk - - -#temp_file_limit = -1 # limits per-process temp file space - # in kilobytes, or -1 for no limit - -# - Kernel Resources - - -#max_files_per_process = 1000 # min 64 - # (change requires restart) - -# - Cost-Based Vacuum Delay - - -#vacuum_cost_delay = 0 # 0-100 milliseconds (0 disables) -#vacuum_cost_page_hit = 1 # 0-10000 credits -#vacuum_cost_page_miss = 2 # 0-10000 credits -#vacuum_cost_page_dirty = 20 # 0-10000 credits -#vacuum_cost_limit = 200 # 1-10000 credits - -# - Background Writer - - -#bgwriter_delay = 200ms # 10-10000ms between rounds -#bgwriter_lru_maxpages = 100 # max buffers written/round, 0 disables -#bgwriter_lru_multiplier = 2.0 # 0-10.0 multiplier on buffers scanned/round -#bgwriter_flush_after = 0 # measured in pages, 0 disables - -# - Asynchronous Behavior - - -#backend_flush_after = 0 # measured in pages, 0 disables -#effective_io_concurrency = 1 # 1-1000; 0 disables prefetching -#maintenance_io_concurrency = 10 # 1-1000; 0 disables prefetching -#max_worker_processes = 8 # (change requires restart) -#max_parallel_workers_per_gather = 2 # taken from max_parallel_workers -#max_parallel_maintenance_workers = 2 # taken from max_parallel_workers -#max_parallel_workers = 8 # maximum number of max_worker_processes that - # can be used in parallel operations -#parallel_leader_participation = on -#old_snapshot_threshold = -1 # 1min-60d; -1 disables; 0 is immediate - # (change requires restart) - - -#------------------------------------------------------------------------------ -# WRITE-AHEAD LOG -#------------------------------------------------------------------------------ - -# - Settings - - -#wal_level = replica # minimal, replica, or logical - # (change requires restart) -#fsync = on # flush data to disk for crash safety - # (turning this off can cause - # unrecoverable data corruption) -#synchronous_commit = on # synchronization level; - # off, local, remote_write, remote_apply, or on -#wal_sync_method = fsync # the default is the first option - # supported by the operating system: - # open_datasync - # fdatasync (default on Linux and FreeBSD) - # fsync - # fsync_writethrough - # open_sync -#full_page_writes = on # recover from partial page writes -#wal_log_hints = off # also do full page writes of non-critical updates - # (change requires restart) -#wal_compression = off # enables compression of full-page writes; - # off, pglz, lz4, zstd, or on -#wal_init_zero = on # zero-fill new WAL files -#wal_recycle = on # recycle WAL files -#wal_buffers = -1 # min 32kB, -1 sets based on shared_buffers - # (change requires restart) -#wal_writer_delay = 200ms # 1-10000 milliseconds -#wal_writer_flush_after = 1MB # measured in pages, 0 disables -#wal_skip_threshold = 2MB - -#commit_delay = 0 # range 0-100000, in microseconds -#commit_siblings = 5 # range 1-1000 - -# - Checkpoints - - -#checkpoint_timeout = 5min # range 30s-1d -#checkpoint_completion_target = 0.9 # checkpoint target duration, 0.0 - 1.0 -#checkpoint_flush_after = 0 # measured in pages, 0 disables -#checkpoint_warning = 30s # 0 disables -#max_wal_size = 1GB -#min_wal_size = 80MB - -# - Prefetching during recovery - - -#recovery_prefetch = try # prefetch pages referenced in the WAL? -#wal_decode_buffer_size = 512kB # lookahead window used for prefetching - # (change requires restart) - -# - Archiving - - -#archive_mode = off # enables archiving; off, on, or always - # (change requires restart) -#archive_library = '' # library to use to archive a WAL file - # (empty string indicates archive_command should - # be used) -#archive_command = '' # command to use to archive a WAL file - # placeholders: %p = path of file to archive - # %f = file name only - # e.g. 'test ! -f /mnt/server/archivedir/%f && cp %p /mnt/server/archivedir/%f' -#archive_timeout = 0 # force a WAL file switch after this - # number of seconds; 0 disables - -# - Archive Recovery - - -# These are only used in recovery mode. - -#restore_command = '' # command to use to restore an archived WAL file - # placeholders: %p = path of file to restore - # %f = file name only - # e.g. 'cp /mnt/server/archivedir/%f %p' -#archive_cleanup_command = '' # command to execute at every restartpoint -#recovery_end_command = '' # command to execute at completion of recovery - -# - Recovery Target - - -# Set these only when performing a targeted recovery. - -#recovery_target = '' # 'immediate' to end recovery as soon as a - # consistent state is reached - # (change requires restart) -#recovery_target_name = '' # the named restore point to which recovery will proceed - # (change requires restart) -#recovery_target_time = '' # the time stamp up to which recovery will proceed - # (change requires restart) -#recovery_target_xid = '' # the transaction ID up to which recovery will proceed - # (change requires restart) -#recovery_target_lsn = '' # the WAL LSN up to which recovery will proceed - # (change requires restart) -#recovery_target_inclusive = on # Specifies whether to stop: - # just after the specified recovery target (on) - # just before the recovery target (off) - # (change requires restart) -#recovery_target_timeline = 'latest' # 'current', 'latest', or timeline ID - # (change requires restart) -#recovery_target_action = 'pause' # 'pause', 'promote', 'shutdown' - # (change requires restart) - - -#------------------------------------------------------------------------------ -# REPLICATION -#------------------------------------------------------------------------------ - -# - Sending Servers - - -# Set these on the primary and on any standby that will send replication data. - -#max_wal_senders = 10 # max number of walsender processes - # (change requires restart) -#max_replication_slots = 10 # max number of replication slots - # (change requires restart) -#wal_keep_size = 0 # in megabytes; 0 disables -#max_slot_wal_keep_size = -1 # in megabytes; -1 disables -#wal_sender_timeout = 60s # in milliseconds; 0 disables -#track_commit_timestamp = off # collect timestamp of transaction commit - # (change requires restart) - -# - Primary Server - - -# These settings are ignored on a standby server. - -#synchronous_standby_names = '' # standby servers that provide sync rep - # method to choose sync standbys, number of sync standbys, - # and comma-separated list of application_name - # from standby(s); '*' = all -#vacuum_defer_cleanup_age = 0 # number of xacts by which cleanup is delayed - -# - Standby Servers - - -# These settings are ignored on a primary server. - -#primary_conninfo = '' # connection string to sending server -#primary_slot_name = '' # replication slot on sending server -#hot_standby = on # "off" disallows queries during recovery - # (change requires restart) -#max_standby_archive_delay = 30s # max delay before canceling queries - # when reading WAL from archive; - # -1 allows indefinite delay -#max_standby_streaming_delay = 30s # max delay before canceling queries - # when reading streaming WAL; - # -1 allows indefinite delay -#wal_receiver_create_temp_slot = off # create temp slot if primary_slot_name - # is not set -#wal_receiver_status_interval = 10s # send replies at least this often - # 0 disables -#hot_standby_feedback = off # send info from standby to prevent - # query conflicts -#wal_receiver_timeout = 60s # time that receiver waits for - # communication from primary - # in milliseconds; 0 disables -#wal_retrieve_retry_interval = 5s # time to wait before retrying to - # retrieve WAL after a failed attempt -#recovery_min_apply_delay = 0 # minimum delay for applying changes during recovery - -# - Subscribers - - -# These settings are ignored on a publisher. - -#max_logical_replication_workers = 4 # taken from max_worker_processes - # (change requires restart) -#max_sync_workers_per_subscription = 2 # taken from max_logical_replication_workers -#max_parallel_apply_workers_per_subscription = 2 # taken from max_logical_replication_workers - - -#------------------------------------------------------------------------------ -# QUERY TUNING -#------------------------------------------------------------------------------ - -# - Planner Method Configuration - - -#enable_async_append = on -#enable_bitmapscan = on -#enable_gathermerge = on -#enable_hashagg = on -#enable_hashjoin = on -#enable_incremental_sort = on -#enable_indexscan = on -#enable_indexonlyscan = on -#enable_material = on -#enable_memoize = on -#enable_mergejoin = on -#enable_nestloop = on -#enable_parallel_append = on -#enable_parallel_hash = on -#enable_partition_pruning = on -#enable_partitionwise_join = off -#enable_partitionwise_aggregate = off -#enable_presorted_aggregate = on -#enable_seqscan = on -#enable_sort = on -#enable_tidscan = on - -# - Planner Cost Constants - - -#seq_page_cost = 1.0 # measured on an arbitrary scale -#random_page_cost = 4.0 # same scale as above -#cpu_tuple_cost = 0.01 # same scale as above -#cpu_index_tuple_cost = 0.005 # same scale as above -#cpu_operator_cost = 0.0025 # same scale as above -#parallel_setup_cost = 1000.0 # same scale as above -#parallel_tuple_cost = 0.1 # same scale as above -#min_parallel_table_scan_size = 8MB -#min_parallel_index_scan_size = 512kB -#effective_cache_size = 4GB - -#jit_above_cost = 100000 # perform JIT compilation if available - # and query more expensive than this; - # -1 disables -#jit_inline_above_cost = 500000 # inline small functions if query is - # more expensive than this; -1 disables -#jit_optimize_above_cost = 500000 # use expensive JIT optimizations if - # query is more expensive than this; - # -1 disables - -# - Genetic Query Optimizer - - -#geqo = on -#geqo_threshold = 12 -#geqo_effort = 5 # range 1-10 -#geqo_pool_size = 0 # selects default based on effort -#geqo_generations = 0 # selects default based on effort -#geqo_selection_bias = 2.0 # range 1.5-2.0 -#geqo_seed = 0.0 # range 0.0-1.0 - -# - Other Planner Options - - -#default_statistics_target = 100 # range 1-10000 -#constraint_exclusion = partition # on, off, or partition -#cursor_tuple_fraction = 0.1 # range 0.0-1.0 -#from_collapse_limit = 8 -#jit = on # allow JIT compilation -#join_collapse_limit = 8 # 1 disables collapsing of explicit - # JOIN clauses -#plan_cache_mode = auto # auto, force_generic_plan or - # force_custom_plan -#recursive_worktable_factor = 10.0 # range 0.001-1000000 - - -#------------------------------------------------------------------------------ -# REPORTING AND LOGGING -#------------------------------------------------------------------------------ - -# - Where to Log - - -#log_destination = 'stderr' # Valid values are combinations of - # stderr, csvlog, jsonlog, syslog, and - # eventlog, depending on platform. - # csvlog and jsonlog require - # logging_collector to be on. - -# This is used when logging to stderr: -#logging_collector = off # Enable capturing of stderr, jsonlog, - # and csvlog into log files. Required - # to be on for csvlogs and jsonlogs. - # (change requires restart) - -# These are only used if logging_collector is on: -#log_directory = 'log' # directory where log files are written, - # can be absolute or relative to PGDATA -#log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log' # log file name pattern, - # can include strftime() escapes -#log_file_mode = 0600 # creation mode for log files, - # begin with 0 to use octal notation -#log_rotation_age = 1d # Automatic rotation of logfiles will - # happen after that time. 0 disables. -#log_rotation_size = 10MB # Automatic rotation of logfiles will - # happen after that much log output. - # 0 disables. -#log_truncate_on_rotation = off # If on, an existing log file with the - # same name as the new log file will be - # truncated rather than appended to. - # But such truncation only occurs on - # time-driven rotation, not on restarts - # or size-driven rotation. Default is - # off, meaning append to existing files - # in all cases. - -# These are relevant when logging to syslog: -#syslog_facility = 'LOCAL0' -#syslog_ident = 'postgres' -#syslog_sequence_numbers = on -#syslog_split_messages = on - -# This is only relevant when logging to eventlog (Windows): -# (change requires restart) -#event_source = 'PostgreSQL' - -# - When to Log - - -#log_min_messages = warning # values in order of decreasing detail: - # debug5 - # debug4 - # debug3 - # debug2 - # debug1 - # info - # notice - # warning - # error - # log - # fatal - # panic - -#log_min_error_statement = error # values in order of decreasing detail: - # debug5 - # debug4 - # debug3 - # debug2 - # debug1 - # info - # notice - # warning - # error - # log - # fatal - # panic (effectively off) - -#log_min_duration_statement = -1 # -1 is disabled, 0 logs all statements - # and their durations, > 0 logs only - # statements running at least this number - # of milliseconds - -#log_min_duration_sample = -1 # -1 is disabled, 0 logs a sample of statements - # and their durations, > 0 logs only a sample of - # statements running at least this number - # of milliseconds; - # sample fraction is determined by log_statement_sample_rate - -#log_statement_sample_rate = 1.0 # fraction of logged statements exceeding - # log_min_duration_sample to be logged; - # 1.0 logs all such statements, 0.0 never logs - - -#log_transaction_sample_rate = 0.0 # fraction of transactions whose statements - # are logged regardless of their duration; 1.0 logs all - # statements from all transactions, 0.0 never logs - -#log_startup_progress_interval = 10s # Time between progress updates for - # long-running startup operations. - # 0 disables the feature, > 0 indicates - # the interval in milliseconds. - -# - What to Log - - -#debug_print_parse = off -#debug_print_rewritten = off -#debug_print_plan = off -#debug_pretty_print = on -#log_autovacuum_min_duration = 10min # log autovacuum activity; - # -1 disables, 0 logs all actions and - # their durations, > 0 logs only - # actions running at least this number - # of milliseconds. -#log_checkpoints = on -#log_connections = off -#log_disconnections = off -#log_duration = off -#log_error_verbosity = default # terse, default, or verbose messages -#log_hostname = off -#log_line_prefix = '%m [%p] ' # special values: - # %a = application name - # %u = user name - # %d = database name - # %r = remote host and port - # %h = remote host - # %b = backend type - # %p = process ID - # %P = process ID of parallel group leader - # %t = timestamp without milliseconds - # %m = timestamp with milliseconds - # %n = timestamp with milliseconds (as a Unix epoch) - # %Q = query ID (0 if none or not computed) - # %i = command tag - # %e = SQL state - # %c = session ID - # %l = session line number - # %s = session start timestamp - # %v = virtual transaction ID - # %x = transaction ID (0 if none) - # %q = stop here in non-session - # processes - # %% = '%' - # e.g. '<%u%%%d> ' -#log_lock_waits = off # log lock waits >= deadlock_timeout -#log_recovery_conflict_waits = off # log standby recovery conflict waits - # >= deadlock_timeout -#log_parameter_max_length = -1 # when logging statements, limit logged - # bind-parameter values to N bytes; - # -1 means print in full, 0 disables -#log_parameter_max_length_on_error = 0 # when logging an error, limit logged - # bind-parameter values to N bytes; - # -1 means print in full, 0 disables -#log_statement = 'none' # none, ddl, mod, all -#log_replication_commands = off -#log_temp_files = -1 # log temporary files equal or larger - # than the specified size in kilobytes; - # -1 disables, 0 logs all temp files -#log_timezone = 'GMT' - -# - Process Title - - -#cluster_name = '' # added to process titles if nonempty - # (change requires restart) -#update_process_title = on - - -#------------------------------------------------------------------------------ -# STATISTICS -#------------------------------------------------------------------------------ - -# - Cumulative Query and Index Statistics - - -#track_activities = on -#track_activity_query_size = 1024 # (change requires restart) -#track_counts = on -#track_io_timing = off -#track_wal_io_timing = off -#track_functions = none # none, pl, all -#stats_fetch_consistency = cache - - -# - Monitoring - - -#compute_query_id = auto -#log_statement_stats = off -#log_parser_stats = off -#log_planner_stats = off -#log_executor_stats = off - - -#------------------------------------------------------------------------------ -# AUTOVACUUM -#------------------------------------------------------------------------------ - -#autovacuum = on # Enable autovacuum subprocess? 'on' - # requires track_counts to also be on. -#autovacuum_max_workers = 3 # max number of autovacuum subprocesses - # (change requires restart) -#autovacuum_naptime = 1min # time between autovacuum runs -#autovacuum_vacuum_threshold = 50 # min number of row updates before - # vacuum -#autovacuum_vacuum_insert_threshold = 1000 # min number of row inserts - # before vacuum; -1 disables insert - # vacuums -#autovacuum_analyze_threshold = 50 # min number of row updates before - # analyze -#autovacuum_vacuum_scale_factor = 0.2 # fraction of table size before vacuum -#autovacuum_vacuum_insert_scale_factor = 0.2 # fraction of inserts over table - # size before insert vacuum -#autovacuum_analyze_scale_factor = 0.1 # fraction of table size before analyze -#autovacuum_freeze_max_age = 200000000 # maximum XID age before forced vacuum - # (change requires restart) -#autovacuum_multixact_freeze_max_age = 400000000 # maximum multixact age - # before forced vacuum - # (change requires restart) -#autovacuum_vacuum_cost_delay = 2ms # default vacuum cost delay for - # autovacuum, in milliseconds; - # -1 means use vacuum_cost_delay -#autovacuum_vacuum_cost_limit = -1 # default vacuum cost limit for - # autovacuum, -1 means use - # vacuum_cost_limit - - -#------------------------------------------------------------------------------ -# CLIENT CONNECTION DEFAULTS -#------------------------------------------------------------------------------ - -# - Statement Behavior - - -#client_min_messages = notice # values in order of decreasing detail: - # debug5 - # debug4 - # debug3 - # debug2 - # debug1 - # log - # notice - # warning - # error -#search_path = '"$user", public' # schema names -#row_security = on -#default_table_access_method = 'heap' -#default_tablespace = '' # a tablespace name, '' uses the default -#default_toast_compression = 'pglz' # 'pglz' or 'lz4' -#temp_tablespaces = '' # a list of tablespace names, '' uses - # only default tablespace -#check_function_bodies = on -#default_transaction_isolation = 'read committed' -#default_transaction_read_only = off -#default_transaction_deferrable = off -#session_replication_role = 'origin' -#statement_timeout = 0 # in milliseconds, 0 is disabled -#lock_timeout = 0 # in milliseconds, 0 is disabled -#idle_in_transaction_session_timeout = 0 # in milliseconds, 0 is disabled -#idle_session_timeout = 0 # in milliseconds, 0 is disabled -#vacuum_freeze_table_age = 150000000 -#vacuum_freeze_min_age = 50000000 -#vacuum_failsafe_age = 1600000000 -#vacuum_multixact_freeze_table_age = 150000000 -#vacuum_multixact_freeze_min_age = 5000000 -#vacuum_multixact_failsafe_age = 1600000000 -#bytea_output = 'hex' # hex, escape -#xmlbinary = 'base64' -#xmloption = 'content' -#gin_pending_list_limit = 4MB -#createrole_self_grant = '' # set and/or inherit - -# - Locale and Formatting - - -#datestyle = 'iso, mdy' -#intervalstyle = 'postgres' -#timezone = 'GMT' -#timezone_abbreviations = 'Default' # Select the set of available time zone - # abbreviations. Currently, there are - # Default - # Australia (historical usage) - # India - # You can create your own file in - # share/timezonesets/. -#extra_float_digits = 1 # min -15, max 3; any value >0 actually - # selects precise output mode -#client_encoding = sql_ascii # actually, defaults to database - # encoding - -# These settings are initialized by initdb, but they can be changed. -#lc_messages = 'C' # locale for system error message - # strings -#lc_monetary = 'C' # locale for monetary formatting -#lc_numeric = 'C' # locale for number formatting -#lc_time = 'C' # locale for time formatting - -# default configuration for text search -#default_text_search_config = 'pg_catalog.simple' - -# - Shared Library Preloading - - -#local_preload_libraries = '' -#session_preload_libraries = '' -#shared_preload_libraries = '' # (change requires restart) -#jit_provider = 'llvmjit' # JIT library to use - -# - Other Defaults - - -#dynamic_library_path = '$libdir' -#gin_fuzzy_search_limit = 0 - - -#------------------------------------------------------------------------------ -# LOCK MANAGEMENT -#------------------------------------------------------------------------------ - -#deadlock_timeout = 1s -#max_locks_per_transaction = 64 # min 10 - # (change requires restart) -#max_pred_locks_per_transaction = 64 # min 10 - # (change requires restart) -#max_pred_locks_per_relation = -2 # negative values mean - # (max_pred_locks_per_transaction - # / -max_pred_locks_per_relation) - 1 -#max_pred_locks_per_page = 2 # min 0 - - -#------------------------------------------------------------------------------ -# VERSION AND PLATFORM COMPATIBILITY -#------------------------------------------------------------------------------ - -# - Previous PostgreSQL Versions - - -#array_nulls = on -#backslash_quote = safe_encoding # on, off, or safe_encoding -#escape_string_warning = on -#lo_compat_privileges = off -#quote_all_identifiers = off -#standard_conforming_strings = on -#synchronize_seqscans = on - -# - Other Platforms and Clients - - -#transform_null_equals = off - - -#------------------------------------------------------------------------------ -# ERROR HANDLING -#------------------------------------------------------------------------------ - -#exit_on_error = off # terminate session on any error? -#restart_after_crash = on # reinitialize after backend crash? -#data_sync_retry = off # retry or panic on failure to fsync - # data? - # (change requires restart) -#recovery_init_sync_method = fsync # fsync, syncfs (Linux 5.8+) - - -#------------------------------------------------------------------------------ -# CONFIG FILE INCLUDES -#------------------------------------------------------------------------------ - -# These options allow settings to be loaded from files other than the -# default postgresql.conf. Note that these are directives, not variable -# assignments, so they can usefully be given more than once. - -#include_dir = '...' # include files ending in '.conf' from - # a directory, e.g., 'conf.d' -#include_if_exists = '...' # include file only if it exists -#include = '...' # include file - - -#------------------------------------------------------------------------------ -# CUSTOMIZED OPTIONS -#------------------------------------------------------------------------------ - -# Add settings for extensions here \ No newline at end of file diff --git a/toolset/run-tests.py b/toolset/run-tests.py index 153a2b029bd..ac24969c4e4 100644 --- a/toolset/run-tests.py +++ b/toolset/run-tests.py @@ -10,8 +10,8 @@ from toolset.utils.output_helper import log # Enable cross-platform colored output -from colorama import init, Fore -init() +from colorama import Fore, just_fix_windows_console +just_fix_windows_console() class StoreSeqAction(argparse.Action): @@ -67,6 +67,11 @@ def main(argv=None): ''') # Suite options + # CPU set options + parser.add_argument( + '--cpuset-cpus', + default=None, + help='The cpu set to run framework container on') parser.add_argument( '--audit', action='store_true', @@ -84,6 +89,13 @@ def main(argv=None): help= 'Only print a limited set of messages to stdout, keep the bulk of messages in log files only' ) + parser.add_argument( + '--reverse-order', + action='store_true', + default=False, + help= + 'Run the tests in reverse order, starting with the last test in the list' + ) parser.add_argument( '--results-name', help='Gives a name to this set of results, formatted as a date', @@ -196,6 +208,10 @@ def main(argv=None): nargs='*', default=None, help='Extra docker arguments to be passed to the test container') + parser.add_argument( + '--force-rm', + default=False, + help='Remove intermediate docker containers after running.') # Network options parser.add_argument( diff --git a/toolset/scaffolding/README.md b/toolset/scaffolding/README.md old mode 100755 new mode 100644 diff --git a/toolset/scaffolding/benchmark_config.json b/toolset/scaffolding/benchmark_config.json old mode 100755 new mode 100644 diff --git a/toolset/test_types/__init__.py b/toolset/test_types/__init__.py index 604df6682f7..9b5ea627fd0 100644 --- a/toolset/test_types/__init__.py +++ b/toolset/test_types/__init__.py @@ -1,4 +1,4 @@ -import imp +import importlib import re from glob import glob @@ -14,5 +14,7 @@ # ignore generated __pycache__ folder if test_type_name == '__pycache__': continue - test_type = imp.load_source("TestType", "%s%s.py" % (folder, test_type_name)) + spec = importlib.util.spec_from_file_location("TestType", "%s%s.py" % (folder, test_type_name)) + test_type = importlib.util.module_from_spec(spec) + spec.loader.exec_module(test_type) test_types[test_type_name] = test_type.TestType diff --git a/toolset/test_types/abstract_test_type.py b/toolset/test_types/abstract_test_type.py index c8fc00a3e6b..0f6d5300b7f 100644 --- a/toolset/test_types/abstract_test_type.py +++ b/toolset/test_types/abstract_test_type.py @@ -28,6 +28,7 @@ def __init__(self, self.args = args self.headers = "" self.body = "" + self.status = None if accept_header is None: self.accept_header = self.accept('json') @@ -64,7 +65,7 @@ def parse(self, test_keys): "A %s requires the benchmark_config.json to contain %s" % (self.name, self.args)) - def request_headers_and_body(self, url): + def request_headers_and_body_and_status(self, url): ''' Downloads a URL and returns the HTTP response headers and body content as a tuple @@ -76,7 +77,8 @@ def request_headers_and_body(self, url): self.headers = r.headers self.body = r.content - return self.headers, self.body + self.status = r.status_code + return self.headers, self.body, self.status def output_headers_and_body(self): log(str(self.headers)) diff --git a/toolset/test_types/cached-query/cached-query.py b/toolset/test_types/cached-query/cached-query.py index 83f5302a641..e2cd57d1b7b 100644 --- a/toolset/test_types/cached-query/cached-query.py +++ b/toolset/test_types/cached-query/cached-query.py @@ -1,5 +1,5 @@ from toolset.test_types.abstract_test_type import AbstractTestType -from toolset.test_types.verifications import verify_query_cases +from toolset.test_types.verifications import verify_query_cases, verify_status, verify_headers class TestType(AbstractTestType): @@ -39,6 +39,10 @@ def verify(self, base_url): "Route for cached queries must be at least 15 characters, found '{}' instead".format(self.cached_query_url), url)) + headers, body, status = self.request_headers_and_body_and_status(url) + problems += verify_status(self.request_headers_and_body_and_status, status, url) + problems += verify_headers(self.request_headers_and_body_and_status, headers, url, should_be='json') + if len(problems) == 0: return [('pass', '', url + case) for case, _ in cases] else: diff --git a/toolset/test_types/db/db.py b/toolset/test_types/db/db.py index 065667a19a7..508c1b45b75 100644 --- a/toolset/test_types/db/db.py +++ b/toolset/test_types/db/db.py @@ -1,5 +1,5 @@ from toolset.test_types.abstract_test_type import AbstractTestType -from toolset.test_types.verifications import basic_body_verification, verify_headers, verify_randomnumber_object, verify_queries_count +from toolset.test_types.verifications import basic_body_verification, verify_status, verify_headers, verify_randomnumber_object, verify_queries_count class TestType(AbstractTestType): @@ -28,7 +28,7 @@ def verify(self, base_url): expected_queries = repetitions * concurrency url = base_url + self.db_url - headers, body = self.request_headers_and_body(url) + headers, body, status = self.request_headers_and_body_and_status(url) response, problems = basic_body_verification(body, url) @@ -62,7 +62,8 @@ def verify(self, base_url): # Verify response content problems += verify_randomnumber_object(response, url) - problems += verify_headers(self.request_headers_and_body, headers, url, should_be='json') + problems += verify_status(self.request_headers_and_body_and_status, status, url) + problems += verify_headers(self.request_headers_and_body_and_status, headers, url, should_be='json') if len(problems) == 0: problems += verify_queries_count(self, "World", url, concurrency, repetitions, expected_queries, expected_queries) diff --git a/toolset/test_types/fortune/fortune.py b/toolset/test_types/fortune/fortune.py index 6c42a4665bb..f14b3990c8a 100644 --- a/toolset/test_types/fortune/fortune.py +++ b/toolset/test_types/fortune/fortune.py @@ -30,7 +30,7 @@ def verify(self, base_url): expected_rows = 12 * expected_queries url = base_url + self.fortune_url - headers, body = self.request_headers_and_body(url) + headers, body, status = self.request_headers_and_body_and_status(url) _, problems = basic_body_verification(body, url, is_json_check=False) @@ -49,7 +49,7 @@ def verify(self, base_url): (valid, diff) = parser.isValidFortune(self.name, body.decode()) if valid: - problems += verify_headers(self.request_headers_and_body, headers, url, should_be='html') + problems += verify_headers(self.request_headers_and_body_and_status, headers, url, should_be='html') if len(problems) == 0: problems += verify_queries_count(self, "fortune", url, concurrency, repetitions, expected_queries, expected_rows) if len(problems) == 0: diff --git a/toolset/test_types/fortune/fortune_html_parser.py b/toolset/test_types/fortune/fortune_html_parser.py index c01a5870386..b076b367575 100644 --- a/toolset/test_types/fortune/fortune_html_parser.py +++ b/toolset/test_types/fortune/fortune_html_parser.py @@ -8,8 +8,17 @@ class FortuneHTMLParser(HTMLParser): + IGNORED_TAGS = ( + "", "", + "", "", + "", + "", "", + "", "", + ) + def __init__(self): HTMLParser.__init__(self, convert_charrefs=False) + self.ignore_content = False self.body = [] valid_fortune = ''' @@ -41,7 +50,7 @@ def handle_decl(self, decl): # and since we did not specify xml compliance (where # incorrect casing would throw a syntax error), we must # allow all casings. We will lower for our normalization. - self.body.append("".format(d=decl.lower())) + self.append("".format(d=decl.lower())) def handle_charref(self, name): ''' @@ -63,37 +72,37 @@ def handle_charref(self, name): # equality. if val == "34" or val == "034" or val == "x22": # Append our normalized entity reference to our body. - self.body.append(""") + self.append(""") # "'" is a valid escaping of "-", but it is not # required, so we normalize for equality checking. if val == "39" or val == "039" or val == "x27": - self.body.append("'") + self.append("'") # Again, "+" is a valid escaping of the "+", but # it is not required, so we need to normalize for out # final parse and equality check. if val == "43" or val == "043" or val == "x2b": - self.body.append("+") + self.append("+") # Again, ">" is a valid escaping of ">", but we # need to normalize to ">" for equality checking. if val == "62" or val == "062" or val == "x3e": - self.body.append(">") + self.append(">") # Again, "<" is a valid escaping of "<", but we # need to normalize to "<" for equality checking. if val == "60" or val == "060" or val == "x3c": - self.body.append("<") + self.append("<") # Not sure why some are escaping '/' if val == "47" or val == "047" or val == "x2f": - self.body.append("/") + self.append("/") # "(" is a valid escaping of "(", but # it is not required, so we need to normalize for out # final parse and equality check. if val == "40" or val == "040" or val == "x28": - self.body.append("(") + self.append("(") # ")" is a valid escaping of ")", but # it is not required, so we need to normalize for out # final parse and equality check. if val == "41" or val == "041" or val == "x29": - self.body.append(")") + self.append(")") def handle_entityref(self, name): ''' @@ -101,20 +110,20 @@ def handle_entityref(self, name): need to normalize to "—" for equality checking. ''' if name == "mdash": - self.body.append("—") + self.append("—") else: - self.body.append("&{n};".format(n=name)) + self.append("&{n};".format(n=name)) def handle_starttag(self, tag, attrs): ''' This is called every time a tag is opened. We append each one wrapped in "<" and ">". ''' - self.body.append("<{t}>".format(t=tag)) + self.append("<{t}>".format(t=tag)) # Append a newline after the and if tag.lower() == 'table' or tag.lower() == 'html': - self.body.append(os.linesep) + self.append(os.linesep) def handle_data(self, data): ''' @@ -146,18 +155,24 @@ def handle_data(self, data): data = data.replace('"', '"') data = data.replace('>', '>') - self.body.append("{d}".format(d=data)) + self.append("{d}".format(d=data)) def handle_endtag(self, tag): ''' This is called every time a tag is closed. We append each one wrapped in "". ''' - self.body.append("".format(t=tag)) + self.append("".format(t=tag)) # Append a newline after each and if tag.lower() == 'tr' or tag.lower() == 'head': - self.body.append(os.linesep) + self.append(os.linesep) + + def append(self, item): + self.ignore_content = item == "") + + if not (self.ignore_content or item in self.IGNORED_TAGS): + self.body.append(item) def isValidFortune(self, name, out): ''' diff --git a/toolset/test_types/json/json.py b/toolset/test_types/json/json.py index ebaf0d5fe4a..0c03aa10965 100644 --- a/toolset/test_types/json/json.py +++ b/toolset/test_types/json/json.py @@ -1,5 +1,5 @@ from toolset.test_types.abstract_test_type import AbstractTestType -from toolset.test_types.verifications import basic_body_verification, verify_headers, verify_helloworld_object +from toolset.test_types.verifications import basic_body_verification, verify_status, verify_headers, verify_helloworld_object class TestType(AbstractTestType): def __init__(self, config): @@ -23,7 +23,7 @@ def verify(self, base_url): ''' url = base_url + self.json_url - headers, body = self.request_headers_and_body(url) + headers, body, status = self.request_headers_and_body_and_status(url) response, problems = basic_body_verification(body, url) @@ -38,7 +38,8 @@ def verify(self, base_url): return problems problems += verify_helloworld_object(response, url) - problems += verify_headers(self.request_headers_and_body, headers, url, should_be='json') + problems += verify_status(self.request_headers_and_body_and_status, status, url) + problems += verify_headers(self.request_headers_and_body_and_status, headers, url, should_be='json') if len(problems) > 0: return problems diff --git a/toolset/test_types/plaintext/plaintext.py b/toolset/test_types/plaintext/plaintext.py index c1fa1bbbabf..ed713c4dd10 100644 --- a/toolset/test_types/plaintext/plaintext.py +++ b/toolset/test_types/plaintext/plaintext.py @@ -1,4 +1,4 @@ -from toolset.test_types.verifications import basic_body_verification, verify_headers +from toolset.test_types.verifications import basic_body_verification, verify_status, verify_headers from toolset.test_types.abstract_test_type import AbstractTestType @@ -15,7 +15,7 @@ def __init__(self, config): def verify(self, base_url): url = base_url + self.plaintext_url - headers, body = self.request_headers_and_body(url) + headers, body, status = self.request_headers_and_body_and_status(url) _, problems = basic_body_verification(body, url, is_json_check=False) @@ -45,7 +45,8 @@ def verify(self, base_url): "This may negatively affect benchmark performance." % extra_bytes), url)) - problems += verify_headers(self.request_headers_and_body, headers, url, should_be='plaintext') + problems += verify_status(self.request_headers_and_body_and_status, status, url) + problems += verify_headers(self.request_headers_and_body_and_status, headers, url, should_be='plaintext') if len(problems) == 0: return [('pass', '', url)] diff --git a/toolset/test_types/query/query.py b/toolset/test_types/query/query.py index ebf57d1aa9d..0ae9cd722e3 100644 --- a/toolset/test_types/query/query.py +++ b/toolset/test_types/query/query.py @@ -1,5 +1,5 @@ from toolset.test_types.abstract_test_type import AbstractTestType -from toolset.test_types.verifications import verify_query_cases +from toolset.test_types.verifications import verify_query_cases, verify_status, verify_headers class TestType(AbstractTestType): @@ -39,6 +39,10 @@ def verify(self, base_url): "Route for queries must be at least 9 characters, found '{}' instead".format(self.query_url), url)) + headers, body, status = self.request_headers_and_body_and_status(url) + problems += verify_status(self.request_headers_and_body_and_status, status, url) + problems += verify_headers(self.request_headers_and_body_and_status, headers, url, should_be='json') + if len(problems) == 0: return [('pass', '', url + case) for case, _ in cases] else: diff --git a/toolset/test_types/update/update.py b/toolset/test_types/update/update.py index e904e6c356b..e518c6bfc80 100644 --- a/toolset/test_types/update/update.py +++ b/toolset/test_types/update/update.py @@ -1,5 +1,5 @@ from toolset.test_types.abstract_test_type import AbstractTestType -from toolset.test_types.verifications import verify_query_cases +from toolset.test_types.verifications import verify_query_cases, verify_status, verify_headers class TestType(AbstractTestType): @@ -38,6 +38,10 @@ def verify(self, base_url): "Route for update must be at least 8 characters, found '{}' instead".format(self.update_url), url)) + headers, body, status = self.request_headers_and_body_and_status(url) + problems += verify_status(self.request_headers_and_body_and_status, status, url) + problems += verify_headers(self.request_headers_and_body_and_status, headers, url, should_be='json') + if len(problems) == 0: return [('pass', '', url + case) for (case, _) in cases] else: diff --git a/toolset/test_types/verifications.py b/toolset/test_types/verifications.py index d7c040f0737..19d1e4b900d 100644 --- a/toolset/test_types/verifications.py +++ b/toolset/test_types/verifications.py @@ -41,8 +41,23 @@ def basic_body_verification(body, url, is_json_check=True): # they do not need or expect a dict back return None, [] +def verify_status(request_headers_and_body_and_status, status, url, expected_status=200): + ''' + Verifies the status code of a framework response + ''' + + problems = [] + + if status is not expected_status: + problems.append(( + 'fail', + 'Invalid response status, found \"%s\", did not match \"%s\"' + % (status, expected_status), url)) + + return problems + -def verify_headers(request_headers_and_body, headers, url, should_be='json'): +def verify_headers(request_headers_and_body_and_status, headers, url, should_be='json'): ''' Verifies the headers of a framework response param `should_be` is a switch for the three acceptable content types @@ -76,7 +91,7 @@ def verify_headers(request_headers_and_body, headers, url, should_be='json'): # Verify response content # Make sure that the date object isn't cached sleep(3) - second_headers, body2 = request_headers_and_body(url) + second_headers, body2, status2 = request_headers_and_body_and_status(url) second_date = second_headers.get('Date') date2 = second_headers.get('Date') @@ -311,7 +326,7 @@ def verify_updates(old_worlds, new_worlds, updates_expected, url): return problems -def verify_query_cases(self, cases, url, check_updates=False): +def verify_query_cases(test_instance, cases, url, check_updates=False): ''' The /updates and /queries tests accept a `queries` parameter that is expected to be between 1-500. @@ -337,19 +352,19 @@ def verify_query_cases(self, cases, url, check_updates=False): MIN = 1 # Initialization for query counting repetitions = 1 - concurrency = max(self.config.concurrency_levels) + concurrency = max(test_instance.config.concurrency_levels) expected_queries = 20 * repetitions * concurrency expected_rows = expected_queries # Only load in the World table if we are doing an Update verification world_db_before = {} if check_updates: - world_db_before = databases[self.database.lower()].get_current_world_table(self.config) + world_db_before = databases[test_instance.database.lower()].get_current_world_table(test_instance.config) expected_queries = expected_queries + concurrency * repetitions # eventually bulk updates! for q, max_infraction in cases: case_url = url + q - headers, body = self.request_headers_and_body(case_url) + headers, body, status = test_instance.request_headers_and_body_and_status(case_url) try: queries = int(q) # drops down for 'foo' and '' @@ -363,14 +378,14 @@ def verify_query_cases(self, cases, url, check_updates=False): problems += verify_randomnumber_list(expected_len, headers, body, case_url, max_infraction) - problems += verify_headers(self.request_headers_and_body, headers, case_url) + problems += verify_headers(test_instance.request_headers_and_body_and_status, headers, case_url) # Only check update changes if we are doing an Update verification and if we're testing # the highest number of queries, to ensure that we don't accidentally FAIL for a query # that only updates 1 item and happens to set its randomNumber to the same value it # previously held if check_updates and queries >= MAX: - world_db_after = databases[self.database.lower()].get_current_world_table(self.config) + world_db_after = databases[test_instance.database.lower()].get_current_world_table(test_instance.config) problems += verify_updates(world_db_before, world_db_after, MAX, case_url) @@ -393,16 +408,16 @@ def verify_query_cases(self, cases, url, check_updates=False): # parameter input problems += verify_randomnumber_list( expected_len, headers, body, case_url, max_infraction) - problems += verify_headers(self.request_headers_and_body, headers, case_url) + problems += verify_headers(test_instance.request_headers_and_body_and_status, headers, case_url) - if hasattr(self, 'database'): + if hasattr(test_instance, 'database'): # verify the number of queries and rows read for 20 queries, with a concurrency level of 512, with 2 repetitions - problems += verify_queries_count(self, "world", url + "20", concurrency, repetitions, expected_queries, + problems += verify_queries_count(test_instance, "world", url + "20", concurrency, repetitions, expected_queries, expected_rows, check_updates) return problems -def verify_queries_count(self, tbl_name, url, concurrency=512, count=2, expected_queries=1024, expected_rows=1024, +def verify_queries_count(test_instance, tbl_name, url, concurrency=512, count=2, expected_queries=1024, expected_rows=1024, check_updates=False): ''' Checks that the number of executed queries, at the given concurrency level, @@ -416,20 +431,20 @@ def verify_queries_count(self, tbl_name, url, concurrency=512, count=2, expected problems = [] - queries, rows, rows_updated, margin, trans_failures = databases[self.database.lower()].verify_queries(self.config, - tbl_name, url, - concurrency, - count, - check_updates) + queries, rows, rows_updated, margin, trans_failures = databases[test_instance.database.lower()].verify_queries(test_instance.config, + tbl_name, url, + concurrency, + count, + check_updates) isBulk = check_updates and (queries < 1.001 * expected_queries) and (queries > 0.999 * expected_queries) if check_updates and not isBulk: # Restore the normal queries number if bulk queries are not used expected_queries = (expected_queries - count * concurrency) * 2 - # Add a margin based on the number of cpu cores - queries_margin = 1.015 # For a run on Travis - if multiprocessing.cpu_count() > 2: + # Add a margin based on whether we're running in a CI environment + queries_margin = 1.015 # For a run in CI environment + if not test_instance.config.is_ci: queries_margin = 1 # real run (Citrine or Azure) -> no margin on queries # Check for transactions failures (socket errors...) if trans_failures > 0: diff --git a/toolset/utils/__init__.py b/toolset/utils/__init__.py old mode 100755 new mode 100644 diff --git a/toolset/utils/benchmark_config.py b/toolset/utils/benchmark_config.py old mode 100755 new mode 100644 index a64ca87af4f..d73dcb4125c --- a/toolset/utils/benchmark_config.py +++ b/toolset/utils/benchmark_config.py @@ -22,9 +22,12 @@ def __init__(self, args): else: self.types = {t: types[t] for t in args.type} + # Check if we're running in a CI environment + self.is_ci = os.getenv('CI') self.duration = args.duration self.exclude = args.exclude self.quiet = args.quiet + self.reverse_order = args.reverse_order self.server_host = args.server_host self.database_host = args.database_host self.client_host = args.client_host @@ -51,8 +54,10 @@ def __init__(self, args): self.database_docker_host = None self.client_docker_host = None self.network = None + self.cpuset_cpus = args.cpuset_cpus self.test_container_memory = args.test_container_memory self.extra_docker_runtime_args = args.extra_docker_runtime_args + self.force_rm_intermediate_docker_layers = args.force_rm if self.network_mode is None: self.network = 'tfb' diff --git a/toolset/utils/docker_helper.py b/toolset/utils/docker_helper.py index c58bb71d6a2..f25a9d133a0 100644 --- a/toolset/utils/docker_helper.py +++ b/toolset/utils/docker_helper.py @@ -39,7 +39,7 @@ def __build(self, base_url, path, build_log_file, log_prefix, dockerfile, path=path, dockerfile=dockerfile, tag=tag, - forcerm=True, + forcerm=self.benchmarker.config.force_rm_intermediate_docker_layers, timeout=3600, pull=True, buildargs=buildargs, @@ -189,6 +189,13 @@ def watch_container(docker_container, docker_file): 'soft': 99 }] + cpuset_cpus = '' + + if self.benchmarker.config.cpuset_cpus is not None: + cpuset_cpus = self.benchmarker.config.cpuset_cpus + + log("Running docker container with cpu set: %s" %cpuset_cpus) + docker_cmd = '' if hasattr(test, 'docker_cmd'): docker_cmd = test.docker_cmd @@ -235,6 +242,7 @@ def watch_container(docker_container, docker_file): sysctls=sysctl, remove=True, log_config={'type': None}, + cpuset_cpus=cpuset_cpus, **extra_docker_args ) @@ -412,16 +420,11 @@ def server_container_exists(self, container_id_or_name): except: return False - def benchmark(self, script, variables, raw_file): + def benchmark(self, script, variables): ''' Runs the given remote_script on the wrk container on the client machine. ''' - def watch_container(container): - with open(raw_file, 'w') as benchmark_file: - for line in container.logs(stream=True): - log(line.decode(), file=benchmark_file) - if self.benchmarker.config.network_mode is None: sysctl = {'net.core.somaxconn': 65535} else: @@ -430,8 +433,7 @@ def watch_container(container): ulimit = [{'name': 'nofile', 'hard': 65535, 'soft': 65535}] - watch_container( - self.client.containers.run( + return self.client.containers.run( "techempower/tfb.wrk", "/bin/bash /%s" % script, environment=variables, @@ -442,4 +444,4 @@ def watch_container(container): ulimits=ulimit, sysctls=sysctl, remove=True, - log_config={'type': None})) + log_config={'type': None}) diff --git a/toolset/utils/metadata.py b/toolset/utils/metadata.py index 6e440fc23ab..6f7388828b8 100644 --- a/toolset/utils/metadata.py +++ b/toolset/utils/metadata.py @@ -191,6 +191,18 @@ def parse_config(self, config, directory): % config['framework'], color=Fore.YELLOW) + # 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)) + if len(non_broken_tests_to_run) > maximum_tests: + message = [ + "Framework %s defines %s tests in benchmark_config.json (max is %s)." + % (config['framework'], len(non_broken_tests_to_run), maximum_tests), + "Contact maintainers and remove deprecated or discarded ones to make room." + ] + log("\n".join(message), color=Fore.YELLOW) + # Check that each test configuration is acceptable # Throw exceptions if a field is missing, or how to improve the field for test_name, test_keys in test.items(): diff --git a/toolset/utils/output_helper.py b/toolset/utils/output_helper.py old mode 100755 new mode 100644 diff --git a/toolset/utils/results.py b/toolset/utils/results.py index 7b745a90bc0..0df26636404 100644 --- a/toolset/utils/results.py +++ b/toolset/utils/results.py @@ -212,29 +212,34 @@ def load(self): except (ValueError, IOError): pass + def __make_dir_for_file(self, test_name: str, test_type: str, file_name: str): + path = os.path.join(self.directory, test_name, test_type, file_name) + try: + os.makedirs(os.path.dirname(path), exist_ok=True) + except OSError: + pass + return path + + def get_docker_stats_file(self, test_name, test_type): + ''' + Returns the stats file name for this test_name and + Example: fw_root/results/timestamp/test_type/test_name/stats.txt + ''' + return self.__make_dir_for_file(test_name, test_type, "docker_stats.json") + def get_raw_file(self, test_name, test_type): ''' Returns the output file for this test_name and test_type Example: fw_root/results/timestamp/test_type/test_name/raw.txt ''' - path = os.path.join(self.directory, test_name, test_type, "raw.txt") - try: - os.makedirs(os.path.dirname(path)) - except OSError: - pass - return path + return self.__make_dir_for_file(test_name, test_type, "raw.txt") def get_stats_file(self, test_name, test_type): ''' Returns the stats file name for this test_name and Example: fw_root/results/timestamp/test_type/test_name/stats.txt ''' - path = os.path.join(self.directory, test_name, test_type, "stats.txt") - try: - os.makedirs(os.path.dirname(path)) - except OSError: - pass - return path + return self.__make_dir_for_file(test_name, test_type, "stats.txt") def report_verify_results(self, framework_test, test_type, result): ''' diff --git a/toolset/utils/scaffolding.py b/toolset/utils/scaffolding.py old mode 100755 new mode 100644 index 9eceb57e122..ec866e5bc76 --- a/toolset/utils/scaffolding.py +++ b/toolset/utils/scaffolding.py @@ -8,7 +8,7 @@ class Scaffolding: def __init__(self, benchmarker): print(""" ------------------------------------------------------------------------------- - This wizard is intended to help build the scaffolding required for a new + This wizard is intended to help build the scaffolding required for a new test to be benchmarked. From here, you will be prompted for values related to the test you @@ -87,12 +87,12 @@ def __prompt_language(self): print(""" That language is not currently in our list of known languages. - + Here is a list of similar languages present in our benchmark suite that you may have meant: %s - + Did you mean to add the new language, '%s', to the benchmark suite? """ % (similar, self.language)) valid = self.__prompt_confirm_new_language() @@ -115,8 +115,8 @@ def __gather_approach(self): print(""" The approach of your test implementation. - 1) Realistic: Uses the framework with most out-of-the-box functionality - enabled. We consider this realistic because most applications + 1) Realistic: Uses the framework with most out-of-the-box functionality + enabled. We consider this realistic because most applications built with the framework will leave these features enabled. 2) Stripped: Removes or outright avoids implementing features that are unnecessary for the particulars of the benchmark exercise. This @@ -143,14 +143,14 @@ def __gather_classification(self): print(""" The classification of your test implementation. - 1) Fullstack: Robust framework expected to provide high-level functionality - for serving as a web application; for example, ability to - compose views, provide functions for responding with several - data types (json, html, etc), connecting to a database, form + 1) Fullstack: Robust framework expected to provide high-level functionality + for serving as a web application; for example, ability to + compose views, provide functions for responding with several + data types (json, html, etc), connecting to a database, form processing, etc. 2) Micro: Simple framework expected to provide enough middleware to build - a robust web application such as request routing and some - simple plumbing, but may not include built-in functionality + a robust web application such as request routing and some + simple plumbing, but may not include built-in functionality such as, for example, server-composed views. 3) Platform: Barebones infrastructure for servicing HTTP requests, but does not include a framework at all. @@ -181,7 +181,7 @@ def __gather_platform(self): print(""" The platform of your test implementation. - The platform is the low-level software or API used to host web applications + The platform is the low-level software or API used to host web applications for the framework; the platform provides an implementation of the HTTP fundamentals. @@ -233,11 +233,11 @@ def __gather_orm(self): print(""" How you would classify the ORM (object relational mapper) of your test? - 1) Full: A feature-rich ORM which provides functionality for interacting - with a database without writing a query in all but the most edge + 1) Full: A feature-rich ORM which provides functionality for interacting + with a database without writing a query in all but the most edge cases. 2) Micro: An ORM which provides functionality for interacting with a database - for many trivial operations (querying, updating), but not more + for many trivial operations (querying, updating), but not more robust cases (for example, gathering relations). 3) Raw: No ORM; raw database access. """) @@ -277,9 +277,9 @@ def __gather_versus(self): print(""" The name of another test (elsewhere in this project) that is a subset of this framework. - This allows for the generation of the framework efficiency chart in the + This allows for the generation of the framework efficiency chart in the results web site. - For example, Compojure is compared to "servlet" since Compojure is built on + For example, Compojure is compared to "servlet" since Compojure is built on the Servlet platform. Example: Servlet, Wai, Undertow @@ -344,31 +344,31 @@ def __copy_scaffold_files(self): def __edit_scaffold_files(self): for file in os.listdir(os.path.join(self.test_dir)): self.__replace_text( - os.path.join(self.test_dir, file), "\$NAME", self.name) + os.path.join(self.test_dir, file), r'\$NAME', self.name) self.__replace_text( - os.path.join(self.test_dir, file), "\$DISPLAY_NAME", + os.path.join(self.test_dir, file), r'\$DISPLAY_NAME', self.display_name) self.__replace_text( - os.path.join(self.test_dir, file), "\$APPROACH", self.approach) + os.path.join(self.test_dir, file), r'\$APPROACH', self.approach) self.__replace_text( - os.path.join(self.test_dir, file), "\$CLASSIFICATION", + os.path.join(self.test_dir, file), r'\$CLASSIFICATION', self.classification) self.__replace_text( - os.path.join(self.test_dir, file), "\$FRAMEWORK", + os.path.join(self.test_dir, file), r'\$FRAMEWORK', self.framework) self.__replace_text( - os.path.join(self.test_dir, file), "\$LANGUAGE", self.language) + os.path.join(self.test_dir, file), r'\$LANGUAGE', self.language) self.__replace_text( - os.path.join(self.test_dir, file), "\$DATABASE", self.database) + os.path.join(self.test_dir, file), r'\$DATABASE', self.database) self.__replace_text( - os.path.join(self.test_dir, file), "\$ORM", self.orm) + os.path.join(self.test_dir, file), r'\$ORM', self.orm) self.__replace_text( - os.path.join(self.test_dir, file), "\$PLATFORM", self.platform) + os.path.join(self.test_dir, file), r'\$PLATFORM', self.platform) self.__replace_text( - os.path.join(self.test_dir, file), "\$WEBSERVER", + os.path.join(self.test_dir, file), r'\$WEBSERVER', self.webserver) self.__replace_text( - os.path.join(self.test_dir, file), "\$VERSUS", self.versus) + os.path.join(self.test_dir, file), r'\$VERSUS', self.versus) def __print_success(self): print(""" diff --git a/toolset/wrk/concurrency.sh b/toolset/wrk/concurrency.sh old mode 100644 new mode 100755 diff --git a/toolset/wrk/pipeline.sh b/toolset/wrk/pipeline.sh old mode 100644 new mode 100755 diff --git a/toolset/wrk/query.sh b/toolset/wrk/query.sh old mode 100644 new mode 100755 diff --git a/toolset/wrk/wrk.dockerfile b/toolset/wrk/wrk.dockerfile index 01d7d4ae579..772fe3268fa 100644 --- a/toolset/wrk/wrk.dockerfile +++ b/toolset/wrk/wrk.dockerfile @@ -1,14 +1,10 @@ -FROM ubuntu:22.04 +FROM ubuntu:24.04 # Required scripts for benchmarking COPY concurrency.sh pipeline.lua pipeline.sh query.sh ./ ARG DEBIAN_FRONTEND=noninteractive -RUN apt-get -yqq update >/dev/null && \ - apt-get -yqq install >/dev/null \ - curl \ - wrk && \ - chmod 777 concurrency.sh pipeline.sh query.sh +RUN apt-get install --no-install-recommends -qqUy curl wrk > /dev/null # Environment vars required by the wrk scripts with nonsense defaults ENV accept=accept \